From 3e80fa3dbc943de9b784fedc202ba38cf238f46d Mon Sep 17 00:00:00 2001 From: David Parks Date: Mon, 2 Nov 2009 19:55:37 +0000 Subject: Sync up with render-pipeline-7 ignore-dead-branch --- indra/cmake/00-Common.cmake | 5 +- indra/cmake/LLPrimitive.cmake | 22 +- indra/llcommon/llassettype.cpp | 1 + indra/llcommon/llassettype.h | 6 +- indra/llcommon/llthread.cpp | 2 +- indra/llcommon/stdenums.h | 3 +- indra/llinventory/llinventorytype.cpp | 7 +- indra/llinventory/llinventorytype.h | 3 +- indra/llmath/llvolume.cpp | 350 ++++++++++- indra/llmath/llvolume.h | 22 +- indra/llmath/llvolumemgr.cpp | 2 +- indra/llmath/m4math.cpp | 11 + indra/llmath/m4math.h | 1 + indra/llmath/v2math.cpp | 15 + indra/llmath/v2math.h | 3 + indra/llmessage/llassetstorage.cpp | 2 +- indra/llmessage/lltransfermanager.cpp | 2 +- indra/llmessage/lltransfersourceasset.cpp | 2 + indra/llprimitive/CMakeLists.txt | 4 + indra/llprimitive/llprimitive.cpp | 15 +- indra/llprimitive/llprimitive.h | 2 +- indra/llvfs/llvfile.cpp | 2 +- indra/llvfs/llvfs.cpp | 3 + indra/newview/CMakeLists.txt | 10 + indra/newview/app_settings/settings.xml | 14 +- .../shaders/class2/deferred/multiSpotLightF.glsl | 2 +- .../shaders/class2/deferred/sunLightF.glsl | 4 +- indra/newview/licenses-win32.txt | 69 +++ indra/newview/llassetuploadresponders.cpp | 661 +++++++++++++++++---- indra/newview/llassetuploadresponders.h | 51 +- indra/newview/lldrawable.h | 6 +- indra/newview/lldrawpoolbump.cpp | 12 + indra/newview/lldrawpoolbump.h | 2 +- indra/newview/llface.cpp | 2 +- indra/newview/llfilepicker.cpp | 5 + indra/newview/llfilepicker.h | 3 + indra/newview/llfloaterinventory.cpp | 3 + indra/newview/llhudtext.cpp | 12 + indra/newview/llhudtext.h | 1 + indra/newview/llinventorybridge.cpp | 94 ++- indra/newview/llinventorybridge.h | 35 +- indra/newview/llpanelgroupnotices.cpp | 1 + indra/newview/llselectmgr.cpp | 80 ++- indra/newview/llselectmgr.h | 1 + indra/newview/llspatialpartition.cpp | 1 - indra/newview/llspatialpartition.h | 1 + indra/newview/lltexturectrl.cpp | 6 +- indra/newview/lltooldraganddrop.cpp | 11 + indra/newview/llviewerdisplay.cpp | 8 +- indra/newview/llviewerfloaterreg.cpp | 4 +- indra/newview/llviewermenu.cpp | 2 +- indra/newview/llviewermenufile.cpp | 330 +++++++--- indra/newview/llviewermenufile.h | 77 ++- indra/newview/llviewermessage.cpp | 1 + indra/newview/llviewerregion.cpp | 2 + indra/newview/llviewertexteditor.cpp | 1 + indra/newview/llviewertexture.cpp | 2 +- indra/newview/llviewerwindow.cpp | 134 ----- indra/newview/llvovolume.cpp | 183 +++++- indra/newview/llvovolume.h | 9 + indra/newview/pipeline.cpp | 241 +++++++- indra/newview/pipeline.h | 33 + indra/newview/skins/default/textures/textures.xml | 2 + .../newview/skins/default/xui/en/floater_about.xml | 3 + .../skins/default/xui/en/floater_inventory.xml | 10 + .../newview/skins/default/xui/en/floater_tools.xml | 3 + indra/newview/skins/default/xui/en/menu_viewer.xml | 4 +- .../newview/skins/default/xui/en/notifications.xml | 25 +- indra/newview/skins/default/xui/en/strings.xml | 1 + indra/newview/viewer_manifest.py | 6 + install.xml | 166 ++++++ 71 files changed, 2351 insertions(+), 468 deletions(-) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 173e650961..3bd10ea9ee 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -49,11 +49,12 @@ if (WINDOWS) add_definitions( /DLL_WINDOWS=1 + /DDOM_DYNAMIC /DUNICODE /D_UNICODE /GS /TP - /W3 + /W2 /c /Zc:forScope /nologo @@ -195,7 +196,7 @@ endif (DARWIN) if (LINUX OR DARWIN) - set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-non-virtual-dtor -Woverloaded-virtual") + set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-non-virtual-dtor") if (NOT GCC_DISABLE_FATAL_WARNINGS) set(GCC_WARNINGS "${GCC_WARNINGS} -Werror") diff --git a/indra/cmake/LLPrimitive.cmake b/indra/cmake/LLPrimitive.cmake index d397b78f1c..9f8d99a0bf 100644 --- a/indra/cmake/LLPrimitive.cmake +++ b/indra/cmake/LLPrimitive.cmake @@ -1,7 +1,27 @@ # -*- cmake -*- +# these should be moved to their own cmake file +include(Prebuilt) +use_prebuilt_binary(colladadom) +use_prebuilt_binary(pcre) +use_prebuilt_binary(libxml) + set(LLPRIMITIVE_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llprimitive ) -set(LLPRIMITIVE_LIBRARIES llprimitive) +if (WINDOWS) + set(LLPRIMITIVE_LIBRARIES + llprimitive + libcollada14dom21 + ) +else (WINDOWS) + set(LLPRIMITIVE_LIBRARIES + llprimitive + collada14dom + xml2 + pcrecpp + pcre + ) +endif (WINDOWS) + diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 0b016b81fb..d57494b444 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -107,6 +107,7 @@ LLAssetDictionary::LLAssetDictionary() addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "symbolic link", "Link", DAD_LINK, FALSE, TRUE)); addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "symbolic folder link", "New Folder", DAD_LINK, FALSE, TRUE)); + addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", "Meshes", DAD_MESH, FALSE, TRUE)); for (S32 ensemble_num = S32(LLAssetType::AT_FOLDER_ENSEMBLE_START); ensemble_num <= S32(LLAssetType::AT_FOLDER_ENSEMBLE_END); diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 5e51188541..a1154d16e3 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -147,9 +147,11 @@ public: AT_MY_OUTFITS = 48, // Folder that holds your outfits. + + AT_MESH = 49, + // Mesh data in our proprietary SLM format - - AT_COUNT = 49, + AT_COUNT = 50, // +*********************************************************+ // | TO ADD AN ELEMENT TO THIS ENUM: | // +*********************************************************+ diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 920d8c0977..e3906bc86e 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -75,7 +75,7 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap // Run the user supplied function threadp->run(); - llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl; + //llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl; // We're done with the run function, this thread is done executing now. threadp->mStatus = STOPPED; diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h index 1a5678dde1..6eead924da 100644 --- a/indra/llcommon/stdenums.h +++ b/indra/llcommon/stdenums.h @@ -55,7 +55,8 @@ enum EDragAndDropType DAD_ANIMATION = 12, DAD_GESTURE = 13, DAD_LINK = 14, - DAD_COUNT = 15, // number of types in this enum + DAD_MESH = 15, + DAD_COUNT = 16, // number of types in this enum }; // Reasons for drags to be denied. diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp index a445466b26..ae3cb2697b 100644 --- a/indra/llinventory/llinventorytype.cpp +++ b/indra/llinventory/llinventorytype.cpp @@ -96,7 +96,9 @@ LLInventoryDictionary::LLInventoryDictionary() addEntry(LLInventoryType::IT_WEARABLE, new InventoryEntry("wearable", "wearable", 2, LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART)); addEntry(LLInventoryType::IT_ANIMATION, new InventoryEntry("animation", "animation", 1, LLAssetType::AT_ANIMATION)); addEntry(LLInventoryType::IT_GESTURE, new InventoryEntry("gesture", "gesture", 1, LLAssetType::AT_GESTURE)); - addEntry(LLInventoryType::IT_FAVORITE, new InventoryEntry("favorite", "favorite", 1, LLAssetType::AT_FAVORITE)); + addEntry(LLInventoryType::IT_FAVORITE, new InventoryEntry("favorite", "favorite", 1, LLAssetType::AT_FAVORITE)); + addEntry(LLInventoryType::IT_MESH, new InventoryEntry("mesh", "mesh", 1, LLAssetType::AT_MESH)); + } @@ -132,7 +134,7 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] = LLInventoryType::IT_NONE, // AT_LINK LLInventoryType::IT_NONE, // AT_LINK_FOLDER - + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE @@ -157,6 +159,7 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] = LLInventoryType::IT_CATEGORY, // AT_CURRENT_OUTFIT LLInventoryType::IT_CATEGORY, // AT_OUTFIT LLInventoryType::IT_CATEGORY, // AT_MY_OUTFITS + LLInventoryType::IT_MESH, // AT_MESH }; // static diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h index 14b28bfe4b..0d580d3000 100644 --- a/indra/llinventory/llinventorytype.h +++ b/indra/llinventory/llinventorytype.h @@ -68,7 +68,8 @@ public: IT_ANIMATION = 19, IT_GESTURE = 20, IT_FAVORITE = 21, - IT_COUNT = 22, + IT_MESH = 22, + IT_COUNT = 23, IT_NONE = -1 }; diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index b8ef92f9a9..afa82ed399 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -46,6 +46,9 @@ #include "lldarray.h" #include "llvolume.h" #include "llstl.h" +#include "llsdserialize.h" +#include "zlib/zlib.h" + #define DEBUG_SILHOUETTE_BINORMALS 0 #define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette @@ -1688,7 +1691,7 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mGenerateSingleFace = generate_single_face; generate(); - if (mParams.getSculptID().isNull()) + if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE) { createVolumeFaces(); } @@ -1839,6 +1842,295 @@ BOOL LLVolume::generate() return FALSE; } +bool LLVolumeFace::VertexData::operator<(const LLVolumeFace::VertexData& rhs)const +{ + const U8* l = (const U8*) this; + const U8* r = (const U8*) &rhs; + + for (U32 i = 0; i < sizeof(VertexData); ++i) + { + if (l[i] != r[i]) + { + return r[i] < l[i]; + } + } + + return false; +} + +bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const +{ + const U8* l = (const U8*) this; + const U8* r = (const U8*) &rhs; + + for (U32 i = 0; i < sizeof(VertexData); ++i) + { + if (l[i] != r[i]) + { + return false; + } + } + + return true; +} + + +BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name) +{ + std::ifstream is; + + is.open(file_name.c_str(), std::ifstream::in | std::ifstream::binary); + + BOOL success = createVolumeFacesFromStream(is); + + is.close(); + + return success; +} + +BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) +{ + mSculptLevel = -1; // default is an error occured + + LLSD header; + { + if (!LLSDSerialize::deserialize(header, is, 1024*1024*1024)) + { + llwarns << "not a valid mesh asset!" << llendl; + return FALSE; + } + } + + std::string nm[] = + { + "impostor", + "low_lod", + "medium_lod", + "high_lod" + }; + + S32 lod = llclamp((S32) mDetail, 0, 3); + + while (lod < 4 && header[nm[lod]]["offset"].asInteger() == -1) + { + ++lod; + } + + if (lod >= 4) + { + llwarns << "Couldn't load model for given lod" << llendl; + return FALSE; + } + + is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur); + + + U8* result = NULL; + U32 cur_size = 0; + + { + //input stream is now pointing at a zlib compressed block of LLSD + //decompress block + z_stream strm; + + const U32 CHUNK = 65536; + + S32 size = header[nm[lod]]["size"].asInteger(); + U8 *in = new U8[size]; + is.read((char*) in, size); + + U8 out[CHUNK]; + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = size; + strm.next_in = in; + + S32 ret = inflateInit(&strm); + + if (ret != Z_OK) + { + llerrs << "WTF?" << llendl; + } + + do + { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR) + { + inflateEnd(&strm); + free(result); + delete [] in; + return FALSE; + } + + switch (ret) + { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&strm); + free(result); + delete [] in; + return FALSE; + break; + } + + U32 have = CHUNK-strm.avail_out; + + result = (U8*) realloc(result, cur_size + have); + memcpy(result+cur_size, out, have); + cur_size += have; + + } while (strm.avail_out == 0); + + inflateEnd(&strm); + delete [] in; + + if (ret != Z_STREAM_END) + { + free(result); + return FALSE; + } + } + + //result now points to the decompressed LLSD block + + LLSD mdl; + + { + std::string res_str((char*) result, cur_size); + std::istringstream istr(res_str); + + if (!LLSDSerialize::deserialize(mdl, istr, cur_size)) + { + llwarns << "not a valid mesh asset!" << llendl; + return FALSE; + } + } + + + free(result); + + + { + U32 face_count = mdl.size(); + + mVolumeFaces.resize(face_count); + + for (U32 i = 0; i < face_count; ++i) + { + LLSD::Binary pos = mdl[i]["Position"]; + LLSD::Binary norm = mdl[i]["Normal"]; + LLSD::Binary tc = mdl[i]["TexCoord0"]; + LLSD::Binary idx = mdl[i]["TriangleList"]; + + LLVolumeFace& face = mVolumeFaces[i]; + + face.mHasBinormals = FALSE; + + //copy out indices + face.mIndices.resize(idx.size()/2); + if (idx.empty()) + { //why is there an empty index list? + continue; + } + + U16* indices = (U16*) &(idx[0]); + for (U32 j = 0; j < idx.size()/2; ++j) + { + face.mIndices[j] = indices[j]; + } + + //copy out vertices + U32 num_verts = pos.size()/(3*2); + face.mVertices.resize(num_verts); + + LLVector3 min_pos; + LLVector3 max_pos; + LLVector2 min_tc; + LLVector2 max_tc; + + min_pos.setValue(mdl[i]["PositionDomain"]["Min"]); + max_pos.setValue(mdl[i]["PositionDomain"]["Max"]); + min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]); + max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]); + + F32 scale = llclamp((F32) mdl[i]["Scale"].asReal(), 1.f, 10.f); + + LLVector3 pos_range = max_pos - min_pos; + LLVector2 tc_range = max_tc - min_tc; + + LLVector3& min = face.mExtents[0]; + LLVector3& max = face.mExtents[1]; + + min = max = LLVector3(0,0,0); + + for (U32 j = 0; j < num_verts; ++j) + { + U16* v = (U16*) &(pos[j*3*2]); + + face.mVertices[j].mPosition.setVec( + (F32) v[0] / 65535.f * pos_range.mV[0] + min_pos.mV[0], + (F32) v[1] / 65535.f * pos_range.mV[1] + min_pos.mV[1], + (F32) v[2] / 65535.f * pos_range.mV[2] + min_pos.mV[2]); + + face.mVertices[j].mPosition *= scale; + + if (j == 0) + { + min = max = face.mVertices[j].mPosition; + } + else + { + update_min_max(min,max,face.mVertices[j].mPosition); + } + + U16* n = (U16*) &(norm[j*3*2]); + + face.mVertices[j].mNormal.setVec( + (F32) n[0] / 65535.f * 2.f - 1.f, + (F32) n[1] / 65535.f * 2.f - 1.f, + (F32) n[2] / 65535.f * 2.f - 1.f); + + U16* t = (U16*) &(tc[j*2*2]); + + face.mVertices[j].mTexCoord.setVec( + (F32) t[0] / 65535.f * tc_range.mV[0] + min_tc.mV[0], + (F32) t[1] / 65535.f * tc_range.mV[1] + min_tc.mV[1]); + } + + } + } + + mSculptLevel = 0; // success! + return TRUE; +} + +void LLVolume::copyVolumeFaces(LLVolume* volume) +{ + mVolumeFaces = volume->mVolumeFaces; + mSculptLevel = 0; +} + +S32 const LL_SCULPT_MESH_MAX_FACES = 8; + +S32 LLVolume::getNumFaces() const +{ + U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK); + + if (sculpt_type == LL_SCULPT_TYPE_MESH) + { + return LL_SCULPT_MESH_MAX_FACES; + } + + return (S32)mProfilep->mFaces.size(); +} + void LLVolume::createVolumeFaces() { @@ -1864,6 +2156,11 @@ void LLVolume::createVolumeFaces() LLProfile::Face& face = mProfilep->mFaces[i]; vf.mBeginS = face.mIndex; vf.mNumS = face.mCount; + if (vf.mNumS < 0) + { + llerrs << "Volume face corruption detected." << llendl; + } + vf.mBeginT = 0; vf.mNumT= getPath().mPath.size(); vf.mID = i; @@ -1907,6 +2204,10 @@ void LLVolume::createVolumeFaces() if (face.mFlat && vf.mNumS > 2) { //flat inner faces have to copy vert normals vf.mNumS = vf.mNumS*2; + if (vf.mNumS < 0) + { + llerrs << "Volume face corruption detected." << llendl; + } } } else @@ -2309,7 +2610,6 @@ bool LLVolumeParams::operator<(const LLVolumeParams ¶ms) const return mSculptID < params.mSculptID; } - return mSculptType < params.mSculptType; @@ -3379,22 +3679,29 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, S32 face_mask) { LLMemType m1(LLMemType::MTYPE_VOLUME); - + vertices.clear(); normals.clear(); segments.clear(); + if (mParams.getSculptType() == LL_SCULPT_TYPE_MESH) + { + return; + } + S32 cur_index = 0; //for each face for (face_list_t::iterator iter = mVolumeFaces.begin(); iter != mVolumeFaces.end(); ++iter) { - const LLVolumeFace& face = *iter; + LLVolumeFace& face = *iter; - if (!(face_mask & (0x1 << cur_index++))) + if (!(face_mask & (0x1 << cur_index++)) || + face.mIndices.empty() || face.mEdge.empty()) { continue; } + if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) { } @@ -3594,6 +3901,8 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, F32 closest_t = 2.f; // must be larger than 1 + end_face = llmin(end_face, getNumVolumeFaces()-1); + for (S32 i = start_face; i <= end_face; i++) { const LLVolumeFace &face = getVolumeFace((U32)i); @@ -4103,11 +4412,28 @@ BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const return TRUE; } +LLSD LLVolumeParams::sculptAsLLSD() const +{ + LLSD sd = LLSD(); + sd["id"] = getSculptID(); + sd["type"] = getSculptType(); + + return sd; +} + +bool LLVolumeParams::sculptFromLLSD(LLSD& sd) +{ + setSculptID(sd["id"].asUUID(), (U8)sd["type"].asInteger()); + return true; +} + LLSD LLVolumeParams::asLLSD() const { LLSD sd = LLSD(); sd["path"] = mPathParams; sd["profile"] = mProfileParams; + sd["sculpt"] = sculptAsLLSD(); + return sd; } @@ -4115,6 +4441,8 @@ bool LLVolumeParams::fromLLSD(LLSD& sd) { mPathParams.fromLLSD(sd["path"]); mProfileParams.fromLLSD(sd["profile"]); + sculptFromLLSD(sd["sculpt"]); + return true; } @@ -4157,6 +4485,12 @@ const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity // for collison purposes BOOL LLVolumeParams::isConvex() const { + if (!getSculptID().isNull()) + { + // can't determine, be safe and say no: + return FALSE; + } + F32 path_length = mPathParams.getEnd() - mPathParams.getBegin(); F32 hollow = mProfileParams.getHollow(); @@ -5011,7 +5345,11 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) if (!partial_build) { mIndices.resize(num_indices); - mEdge.resize(num_indices); + + if (volume->getParams().getSculptType() != LL_SCULPT_TYPE_MESH) + { + mEdge.resize(num_indices); + } } else { diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 871b334452..9f595ccbc4 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -186,6 +186,9 @@ const U8 LL_SCULPT_TYPE_CYLINDER = 4; const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | LL_SCULPT_TYPE_CYLINDER; +// need to change this (these) names +const U8 LL_SCULPT_TYPE_MESH = 5; + const U8 LL_SCULPT_FLAG_INVERT = 64; const U8 LL_SCULPT_FLAG_MIRROR = 128; @@ -575,6 +578,9 @@ public: BOOL importLegacyStream(std::istream& input_stream); BOOL exportLegacyStream(std::ostream& output_stream) const; + LLSD sculptAsLLSD() const; + bool sculptFromLLSD(LLSD& sd); + LLSD asLLSD() const; operator LLSD() const { return asLLSD(); } bool fromLLSD(LLSD& sd); @@ -634,7 +640,6 @@ public: const F32& getSkew() const { return mPathParams.getSkew(); } const LLUUID& getSculptID() const { return mSculptID; } const U8& getSculptType() const { return mSculptType; } - BOOL isConvex() const; // 'begin' and 'end' should be in range [0, 1] (they will be clamped) @@ -798,7 +803,7 @@ public: BOOL create(LLVolume* volume, BOOL partial_build = FALSE); void createBinormals(); - + class VertexData { public: @@ -806,6 +811,9 @@ public: LLVector3 mNormal; LLVector3 mBinormal; LLVector2 mTexCoord; + + bool operator<(const VertexData& rhs) const; + bool operator==(const VertexData& rhs) const; }; enum @@ -851,8 +859,7 @@ class LLVolume : public LLRefCount { friend class LLVolumeLODGroup; -private: - LLVolume(const LLVolume&); // Don't implement +protected: ~LLVolume(); // use unref public: @@ -874,7 +881,7 @@ public: U8 getProfileType() const { return mParams.getProfileParams().getCurveType(); } U8 getPathType() const { return mParams.getPathParams().getCurveType(); } - S32 getNumFaces() const { return (S32)mProfilep->mFaces.size(); } + S32 getNumFaces() const; S32 getNumVolumeFaces() const { return mVolumeFaces.size(); } F32 getDetail() const { return mDetail; } const LLVolumeParams& getParams() const { return mParams; } @@ -946,6 +953,8 @@ public: LLVector3 mLODScaleBias; // vector for biasing LOD based on scale void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level); + void copyVolumeFaces(LLVolume* volume); + private: void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type); F32 sculptGetSurfaceArea(); @@ -956,6 +965,9 @@ private: protected: BOOL generate(); void createVolumeFaces(); +public: + virtual BOOL createVolumeFacesFromFile(const std::string& file_name); + virtual BOOL createVolumeFacesFromStream(std::istream& is); protected: BOOL mUnique; diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index 53641fceab..61c5a0adc9 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -320,7 +320,7 @@ BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep) { llassert_always(mLODRefs[i] > 0); mLODRefs[i]--; -#if 1 // SJB: Possible opt: keep other lods around +#if 0 // SJB: Possible opt: keep other lods around if (!mLODRefs[i]) { mVolumeLODs[i] = NULL; diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp index d8e7b4aaf9..7c7f60154d 100644 --- a/indra/llmath/m4math.cpp +++ b/indra/llmath/m4math.cpp @@ -428,6 +428,17 @@ const LLMatrix4& LLMatrix4::initRotTrans(const LLQuaternion &q, const LLVector return (*this); } +const LLMatrix4& LLMatrix4::initScale(const LLVector3 &scale) +{ + setIdentity(); + + mMatrix[VX][VX] = scale.mV[VX]; + mMatrix[VY][VY] = scale.mV[VY]; + mMatrix[VZ][VZ] = scale.mV[VZ]; + + return (*this); +} + const LLMatrix4& LLMatrix4::initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos) { F32 sx, sy, sz; diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h index e74b7afe9b..de981b7646 100644 --- a/indra/llmath/m4math.h +++ b/indra/llmath/m4math.h @@ -159,6 +159,7 @@ public: const LLMatrix4& initRotTrans(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &pos); // Rotation from Euler + translation const LLMatrix4& initRotTrans(const LLQuaternion &q, const LLVector4 &pos); // Set with Quaternion and position + const LLMatrix4& initScale(const LLVector3 &scale); // Set all const LLMatrix4& initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos); diff --git a/indra/llmath/v2math.cpp b/indra/llmath/v2math.cpp index 555e1f92bb..220336e0c2 100644 --- a/indra/llmath/v2math.cpp +++ b/indra/llmath/v2math.cpp @@ -115,3 +115,18 @@ LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u) a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u, a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u ); } + +LLSD LLVector2::getValue() const +{ + LLSD ret; + ret[0] = mV[0]; + ret[1] = mV[1]; + return ret; +} + +void LLVector2::setValue(LLSD& sd) +{ + mV[0] = (F32) sd[0].asReal(); + mV[1] = (F32) sd[1].asReal(); +} + diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h index 9fef8851cc..f9f1c024f2 100644 --- a/indra/llmath/v2math.h +++ b/indra/llmath/v2math.h @@ -66,6 +66,9 @@ class LLVector2 void set(const LLVector2 &vec); // Sets LLVector2 to vec void set(const F32 *vec); // Sets LLVector2 to vec + LLSD getValue() const; + void setValue(LLSD& sd); + void setVec(F32 x, F32 y); // deprecated void setVec(const LLVector2 &vec); // deprecated void setVec(const F32 *vec); // deprecated diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index b3087bcc3f..eeb903de6a 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -502,7 +502,7 @@ void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType at tpvf.setAsset(uuid, atype); tpvf.setCallback(downloadCompleteCallback, req); - llinfos << "Starting transfer for " << uuid << llendl; + //llinfos << "Starting transfer for " << uuid << llendl; LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET); ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f)); } diff --git a/indra/llmessage/lltransfermanager.cpp b/indra/llmessage/lltransfermanager.cpp index d67911e8e2..72662bb782 100644 --- a/indra/llmessage/lltransfermanager.cpp +++ b/indra/llmessage/lltransfermanager.cpp @@ -344,7 +344,7 @@ void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) } } - llinfos << "Receiving " << transfer_id << ", size " << size << " bytes" << llendl; + //llinfos << "Receiving " << transfer_id << ", size " << size << " bytes" << llendl; ttp->setSize(size); ttp->setGotInfo(TRUE); diff --git a/indra/llmessage/lltransfersourceasset.cpp b/indra/llmessage/lltransfersourceasset.cpp index 5a1cd95ffc..f255a2cf7e 100644 --- a/indra/llmessage/lltransfersourceasset.cpp +++ b/indra/llmessage/lltransfersourceasset.cpp @@ -271,6 +271,7 @@ bool is_asset_fetch_by_id_allowed(LLAssetType::EType type) case LLAssetType::AT_ANIMATION: case LLAssetType::AT_GESTURE: case LLAssetType::AT_FAVORITE: + case LLAssetType::AT_MESH: rv = true; break; default: @@ -296,6 +297,7 @@ bool is_asset_id_knowable(LLAssetType::EType type) case LLAssetType::AT_FAVORITE: case LLAssetType::AT_LINK: case LLAssetType::AT_LINK_FOLDER: + case LLAssetType::AT_MESH: rv = true; break; default: diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt index d130513637..f9392a2b75 100644 --- a/indra/llprimitive/CMakeLists.txt +++ b/indra/llprimitive/CMakeLists.txt @@ -13,11 +13,14 @@ include_directories( ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} + ${LIBS_PREBUILT_DIR}/include/collada + ${LIBS_PREBUILT_DIR}/include/collada/1.4 ) set(llprimitive_SOURCE_FILES llmaterialtable.cpp llmediaentry.cpp + llmodel.cpp llprimitive.cpp llprimtexturelist.cpp lltextureanim.cpp @@ -33,6 +36,7 @@ set(llprimitive_HEADER_FILES legacy_object_types.h llmaterialtable.h llmediaentry.h + llmodel.h llprimitive.h llprimtexturelist.h lltextureanim.h diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index b102254b62..2675a27c08 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -744,18 +744,11 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai return TRUE; } - U32 old_face_mask = mVolumep->mFaceMask; - // build the new object sVolumeManager->unrefVolume(mVolumep); mVolumep = volumep; - - U32 new_face_mask = mVolumep->mFaceMask; - if (old_face_mask != new_face_mask) - { - setNumTEs(mVolumep->getNumFaces()); - } - + setNumTEs(mVolumep->getNumFaces()); + return TRUE; } @@ -898,7 +891,7 @@ BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const U8 packed_buffer[MAX_TE_BUFFER]; U8 *cur_ptr = packed_buffer; - S32 last_face_index = getNumTEs() - 1; + S32 last_face_index = llmin((U32) getNumTEs(), MAX_TES) - 1; if (last_face_index > -1) { @@ -1179,7 +1172,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) return retval; } - face_count = getNumTEs(); + face_count = llmin((U32) getNumTEs(), MAX_TES); U32 i; cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_data, 16, face_count, MVT_LLUUID); diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 4f828186cb..4db7aa7261 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -328,7 +328,7 @@ public: 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; diff --git a/indra/llvfs/llvfile.cpp b/indra/llvfs/llvfile.cpp index 5fdf41188d..e0e282d7af 100644 --- a/indra/llvfs/llvfile.cpp +++ b/indra/llvfs/llvfile.cpp @@ -428,7 +428,7 @@ bool LLVFile::isLocked(EVFSLock lock) void LLVFile::waitForLock(EVFSLock lock) { - LLFastTimer t(FTM_VFILE_WAIT); + //LLFastTimer t(FTM_VFILE_WAIT); // spin until the lock clears while (isLocked(lock)) { diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp index 9ce1e75d06..ddb76fb2ba 100644 --- a/indra/llvfs/llvfs.cpp +++ b/indra/llvfs/llvfs.cpp @@ -2041,6 +2041,9 @@ std::string get_extension(LLAssetType::EType type) case LLAssetType::AT_ANIMATION: extension = ".lla"; break; + case LLAssetType::AT_MESH: + extension = ".slm"; + break; default: // Just use the asset server filename extension in most cases extension += "."; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 26170d1713..3cee6394e0 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -36,6 +36,7 @@ include(UI) include(UnixInstall) include(LLKDU) include(ViewerMiscLibs) +include(GLOD) if (WINDOWS) include(CopyWinLibs) @@ -44,6 +45,7 @@ endif (WINDOWS) include_directories( ${DBUSGLIB_INCLUDE_DIRS} ${ELFIO_INCLUDE_DIR} + ${GLOD_INCLUDE_DIR} ${LLAUDIO_INCLUDE_DIRS} ${LLCHARACTER_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} @@ -61,6 +63,8 @@ include_directories( ${LLXUIXML_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS}/lscript_compile + ${LIBS_PREBUILT_DIR}/include/collada + ${LIBS_PREBUILT_DIR}/include/collada/1.4 ) set(viewer_SOURCE_FILES @@ -175,6 +179,7 @@ set(viewer_SOURCE_FILES llfloatermediasettings.cpp llfloaterhud.cpp llfloaterimagepreview.cpp + llfloaterimportcollada.cpp llfloaterinspect.cpp llfloaterinventory.cpp llfloaterjoystick.cpp @@ -183,6 +188,7 @@ set(viewer_SOURCE_FILES llfloaterlandholdings.cpp llfloatermap.cpp llfloatermemleak.cpp + llfloatermodelpreview.cpp llfloaternamedesc.cpp llfloaternotificationsconsole.cpp llfloateropenobject.cpp @@ -647,6 +653,7 @@ set(viewer_HEADER_FILES llfloatermediasettings.h llfloaterhud.h llfloaterimagepreview.h + llfloaterimportcollada.h llfloaterinspect.h llfloaterinventory.h llfloaterjoystick.h @@ -655,6 +662,7 @@ set(viewer_HEADER_FILES llfloaterlandholdings.h llfloatermap.h llfloatermemleak.h + llfloatermodelpreview.h llfloaternamedesc.h llfloaternotificationsconsole.h llfloateropenobject.h @@ -1139,6 +1147,7 @@ if (WINDOWS) ${DXGUID_LIBRARY} fmodvc kernel32 + libboost_system odbc32 odbccp32 ole32 @@ -1405,6 +1414,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${DBUSGLIB_LIBRARIES} ${OPENGL_LIBRARIES} ${FMODWRAPPER_LIBRARY} + ${GLOD_LIBRARIES} ${OPENGL_LIBRARIES} ${SDL_LIBRARY} ${SMARTHEAP_LIBRARY} diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7e368b0c9c..073ea766fe 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7252,7 +7252,19 @@ Value 0 - SafeMode + MeshThreadCount + + Comment + Number of threads to use for loading meshes. + Persist + 1 + Type + U32 + Value + 8 + + + SafeMode Comment Reset preferences, run in safe mode. diff --git a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl index 651959413c..45884d5732 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl @@ -137,7 +137,7 @@ void main() } //float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); - vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, proj_ambient_lod); + vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, proj_lod); amb_da += (da*da*0.5+0.5)*proj_ambiance; diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl index a0026edcd2..4333cc64a7 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl @@ -224,11 +224,11 @@ void main() //spotlight shadow 1 vec4 lpos = shadow_matrix[4]*spos; - gl_FragColor[2] = pcfShadow(shadowMap4, lpos, 0.1).x; + gl_FragColor[2] = pcfShadow(shadowMap4, lpos, 0.8).x; //spotlight shadow 2 lpos = shadow_matrix[5]*spos; - gl_FragColor[3] = pcfShadow(shadowMap5, lpos, 0.1).x; + gl_FragColor[3] = pcfShadow(shadowMap5, lpos, 0.8).x; //gl_FragColor.rgb = pos.xyz; //gl_FragColor.b = shadow; diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt index 7e6d4b4561..8736626907 100644 --- a/indra/newview/licenses-win32.txt +++ b/indra/newview/licenses-win32.txt @@ -769,3 +769,72 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +============= +GLOD license +============= +The GLOD Open-Source License Version 1.0 June 16, 2004 + +Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns +Hopkins University and David Luebke, Brenden Schubert, University of +Virginia. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, is permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer and + request. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer and + request in the documentation and/or other materials provided with + the distribution. + +3. The name "GLOD" must not be used to endorse or promote products + derived from this software without prior written permission. + +4. Redistributions of any modified version of this source, whether in + source or binary form , must include a form of the following + acknowledgment: "This product is derived from the GLOD library, + which is available from http://www.cs.jhu.edu/~graphics/GLOD." + +5. Redistributions of any modified version of this source in binary + form must provide, free of charge, access to the modified version + of the code. + +6. This license shall be governed by and construed and enforced in + accordance with the laws of the State of Maryland, without + reference to its conflicts of law provisions. The exclusive + jurisdiction and venue for all legal actions relating to this + license shall be in courts of competent subject matter jurisdiction + located in the State of Maryland. + +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, GLOD IS PROVIDED +UNDER THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +THAT GLOD IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR +PURPOSE OR NON-INFRINGING. ALL WARRANTIES ARE DISCLAIMED AND THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE CODE IS WITH +YOU. SHOULD ANY CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE +COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY +NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY +CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY CODE IS +AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY +SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES FOR LOSS OF +PROFITS, REVENUE, OR FOR LOSS OF INFORMATION OR ANY OTHER LOSS. + +YOU EXPRESSLY AGREE TO FOREVER INDEMNIFY, DEFEND AND HOLD HARMLESS THE +COPYRIGHT HOLDERS AND CONTRIBUTORS OF GLOD AGAINST ALL CLAIMS, +DEMANDS, SUITS OR OTHER ACTIONS ARISING DIRECTLY OR INDIRECTLY FROM +YOUR ACCEPTANCE AND USE OF GLOD. + +Although NOT REQUIRED, we would appreciate it if active users of GLOD +put a link on their web site to the GLOD web site when possible. + + diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index cd3963050f..cb03379b23 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -64,6 +64,7 @@ #include "llfocusmgr.h" #include "llscrolllistctrl.h" #include "llsdserialize.h" +#include "llsdutil.h" #include "llvfs.h" // When uploading multiple files, don't display any of them when uploading more than this number. @@ -71,6 +72,120 @@ static const S32 FILE_COUNT_DISPLAY_THRESHOLD = 5; void dialog_refresh_all(); +void on_new_single_inventory_upload_complete( + LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + const std::string inventory_type_string, + const LLUUID& item_folder_id, + const std::string& item_name, + const std::string& item_description, + const LLSD& server_response, + S32 upload_price) +{ + if ( upload_price > 0 ) + { + // this upload costed us L$, update our balance + // and display something saying that it cost L$ + LLStatusBar::sendMoneyBalanceRequest(); + + LLSD args; + args["AMOUNT"] = llformat("%d", upload_price); + LLNotifications::instance().add("UploadPayment", args); + } + + // Actually add the upload to viewer inventory + llinfos << "Adding " << server_response["new_inventory_item"].asUUID() + << " " << server_response["new_asset"].asUUID() + << " to inventory." << llendl; + + if( item_folder_id.notNull() ) + { + U32 everyone_perms = PERM_NONE; + U32 group_perms = PERM_NONE; + U32 next_owner_perms = PERM_ALL; + if( server_response.has("new_next_owner_mask") ) + { + // The server provided creation perms so use them. + // Do not assume we got the perms we asked for in + // since the server may not have granted them all. + everyone_perms = server_response["new_everyone_mask"].asInteger(); + group_perms = server_response["new_group_mask"].asInteger(); + next_owner_perms = server_response["new_next_owner_mask"].asInteger(); + } + else + { + // The server doesn't provide creation perms + // so use old assumption-based perms. + if( inventory_type_string != "snapshot") + { + next_owner_perms = PERM_MOVE | PERM_TRANSFER; + } + } + + LLPermissions new_perms; + new_perms.init( + gAgent.getID(), + gAgent.getID(), + LLUUID::null, + LLUUID::null); + + new_perms.initMasks( + PERM_ALL, + PERM_ALL, + everyone_perms, + group_perms, + next_owner_perms); + + S32 creation_date_now = time_corrected(); + LLPointer item = new LLViewerInventoryItem( + server_response["new_inventory_item"].asUUID(), + item_folder_id, + new_perms, + server_response["new_asset"].asUUID(), + asset_type, + inventory_type, + item_name, + item_description, + LLSaleInfo::DEFAULT, + LLInventoryItem::II_FLAGS_NONE, + creation_date_now); + + gInventory.updateItem(item); + gInventory.notifyObservers(); + + // Show the preview panel for textures and sounds to let + // user know that the image (or snapshot) arrived intact. + LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); + if ( view ) + { + LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); + + view->getPanel()->setSelection( + server_response["new_inventory_item"].asUUID(), + TAKE_FOCUS_NO); + + if( + (LLAssetType::AT_TEXTURE == asset_type || + LLAssetType::AT_SOUND == asset_type) && + (LLFilePicker::instance().getFileCount() <= + FILE_COUNT_DISPLAY_THRESHOLD) ) + { + view->getPanel()->openSelected(); + } + + // restore keyboard focus + gFocusMgr.setKeyboardFocus(focus); + } + } + else + { + llwarns << "Can't find a folder to put it in" << llendl; + } + + // remove the "Uploading..." message + LLUploadDialog::modalUploadFinished(); +} + LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data, const LLUUID& vfile_id, LLAssetType::EType asset_type) @@ -88,9 +203,10 @@ LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data, } } -LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data, - const std::string& file_name, - LLAssetType::EType asset_type) +LLAssetUploadResponder::LLAssetUploadResponder( + const LLSD &post_data, + const std::string& file_name, + LLAssetType::EType asset_type) : LLHTTPClient::Responder(), mPostData(post_data), mFileName(file_name), @@ -196,15 +312,19 @@ void LLAssetUploadResponder::uploadComplete(const LLSD& content) { } -LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, vfile_id, asset_type) +LLNewAgentInventoryResponder::LLNewAgentInventoryResponder( + const LLSD& post_data, + const LLUUID& vfile_id, + LLAssetType::EType asset_type) + : LLAssetUploadResponder(post_data, vfile_id, asset_type) { } -LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data, const std::string& file_name, LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, file_name, asset_type) +LLNewAgentInventoryResponder::LLNewAgentInventoryResponder( + const LLSD& post_data, + const std::string& file_name, + LLAssetType::EType asset_type) + : LLAssetUploadResponder(post_data, file_name, asset_type) { } @@ -219,96 +339,31 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) LLAssetType::EType asset_type = LLAssetType::lookup(mPostData["asset_type"].asString()); LLInventoryType::EType inventory_type = LLInventoryType::lookup(mPostData["inventory_type"].asString()); - S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); + S32 expected_upload_cost = 0; // Update L$ and ownership credit information // since it probably changed on the server if (asset_type == LLAssetType::AT_TEXTURE || asset_type == LLAssetType::AT_SOUND || - asset_type == LLAssetType::AT_ANIMATION) + asset_type == LLAssetType::AT_ANIMATION || + asset_type == LLAssetType::AT_MESH) { - LLStatusBar::sendMoneyBalanceRequest(); - - LLSD args; - args["AMOUNT"] = llformat("%d", expected_upload_cost); - LLNotifications::instance().add("UploadPayment", args); + expected_upload_cost = + LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); } - // Actually add the upload to viewer inventory - llinfos << "Adding " << content["new_inventory_item"].asUUID() << " " - << content["new_asset"].asUUID() << " to inventory." << llendl; - if(mPostData["folder_id"].asUUID().notNull()) - { - //std::ostringstream out; - //LLSDXMLFormatter *formatter = new LLSDXMLFormatter; - //formatter->format(mPostData, out, LLSDFormatter::OPTIONS_PRETTY); - //llinfos << "Post Data: " << out.str() << llendl; - - U32 everyone_perms = PERM_NONE; - U32 group_perms = PERM_NONE; - U32 next_owner_perms = PERM_ALL; - if(content.has("new_next_owner_mask")) - { - // This is a new sim that provides creation perms so use them. - // Do not assume we got the perms we asked for in mPostData - // since the sim may not have granted them all. - everyone_perms = content["new_everyone_mask"].asInteger(); - group_perms = content["new_group_mask"].asInteger(); - next_owner_perms = content["new_next_owner_mask"].asInteger(); - } - else - { - // This old sim doesn't provide creation perms so use old assumption-based perms. - if(mPostData["inventory_type"].asString() != "snapshot") - { - next_owner_perms = PERM_MOVE | PERM_TRANSFER; - } - } - LLPermissions new_perms; - new_perms.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); - new_perms.initMasks(PERM_ALL, PERM_ALL, everyone_perms, group_perms, next_owner_perms); - S32 creation_date_now = time_corrected(); - LLPointer item - = new LLViewerInventoryItem(content["new_inventory_item"].asUUID(), - mPostData["folder_id"].asUUID(), - new_perms, - content["new_asset"].asUUID(), - asset_type, - inventory_type, - mPostData["name"].asString(), - mPostData["description"].asString(), - LLSaleInfo::DEFAULT, - LLInventoryItem::II_FLAGS_NONE, - creation_date_now); - gInventory.updateItem(item); - gInventory.notifyObservers(); - - // Show the preview panel for textures and sounds to let - // user know that the image (or snapshot) arrived intact. - LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); - if(view) - { - LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); + on_new_single_inventory_upload_complete( + asset_type, + inventory_type, + mPostData["asset_type"].asString(), + mPostData["folder_id"].asUUID(), + mPostData["name"], + mPostData["description"], + content, + expected_upload_cost); - view->getPanel()->setSelection(content["new_inventory_item"].asUUID(), TAKE_FOCUS_NO); - if((LLAssetType::AT_TEXTURE == asset_type || LLAssetType::AT_SOUND == asset_type) - && LLFilePicker::instance().getFileCount() <= FILE_COUNT_DISPLAY_THRESHOLD) - { - view->getPanel()->openSelected(); - } - //LLFloaterInventory::dumpSelectionInformation((void*)view); - // restore keyboard focus - gFocusMgr.setKeyboardFocus(focus); - } - } - else - { - llwarns << "Can't find a folder to put it in" << llendl; - } + // continue uploading for bulk uploads - // remove the "Uploading..." message - LLUploadDialog::modalUploadFinished(); - // *FIX: This is a pretty big hack. What this does is check the // file picker if there are any more pending uploads. If so, // upload that file. @@ -325,18 +380,39 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) // Continuing the horrible hack above, we need to extract the originally requested permissions data, if any, // and use them for each next file to be uploaded. Note the requested perms are not the same as the - // granted ones found in the given "content" structure but can still be found in mPostData. -MG - U32 everyone_perms = mPostData.has("everyone_mask") ? mPostData.get("everyone_mask" ).asInteger() : PERM_NONE; - U32 group_perms = mPostData.has("group_mask") ? mPostData.get("group_mask" ).asInteger() : PERM_NONE; - U32 next_owner_perms = mPostData.has("next_owner_mask") ? mPostData.get("next_owner_mask").asInteger() : PERM_NONE; + U32 everyone_perms = + content.has("everyone_mask") ? + content["everyone_mask"].asInteger() : + PERM_NONE; + + U32 group_perms = + content.has("group_mask") ? + content["group_mask"].asInteger() : + PERM_NONE; + + U32 next_owner_perms = + content.has("next_owner_mask") ? + content["next_owner_mask"].asInteger() : + PERM_NONE; + std::string display_name = LLStringUtil::null; LLAssetStorage::LLStoreAssetCallback callback = NULL; void *userdata = NULL; - upload_new_resource(next_file, asset_name, asset_name, - 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE, - next_owner_perms, group_perms, - everyone_perms, display_name, - callback, expected_upload_cost, userdata); + + upload_new_resource( + next_file, + asset_name, + asset_name, + 0, + LLAssetType::AT_NONE, + LLInventoryType::IT_NONE, + next_owner_perms, + group_perms, + everyone_perms, + display_name, + callback, + LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(), + userdata); } } @@ -383,17 +459,19 @@ void LLSendTexLayerResponder::uploadComplete(const LLSD& content) } -LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, vfile_id, asset_type) +LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder( + const LLSD& post_data, + const LLUUID& vfile_id, + LLAssetType::EType asset_type) + : LLAssetUploadResponder(post_data, vfile_id, asset_type) { } -LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data, - const std::string& file_name, - LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, file_name, asset_type) +LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder( + const LLSD& post_data, + const std::string& file_name, + LLAssetType::EType asset_type) + : LLAssetUploadResponder(post_data, file_name, asset_type) { } @@ -576,3 +654,374 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content) break; } } + + +///////////////////////////////////////////////////// +// LLNewAgentInventoryVariablePriceResponder::Impl // +///////////////////////////////////////////////////// +class LLNewAgentInventoryVariablePriceResponder::Impl +{ +public: + Impl( + const LLUUID& vfile_id, + const LLSD& inventory_data) : + mVFileID(vfile_id), + mInventoryData(inventory_data) + { + } + + Impl( + const std::string& file_name, + const LLSD& inventory_data) : + mFileName(file_name), + mInventoryData(inventory_data) + { + } + + std::string getFilenameOrIDString() const + { + return (mFileName.empty() ? mVFileID.asString() : mFileName); + } + + LLUUID getVFileID() const + { + return mVFileID; + } + + std::string getFilename() const + { + return mFileName; + } + + LLAssetType::EType getAssetType() const + { + return LLAssetType::lookup( + mInventoryData["asset_type"].asString()); + } + + LLInventoryType::EType getInventoryType() const + { + return LLInventoryType::lookup( + mInventoryData["inventory_type"].asString()); + } + + std::string getInventoryTypeString() const + { + return mInventoryData["inventory_type"].asString(); + } + + LLUUID getFolderID() const + { + return mInventoryData["folder_id"].asUUID(); + } + + std::string getItemName() const + { + return mInventoryData["name"].asString(); + } + + std::string getItemDescription() const + { + return mInventoryData["description"].asString(); + } + + void displayCannotUploadReason(const std::string& reason) + { + LLSD args; + args["FILE"] = getFilenameOrIDString(); + args["REASON"] = reason; + + + LLNotifications::instance().add("CannotUploadReason", args); + LLUploadDialog::modalUploadFinished(); + } + + void onApplicationLevelError(const std::string& error_identifier) + { + // TODO*: Pull these user visible strings from an xml file + // to be localized + static const std::string _INSUFFICIENT_FUNDS = + "NewAgentInventory_InsufficientLindenDollarBalance"; + + + if ( _INSUFFICIENT_FUNDS == error_identifier ) + { + displayCannotUploadReason("You do not have a sufficient L$ balance to complete this upload."); + } + else + { + displayCannotUploadReason("Unknown Error"); + + } + } + + void onTransportError() + { + displayCannotUploadReason( + "The server is experiencing unexpected difficulties."); + } + + void onTransportError(const std::string& error_identifier) + { + // TODO*: Pull these user visible strings from an xml file + // to be localized + + static const std::string _SERVER_ERROR_AFTER_CHARGE = + "NewAgentInventory_ServerErrorAfterCharge"; + + if ( _SERVER_ERROR_AFTER_CHARGE == error_identifier ) + { + displayCannotUploadReason( + "The server is experiencing unexpected difficulties. You may have been charged for the upload."); + } + else + { + displayCannotUploadReason( + "The server is experiencing unexpected difficulties."); + } + + } + + bool uploadConfirmationCallback( + const LLSD& notification, + const LLSD& response, + boost::intrusive_ptr responder) + { + S32 option; + std::string confirmation_url; + + option = LLNotification::getSelectedOption( + notification, + response); + + confirmation_url = + notification["payload"]["confirmation_url"].asString(); + + // Yay! We are confirming or cancelling our upload + LLSD body; + + body["confirm_upload"] = false; + + switch(option) + { + case 0: + { + body["confirm_upload"] = true; + body["expected_upload_price"] = + notification["payload"]["expected_upload_price"]; + } + break; + case 1: + default: + break; + } + + LLHTTPClient::post(confirmation_url, body, responder); + + return false; + } + +private: + std::string mFileName; + + LLSD mInventoryData; + LLUUID mVFileID; +}; + +/////////////////////////////////////////////// +// LLNewAgentInventoryVariablePriceResponder // +/////////////////////////////////////////////// +LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder( + const LLUUID& vfile_id, + const LLSD& inventory_info) +{ + mImpl = new Impl( + vfile_id, + inventory_info); +} + +LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder( + const std::string& file_name, + const LLSD& inventory_info) +{ + mImpl = new Impl( + file_name, + inventory_info); +} + +LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResponder() +{ + delete mImpl; +} + +void LLNewAgentInventoryVariablePriceResponder::errorWithContent( + U32 statusNum, + const std::string& reason, + const LLSD& content) +{ + llinfos << "LLNewAgentInventoryVariablePrice::error " << statusNum + << " reason: " << reason << llendl; + + if ( content.has("error") ) + { + static const std::string _ERROR = "error"; + static const std::string _IDENTIFIER = "identifier"; + + mImpl->onTransportError(content[_ERROR][_IDENTIFIER].asString()); + } + else + { + mImpl->onTransportError(); + } +} + +void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) +{ + // Parse out application level errors and the appropriate + // responses for them + static const std::string _ERROR = "error"; + static const std::string _IDENTIFIER = "identifier"; + static const std::string _STATE = "state"; + + static const std::string _COMPLETE = "complete"; + static const std::string _COST_ANALYSIS = "cost_analysis"; + static const std::string _NEEDS_CONFIRMATION = "needs_confirmation"; + static const std::string _CANCEL = "cancel"; + + static const std::string _RESOURCE_COST = "resource_cost"; + static const std::string _UPLOAD_PRICE = "upload_price"; + + static const std::string _ANALYZER = "analyzer"; + static const std::string _RSVP = "rsvp"; + + // Check for application level errors + if ( content.has(_ERROR) ) + { + onApplicationLevelError(content[_ERROR][_IDENTIFIER].asString()); + return; + } + + std::string state = content[_STATE]; + LLAssetType::EType asset_type = mImpl->getAssetType(); + + if ( _COST_ANALYSIS == state ) + { + std::string analyzer_url = content[_ANALYZER]; + + if ( mImpl->getFilename().empty() ) + { + // we have no filename, use virtual file ID instead + LLHTTPClient::postFile( + analyzer_url, + mImpl->getVFileID(), + asset_type, + this); + } + else + { + LLHTTPClient::postFile( + analyzer_url, + mImpl->getFilename(), + this); + } + } + else if ( _COMPLETE == state ) + { + // rename file in VFS with new asset id + if (mImpl->getFilename().empty()) + { + // rename the file in the VFS to the actual asset id + // llinfos << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << llendl; + gVFS->renameFile( + mImpl->getVFileID(), + asset_type, + content["new_asset"].asUUID(), + asset_type); + } + + on_new_single_inventory_upload_complete( + asset_type, + mImpl->getInventoryType(), + mImpl->getInventoryTypeString(), + mImpl->getFolderID(), + mImpl->getItemName(), + mImpl->getItemDescription(), + content, + content["upload_price"].asInteger()); + + // TODO* Add bulk (serial) uploading or add + // a super class of this that does so + } + else if ( _NEEDS_CONFIRMATION == state ) + { + showConfirmationDialog( + content[_UPLOAD_PRICE].asInteger(), + content[_RESOURCE_COST].asInteger(), + content[_RSVP].asString()); + } + else if ( _CANCEL == state ) + { + // cancelled, do nothing + } + else + { + onApplicationLevelError(""); + } +} + +void LLNewAgentInventoryVariablePriceResponder::onApplicationLevelError( + const std::string& error_identifier) +{ + mImpl->onApplicationLevelError(error_identifier); +} + +void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog( + S32 upload_price, + S32 resource_cost, + const std::string& confirmation_url) +{ + if ( 0 == upload_price ) + { + // don't show confirmation dialog for free uploads, I mean, + // they're free! + LLSD body; + body["confirm_upload"] = true; + body["expected_upload_price"] = upload_price; + + LLHTTPClient::post(confirmation_url, body, this); + } + else + { + LLSD substitutions; + LLSD payload; + + substitutions["PRICE"] = upload_price; + + payload["confirmation_url"] = confirmation_url; + payload["expected_upload_price"] = upload_price; + + // The creating of a new instrusive_ptr(this) + // creates a new boost::intrusive_ptr + // which is a copy of this. This code is required because + // 'this' is always of type Class* and not the intrusive_ptr, + // and thus, a reference to 'this' is not registered + // by using just plain 'this'. + + // Since LLNewAgentInventoryVariablePriceResponder is a + // reference counted class, it is possible (since the + // reference to a plain 'this' would be missed here) that, + // when using plain ol' 'this', that this object + // would be deleted before the callback is triggered + // and cause sadness. + LLNotifications::instance().add( + "UploadCostConfirmation", + substitutions, + payload, + boost::bind( + &LLNewAgentInventoryVariablePriceResponder::Impl::uploadConfirmationCallback, + mImpl, + _1, + _2, + boost::intrusive_ptr(this))); + } +} diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index a08d70213c..adbf13519b 100644 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -61,17 +61,58 @@ protected: std::string mFileName; }; + +// TODO*: Remove this once deprecated class LLNewAgentInventoryResponder : public LLAssetUploadResponder { public: - LLNewAgentInventoryResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type); - LLNewAgentInventoryResponder(const LLSD& post_data, const std::string& file_name, - LLAssetType::EType asset_type); + LLNewAgentInventoryResponder( + const LLSD& post_data, + const LLUUID& vfile_id, + LLAssetType::EType asset_type); + LLNewAgentInventoryResponder( + const LLSD& post_data, + const std::string& file_name, + LLAssetType::EType asset_type); virtual void uploadComplete(const LLSD& content); }; +// A base class which goes through and performs some default +// actions for variable price uploads. If more specific actions +// are needed (such as different confirmation messages, etc.) +// the functions onApplicationLevelError and showConfirmationDialog. +class LLNewAgentInventoryVariablePriceResponder : + public LLHTTPClient::Responder +{ +public: + LLNewAgentInventoryVariablePriceResponder( + const LLUUID& vfile_id, + const LLSD& inventory_info); + + LLNewAgentInventoryVariablePriceResponder( + const std::string& file_name, + const LLSD& inventory_info); + + virtual ~LLNewAgentInventoryVariablePriceResponder(); + + void errorWithContent( + U32 statusNum, + const std::string& reason, + const LLSD& content); + void result(const LLSD& content); + + virtual void onApplicationLevelError( + const std::string& error_identifier); + virtual void showConfirmationDialog( + S32 upload_price, + S32 resource_cost, + const std::string& confirmation_url); + +private: + class Impl; + Impl* mImpl; +}; + class LLBakedUploadData; class LLSendTexLayerResponder : public LLAssetUploadResponder { diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index 5a10b688da..27c9ab319a 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -314,8 +314,10 @@ private: inline LLFace* LLDrawable::getFace(const S32 i) const { - llassert((U32)i < mFaces.size()); - llassert(mFaces[i]); + if ((U32) i >= mFaces.size()) + { + return NULL; + } return mFaces[i]; } diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index e087feeaec..e74b488be9 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -701,6 +701,18 @@ void LLDrawPoolBump::endBump() gGL.setSceneBlendType(LLRender::BT_ALPHA); } +S32 LLDrawPoolBump::getNumDeferredPasses() +{ + if (gSavedSettings.getBOOL("RenderObjectBump")) + { + return 1; + } + else + { + return 0; + } +} + void LLDrawPoolBump::beginDeferredPass(S32 pass) { if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP)) diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h index bf940cf1e4..2019f1df26 100644 --- a/indra/newview/lldrawpoolbump.h +++ b/indra/newview/lldrawpoolbump.h @@ -79,7 +79,7 @@ public: void renderBump(); void endBump(); - virtual S32 getNumDeferredPasses() { return 1; } + virtual S32 getNumDeferredPasses(); /*virtual*/ void beginDeferredPass(S32 pass); /*virtual*/ void endDeferredPass(S32 pass); /*virtual*/ void renderDeferred(S32 pass); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 4246cbc27f..e49ef8b969 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1040,7 +1040,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (full_rebuild) { mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex); - for (U16 i = 0; i < num_indices; i++) + for (S32 i = 0; i < num_indices; i++) { *indicesp++ = vf.mIndices[i] + index_offset; } diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 028e1cc098..e12db901bd 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -61,6 +61,7 @@ LLFilePicker LLFilePicker::sInstance; #define XML_FILTER L"XML files (*.xml)\0*.xml\0" #define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0" #define RAW_FILTER L"RAW files (*.raw)\0*.raw\0" +#define MODEL_FILTER L"Model files (*.dae)\0*.dae\0" #endif // @@ -193,6 +194,10 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) mOFN.lpstrFilter = RAW_FILTER \ L"\0"; break; + case FFLOAD_MODEL: + mOFN.lpstrFilter = MODEL_FILTER \ + L"\0"; + break; default: res = FALSE; break; diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index ab2455620f..7600922e9c 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -93,6 +93,7 @@ public: FFLOAD_XML = 6, FFLOAD_SLOBJECT = 7, FFLOAD_RAW = 8, + FFLOAD_MODEL = 9, }; enum ESaveFilter @@ -198,4 +199,6 @@ public: ~LLFilePicker(); }; +const std::string upload_pick(void* data); + #endif diff --git a/indra/newview/llfloaterinventory.cpp b/indra/newview/llfloaterinventory.cpp index c890f9f122..364c79e3c1 100644 --- a/indra/newview/llfloaterinventory.cpp +++ b/indra/newview/llfloaterinventory.cpp @@ -1143,6 +1143,9 @@ const std::string& get_item_icon_name(LLAssetType::EType asset_type, case LLAssetType::AT_LINK_FOLDER: idx = LINKFOLDER_ICON_NAME; break; + case LLAssetType::AT_MESH: + idx = MESH_ICON_NAME; + break; default: break; } diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index 55019f91f8..58637329d7 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -567,6 +567,18 @@ void LLHUDText::setStringUTF8(const std::string &wtext) setString(utf8str_to_wstring(wtext)); } +std::string LLHUDText::getString() +{ + std::ostringstream ostr; + for (U32 i = 0; i < mTextSegments.size(); ++i) + { + const std::string str = wstring_to_utf8str(mTextSegments[i].getText()); + ostr << str; + } + + return ostr.str(); +} + void LLHUDText::setString(const LLWString &wtext) { mTextSegments.clear(); diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h index dc14a8c764..4787a15eaf 100644 --- a/indra/newview/llhudtext.h +++ b/indra/newview/llhudtext.h @@ -90,6 +90,7 @@ public: public: void setStringUTF8(const std::string &utf8string); + std::string getString(); void setString(const LLWString &wstring); void clearString(); void addLine(const std::string &text, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index ca9ebf8dc1..028505456b 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -154,7 +154,9 @@ std::string ICON_NAME[ICON_NAME_COUNT] = "Inv_Gesture", "inv_item_linkitem.tga", - "inv_item_linkfolder.tga" + "inv_item_linkfolder.tga", + + "inv_item_mesh.tga" }; @@ -891,6 +893,14 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, // Only should happen for broken links. new_listener = new LLLinkItemBridge(inventory, uuid); break; + case LLAssetType::AT_MESH: + if(!(inv_type == LLInventoryType::IT_MESH)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLMeshBridge(inventory, uuid); + break; + default: llinfos << "Unhandled asset type (llassetstorage.h): " << (S32)asset_type << llendl; @@ -2189,6 +2199,9 @@ LLUIImagePtr LLFolderBridge::getIcon(LLAssetType::EType preferred_type) { // we only have one folder image now return LLUI::getUIImage("Inv_FolderClosed"); + /*case LLAssetType::AT_MESH: + control = "inv_folder_mesh.tga"; + break;*/ } BOOL LLFolderBridge::renameItem(const std::string& new_name) @@ -2558,6 +2571,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_ANIMATION: case DAD_GESTURE: case DAD_LINK: + case DAD_MESH: accept = dragItemIntoFolder((LLInventoryItem*)cargo_data, drop); break; @@ -3457,6 +3471,7 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_BODYPART: case DAD_ANIMATION: case DAD_GESTURE: + case DAD_MESH: { LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; const LLPermissions& perm = inv_item->getPermissions(); @@ -4713,6 +4728,65 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, delete on_remove_struct; } + +// +=================================================+ +// | LLMeshBridge | +// +=================================================+ + +LLUIImagePtr LLMeshBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_MESH, LLInventoryType::IT_MESH, 0, FALSE); +} + +void LLMeshBridge::openItem() +{ + LLViewerInventoryItem* item = getItem(); + + if (item) + { + // open mesh + } +} + +void LLMeshBridge::previewItem() +{ + LLViewerInventoryItem* item = getItem(); + if(item) + { + // preview mesh + } +} + + +void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + lldebugs << "LLMeshBridge::buildContextMenu()" << llendl; + std::vector items; + std::vector disabled_items; + + if(isInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { + items.push_back(std::string("Properties")); + + getClipboardEntries(true, items, disabled_items, flags); + } + + + hideContextEntries(menu, items, disabled_items); +} + + + LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_type, const LLUUID& uuid,LLInventoryModel* model) { @@ -4761,6 +4835,12 @@ LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_ break; + case LLAssetType::AT_MESH: + action = new LLMeshBridgeAction(uuid,model); + break; + + + default: break; } @@ -4998,6 +5078,18 @@ void LLWearableBridgeAction::doIt() LLInvFVBridgeAction::doIt(); } +//virtual +void LLMeshBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if(item) + { + // do it + } + + LLInvFVBridgeAction::doIt(); +} + // +=================================================+ // | LLLinkItemBridge | // +=================================================+ diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 6b2a2d32de..95a5f97e7b 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -79,6 +79,8 @@ enum EInventoryIcon LINKITEM_ICON_NAME, LINKFOLDER_ICON_NAME, + + MESH_ICON_NAME, ICON_NAME_COUNT }; @@ -609,7 +611,6 @@ protected: static std::string sPrefix; }; - class LLLinkFolderBridge : public LLItemBridge { friend class LLInvFVBridge; @@ -630,6 +631,25 @@ protected: static std::string sPrefix; }; + + +class LLMeshBridge : public LLItemBridge +{ + friend class LLInvFVBridge; +public: + virtual LLUIImagePtr getIcon() const; + virtual void openItem(); + virtual void previewItem(); + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + +protected: + LLMeshBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : + LLItemBridge(inventory, uuid) {} +}; + + + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInvFVBridgeAction (& its derived classes) // @@ -790,6 +810,19 @@ protected: }; +class LLMeshBridgeAction: public LLInvFVBridgeAction +{ + friend class LLInvFVBridgeAction; +public: + virtual void doIt() ; + virtual ~LLMeshBridgeAction(){} +protected: + LLMeshBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){} + +}; + + + void wear_inventory_item_on_avatar(LLInventoryItem* item); class LLViewerJointAttachment; diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 0ce85818dd..a824025723 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -157,6 +157,7 @@ BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, case DAD_ANIMATION: case DAD_GESTURE: case DAD_CALLINGCARD: + case DAD_MESH: { LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data; if(gInventory.getItem(inv_item->getUUID()) diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index a7f0ce16d3..a5e3a0492b 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -173,7 +173,6 @@ LLObjectSelection *get_null_object_selection() return sNullSelection; } - //----------------------------------------------------------------------------- // LLSelectMgr() //----------------------------------------------------------------------------- @@ -5301,6 +5300,78 @@ BOOL LLSelectNode::allowOperationOnNode(PermissionBit op, U64 group_proxy_power) return (mPermissions->allowOperationBy(op, proxy_agent_id, group_id)); } +void LLSelectNode::renderOneWireframe(const LLColor4& color) +{ + LLViewerObject* objectp = getObject(); + if (!objectp) + { + return; + } + + LLDrawable* drawable = objectp->mDrawable; + if(!drawable) + { + return; + } + + glMatrixMode(GL_MODELVIEW); + gGL.pushMatrix(); + + BOOL is_hud_object = objectp->isHUDAttachment(); + + if (!is_hud_object) + { + glLoadIdentity(); + glMultMatrixd(gGLModelView); + } + + if (drawable->isActive()) + { + glMultMatrixf((F32*) objectp->getRenderMatrix().mMatrix); + } + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + if (LLSelectMgr::sRenderHiddenSelections) // && gFloaterTools && gFloaterTools->getVisible()) + { + gGL.blendFunc(LLRender::BF_SOURCE_COLOR, LLRender::BF_ONE); + LLGLEnable fog(GL_FOG); + glFogi(GL_FOG_MODE, GL_LINEAR); + float d = (LLViewerCamera::getInstance()->getPointOfInterest()-LLViewerCamera::getInstance()->getOrigin()).magVec(); + LLColor4 fogCol = color * (F32)llclamp((LLSelectMgr::getInstance()->getSelectionCenterGlobal()-gAgent.getCameraPositionGlobal()).magVec()/(LLSelectMgr::getInstance()->getBBoxOfSelection().getExtentLocal().magVec()*4), 0.0, 1.0); + glFogf(GL_FOG_START, d); + glFogf(GL_FOG_END, d*(1 + (LLViewerCamera::getInstance()->getView() / LLViewerCamera::getInstance()->getDefaultFOV()))); + glFogfv(GL_FOG_COLOR, fogCol.mV); + + LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GEQUAL); + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + { + glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f); + for (S32 i = 0; i < drawable->getNumFaces(); ++i) + { + LLFace* face = drawable->getFace(i); + pushVerts(face, LLVertexBuffer::MAP_VERTEX); + } + } + } + + gGL.flush(); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + glColor4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2); + LLGLEnable offset(GL_POLYGON_OFFSET_LINE); + glPolygonOffset(3.f, 2.f); + glLineWidth(3.f); + for (S32 i = 0; i < drawable->getNumFaces(); ++i) + { + LLFace* face = drawable->getFace(i); + pushVerts(face, LLVertexBuffer::MAP_VERTEX); + } + glLineWidth(1.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.popMatrix(); +} + //----------------------------------------------------------------------------- // renderOneSilhouette() //----------------------------------------------------------------------------- @@ -5318,6 +5389,13 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) return; } + LLVOVolume* vobj = drawable->getVOVolume(); + if (vobj && vobj->isMesh()) + { + renderOneWireframe(color); + return; + } + if (!mSilhouetteExists) { return; diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 6e757ef976..b518765946 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -140,6 +140,7 @@ public: BOOL isTESelected(S32 te_index); S32 getLastSelectedTE(); S32 getTESelectMask() { return mTESelectMask; } + void renderOneWireframe(const LLColor4& color); void renderOneSilhouette(const LLColor4 &color); void setTransient(BOOL transient) { mTransient = transient; } BOOL isTransient() { return mTransient; } diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 9f317803ce..9704fe71b7 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -2294,7 +2294,6 @@ void pushVerts(LLFace* face, U32 mask) U16 offset = face->getIndicesStart(); buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset); } - } void pushBufferVerts(LLVertexBuffer* buffer, U32 mask) diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 64c2a9acbc..1d9127639a 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -59,6 +59,7 @@ class LLTextureAtlasSlot; S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad); S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &radius_squared); +void pushVerts(LLFace* face, U32 mask); // get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera U8* get_box_fan_indices(LLCamera* camera, const LLVector3& center); diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index b5aec1b80b..ae4ec75a1b 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -289,7 +289,7 @@ BOOL LLFloaterTexturePicker::handleDragAndDrop( { BOOL handled = FALSE; - if (cargo_type == DAD_TEXTURE) + if ((cargo_type == DAD_TEXTURE) || (cargo_type == DAD_MESH)) { LLInventoryItem *item = (LLInventoryItem *)cargo_data; @@ -1152,7 +1152,9 @@ BOOL LLTextureCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, // returns true, then the cast was valid, and we can perform // the third test without problems. LLInventoryItem* item = (LLInventoryItem*)cargo_data; - if (getEnabled() && (cargo_type == DAD_TEXTURE) && allowDrop(item)) + if (getEnabled() && + ((cargo_type == DAD_TEXTURE) || (cargo_type == DAD_MESH)) && + allowDrop(item)) { if (drop) { diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 9a63f07a7e..643a81be1f 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -483,6 +483,16 @@ LLToolDragAndDrop::dragOrDrop3dImpl LLToolDragAndDrop::sDragAndDrop3d[DAD_COUNT] &LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND }, + + +// Source: DAD_MESH + { + &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE + &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF + &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR + &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT + &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND + }, }; LLToolDragAndDrop::LLToolDragAndDrop() @@ -2007,6 +2017,7 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_ case DAD_ANIMATION: case DAD_GESTURE: case DAD_CALLINGCARD: + case DAD_MESH: { LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data; if(gInventory.getItem(inv_item->getUUID()) diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index a6a72e9666..3b727e2861 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -869,12 +869,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) } } - /// We copy the frame buffer straight into a texture here, - /// and then display it again with compositor effects. - /// Using render to texture would be faster/better, but I don't have a - /// grasp of their full display stack just yet. - // gPostProcess->apply(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight()); - if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) { gPipeline.renderDeferredLighting(); @@ -1097,7 +1091,7 @@ void render_ui(F32 zoom_factor, int subfield) { gPipeline.renderBloom(gSnapshot, zoom_factor, subfield); } - + render_hud_elements(); render_hud_attachments(); } diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index dace3f875f..7c5f5e8b2f 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -122,6 +122,8 @@ #include "llpreviewsound.h" #include "llpreviewtexture.h" #include "llsyswellwindow.h" +#include "llfloatermodelpreview.h" + // *NOTE: Please add files in alphabetical order to keep merges easy. @@ -236,7 +238,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("upload_anim", "floater_animation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); - + LLFloaterReg::add("upload_model", "floater_model_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); LLFloaterReg::add("voice_call", "floater_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index dc291d6c34..56f70e0f5d 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -268,7 +268,6 @@ LLMenuItemCallGL* gBusyMenu = NULL; // Local prototypes // File Menu -const char* upload_pick(void* data); void handle_compress_image(void*); @@ -557,6 +556,7 @@ void init_menus() gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", upload_cost); gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", upload_cost); gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", upload_cost); + gMenuHolder->childSetLabelArg("Upload Model", "[COST]", upload_cost); gAFKMenu = gMenuBarView->getChild("Set Away", TRUE); gBusyMenu = gMenuBarView->getChild("Set Busy", TRUE); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index d3a9e1cef8..836ac79a87 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -39,6 +39,7 @@ #include "llfilepicker.h" #include "llfloaterreg.h" #include "llfloaterbuycurrency.h" +#include "llfloatermodelpreview.h" #include "llfloatersnapshot.h" #include "llinventorymodel.h" // gInventory #include "llresourcedata.h" @@ -62,6 +63,7 @@ #include "lleconomy.h" #include "llhttpclient.h" #include "llsdserialize.h" +#include "llsdutil.h" #include "llstring.h" #include "lltransactiontypes.h" #include "lluuid.h" @@ -101,6 +103,7 @@ static std::string XML_EXTENSIONS = "xml"; static std::string SLOBJECT_EXTENSIONS = "slobject"; #endif static std::string ALL_FILE_EXTENSIONS = "*.*"; +static std::string MODEL_EXTENSIONS = "dae"; std::string build_extensions_string(LLFilePicker::ELoadFilter filter) { @@ -115,6 +118,8 @@ std::string build_extensions_string(LLFilePicker::ELoadFilter filter) return ANIM_EXTENSIONS; case LLFilePicker::FFLOAD_SLOBJECT: return SLOBJECT_EXTENSIONS; + case LLFilePicker::FFLOAD_MODEL: + return MODEL_EXTENSIONS; #ifdef _CORY_TESTING case LLFilePicker::FFLOAD_GEOMETRY: return GEOMETRY_EXTENSIONS; @@ -258,6 +263,16 @@ class LLFileUploadImage : public view_listener_t } }; +class LLFileUploadModel : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::showInstance("upload_model"); + + return TRUE; + } +}; + class LLFileUploadSound : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -319,10 +334,21 @@ class LLFileUploadBulk : public view_listener_t LLAssetStorage::LLStoreAssetCallback callback = NULL; S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); void *userdata = NULL; - upload_new_resource(filename, asset_name, asset_name, 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), - display_name, - callback, expected_upload_cost, userdata); + + upload_new_resource( + filename, + asset_name, + asset_name, + 0, + LLAssetType::AT_NONE, + LLInventoryType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms(), + LLFloaterPerms::getGroupPerms(), + LLFloaterPerms::getEveryonePerms(), + display_name, + callback, + expected_upload_cost, + userdata); // *NOTE: Ew, we don't iterate over the file list here, // we handle the next files in upload_done_callback() @@ -491,17 +517,20 @@ void handle_compress_image(void*) } } -void upload_new_resource(const std::string& src_filename, std::string name, - std::string desc, S32 compression_info, - LLAssetType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata) +void upload_new_resource( + const std::string& src_filename, + std::string name, + std::string desc, + S32 compression_info, + LLAssetType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + S32 expected_upload_cost, + void *userdata) { // Generate the temporary UUID. std::string filename = gDirUtilp->getTempFilename(); @@ -783,9 +812,21 @@ void upload_new_resource(const std::string& src_filename, std::string name, { t_disp_name = src_filename; } - upload_new_resource(tid, asset_type, name, desc, compression_info, // tid - destination_folder_type, inv_type, next_owner_perms, group_perms, everyone_perms, - display_name, callback, expected_upload_cost, userdata); + upload_new_resource( + tid, + asset_type, + name, + desc, + compression_info, // tid + destination_folder_type, + inv_type, + next_owner_perms, + group_perms, + everyone_perms, + display_name, + callback, + expected_upload_cost, + userdata); } else { @@ -801,7 +842,11 @@ void upload_new_resource(const std::string& src_filename, std::string name, } } -void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExtStat ext_status) // StoreAssetData callback (fixed) +void upload_done_callback( + const LLUUID& uuid, + void* user_data, + S32 result, + LLExtStat ext_status) // StoreAssetData callback (fixed) { LLResourceData* data = (LLResourceData*)user_data; S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0; @@ -902,71 +947,134 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt std::string display_name = LLStringUtil::null; LLAssetStorage::LLStoreAssetCallback callback = NULL; void *userdata = NULL; - upload_new_resource(next_file, asset_name, asset_name, // file - 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE, - PERM_NONE, PERM_NONE, PERM_NONE, - display_name, - callback, - expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost - userdata); + upload_new_resource( + next_file, + asset_name, + asset_name, // file + 0, + LLAssetType::AT_NONE, + LLInventoryType::IT_NONE, + PERM_NONE, + PERM_NONE, + PERM_NONE, + display_name, + callback, + expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost + userdata); } } -void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_type, - std::string name, - std::string desc, S32 compression_info, - LLAssetType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata) +LLAssetID upload_new_resource_prep( + const LLTransactionID &tid, + LLAssetType::EType asset_type, + LLInventoryType::EType& inventory_type, + std::string& name, + const std::string& display_name, + std::string& description) { - if(gDisconnected) + if ( gDisconnected ) { - return ; + LLAssetID rv; + + rv.setNull(); + return rv; } LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID()); - if( LLAssetType::AT_SOUND == asset_type ) + if ( LLAssetType::AT_SOUND == asset_type ) { - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_SOUND_COUNT ); + LLViewerStats::getInstance()->incStat( + LLViewerStats::ST_UPLOAD_SOUND_COUNT ); } - else - if( LLAssetType::AT_TEXTURE == asset_type ) + else if ( LLAssetType::AT_TEXTURE == asset_type ) { - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_TEXTURE_COUNT ); + LLViewerStats::getInstance()->incStat( + LLViewerStats::ST_UPLOAD_TEXTURE_COUNT ); } - else - if( LLAssetType::AT_ANIMATION == asset_type) + else if ( LLAssetType::AT_ANIMATION == asset_type ) { - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_ANIM_COUNT ); + LLViewerStats::getInstance()->incStat( + LLViewerStats::ST_UPLOAD_ANIM_COUNT ); } - if(LLInventoryType::IT_NONE == inv_type) + if ( LLInventoryType::IT_NONE == inventory_type ) { - inv_type = LLInventoryType::defaultForAssetType(asset_type); + inventory_type = LLInventoryType::defaultForAssetType(asset_type); } LLStringUtil::stripNonprintable(name); - LLStringUtil::stripNonprintable(desc); - if(name.empty()) + LLStringUtil::stripNonprintable(description); + + if ( name.empty() ) { name = "(No Name)"; } - if(desc.empty()) + if ( description.empty() ) { - desc = "(No Description)"; + description = "(No Description)"; } - + // At this point, we're ready for the upload. std::string upload_message = "Uploading...\n\n"; upload_message.append(display_name); LLUploadDialog::modalUploadDialog(upload_message); + return uuid; +} + +LLSD generate_new_resource_upload_capability_body( + LLAssetType::EType asset_type, + const std::string& name, + const std::string& desc, + LLAssetType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms) +{ + LLSD body; + + body["folder_id"] = gInventory.findCategoryUUIDForType( + (destination_folder_type == LLAssetType::AT_NONE) ? + asset_type : + destination_folder_type); + + body["asset_type"] = LLAssetType::lookup(asset_type); + body["inventory_type"] = LLInventoryType::lookup(inv_type); + body["name"] = name; + body["description"] = desc; + body["next_owner_mask"] = LLSD::Integer(next_owner_perms); + body["group_mask"] = LLSD::Integer(group_perms); + body["everyone_mask"] = LLSD::Integer(everyone_perms); + + return body; +} + +void upload_new_resource( + const LLTransactionID &tid, + LLAssetType::EType asset_type, + std::string name, + std::string desc, + S32 compression_info, + LLAssetType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + S32 expected_upload_cost, + void *userdata) +{ + LLAssetID uuid = + upload_new_resource_prep( + tid, + asset_type, + inv_type, + name, + display_name, + desc); + llinfos << "*** Uploading: " << llendl; llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl; llinfos << "UUID: " << uuid << llendl; @@ -975,26 +1083,32 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty llinfos << "Expected Upload Cost: " << expected_upload_cost << llendl; lldebugs << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLAssetType::AT_NONE) ? asset_type : destination_folder_type) << llendl; lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl; - std::string url = gAgent.getRegion()->getCapability("NewFileAgentInventory"); - if (!url.empty()) + + std::string url = gAgent.getRegion()->getCapability( + "NewFileAgentInventory"); + + if ( !url.empty() ) { llinfos << "New Agent Inventory via capability" << llendl; - LLSD body; - body["folder_id"] = gInventory.findCategoryUUIDForType((destination_folder_type == LLAssetType::AT_NONE) ? asset_type : destination_folder_type); - body["asset_type"] = LLAssetType::lookup(asset_type); - body["inventory_type"] = LLInventoryType::lookup(inv_type); - body["name"] = name; - body["description"] = desc; - body["next_owner_mask"] = LLSD::Integer(next_owner_perms); - body["group_mask"] = LLSD::Integer(group_perms); - body["everyone_mask"] = LLSD::Integer(everyone_perms); - body["expected_upload_cost"] = LLSD::Integer(expected_upload_cost); - - //std::ostringstream llsdxml; - //LLSDSerialize::toPrettyXML(body, llsdxml); - //llinfos << "posting body to capability: " << llsdxml.str() << llendl; - LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, uuid, asset_type)); + LLSD body; + body = generate_new_resource_upload_capability_body( + asset_type, + name, + desc, + destination_folder_type, + inv_type, + next_owner_perms, + group_perms, + everyone_perms); + + LLHTTPClient::post( + url, + body, + new LLNewAgentInventoryResponder( + body, + uuid, + asset_type)); } else { @@ -1039,11 +1153,83 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty } } +BOOL upload_new_variable_cost_resource( + const LLTransactionID &tid, + LLAssetType::EType asset_type, + std::string name, + std::string desc, + S32 compression_info, + LLAssetType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + void *userdata) +{ + LLAssetID uuid = + upload_new_resource_prep( + tid, + asset_type, + inv_type, + name, + display_name, + desc); + + llinfos << "*** Uploading: " << llendl; + llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl; + llinfos << "UUID: " << uuid << llendl; + llinfos << "Name: " << name << llendl; + llinfos << "Desc: " << desc << llendl; + lldebugs << "Folder: " + << gInventory.findCategoryUUIDForType((destination_folder_type == LLAssetType::AT_NONE) ? asset_type : destination_folder_type) << llendl; + lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl; + + std::string url = gAgent.getRegion()->getCapability( + "NewFileAgentInventoryVariablePrice"); + + if ( !url.empty() ) + { + llinfos << "New Agent Inventory variable price upload" + << llendl; + + // Each of the two capabilities has similar data, so + // let's reuse that code + + LLSD body; + + body = generate_new_resource_upload_capability_body( + asset_type, + name, + desc, + destination_folder_type, + inv_type, + next_owner_perms, + group_perms, + everyone_perms); + + LLHTTPClient::post( + url, + body, + new LLNewAgentInventoryVariablePriceResponder( + uuid, + body)); + + return TRUE; + } + else + { + return FALSE; + } +} + void init_menu_file() { view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage"); view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound"); view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim"); + view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel"); view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk"); view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow"); view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows"); diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index bf21292082..b51192b499 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -41,33 +41,56 @@ class LLTransactionID; void init_menu_file(); -void upload_new_resource(const std::string& src_filename, - std::string name, - std::string desc, - S32 compression_info, - LLAssetType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata); +void upload_new_resource( + const std::string& src_filename, + std::string name, + std::string desc, + S32 compression_info, + LLAssetType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + S32 expected_upload_cost, + void *userdata); + +void upload_new_resource( + const LLTransactionID &tid, + LLAssetType::EType type, + std::string name, + std::string desc, + S32 compression_info, + LLAssetType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + S32 expected_upload_cost, + void *userdata); + +// TODO* : Move all uploads to use this new function +// since at some point, that upload path will be deprecated and no longer +// used + +// We make a new function here to ensure that previous code is not broken +BOOL upload_new_variable_cost_resource( + const LLTransactionID &tid, + LLAssetType::EType type, + std::string name, + std::string desc, + S32 compression_info, + LLAssetType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + void *userdata); -void upload_new_resource(const LLTransactionID &tid, - LLAssetType::EType type, - std::string name, - std::string desc, - S32 compression_info, - LLAssetType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata); #endif diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 791ec07349..f16465acba 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -4530,6 +4530,7 @@ void process_economy_data(LLMessageSystem *msg, void** /*user_data*/) gMenuHolder->childSetLabelArg("Upload Image", "[COST]", llformat("%d", upload_cost)); gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", llformat("%d", upload_cost)); + gMenuHolder->childSetLabelArg("Upload Model", "[COST]", llformat("%d", upload_cost)); gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", llformat("%d", upload_cost)); gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", llformat("%d", upload_cost)); } diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 7ea55b49e8..986264ad34 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1437,6 +1437,8 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("MapLayer"); capabilityNames.append("MapLayerGod"); capabilityNames.append("NewFileAgentInventory"); + capabilityNames.append("NewFileAgentInventoryVariablePrice"); + capabilityNames.append("ObjectAdd"); capabilityNames.append("ParcelPropertiesUpdate"); capabilityNames.append("ParcelMediaURLFilterList"); capabilityNames.append("ParcelNavigateMedia"); diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 65994dfb30..ed8d820844 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -477,6 +477,7 @@ LLUIImagePtr LLEmbeddedItems::getItemImage(llwchar ext_char) const case LLAssetType::AT_GESTURE: img_name = "Inv_Gesture"; break; //TODO need img_name case LLAssetType::AT_FAVORITE: img_name = "Inv_Landmark"; break; + case LLAssetType::AT_MESH: img_name = "inv_item_mesh.tga"; break; default: llassert(0); } diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index a0ab4cb1e6..32baa29afb 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -583,7 +583,7 @@ BOOL LLViewerTexture::createGLTexture(S32 discard_level, const LLImageRaw* image llassert_always(mGLTexturep.notNull()) ; BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename) ; - + if(ret) { mFullWidth = mGLTexturep->getCurrentWidth() ; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 5f95e9ccf1..72e40e3030 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -3733,140 +3733,6 @@ void LLViewerWindow::playSnapshotAnimAndSound() BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) { return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type); - - // *TODO below code was broken in deferred pipeline - /* - if ((!raw) || preview_width < 10 || preview_height < 10) - { - return FALSE; - } - - if(gResizeScreenTexture) //the window is resizing - { - return FALSE ; - } - - setCursor(UI_CURSOR_WAIT); - - // Hide all the UI widgets first and draw a frame - BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI); - - if ( prev_draw_ui != show_ui) - { - LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI); - } - - BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments; - if (hide_hud) - { - LLPipeline::sShowHUDAttachments = FALSE; - } - - S32 render_name = gSavedSettings.getS32("RenderName"); - gSavedSettings.setS32("RenderName", 0); - LLVOAvatar::updateFreezeCounter(1) ; //pause avatar updating for one frame - - S32 w = preview_width ; - S32 h = preview_height ; - LLVector2 display_scale = mDisplayScale ; - mDisplayScale.setVec((F32)w / mWindowRect.getWidth(), (F32)h / mWindowRect.getHeight()) ; - LLRect window_rect = mWindowRect; - mWindowRect.set(0, h, w, 0); - - gDisplaySwapBuffers = FALSE; - gDepthDirty = TRUE; - glClearColor(0.f, 0.f, 0.f, 0.f); - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - setup3DRender(); - - LLFontGL::setFontDisplay(FALSE) ; - LLHUDText::setDisplayText(FALSE) ; - if (type == SNAPSHOT_TYPE_OBJECT_ID) - { - gObjectList.renderPickList(gViewerWindow->getVirtualWindowRect(), FALSE, FALSE); - } - else - { - display(do_rebuild, 1.0f, 0, TRUE); - render_ui(); - } - - S32 glformat, gltype, glpixel_length ; - if(SNAPSHOT_TYPE_DEPTH == type) - { - glpixel_length = 4 ; - glformat = GL_DEPTH_COMPONENT ; - gltype = GL_FLOAT ; - } - else - { - glpixel_length = 3 ; - glformat = GL_RGB ; - gltype = GL_UNSIGNED_BYTE ; - } - - raw->resize(w, h, glpixel_length); - glReadPixels(0, 0, w, h, glformat, gltype, raw->getData()); - - if(SNAPSHOT_TYPE_DEPTH == type) - { - LLViewerCamera* camerap = LLViewerCamera::getInstance(); - F32 depth_conversion_factor_1 = (camerap->getFar() + camerap->getNear()) / (2.f * camerap->getFar() * camerap->getNear()); - F32 depth_conversion_factor_2 = (camerap->getFar() - camerap->getNear()) / (2.f * camerap->getFar() * camerap->getNear()); - - //calculate the depth - for (S32 y = 0 ; y < h ; y++) - { - for(S32 x = 0 ; x < w ; x++) - { - S32 i = (w * y + x) << 2 ; - - F32 depth_float_i = *(F32*)(raw->getData() + i); - - F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float_i * depth_conversion_factor_2)); - U8 depth_byte = F32_to_U8(linear_depth_float, camerap->getNear(), camerap->getFar()); - *(raw->getData() + i + 0) = depth_byte; - *(raw->getData() + i + 1) = depth_byte; - *(raw->getData() + i + 2) = depth_byte; - *(raw->getData() + i + 3) = 255; - } - } - } - - LLFontGL::setFontDisplay(TRUE) ; - LLHUDText::setDisplayText(TRUE) ; - mDisplayScale.setVec(display_scale) ; - mWindowRect = window_rect; - setup3DRender(); - gDisplaySwapBuffers = FALSE; - gDepthDirty = TRUE; - - // POST SNAPSHOT - if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI); - } - - if (hide_hud) - { - LLPipeline::sShowHUDAttachments = TRUE; - } - - setCursor(UI_CURSOR_ARROW); - - if (do_rebuild) - { - // If we had to do a rebuild, that means that the lists of drawables to be rendered - // was empty before we started. - // Need to reset these, otherwise we call state sort on it again when render gets called the next time - // and we stand a good chance of crashing on rebuild because the render drawable arrays have multiple copies of - // objects on them. - gPipeline.resetDrawOrders(); - } - - gSavedSettings.setS32("RenderName", render_name); - - return TRUE;*/ } // Saves the image from the screen to the specified filename and path. diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 583246c23e..ef3244b199 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -36,6 +36,8 @@ #include "llvovolume.h" +#include + #include "llviewercontrol.h" #include "lldir.h" #include "llflexibleobject.h" @@ -61,6 +63,7 @@ #include "llsky.h" #include "llviewercamera.h" #include "llviewertexturelist.h" +#include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llviewertextureanim.h" #include "llworld.h" @@ -90,6 +93,12 @@ LLPointer LLVOVolume::sObjectMediaNavigateClient = static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles"); static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes"); +static LLFastTimer::DeclareTimer FTM_BUILD_MESH("Mesh"); +static LLFastTimer::DeclareTimer FTM_MESH_VFS("VFS"); +static LLFastTimer::DeclareTimer FTM_MESH_STREAM("Stream"); +static LLFastTimer::DeclareTimer FTM_MESH_FACES("Faces"); +static LLFastTimer::DeclareTimer FTM_VOLUME_TEXTURES("Volume Textures"); + LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) : LLViewerObject(id, pcode, regionp), @@ -513,6 +522,7 @@ void LLVOVolume::updateTextures(LLAgent &agent) void LLVOVolume::updateTextures() { + LLFastTimer ftm(FTM_VOLUME_TEXTURES); // Update the pixel area of all faces if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE)) @@ -599,36 +609,60 @@ void LLVOVolume::updateTextures() if (isSculpted()) { LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLUUID id = sculpt_params->getSculptTexture(); - mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); - if (mSculptTexture.notNull()) - { - S32 lod = llmin(mLOD, 3); - F32 lodf = ((F32)(lod + 1.0f)/4.f); - F32 tex_size = lodf * MAX_SCULPT_REZ; - mSculptTexture->addTextureStats(2.f * tex_size * tex_size); - mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(), - (S32)LLViewerTexture::BOOST_SCULPTED)); - mSculptTexture->setForSculpt() ; - } - - S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture - S32 current_discard = mSculptLevel; + LLUUID id = sculpt_params->getSculptTexture(); + U8 sculpt_type = sculpt_params->getSculptType(); - if (texture_discard >= 0 && //texture has some data available - (texture_discard < current_discard || //texture has more data than last rebuild - current_discard < 0)) //no previous rebuild + if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) + // mesh is a mesh { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE); - mSculptChanged = TRUE; + if (mSculptLevel == -2) + { + // get the asset please + gPipeline.loadMesh(this, id); + /*gAssetStorage->getAssetData(id, LLAssetType::AT_MESH, (LLGetAssetCallback)NULL, NULL, TRUE); + + if (gAssetStorage->hasLocalAsset(id, LLAssetType::AT_MESH)) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE); + mSculptChanged = TRUE; + }*/ + } } - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SCULPTED)) + else + // mesh is a sculptie + { + mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); + + if (mSculptTexture.notNull()) + { + S32 lod = llmin(mLOD, 3); + F32 lodf = ((F32)(lod + 1.0f)/4.f); + F32 tex_size = lodf * MAX_SCULPT_REZ; + mSculptTexture->addTextureStats(2.f * tex_size * tex_size); + mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(), + (S32)LLViewerTexture::BOOST_SCULPTED)); + mSculptTexture->setForSculpt() ; + } + + S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture + S32 current_discard = mSculptLevel; + + if (texture_discard >= 0 && //texture has some data available + (texture_discard < current_discard || //texture has more data than last rebuild + current_discard < 0)) //no previous rebuild + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE); + mSculptChanged = TRUE; + } + + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SCULPTED)) { setDebugText(llformat("T%d C%d V%d\n%dx%d", texture_discard, current_discard, getVolume()->getSculptLevel(), mSculptTexture->getHeight(), mSculptTexture->getWidth())); } + } } if (getLightTextureID().notNull()) @@ -771,8 +805,10 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline) } -BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume) +BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms, const S32 detail, bool unique_volume) { + LLVolumeParams volume_params = params; + // Check if we need to change implementations bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE); if (is_flexible) @@ -811,21 +847,39 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail if (isSculpted()) { - mSculptTexture = LLViewerTextureManager::getFetchedTexture(volume_params.getSculptID(), TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); - if (mSculptTexture.notNull()) + // if it's a mesh + if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) { - //ignore sculpt GL usage since bao fixed this in a separate branch - if (!gGLActive) + if (getVolume()->getNumVolumeFaces() == 0) { - gGLActive = TRUE; - sculpt(); - gGLActive = FALSE; + //mesh is not loaded, request pipeline load this mesh + LLUUID asset_id = volume_params.getSculptID(); + gPipeline.loadMesh(this, asset_id); } else { - sculpt(); + mSculptLevel = 1; + } + } + else // otherwise is sculptie + { + mSculptTexture = LLViewerTextureManager::getFetchedTexture(volume_params.getSculptID(), TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); + + if (mSculptTexture.notNull()) + { + //ignore sculpt GL usage since bao fixed this in a separate branch + if (!gGLActive) + { + gGLActive = TRUE; + sculpt(); + gGLActive = FALSE; + } + else + { + sculpt(); + } + mSculptLevel = getVolume()->getSculptLevel(); } - mSculptLevel = getVolume()->getSculptLevel(); } } else @@ -838,6 +892,14 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail return FALSE; } + + +void LLVOVolume::notifyMeshLoaded() +{ + mSculptChanged = TRUE; + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY); +} + // sculpt replaces generate() for sculpted surfaces void LLVOVolume::sculpt() { @@ -1039,6 +1101,11 @@ void LLVOVolume::updateFaceFlags() for (S32 i = 0; i < getVolume()->getNumFaces(); i++) { LLFace *face = mDrawable->getFace(i); + if (!face) + { + return; + } + BOOL fullbright = getTE(i)->getFullbright(); face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT); @@ -1111,6 +1178,10 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global) for (S32 i = 0; i < getVolume()->getNumFaces(); i++) { LLFace *face = mDrawable->getFace(i); + if (!face) + { + continue; + } res &= face->genVolumeBBoxes(*getVolume(), i, mRelativeXform, mRelativeXformInvTrans, (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global); @@ -2218,6 +2289,23 @@ BOOL LLVOVolume::isSculpted() const return FALSE; } +BOOL LLVOVolume::isMesh() const +{ + if (isSculpted()) + { + LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + U8 sculpt_type = sculpt_params->getSculptType(); + + if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) + // mesh is a mesh + { + return TRUE; + } + } + + return FALSE; +} + BOOL LLVOVolume::hasLightTexture() const { if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) @@ -2423,6 +2511,30 @@ F32 LLVOVolume::getBinRadius() { F32 radius; + F32 scale = 1.f; + + if (isSculpted()) + { + LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLUUID id = sculpt_params->getSculptTexture(); + U8 sculpt_type = sculpt_params->getSculptType(); + + if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) + // mesh is a mesh + { + LLVolume* volume = getVolume(); + U32 vert_count = 0; + + for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = volume->getVolumeFace(i); + vert_count += face.mVertices.size(); + } + + scale = 1.f/llmax(vert_count/1024.f, 1.f); + } + } + const LLVector3* ext = mDrawable->getSpatialExtents(); BOOL shrink_wrap = mDrawable->isAnimating(); @@ -2481,7 +2593,7 @@ F32 LLVOVolume::getBinRadius() radius = 8.f; } - return llclamp(radius, 0.5f, 256.f); + return llclamp(radius*scale, 0.5f, 256.f); } const LLVector3 LLVOVolume::getPivotPositionAgent() const @@ -3071,6 +3183,11 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) face->getGeometryVolume(*volume, face->getTEOffset(), vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex()); } + + if (!face) + { + llerrs << "WTF?" << llendl; + } } drawablep->clearState(LLDrawable::REBUILD_ALL); @@ -3354,7 +3471,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: } else { - if (LLPipeline::sRenderDeferred && te->getBumpmap()) + if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap()) { registerFace(group, facep, LLRenderPass::PASS_BUMP); } diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 250c3ed917..6aaf5b2fdd 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -182,6 +182,11 @@ public: /*virtual*/ BOOL setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false); void sculpt(); + static void rebuildMeshAssetCallback(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status); + void updateRelativeXform(); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); /*virtual*/ void updateFaceSize(S32 idx); @@ -227,6 +232,7 @@ public: U32 getVolumeInterfaceID() const; virtual BOOL isFlexible() const; virtual BOOL isSculpted() const; + virtual BOOL isMesh() const; virtual BOOL hasLightTexture() const; BOOL isVolumeGlobal() const; @@ -235,6 +241,7 @@ public: void updateObjectMediaData(const LLSD &media_data_duples); void mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event); + // Sync the given media data with the impl and the given te void syncMediaData(S32 te, const LLSD &media_data, bool merge, bool ignore_agent); @@ -247,6 +254,8 @@ public: bool hasMedia() const; + void notifyMeshLoaded(); + protected: S32 computeLODDetail(F32 distance, F32 radius); BOOL calcLOD(); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index b50e71bf48..7cf5cf75ad 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -342,6 +342,8 @@ LLPipeline::LLPipeline() : mGlowPool(NULL), mBumpPool(NULL), mWLSkyPool(NULL), + mMeshMutex(NULL), + mMeshThreadCount(0), mLightMask(0), mLightMovingMask(0), mLightingDetail(0) @@ -399,6 +401,7 @@ void LLPipeline::init() stop_glerror(); + mMeshMutex = new LLMutex(NULL); for (U32 i = 0; i < 2; ++i) { mSpotLightFade[i] = 1.f; @@ -473,6 +476,9 @@ void LLPipeline::cleanup() //delete mWLSkyPool; mWLSkyPool = NULL; + delete mMeshMutex; + mMeshMutex = NULL; + releaseGLBuffers(); mBloomImagep = NULL; @@ -1783,6 +1789,8 @@ void LLPipeline::rebuildPriorityGroups() assertInitialized(); + notifyLoadedMeshes(); + // Iterate through all drawables on the priority build queue, for (LLSpatialGroup::sg_list_t::iterator iter = mGroupQ1.begin(); iter != mGroupQ1.end(); ++iter) @@ -1793,6 +1801,7 @@ void LLPipeline::rebuildPriorityGroups() } mGroupQ1.clear(); + } void LLPipeline::rebuildGroups() @@ -3419,27 +3428,14 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) gGLLastMatrix = NULL; glLoadMatrixd(gGLModelView); - renderHighlights(); - mHighlightFaces.clear(); - - renderDebug(); - - LLVertexBuffer::unbind(); - - if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - // Render debugging beacons. - gObjectList.renderObjectBeacons(); - LLHUDObject::renderAll(); - gObjectList.resetObjectBeacons(); - } - if (occlude) { occlude = FALSE; gGLLastMatrix = NULL; glLoadMatrixd(gGLModelView); doOcclusion(camera); + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); } } @@ -5836,6 +5832,12 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) gGL.getTexUnit(0)->activate(); gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); + + if (LLRenderTarget::sUseFBO) + { //copy depth buffer from mScreen to framebuffer + LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(), + 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } } @@ -6912,6 +6914,24 @@ void LLPipeline::renderDeferredLighting() mRenderTypeMask = render_mask; } + { + //render highlights, etc. + renderHighlights(); + mHighlightFaces.clear(); + + renderDebug(); + + LLVertexBuffer::unbind(); + + if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + // Render debugging beacons. + gObjectList.renderObjectBeacons(); + LLHUDObject::renderAll(); + gObjectList.resetObjectBeacons(); + } + } + mScreen.flush(); } @@ -7241,18 +7261,12 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) LLGLDisable cull(GL_CULL_FACE); updateCull(camera, ref_result, 1); stateSort(camera, ref_result); - gGL.setColorMask(true, true); - mWaterRef.clear(); - gGL.setColorMask(true, false); - - } - else - { - gGL.setColorMask(true, true); - mWaterRef.clear(); - gGL.setColorMask(true, false); - } - + } + + gGL.setColorMask(true, true); + mWaterRef.clear(); + gGL.setColorMask(true, false); + ref_mask = mRenderTypeMask; mRenderTypeMask = mask; } @@ -7907,6 +7921,7 @@ void LLPipeline::generateHighlight(LLCamera& camera) mHighlight.flush(); gGL.setColorMask(true, false); + gViewerWindow->setup3DViewport(); } } @@ -8886,3 +8901,175 @@ LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups() } +void LLPipeline::loadMesh(LLVOVolume* volume, LLUUID mesh_id) +{ + + { + LLMutexLock lock(mMeshMutex); + //add volume to list of loading meshes + mesh_load_map::iterator iter = mLoadingMeshes.find(mesh_id); + if (iter != mLoadingMeshes.end()) + { //request pending for this mesh, append volume id to list + iter->second.insert(volume->getID()); + return; + } + + //first request for this mesh + mLoadingMeshes[mesh_id].insert(volume->getID()); + } + + if (gAssetStorage->hasLocalAsset(mesh_id, LLAssetType::AT_MESH)) + { //already have asset, load desired LOD in background + mPendingMeshes.push_back(new LLMeshThread(mesh_id, volume->getVolume())); + } + else + { //fetch asset and load when done + gAssetStorage->getAssetData(mesh_id, LLAssetType::AT_MESH, + getMeshAssetCallback, volume->getVolume(), TRUE); + } + +} + +//static +void LLPipeline::getMeshAssetCallback(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + gPipeline.mPendingMeshes.push_back(new LLMeshThread(asset_uuid, (LLVolume*) user_data)); +} + + +LLPipeline::LLMeshThread::LLMeshThread(LLUUID mesh_id, LLVolume* target) +: LLThread("mesh_loading_thread") +{ + mMeshID = mesh_id; + mVolume = NULL; + mDetail = target->getDetail(); + mTargetVolume = target; +} + +LLPipeline::LLMeshThread::~LLMeshThread() +{ + +} + +void LLPipeline::LLMeshThread::run() +{ + if (!gAssetStorage || LLApp::instance()->isQuitting()) + { + return; + } + + char* buffer = NULL; + S32 size = 0; + + LLVFS* vfs = gAssetStorage->mVFS; + + { + LLVFile file(vfs, mMeshID, LLAssetType::AT_MESH, LLVFile::READ); + file.waitForLock(VFSLOCK_READ); + size = file.getSize(); + + if (size == 0) + { + gPipeline.meshLoaded(this); + return; + } + + buffer = new char[size]; + file.read((U8*)&buffer[0], size); + } + + { + std::string buffer_string(buffer, size); + std::istringstream buffer_stream(buffer_string); + + { + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + mVolume = new LLVolume(volume_params, mDetail); + mVolume->createVolumeFacesFromStream(buffer_stream); + } + } + delete[] buffer; + + gPipeline.meshLoaded(this); +} + +void LLPipeline::meshLoaded(LLPipeline::LLMeshThread* mesh_thread) +{ + LLMutexLock lock(mMeshMutex); + mLoadedMeshes.push_back(mesh_thread); +} + +void LLPipeline::notifyLoadedMeshes() +{ //called from main thread + + U32 max_thread_count = llmax(gSavedSettings.getU32("MeshThreadCount"), (U32) 1); + while (mMeshThreadCount < max_thread_count && !mPendingMeshes.empty()) + { + LLMeshThread* mesh_thread = mPendingMeshes.front(); + mesh_thread->start(); + ++mMeshThreadCount; + mPendingMeshes.pop_front(); + } + + LLMutexLock lock(mMeshMutex); + std::list stopping_threads; + + for (std::list::iterator iter = mLoadedMeshes.begin(); iter != mLoadedMeshes.end(); ++iter) + { //for each mesh done loading + LLMeshThread* mesh = *iter; + + if (!mesh->isStopped()) + { //don't process a LLMeshThread until it's stopped + stopping_threads.push_back(mesh); + continue; + } + + //get list of objects waiting to be notified this mesh is loaded + mesh_load_map::iterator obj_iter = mLoadingMeshes.find(mesh->mMeshID); + + if (mesh->mVolume && obj_iter != mLoadingMeshes.end()) + { + //make sure target volume is still valid + BOOL valid = FALSE; + + for (std::set::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) + { + LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter); + + if (vobj) + { + if (vobj->getVolume() == mesh->mTargetVolume) + { + valid = TRUE; + } + } + } + + + if (valid) + { + mesh->mTargetVolume->copyVolumeFaces(mesh->mVolume); + for (std::set::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) + { + LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter); + if (vobj) + { + vobj->notifyMeshLoaded(); + } + } + } + + mLoadingMeshes.erase(mesh->mMeshID); + } + + delete mesh; + --mMeshThreadCount; + } + + mLoadedMeshes = stopping_threads; +} + diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index ce50a37405..bf654f88b1 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -278,6 +278,10 @@ public: LLCullResult::sg_list_t::iterator beginAlphaGroups(); LLCullResult::sg_list_t::iterator endAlphaGroups(); + + //mesh management functions + void loadMesh(LLVOVolume* volume, LLUUID mesh_id); + void addTrianglesDrawn(S32 count); BOOL hasRenderType(const U32 type) const { return (type && (mRenderTypeMask & (1< mSelectedFaces; + typedef std::map > mesh_load_map; + mesh_load_map mLoadingMeshes; + + LLMutex* mMeshMutex; + + class LLMeshThread : public LLThread + { + public: + LLPointer mVolume; + LLVolume* mTargetVolume; + LLUUID mMeshID; + F32 mDetail; + LLMeshThread(LLUUID mesh_id, LLVolume* target); + ~LLMeshThread(); + void run(); + }; + + static void getMeshAssetCallback(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status); + + std::list mLoadedMeshes; + std::list mPendingMeshes; + U32 mMeshThreadCount; + + void meshLoaded(LLMeshThread* mesh_thread); + void notifyLoadedMeshes(); + LLPointer mFaceSelectImagep; LLPointer mBloomImagep; LLPointer mBloomImage2p; diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 01976c9a5c..26b0b39a68 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -568,6 +568,7 @@ + @@ -591,6 +592,7 @@ + diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index 4d7433233a..09240a3e27 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -152,16 +152,19 @@ It is a rare mind indeed that can render the hitherto non-existent blindingly ob word_wrap="true"> 3Dconnexion SDK Copyright (C) 1992-2007 3Dconnexion APR Copyright (C) 2000-2004 The Apache Software Foundation + Collada DOM Copyright 2005 Sony Computer Entertainment Inc. cURL Copyright (C) 1996-2002, Daniel Stenberg, (daniel@haxx.se) DBus/dbus-glib Copyright (C) 2002, 2003 CodeFactory AB / Copyright (C) 2003, 2004 Red Hat, Inc. expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. FreeType Copyright (C) 1996-2002, The FreeType Project (www.freetype.org). GL Copyright (C) 1999-2004 Brian Paul. + GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia. Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) jpeglib Copyright (C) 1991-1998, Thomas G. Lane. ogg/vorbis Copyright (C) 2001, Xiphophorus OpenSSL Copyright (C) 1998-2002 The OpenSSL Project. + PCRE Copyright (c) 1997-2008 University of Cambridge SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) xmlrpc-epi Copyright (C) 2000 Epinions, Inc. diff --git a/indra/newview/skins/default/xui/en/floater_inventory.xml b/indra/newview/skins/default/xui/en/floater_inventory.xml index 0f06558dd1..6afeb4e82d 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory.xml @@ -123,6 +123,16 @@ + + + + + diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 284594426c..d90d1f0635 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2210,10 +2210,10 @@ name="Fast Alpha"> + parameter="RenderFastAlpha" /> + parameter="RenderFastAlpha" /> - @@ -6551,6 +6551,29 @@ Server Error: Media update or get failed. yestext="OK"/> + + +Are you sure you want to delete your teleport history? + + + + +This upload will cost L$[PRICE], do you wish to continue with the upload? + + + Favorites Current Outfit My Outfits + Meshes Friends diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 045990811b..db4b68e9d6 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -194,6 +194,12 @@ class WindowsManifest(ViewerManifest): # For using FMOD for sound... DJS self.path("fmod.dll") + # For automatic level of detail generation in mesh importer + self.path("glod.dll") + + # For reading collada files + self.path("libcollada14dom21.dll") + # For textures if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): self.path("openjpeg.dll") diff --git a/install.xml b/install.xml index 44224664ca..24ade32095 100644 --- a/install.xml +++ b/install.xml @@ -43,6 +43,39 @@ + GLOD + + copyright + Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia. All rights reserved. + description + Geometric Level of Detail for OpenGL + license + GLOD + packages + + darwin + + md5sum + ab78835bafcad3bb7223eaeecb5a6a4b + url + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GLOD-1.0pre4-darwin-20090918.tar.bz2 + + linux + + md5sum + 66ae292063b80f3a9fecb46dcd4fe5ec + url + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GLOD-1.0pre4-linux-20091023.tar.bz2 + + windows + + md5sum + b97aa644a548310ca3c916518bb07b7e + url + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GLOD-windows-20090915.tar.bz2 + + + SDL copyright @@ -220,6 +253,39 @@ + colladadom + + copyright + Copyright 2005 Sony Computer Entertainment Inc. + description + Library for processing collada file format + license + scea + packages + + darwin + + md5sum + 786de8bfebb5df3a3b51a7832119f8d8 + url + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/colladadom-2.1.1-darwin-20090731.tar.bz2 + + linux + + md5sum + 01d17182ecc6728edaa520b3c780d194 + url + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/colladadom-2.1.1-linux-20090921.tar.bz2 + + windows + + md5sum + fd3e5dade35c586ae13a320ab731df0d + url + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/colladadom-2.1.1-windows-20090908.tar.bz2 + + + curl copyright @@ -1186,6 +1252,32 @@ anguage Infrstructure (CLI) international standard + pcre + + copyright + Copyright (c) 1997-2008 University of Cambridge + description + Regular expression library + license + bsd + packages + + darwin + + md5sum + 63e2dc55142b8b36521c1b0c9b6ed6bb + url + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/pcre-7.6-darwin-20090730.tar.bz2 + + linux + + md5sum + 0886d0b1cdf104b6341df1832a8a7e09 + url + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/pcre-7.6-linux-20090804.tar.bz2 + + + quicktime copyright @@ -1400,6 +1492,75 @@ anguage Infrstructure (CLI) international standard url http://www.xfree86.org/4.4.0/LICENSE9.html#sgi + GLOD + + text + The GLOD Open-Source License Version 1.0 July 22, 2003 + +Copyright (C) 2003 Jonathan Cohen, Nat Duca, Johns Hopkins University +and David Luebke, Brenden Schubert, University of Virginia. All rights +reserved. + +Redistribution and use in source and binary forms, with or without +modification, is permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer and + request. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer and + request in the documentation and/or other materials provided with + the distribution. + +3. The name "GLOD" must not be used to endorse or promote products + derived from this software without prior written permission. + +4. Redistributions of any modified version of this source, whether in + source or binary form , must include a form of the following + acknowledgment: "This product is derived from the GLOD library, + which is available from http://www.cs.jhu.edu/~graphics/GLOD." + +5. Redistributions of any modified version of this source in binary + form must provide, free of charge, access to the modified version + of the code. + +6. This license shall be governed by and construed and enforced in + accordance with the laws of the State of Maryland, without + reference to its conflicts of law provisions. The exclusive + jurisdiction and venue for all legal actions relating to this + license shall be in courts of competent subject matter jurisdiction + located in the State of Maryland. + +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, GLOD IS PROVIDED +UNDER THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +THAT GLOD IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR +PURPOSE OR NON-INFRINGING. ALL WARRANTIES ARE DISCLAIMED AND THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE CODE IS WITH +YOU. SHOULD ANY CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE +COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY +NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY +CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY CODE IS +AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY +SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES FOR LOSS OF +PROFITS, REVENUE, OR FOR LOSS OF INFORMATION OR ANY OTHER LOSS. + +YOU EXPRESSLY AGREE TO FOREVER INDEMNIFY, DEFEND AND HOLD HARMLESS THE +COPYRIGHT HOLDERS AND CONTRIBUTORS OF GLOD AGAINST ALL CLAIMS, +DEMANDS, SUITS OR OTHER ACTIONS ARISING DIRECTLY OR INDIRECTLY FROM +YOUR ACCEPTANCE AND USE OF GLOD. + +Although NOT REQUIRED, we would appreciate it if active users of GLOD +put a link on their web site to the GLOD web site when possible. + + url + http://www.cs.jhu.edu/~graphics/GLOD/license/ + MSDTW text @@ -1725,6 +1886,11 @@ IMPORTANT NOTE: To the extent this software may be used to reproduce materials, EA0300 + scea + + url + http://research.scea.com/scea_shared_source_license.html + sleepycat url -- cgit v1.2.3 From 63b9bd43ff41da01d549f630bd838caff0dffd97 Mon Sep 17 00:00:00 2001 From: Palmer Date: Mon, 2 Nov 2009 14:56:46 -0800 Subject: Repairing things that didn't quite merge properly. --- indra/llprimitive/llprimitive.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index c30ef0350f..da1cfc2074 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -743,6 +743,8 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai setNumTEs(mVolumep->getNumFaces()); return TRUE; } + + U32 old_face_mask = mVolumep->mFaceMask; S32 face_bit = 0; S32 cur_mask = 0; -- cgit v1.2.3 From 9c3595465972ba4be916e871f6b0a62cc0c13d4a Mon Sep 17 00:00:00 2001 From: Jon Wolk Date: Tue, 3 Nov 2009 19:36:39 +0000 Subject: Changed variable price upload responders to reflect server changes. I hope this gets pulled into the hg repository --- indra/newview/llassetuploadresponders.cpp | 176 ++++++++++++++++++++---------- indra/newview/llassetuploadresponders.h | 3 +- indra/newview/llviewermenufile.cpp | 138 ++++++++++++++--------- indra/newview/llviewermenufile.h | 16 ++- 4 files changed, 212 insertions(+), 121 deletions(-) diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index cb03379b23..680d1acd81 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -72,7 +72,7 @@ static const S32 FILE_COUNT_DISPLAY_THRESHOLD = 5; void dialog_refresh_all(); -void on_new_single_inventory_upload_complete( +static void on_new_single_inventory_upload_complete( LLAssetType::EType asset_type, LLInventoryType::EType inventory_type, const std::string inventory_type_string, @@ -736,22 +736,103 @@ public: LLUploadDialog::modalUploadFinished(); } - void onApplicationLevelError(const std::string& error_identifier) + void onApplicationLevelError(const LLSD& error) { - // TODO*: Pull these user visible strings from an xml file - // to be localized + static const std::string _IDENTIFIER = "identifier"; + static const std::string _INSUFFICIENT_FUNDS = "NewAgentInventory_InsufficientLindenDollarBalance"; + static const std::string _MISSING_REQUIRED_PARAMETER = + "NewAgentInventory_MissingRequiredParamater"; + static const std::string _INVALID_REQUEST_BODY = + "NewAgentInventory_InvalidRequestBody"; + static const std::string _RESOURCE_COST_DIFFERS = + "NewAgentInventory_ResourceCostDiffers"; + + static const std::string _MISSING_PARAMETER = "missing_parameter"; + static const std::string _INVALID_PARAMETER = "invalid_parameter"; + static const std::string _MISSING_RESOURCE = "missing_resource"; + static const std::string _INVALID_RESOURCE = "invalid_resource"; + + // TODO* Add the other error_identifiers + std::string error_identifier = error[_IDENTIFIER].asString(); + // TODO*: Pull these user visible strings from an xml file + // to be localized if ( _INSUFFICIENT_FUNDS == error_identifier ) { displayCannotUploadReason("You do not have a sufficient L$ balance to complete this upload."); } + else if ( _MISSING_REQUIRED_PARAMETER == error_identifier ) + { + // Missing parameters + if (error.has(_MISSING_PARAMETER) ) + { + std::string message = + "Upload request was missing required parameter '[P]'"; + LLStringUtil::replaceString( + message, + "[P]", + error[_MISSING_PARAMETER].asString()); + + displayCannotUploadReason(message); + } + else + { + std::string message = + "Upload request was missing a required parameter"; + displayCannotUploadReason(message); + } + } + else if ( _INVALID_REQUEST_BODY == error_identifier ) + { + // Invalid request body, check to see if + // a particular parameter was invalid + if ( error.has(_INVALID_PARAMETER) ) + { + std::string message = "Upload parameter '[P]' is invalid."; + LLStringUtil::replaceString( + message, + "[P]", + error[_INVALID_PARAMETER].asString()); + + // See if the server also responds with what resource + // is missing. + if ( error.has(_MISSING_RESOURCE) ) + { + message += "\nMissing resource '[R]'."; + + LLStringUtil::replaceString( + message, + "[R]", + error[_MISSING_RESOURCE].asString()); + } + else if ( error.has(_INVALID_RESOURCE) ) + { + message += "\nInvalid resource '[R]'."; + + LLStringUtil::replaceString( + message, + "[R]", + error[_INVALID_RESOURCE].asString()); + } + + displayCannotUploadReason(message); + } + else + { + std::string message = "Upload request was malformed"; + displayCannotUploadReason(message); + } + } + else if ( _RESOURCE_COST_DIFFERS == error_identifier ) + { + displayCannotUploadReason("The resource cost associated with this upload is not consistent with the server."); + } else { displayCannotUploadReason("Unknown Error"); - } } @@ -761,14 +842,18 @@ public: "The server is experiencing unexpected difficulties."); } - void onTransportError(const std::string& error_identifier) + void onTransportError(const LLSD& error) { - // TODO*: Pull these user visible strings from an xml file - // to be localized + static const std::string _IDENTIFIER = "identifier"; static const std::string _SERVER_ERROR_AFTER_CHARGE = "NewAgentInventory_ServerErrorAfterCharge"; + std::string error_identifier = error[_IDENTIFIER].asString(); + + // TODO*: Pull the user visible strings from an xml file + // to be localized + if ( _SERVER_ERROR_AFTER_CHARGE == error_identifier ) { displayCannotUploadReason( @@ -779,7 +864,6 @@ public: displayCannotUploadReason( "The server is experiencing unexpected difficulties."); } - } bool uploadConfirmationCallback( @@ -798,17 +882,26 @@ public: notification["payload"]["confirmation_url"].asString(); // Yay! We are confirming or cancelling our upload - LLSD body; - - body["confirm_upload"] = false; - switch(option) { case 0: { - body["confirm_upload"] = true; - body["expected_upload_price"] = - notification["payload"]["expected_upload_price"]; + if ( getFilename().empty() ) + { + // we have no filename, use virtual file ID instead + LLHTTPClient::postFile( + confirmation_url, + getVFileID(), + getAssetType(), + responder); + } + else + { + LLHTTPClient::postFile( + confirmation_url, + getFilename(), + responder); + } } break; case 1: @@ -816,8 +909,6 @@ public: break; } - LLHTTPClient::post(confirmation_url, body, responder); - return false; } @@ -865,9 +956,8 @@ void LLNewAgentInventoryVariablePriceResponder::errorWithContent( if ( content.has("error") ) { static const std::string _ERROR = "error"; - static const std::string _IDENTIFIER = "identifier"; - mImpl->onTransportError(content[_ERROR][_IDENTIFIER].asString()); + mImpl->onTransportError(content[_ERROR]); } else { @@ -880,52 +970,25 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) // Parse out application level errors and the appropriate // responses for them static const std::string _ERROR = "error"; - static const std::string _IDENTIFIER = "identifier"; static const std::string _STATE = "state"; static const std::string _COMPLETE = "complete"; - static const std::string _COST_ANALYSIS = "cost_analysis"; - static const std::string _NEEDS_CONFIRMATION = "needs_confirmation"; - static const std::string _CANCEL = "cancel"; + static const std::string _CONFIRM_UPLOAD = "confirm_upload"; - static const std::string _RESOURCE_COST = "resource_cost"; static const std::string _UPLOAD_PRICE = "upload_price"; - - static const std::string _ANALYZER = "analyzer"; static const std::string _RSVP = "rsvp"; // Check for application level errors if ( content.has(_ERROR) ) { - onApplicationLevelError(content[_ERROR][_IDENTIFIER].asString()); + onApplicationLevelError(content[_ERROR]); return; } std::string state = content[_STATE]; LLAssetType::EType asset_type = mImpl->getAssetType(); - if ( _COST_ANALYSIS == state ) - { - std::string analyzer_url = content[_ANALYZER]; - - if ( mImpl->getFilename().empty() ) - { - // we have no filename, use virtual file ID instead - LLHTTPClient::postFile( - analyzer_url, - mImpl->getVFileID(), - asset_type, - this); - } - else - { - LLHTTPClient::postFile( - analyzer_url, - mImpl->getFilename(), - this); - } - } - else if ( _COMPLETE == state ) + if ( _COMPLETE == state ) { // rename file in VFS with new asset id if (mImpl->getFilename().empty()) @@ -952,17 +1015,12 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) // TODO* Add bulk (serial) uploading or add // a super class of this that does so } - else if ( _NEEDS_CONFIRMATION == state ) + else if ( _CONFIRM_UPLOAD == state ) { showConfirmationDialog( content[_UPLOAD_PRICE].asInteger(), - content[_RESOURCE_COST].asInteger(), content[_RSVP].asString()); } - else if ( _CANCEL == state ) - { - // cancelled, do nothing - } else { onApplicationLevelError(""); @@ -970,14 +1028,13 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) } void LLNewAgentInventoryVariablePriceResponder::onApplicationLevelError( - const std::string& error_identifier) + const LLSD& error) { - mImpl->onApplicationLevelError(error_identifier); + mImpl->onApplicationLevelError(error); } void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog( S32 upload_price, - S32 resource_cost, const std::string& confirmation_url) { if ( 0 == upload_price ) @@ -998,7 +1055,6 @@ void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog( substitutions["PRICE"] = upload_price; payload["confirmation_url"] = confirmation_url; - payload["expected_upload_price"] = upload_price; // The creating of a new instrusive_ptr(this) // creates a new boost::intrusive_ptr diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index adbf13519b..04636d4977 100644 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -102,10 +102,9 @@ public: void result(const LLSD& content); virtual void onApplicationLevelError( - const std::string& error_identifier); + const LLSD& error); virtual void showConfirmationDialog( S32 upload_price, - S32 resource_cost, const std::string& confirmation_url); private: diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 836ac79a87..7b9494c02a 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -964,60 +964,24 @@ void upload_done_callback( } } -LLAssetID upload_new_resource_prep( - const LLTransactionID &tid, +static LLAssetID upload_new_resource_prep( + const LLTransactionID& tid, LLAssetType::EType asset_type, LLInventoryType::EType& inventory_type, std::string& name, const std::string& display_name, std::string& description) { - if ( gDisconnected ) - { - LLAssetID rv; + LLAssetID uuid = generate_asset_id_for_new_upload(tid); - rv.setNull(); - return rv; - } + increase_new_upload_stats(asset_type); - LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID()); - - if ( LLAssetType::AT_SOUND == asset_type ) - { - LLViewerStats::getInstance()->incStat( - LLViewerStats::ST_UPLOAD_SOUND_COUNT ); - } - else if ( LLAssetType::AT_TEXTURE == asset_type ) - { - LLViewerStats::getInstance()->incStat( - LLViewerStats::ST_UPLOAD_TEXTURE_COUNT ); - } - else if ( LLAssetType::AT_ANIMATION == asset_type ) - { - LLViewerStats::getInstance()->incStat( - LLViewerStats::ST_UPLOAD_ANIM_COUNT ); - } - - if ( LLInventoryType::IT_NONE == inventory_type ) - { - inventory_type = LLInventoryType::defaultForAssetType(asset_type); - } - LLStringUtil::stripNonprintable(name); - LLStringUtil::stripNonprintable(description); - - if ( name.empty() ) - { - name = "(No Name)"; - } - if ( description.empty() ) - { - description = "(No Description)"; - } - - // At this point, we're ready for the upload. - std::string upload_message = "Uploading...\n\n"; - upload_message.append(display_name); - LLUploadDialog::modalUploadDialog(upload_message); + assign_defaults_and_show_upload_message( + asset_type, + inventory_type, + name, + display_name, + description); return uuid; } @@ -1146,27 +1110,27 @@ void upload_new_resource( { asset_callback = callback; } - gAssetStorage->storeAssetData(data->mAssetInfo.mTransactionID, data->mAssetInfo.mType, - asset_callback, - (void*)data, - FALSE); + gAssetStorage->storeAssetData( + data->mAssetInfo.mTransactionID, + data->mAssetInfo.mType, + asset_callback, + (void*)data, + FALSE); } } -BOOL upload_new_variable_cost_resource( +BOOL upload_new_variable_price_resource( const LLTransactionID &tid, LLAssetType::EType asset_type, std::string name, std::string desc, - S32 compression_info, LLAssetType::EType destination_folder_type, LLInventoryType::EType inv_type, U32 next_owner_perms, U32 group_perms, U32 everyone_perms, const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - void *userdata) + const LLSD& asset_resources) { LLAssetID uuid = upload_new_resource_prep( @@ -1209,6 +1173,8 @@ BOOL upload_new_variable_cost_resource( group_perms, everyone_perms); + body["asset_resources"] = asset_resources; + LLHTTPClient::post( url, body, @@ -1224,6 +1190,70 @@ BOOL upload_new_variable_cost_resource( } } +LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid) +{ + if ( gDisconnected ) + { + LLAssetID rv; + + rv.setNull(); + return rv; + } + + LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID()); + + return uuid; +} + +void increase_new_upload_stats(LLAssetType::EType asset_type) +{ + if ( LLAssetType::AT_SOUND == asset_type ) + { + LLViewerStats::getInstance()->incStat( + LLViewerStats::ST_UPLOAD_SOUND_COUNT ); + } + else if ( LLAssetType::AT_TEXTURE == asset_type ) + { + LLViewerStats::getInstance()->incStat( + LLViewerStats::ST_UPLOAD_TEXTURE_COUNT ); + } + else if ( LLAssetType::AT_ANIMATION == asset_type ) + { + LLViewerStats::getInstance()->incStat( + LLViewerStats::ST_UPLOAD_ANIM_COUNT ); + } +} + +void assign_defaults_and_show_upload_message( + LLAssetType::EType asset_type, + LLInventoryType::EType& inventory_type, + std::string& name, + const std::string& display_name, + std::string& description) +{ + if ( LLInventoryType::IT_NONE == inventory_type ) + { + inventory_type = LLInventoryType::defaultForAssetType(asset_type); + } + LLStringUtil::stripNonprintable(name); + LLStringUtil::stripNonprintable(description); + + if ( name.empty() ) + { + name = "(No Name)"; + } + if ( description.empty() ) + { + description = "(No Description)"; + } + + // At this point, we're ready for the upload. + std::string upload_message = "Uploading...\n\n"; + upload_message.append(display_name); + LLUploadDialog::modalUploadDialog(upload_message); +} + + void init_menu_file() { view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage"); diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index b51192b499..858fcd51de 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -77,20 +77,26 @@ void upload_new_resource( // used // We make a new function here to ensure that previous code is not broken -BOOL upload_new_variable_cost_resource( - const LLTransactionID &tid, +BOOL upload_new_variable_price_resource( + const LLTransactionID& tid, LLAssetType::EType type, std::string name, std::string desc, - S32 compression_info, LLAssetType::EType destination_folder_type, LLInventoryType::EType inv_type, U32 next_owner_perms, U32 group_perms, U32 everyone_perms, const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - void *userdata); + const LLSD& asset_resources); +LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid); +void increase_new_upload_stats(LLAssetType::EType asset_type); +void assign_defaults_and_show_upload_message( + LLAssetType::EType asset_type, + LLInventoryType::EType& inventory_type, + std::string& name, + const std::string& display_name, + std::string& description); #endif -- cgit v1.2.3 From e8eb8a86a69c7ba345dafbadb6aa72fc5bba090e Mon Sep 17 00:00:00 2001 From: Palmer Date: Tue, 3 Nov 2009 17:22:01 -0800 Subject: Quick fix to get collada working. Will need to make collada and boost happier. --- install.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.xml b/install.xml index cb477701b7..2f22ba5c0d 100644 --- a/install.xml +++ b/install.xml @@ -280,9 +280,9 @@ windows md5sum - fd3e5dade35c586ae13a320ab731df0d + c239ce23ed3f0dbbe58a1ddba05aee0b url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/colladadom-2.1.1-windows-20090908.tar.bz2 + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/colladadom-2.1.1-windows-20091103.tar.bz2 -- cgit v1.2.3 From c3bb2669ce30681449f7fe68f0822878565c273f Mon Sep 17 00:00:00 2001 From: "palmer@sansome-guest-196.lindenlab.com" Date: Tue, 3 Nov 2009 17:43:47 -0800 Subject: fix to make build run on mac --- indra/cmake/00-Common.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index e7afe0ecba..5c0e639947 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -208,7 +208,7 @@ if (LINUX OR DARWIN) set(GCC_WARNINGS "${GCC_WARNINGS} -Werror") endif (NOT GCC_DISABLE_FATAL_WARNINGS) - set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual") + set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor") set(CMAKE_C_FLAGS "${GCC_WARNINGS} ${CMAKE_C_FLAGS}") set(CMAKE_CXX_FLAGS "${GCC_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}") -- cgit v1.2.3 From 88292104d9a2332e6169f2add8f0b590bb22dbff Mon Sep 17 00:00:00 2001 From: David Parks Date: Wed, 4 Nov 2009 14:19:05 +0000 Subject: Fix for crash when loading some meshes. Added button to auto-fill LODs. --- indra/llmath/llvolume.cpp | 4 +++- indra/newview/pipeline.cpp | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index afa82ed399..ddd1b4b3db 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1690,9 +1690,11 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mGenerateSingleFace = generate_single_face; - generate(); + mLODScaleBias.setVec(1,1,1); + if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE) { + generate(); createVolumeFaces(); } } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 7cf5cf75ad..4fc94c08bc 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -8988,6 +8988,7 @@ void LLPipeline::LLMeshThread::run() { LLVolumeParams volume_params; volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + volume_params.setSculptID(mMeshID, LL_SCULPT_TYPE_MESH); mVolume = new LLVolume(volume_params, mDetail); mVolume->createVolumeFacesFromStream(buffer_stream); } -- cgit v1.2.3 From 1c495c56c1011f4514d96b75cbcfb5a8256de78f Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 5 Nov 2009 17:12:18 -0600 Subject: Fix for crash on teleport to mesh enabled region. Fix for flashing meshes on LOD switch. --- indra/llprimitive/llprimitive.cpp | 4 ++++ indra/newview/pipeline.cpp | 47 ++++++++++++++++++++++++++++++++++----- indra/newview/pipeline.h | 2 +- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index da1cfc2074..52265e7ad5 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -744,6 +744,7 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai return TRUE; } +#if 0 U32 old_face_mask = mVolumep->mFaceMask; S32 face_bit = 0; @@ -941,6 +942,9 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai setTE(te_num, *(old_tes.getTexture(face_mapping[face_bit]))); } } +#else + setNumTEs(mVolumep->getNumFaces()); +#endif return TRUE; } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 1a1d29ac32..4ac95fa939 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -8902,33 +8902,68 @@ LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups() } -void LLPipeline::loadMesh(LLVOVolume* volume, LLUUID mesh_id) +void LLPipeline::loadMesh(LLVOVolume* vobj, LLUUID mesh_id, S32 detail) { - { LLMutexLock lock(mMeshMutex); //add volume to list of loading meshes mesh_load_map::iterator iter = mLoadingMeshes.find(mesh_id); if (iter != mLoadingMeshes.end()) { //request pending for this mesh, append volume id to list - iter->second.insert(volume->getID()); + iter->second.insert(vobj->getID()); return; } //first request for this mesh - mLoadingMeshes[mesh_id].insert(volume->getID()); + mLoadingMeshes[mesh_id].insert(vobj->getID()); } if (gAssetStorage->hasLocalAsset(mesh_id, LLAssetType::AT_MESH)) { //already have asset, load desired LOD in background - mPendingMeshes.push_back(new LLMeshThread(mesh_id, volume->getVolume())); + mPendingMeshes.push_back(new LLMeshThread(mesh_id, vobj->getVolume())); } else { //fetch asset and load when done gAssetStorage->getAssetData(mesh_id, LLAssetType::AT_MESH, - getMeshAssetCallback, volume->getVolume(), TRUE); + getMeshAssetCallback, vobj->getVolume(), TRUE); } + //do a quick search to see if we can't display something while we wait for this mesh to load + LLVolume* volume = vobj->getVolume(); + + if (volume) + { + LLVolumeParams params = volume->getParams(); + + LLVolumeLODGroup* group = LLPrimitive::getVolumeManager()->getGroup(params); + + if (group) + { + //first see what the next lowest LOD available might be + for (S32 i = detail-1; i >= 0; --i) + { + LLVolume* lod = group->refLOD(i); + if (lod && lod->getNumVolumeFaces() > 0) + { + volume->copyVolumeFaces(lod); + group->derefLOD(lod); + return; + } + } + + //no lower LOD is a available, is a higher lod available? + for (S32 i = detail+1; i < 4; ++i) + { + LLVolume* lod = group->refLOD(i); + if (lod && lod->getNumVolumeFaces() > 0) + { + volume->copyVolumeFaces(lod); + group->derefLOD(lod); + return; + } + } + } + } } //static diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index bf654f88b1..3300f866e3 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -280,7 +280,7 @@ public: //mesh management functions - void loadMesh(LLVOVolume* volume, LLUUID mesh_id); + void loadMesh(LLVOVolume* volume, LLUUID mesh_id, S32 detail = 0); void addTrianglesDrawn(S32 count); BOOL hasRenderType(const U32 type) const { return (type && (mRenderTypeMask & (1< Date: Thu, 5 Nov 2009 19:58:10 -0600 Subject: Fix for prims all being 0 lod. Fix for dangling prim references. --- indra/llmath/llvolume.cpp | 3 ++- indra/llprimitive/llprimitive.cpp | 8 +++++++- indra/newview/llvovolume.cpp | 2 +- indra/newview/pipeline.cpp | 2 ++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index ddd1b4b3db..33a8d33ce1 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1692,9 +1692,10 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mLODScaleBias.setVec(1,1,1); + generate(); + if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE) { - generate(); createVolumeFaces(); } } diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 52265e7ad5..340f60ed1a 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -744,7 +744,10 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai return TRUE; } -#if 0 +#if 0 + // #if 0'd out by davep + // this is a lot of cruft to set texture entry values that just stay the same for LOD switch + // or immediately get overridden by an object update message, also crashes occasionally U32 old_face_mask = mVolumep->mFaceMask; S32 face_bit = 0; @@ -943,6 +946,9 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai } } #else + // build the new object + sVolumeManager->unrefVolume(mVolumep); + mVolumep = volumep; setNumTEs(mVolumep->getNumFaces()); #endif return TRUE; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 78fd371087..7666009a62 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -919,7 +919,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms, const S32 detail, bool { //mesh is not loaded, request pipeline load this mesh LLUUID asset_id = volume_params.getSculptID(); - gPipeline.loadMesh(this, asset_id); + gPipeline.loadMesh(this, asset_id, detail); } else { diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 4ac95fa939..3554ceb7f0 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -8949,6 +8949,7 @@ void LLPipeline::loadMesh(LLVOVolume* vobj, LLUUID mesh_id, S32 detail) group->derefLOD(lod); return; } + group->derefLOD(lod); } //no lower LOD is a available, is a higher lod available? @@ -8961,6 +8962,7 @@ void LLPipeline::loadMesh(LLVOVolume* vobj, LLUUID mesh_id, S32 detail) group->derefLOD(lod); return; } + group->derefLOD(lod); } } } -- cgit v1.2.3 From 4e420a36c67e611cd7d85652b43d9cd65315e563 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Sat, 7 Nov 2009 08:22:39 -0600 Subject: Fix for missing LOD spam. --- indra/llmath/llvolume.cpp | 21 +++++++++++++++------ indra/llprimitive/llprimitive.cpp | 3 ++- indra/newview/pipeline.cpp | 2 ++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 33a8d33ce1..c8ef911cc1 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1676,7 +1676,8 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mFaceMask = 0x0; mDetail = detail; mSculptLevel = -2; - + mLODScaleBias.setVec(1,1,1); + // set defaults if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE) { @@ -1690,8 +1691,6 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mGenerateSingleFace = generate_single_face; - mLODScaleBias.setVec(1,1,1); - generate(); if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE) @@ -1899,7 +1898,7 @@ BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) { if (!LLSDSerialize::deserialize(header, is, 1024*1024*1024)) { - llwarns << "not a valid mesh asset!" << llendl; + llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl; return FALSE; } } @@ -1921,8 +1920,18 @@ BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) if (lod >= 4) { - llwarns << "Couldn't load model for given lod" << llendl; - return FALSE; + lod = llclamp((S32) mDetail, 0, 3); + + while (lod >= 0 && header[nm[lod]]["offset"].asInteger() == -1) + { + --lod; + } + + if (lod < 0) + { + llwarns << "Mesh header missing LOD offsets. Not a valid mesh asset!" << llendl; + return FALSE; + } } is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur); diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 340f60ed1a..4c6d244f3c 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -948,7 +948,8 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai #else // build the new object sVolumeManager->unrefVolume(mVolumep); - mVolumep = volumep; + mVolumep = volumep; + setNumTEs(mVolumep->getNumFaces()); #endif return TRUE; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 3554ceb7f0..f13bb73acf 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -8949,6 +8949,7 @@ void LLPipeline::loadMesh(LLVOVolume* vobj, LLUUID mesh_id, S32 detail) group->derefLOD(lod); return; } + group->derefLOD(lod); } @@ -8962,6 +8963,7 @@ void LLPipeline::loadMesh(LLVOVolume* vobj, LLUUID mesh_id, S32 detail) group->derefLOD(lod); return; } + group->derefLOD(lod); } } -- cgit v1.2.3 From 7fa698252060a72be6b5ebc52f0ff01bcea6134c Mon Sep 17 00:00:00 2001 From: "Karl Stiefvater (qarl)" Date: Mon, 9 Nov 2009 17:57:21 -0600 Subject: super importer stuff (gui, texture upload, etc.) --- indra/newview/llassetuploadresponders.cpp | 3 ++ indra/newview/llfilepicker.cpp | 23 ++++++++++++ indra/newview/llfilepicker.h | 1 + indra/newview/llviewerfloaterreg.cpp | 2 ++ indra/newview/llviewermenufile.cpp | 41 +++++++++++++++------- indra/newview/llviewermenufile.h | 2 +- .../skins/default/xui/en/floater_inventory.xml | 10 ++++++ 7 files changed, 69 insertions(+), 13 deletions(-) diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 680d1acd81..2da40ba4b5 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -42,6 +42,7 @@ #include "llnotify.h" #include "llinventorymodel.h" #include "llfloaterinventory.h" +#include "llfloaterimportcollada.h" #include "llpermissionsflags.h" #include "llpreviewnotecard.h" #include "llpreviewscript.h" @@ -414,6 +415,8 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(), userdata); } + + LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], TRUE); } LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data, diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index e12db901bd..8dfb333530 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -55,6 +55,7 @@ LLFilePicker LLFilePicker::sInstance; #define SOUND_FILTER L"Sounds (*.wav)\0*.wav\0" #define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0" #define ANIM_FILTER L"Animations (*.bvh)\0*.bvh\0" +#define COLLADA_FILTER L"Scene (*.dae)\0*.dae\0" #ifdef _CORY_TESTING #define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0" #endif @@ -176,6 +177,10 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) mOFN.lpstrFilter = ANIM_FILTER \ L"\0"; break; + case FFLOAD_COLLADA: + mOFN.lpstrFilter = COLLADA_FILTER \ + L"\0"; + break; #ifdef _CORY_TESTING case FFLOAD_GEOMETRY: mOFN.lpstrFilter = GEOMETRY_FILTER \ @@ -547,6 +552,15 @@ Boolean LLFilePicker::navOpenFilterProc(AEDesc *theItem, void *info, void *callB result = false; } } + else if (filter == FFLOAD_COLLADA) + { + if (fileInfo.filetype != 'DAE ' && + (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("dae"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) + ) + { + result = false; + } + } #ifdef _CORY_TESTING else if (filter == FFLOAD_GEOMETRY) { @@ -1093,6 +1107,12 @@ static std::string add_bvh_filter_to_gtkchooser(GtkWindow *picker) LLTrans::getString("animation_files") + " (*.bvh)"); } +static std::string add_collada_filter_to_gtkchooser(GtkWindow *picker) +{ + return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae", + LLTrans::getString("scene_files") + " (*.dae)"); +} + static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) { GtkFileFilter *gfilter = gtk_file_filter_new(); @@ -1217,6 +1237,9 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter ) case FFLOAD_ANIM: filtername = add_bvh_filter_to_gtkchooser(picker); break; + case FFLOAD_COLLADA: + filtername = add_collada_filter_to_gtkchooser(picker); + break; case FFLOAD_IMAGE: filtername = add_imageload_filter_to_gtkchooser(picker); break; diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 7600922e9c..10736c7dd0 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -94,6 +94,7 @@ public: FFLOAD_SLOBJECT = 7, FFLOAD_RAW = 8, FFLOAD_MODEL = 9, + FFLOAD_COLLADA = 10, }; enum ESaveFilter diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 4ff1e6c703..f3bf6b70a3 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -73,6 +73,7 @@ #include "llimpanel.h" #include "llfloaterinspect.h" #include "llfloaterinventory.h" +#include "llfloaterimportcollada.h" #include "llfloaterjoystick.h" #include "llfloaterlagmeter.h" #include "llfloaterland.h" @@ -172,6 +173,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("import_collada", "floater_import_collada.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("inventory", "floater_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLInspectAvatarUtil::registerFloater(); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 7b9494c02a..53067c5c93 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -39,6 +39,7 @@ #include "llfilepicker.h" #include "llfloaterreg.h" #include "llfloaterbuycurrency.h" +#include "llfloaterimportcollada.h" #include "llfloatermodelpreview.h" #include "llfloatersnapshot.h" #include "llinventorymodel.h" // gInventory @@ -56,7 +57,7 @@ #include "llappviewer.h" #include "lluploaddialog.h" #include "lltrans.h" - +#include "llfloaterimportcollada.h" // linden libraries #include "llassetuploadresponders.h" @@ -263,6 +264,19 @@ class LLFileUploadImage : public view_listener_t } }; +class LLFileUploadScene : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + std::string filename = upload_pick((void *)LLFilePicker::FFLOAD_COLLADA); + if (!filename.empty()) + { + LLImportCollada::getInstance()->importFile(filename); + } + return TRUE; + } +}; + class LLFileUploadModel : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -517,7 +531,7 @@ void handle_compress_image(void*) } } -void upload_new_resource( +LLUUID upload_new_resource( const std::string& src_filename, std::string name, std::string desc, @@ -555,7 +569,7 @@ void upload_new_resource( short_name.c_str()); args["FILE"] = short_name; upload_error(error_message, "NofileExtension", filename, args); - return; + return LLUUID(); } else if( exten == "bmp") { @@ -569,7 +583,7 @@ void upload_new_resource( args["FILE"] = src_filename; args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); - return; + return LLUUID(); } } else if( exten == "tga") @@ -584,7 +598,7 @@ void upload_new_resource( args["FILE"] = src_filename; args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); - return; + return LLUUID(); } } else if( exten == "jpg" || exten == "jpeg") @@ -599,7 +613,7 @@ void upload_new_resource( args["FILE"] = src_filename; args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); - return; + return LLUUID(); } } else if( exten == "png") @@ -614,7 +628,7 @@ void upload_new_resource( args["FILE"] = src_filename; args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); - return; + return LLUUID(); } } else if(exten == "wav") @@ -642,7 +656,7 @@ void upload_new_resource( upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args); break; } - return; + return LLUUID(); } } else if(exten == "tmp") @@ -682,7 +696,7 @@ void upload_new_resource( error_message = llformat("corrupt resource file: %s", src_filename.c_str()); args["FILE"] = src_filename; upload_error(error_message, "CorruptResourceFile", filename, args); - return; + return LLUUID(); } if (2 == tokens_read) @@ -710,7 +724,7 @@ void upload_new_resource( error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str()); args["FILE"] = src_filename; upload_error(error_message, "UnknownResourceFileVersion", filename, args); - return; + return LLUUID(); } } else @@ -752,7 +766,7 @@ void upload_new_resource( error_message = llformat( "Unable to create output file: %s", filename.c_str()); args["FILE"] = filename; upload_error(error_message, "UnableToCreateOutputFile", filename, args); - return; + return LLUUID(); } fclose(in); @@ -766,7 +780,7 @@ void upload_new_resource( { error_message = llformat("We do not currently support bulk upload of animation files\n"); upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args); - return; + return LLUUID(); } else { @@ -840,6 +854,8 @@ void upload_new_resource( } LLFilePicker::instance().reset(); } + + return uuid; } void upload_done_callback( @@ -1260,6 +1276,7 @@ void init_menu_file() view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound"); view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim"); view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel"); + view_listener_t::addCommit(new LLFileUploadScene(), "File.UploadScene"); view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk"); view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow"); view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows"); diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index 858fcd51de..25469e0168 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -41,7 +41,7 @@ class LLTransactionID; void init_menu_file(); -void upload_new_resource( +LLUUID upload_new_resource( const std::string& src_filename, std::string name, std::string desc, diff --git a/indra/newview/skins/default/xui/en/floater_inventory.xml b/indra/newview/skins/default/xui/en/floater_inventory.xml index c7fcacab8b..5e324f1c6e 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory.xml @@ -135,6 +135,16 @@ parameter="" /> + + + + Date: Thu, 12 Nov 2009 15:02:08 +0000 Subject: newlineorama. --- indra/llui/lluictrlfactory.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index 8ab015f2bb..0d1c486a4b 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -454,4 +454,5 @@ const std::string* LLUICtrlFactory::getWidgetTag(const std::type_info* widget_ty void LLUICtrlFactory::connect(LLView* parent, LLView* child) { parent->addChild(child); -} \ No newline at end of file +} + -- cgit v1.2.3 From 842bf4d7bb7618f34522e9ee8817b7978229d692 Mon Sep 17 00:00:00 2001 From: Palmer Date: Thu, 12 Nov 2009 10:57:39 -0800 Subject: ignoring .orig files --- .hgignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgignore b/.hgignore index 4d98acf5d9..1d4890810f 100644 --- a/.hgignore +++ b/.hgignore @@ -9,6 +9,7 @@ syntax: glob .*.swp #OSX image cache file *.DS_Store +*.orig LICENSES indra/.distcc indra/build-darwin-* -- cgit v1.2.3 From 596d3cfb6018789e3ffca5bf3ae9fa4e1e8a707a Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 12 Nov 2009 13:23:48 -0600 Subject: CTS-15 Force loading of high LOD when opening model import floater. CTS-9 Auto-fill description field with --- indra/newview/llviewermenufile.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 505d2afb69..2ce37612b2 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -281,7 +281,11 @@ class LLFileUploadModel : public view_listener_t { bool handleEvent(const LLSD& userdata) { - LLFloaterReg::showInstance("upload_model"); + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::showInstance("upload_model"); + if (fmp) + { + fmp->loadModel(3); + } return TRUE; } -- cgit v1.2.3 From bb72788392ea6d25adb045abd555419cd60c4888 Mon Sep 17 00:00:00 2001 From: Palmer Date: Thu, 12 Nov 2009 14:05:01 -0800 Subject: Fixes for mesh inventory type correctness. --- indra/llinventory/llinventorytype.cpp | 28 +++++++++++++++++++++++++++- indra/newview/llinventoryfunctions.cpp | 3 +++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp index 2460a2777a..caf8e11929 100644 --- a/indra/llinventory/llinventorytype.cpp +++ b/indra/llinventory/llinventorytype.cpp @@ -125,7 +125,33 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] = LLInventoryType::IT_NONE, // AT_LINK LLInventoryType::IT_NONE, // AT_LINK_FOLDER - LLInventoryType::IT_MESH, // AT_MESH + + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + + LLInventoryType::IT_MESH // AT_MESH }; // static diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 75218e98e0..01c7f0974d 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -323,6 +323,9 @@ const std::string& get_item_icon_name(LLAssetType::EType asset_type, case LLAssetType::AT_LINK_FOLDER: idx = LINKFOLDER_ICON_NAME; break; + case LLAssetType::AT_MESH: + idx = MESH_ICON_NAME; + break; default: break; } -- cgit v1.2.3 From 0c50236a944898502405a31aa1f0b6ae61ae38ae Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 13 Nov 2009 08:59:12 -0600 Subject: CTS-26 Fix for LOD generation always using first file specified. --- indra/llrender/llvertexbuffer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index db4189dfea..6e77bb2aab 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -566,7 +566,7 @@ void LLVertexBuffer::destroyGLBuffer() } mGLBuffer = 0; - unbind(); + //unbind(); } void LLVertexBuffer::destroyGLIndices() @@ -593,7 +593,7 @@ void LLVertexBuffer::destroyGLIndices() } mGLIndices = 0; - unbind(); + //unbind(); } void LLVertexBuffer::updateNumVerts(S32 nverts) -- cgit v1.2.3 From c02702f3871979cb7745b49aa502ac3c71f77681 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 13 Nov 2009 17:01:56 -0600 Subject: CTS-7 Add hard edge threshold capability to normal generation. --- indra/llmath/llvolume.cpp | 12 ++++++++++++ indra/llmath/llvolume.h | 1 + 2 files changed, 13 insertions(+) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 6286d1bcea..f252b2a232 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1876,6 +1876,18 @@ bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)co return true; } +bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const +{ + bool retval = false; + if (rhs.mPosition == mPosition && rhs.mTexCoord == mTexCoord) + { + F32 cur_angle = rhs.mNormal*mNormal; + + retval = cur_angle > angle_cutoff; + } + + return retval; +} BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name) { diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 9f595ccbc4..d2727d8f21 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -814,6 +814,7 @@ public: bool operator<(const VertexData& rhs) const; bool operator==(const VertexData& rhs) const; + bool compareNormal(const VertexData& rhs, F32 angle_cutoff) const; }; enum -- cgit v1.2.3 From a056423e62ad8525919526abb95e8b23f0681064 Mon Sep 17 00:00:00 2001 From: Palmer Date: Tue, 17 Nov 2009 13:42:19 -0800 Subject: Merge of latest viewer 2 changes --- indra/newview/llviewerwindow.cpp | 134 --------------------------------------- 1 file changed, 134 deletions(-) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 7b35125b5b..a1539e24a4 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -3704,140 +3704,6 @@ void LLViewerWindow::playSnapshotAnimAndSound() BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) { return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type); - - // *TODO below code was broken in deferred pipeline - /* - if ((!raw) || preview_width < 10 || preview_height < 10) - { - return FALSE; - } - - if(gResizeScreenTexture) //the window is resizing - { - return FALSE ; - } - - setCursor(UI_CURSOR_WAIT); - - // Hide all the UI widgets first and draw a frame - BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI); - - if ( prev_draw_ui != show_ui) - { - LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI); - } - - BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments; - if (hide_hud) - { - LLPipeline::sShowHUDAttachments = FALSE; - } - - S32 render_name = gSavedSettings.getS32("RenderName"); - gSavedSettings.setS32("RenderName", 0); - LLVOAvatar::updateFreezeCounter(1) ; //pause avatar updating for one frame - - S32 w = preview_width ; - S32 h = preview_height ; - LLVector2 display_scale = mDisplayScale ; - mDisplayScale.setVec((F32)w / mWindowRectRaw.getWidth(), (F32)h / mWindowRectRaw.getHeight()) ; - LLRect window_rect = mWindowRectRaw; - mWindowRectRaw.set(0, h, w, 0); - - gDisplaySwapBuffers = FALSE; - gDepthDirty = TRUE; - glClearColor(0.f, 0.f, 0.f, 0.f); - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - setup3DRender(); - - LLFontGL::setFontDisplay(FALSE) ; - LLHUDText::setDisplayText(FALSE) ; - if (type == SNAPSHOT_TYPE_OBJECT_ID) - { - gObjectList.renderPickList(gViewerWindow->getWindowRectScaled(), FALSE, FALSE); - } - else - { - display(do_rebuild, 1.0f, 0, TRUE); - render_ui(); - } - - S32 glformat, gltype, glpixel_length ; - if(SNAPSHOT_TYPE_DEPTH == type) - { - glpixel_length = 4 ; - glformat = GL_DEPTH_COMPONENT ; - gltype = GL_FLOAT ; - } - else - { - glpixel_length = 3 ; - glformat = GL_RGB ; - gltype = GL_UNSIGNED_BYTE ; - } - - raw->resize(w, h, glpixel_length); - glReadPixels(0, 0, w, h, glformat, gltype, raw->getData()); - - if(SNAPSHOT_TYPE_DEPTH == type) - { - LLViewerCamera* camerap = LLViewerCamera::getInstance(); - F32 depth_conversion_factor_1 = (camerap->getFar() + camerap->getNear()) / (2.f * camerap->getFar() * camerap->getNear()); - F32 depth_conversion_factor_2 = (camerap->getFar() - camerap->getNear()) / (2.f * camerap->getFar() * camerap->getNear()); - - //calculate the depth - for (S32 y = 0 ; y < h ; y++) - { - for(S32 x = 0 ; x < w ; x++) - { - S32 i = (w * y + x) << 2 ; - - F32 depth_float_i = *(F32*)(raw->getData() + i); - - F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float_i * depth_conversion_factor_2)); - U8 depth_byte = F32_to_U8(linear_depth_float, camerap->getNear(), camerap->getFar()); - *(raw->getData() + i + 0) = depth_byte; - *(raw->getData() + i + 1) = depth_byte; - *(raw->getData() + i + 2) = depth_byte; - *(raw->getData() + i + 3) = 255; - } - } - } - - LLFontGL::setFontDisplay(TRUE) ; - LLHUDText::setDisplayText(TRUE) ; - mDisplayScale.setVec(display_scale) ; - mWindowRectRaw = window_rect; - setup3DRender(); - gDisplaySwapBuffers = FALSE; - gDepthDirty = TRUE; - - // POST SNAPSHOT - if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI); - } - - if (hide_hud) - { - LLPipeline::sShowHUDAttachments = TRUE; - } - - setCursor(UI_CURSOR_ARROW); - - if (do_rebuild) - { - // If we had to do a rebuild, that means that the lists of drawables to be rendered - // was empty before we started. - // Need to reset these, otherwise we call state sort on it again when render gets called the next time - // and we stand a good chance of crashing on rebuild because the render drawable arrays have multiple copies of - // objects on them. - gPipeline.resetDrawOrders(); - } - - gSavedSettings.setS32("RenderName", render_name); - - return TRUE;*/ } // Saves the image from the screen to the specified filename and path. -- cgit v1.2.3 From 1f71cd20e831983aa5f4682958a3619b9f37a6f1 Mon Sep 17 00:00:00 2001 From: "Jonathan@Chomp.lindenlab.com" Date: Wed, 18 Nov 2009 11:38:31 -0800 Subject: Fixed variable price upload path. --- indra/newview/llassetuploadresponders.cpp | 98 ++++++++++++++++++++++--------- indra/newview/llassetuploadresponders.h | 3 + indra/newview/llviewermenufile.cpp | 7 ++- 3 files changed, 77 insertions(+), 31 deletions(-) diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index f3dbe6fa31..dddc6fef1c 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -676,18 +676,32 @@ class LLNewAgentInventoryVariablePriceResponder::Impl public: Impl( const LLUUID& vfile_id, + LLAssetType::EType asset_type, const LLSD& inventory_data) : mVFileID(vfile_id), - mInventoryData(inventory_data) + mAssetType(asset_type), + mInventoryData(inventory_data), + mFileName("") { + if (!gVFS->getExists(vfile_id, asset_type)) + { + llwarns + << "LLAssetUploadResponder called with nonexistant " + << "vfile_id " << vfile_id << llendl; + mVFileID.setNull(); + mAssetType = LLAssetType::AT_NONE; + } } Impl( const std::string& file_name, + LLAssetType::EType asset_type, const LLSD& inventory_data) : mFileName(file_name), + mAssetType(asset_type), mInventoryData(inventory_data) { + mVFileID.setNull(); } std::string getFilenameOrIDString() const @@ -707,8 +721,7 @@ public: LLAssetType::EType getAssetType() const { - return LLAssetType::lookup( - mInventoryData["asset_type"].asString()); + return mAssetType; } LLInventoryType::EType getInventoryType() const @@ -898,22 +911,7 @@ public: { case 0: { - if ( getFilename().empty() ) - { - // we have no filename, use virtual file ID instead - LLHTTPClient::postFile( - confirmation_url, - getVFileID(), - getAssetType(), - responder); - } - else - { - LLHTTPClient::postFile( - confirmation_url, - getFilename(), - responder); - } + confirmUpload(confirmation_url, responder); } break; case 1: @@ -923,11 +921,35 @@ public: return false; } - + + void confirmUpload( + const std::string& confirmation_url, + boost::intrusive_ptr responder) + { + if ( getFilename().empty() ) + { + // we have no filename, use virtual file ID instead + LLHTTPClient::postFile( + confirmation_url, + getVFileID(), + getAssetType(), + responder); + } + else + { + LLHTTPClient::postFile( + confirmation_url, + getFilename(), + responder); + } + } + + private: std::string mFileName; LLSD mInventoryData; + LLAssetType::EType mAssetType; LLUUID mVFileID; }; @@ -936,19 +958,23 @@ private: /////////////////////////////////////////////// LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder( const LLUUID& vfile_id, + LLAssetType::EType asset_type, const LLSD& inventory_info) { mImpl = new Impl( vfile_id, + asset_type, inventory_info); } LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder( const std::string& file_name, + LLAssetType::EType asset_type, const LLSD& inventory_info) { mImpl = new Impl( file_name, + asset_type, inventory_info); } @@ -962,8 +988,9 @@ void LLNewAgentInventoryVariablePriceResponder::errorWithContent( const std::string& reason, const LLSD& content) { - llinfos << "LLNewAgentInventoryVariablePrice::error " << statusNum - << " reason: " << reason << llendl; + lldebugs + << "LLNewAgentInventoryVariablePrice::error " << statusNum + << " reason: " << reason << llendl; if ( content.has("error") ) { @@ -988,6 +1015,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) static const std::string _CONFIRM_UPLOAD = "confirm_upload"; static const std::string _UPLOAD_PRICE = "upload_price"; + static const std::string _RESOURCE_COST = "resource_cost"; static const std::string _RSVP = "rsvp"; // Check for application level errors @@ -1022,7 +1050,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) mImpl->getItemName(), mImpl->getItemDescription(), content, - content["upload_price"].asInteger()); + content[_UPLOAD_PRICE].asInteger()); // TODO* Add bulk (serial) uploading or add // a super class of this that does so @@ -1031,6 +1059,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) { showConfirmationDialog( content[_UPLOAD_PRICE].asInteger(), + content[_RESOURCE_COST].asInteger(), content[_RSVP].asString()); } else @@ -1047,17 +1076,30 @@ void LLNewAgentInventoryVariablePriceResponder::onApplicationLevelError( void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog( S32 upload_price, + S32 resource_cost, const std::string& confirmation_url) { - if ( 0 == upload_price ) + if ( 0 == upload_price ) { // don't show confirmation dialog for free uploads, I mean, // they're free! - LLSD body; - body["confirm_upload"] = true; - body["expected_upload_price"] = upload_price; - LLHTTPClient::post(confirmation_url, body, this); + // The creating of a new instrusive_ptr(this) + // creates a new boost::intrusive_ptr + // which is a copy of this. This code is required because + // 'this' is always of type Class* and not the intrusive_ptr, + // and thus, a reference to 'this' is not registered + // by using just plain 'this'. + + // Since LLNewAgentInventoryVariablePriceResponder is a + // reference counted class, it is possible (since the + // reference to a plain 'this' would be missed here) that, + // when using plain ol' 'this', that this object + // would be deleted before the callback is triggered + // and cause sadness. + mImpl->confirmUpload( + confirmation_url, + boost::intrusive_ptr(this)); } else { diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index 9102f1597e..929a7a5f74 100644 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -87,10 +87,12 @@ class LLNewAgentInventoryVariablePriceResponder : public: LLNewAgentInventoryVariablePriceResponder( const LLUUID& vfile_id, + LLAssetType::EType asset_type, const LLSD& inventory_info); LLNewAgentInventoryVariablePriceResponder( const std::string& file_name, + LLAssetType::EType asset_type, const LLSD& inventory_info); virtual ~LLNewAgentInventoryVariablePriceResponder(); @@ -105,6 +107,7 @@ public: const LLSD& error); virtual void showConfirmationDialog( S32 upload_price, + S32 resource_cost, const std::string& confirmation_url); private: diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 8b101748a3..2c0a41e1ff 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -1175,9 +1175,9 @@ BOOL upload_new_variable_price_resource( if ( !url.empty() ) { - llinfos << "New Agent Inventory variable price upload" - << llendl; - + lldebugs + << "New Agent Inventory variable price upload" << llendl; + // Each of the two capabilities has similar data, so // let's reuse that code @@ -1200,6 +1200,7 @@ BOOL upload_new_variable_price_resource( body, new LLNewAgentInventoryVariablePriceResponder( uuid, + asset_type, body)); return TRUE; -- cgit v1.2.3 From 81bfdcbfae4f203e60f00794966383b01475995b Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 18 Nov 2009 18:10:48 -0600 Subject: Tetrahedron displays in place of unloaded mesh. Still has some LOD issues. --- indra/llmath/llvolume.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++- indra/llmath/llvolume.h | 1 + indra/newview/pipeline.cpp | 9 ++++- 3 files changed, 103 insertions(+), 3 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index f252b2a232..84da1b3c62 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1925,7 +1925,9 @@ BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) S32 lod = llclamp((S32) mDetail, 0, 3); - while (lod < 4 && header[nm[lod]]["offset"].asInteger() == -1) + while (lod < 4 && + (header[nm[lod]]["offset"].asInteger() == -1 || + header[nm[lod]]["size"].asInteger() == 0 )) { ++lod; } @@ -1934,7 +1936,9 @@ BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) { lod = llclamp((S32) mDetail, 0, 3); - while (lod >= 0 && header[nm[lod]]["offset"].asInteger() == -1) + while (lod >= 0 && + (header[nm[lod]]["offset"].asInteger() == -1 || + header[nm[lod]]["size"].asInteger() == 0) ) { --lod; } @@ -2135,6 +2139,94 @@ BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) return TRUE; } +void tetrahedron_set_normal(LLVolumeFace::VertexData* cv) +{ + LLVector3 nrm = (cv[1].mPosition-cv[0].mPosition)%(cv[2].mPosition-cv[0].mPosition); + + nrm.normVec(); + + cv[0].mNormal = nrm; + cv[1].mNormal = nrm; + cv[2].mNormal = nrm; +} + +void LLVolume::makeTetrahedron() +{ + mVolumeFaces.clear(); + + LLVolumeFace face; + + F32 x = 0.5f; + LLVector3 p[] = + { //unit tetrahedron corners + LLVector3(x,x,x), + LLVector3(-x,-x,x), + LLVector3(-x,x,-x), + LLVector3(x,-x,-x) + }; + + LLVolumeFace::VertexData cv[3]; + + //set texture coordinates + cv[0].mTexCoord = LLVector2(0,0); + cv[1].mTexCoord = LLVector2(1,0); + cv[2].mTexCoord = LLVector2(0.5f, 0.5f*F_SQRT3); + + + //side 1 + cv[0].mPosition = p[1]; + cv[1].mPosition = p[0]; + cv[2].mPosition = p[2]; + + tetrahedron_set_normal(cv); + + face.mVertices.push_back(cv[0]); + face.mVertices.push_back(cv[1]); + face.mVertices.push_back(cv[2]); + + //side 2 + cv[0].mPosition = p[3]; + cv[1].mPosition = p[0]; + cv[2].mPosition = p[1]; + + tetrahedron_set_normal(cv); + + face.mVertices.push_back(cv[0]); + face.mVertices.push_back(cv[1]); + face.mVertices.push_back(cv[2]); + + //side 3 + cv[0].mPosition = p[3]; + cv[1].mPosition = p[1]; + cv[2].mPosition = p[2]; + + tetrahedron_set_normal(cv); + + face.mVertices.push_back(cv[0]); + face.mVertices.push_back(cv[1]); + face.mVertices.push_back(cv[2]); + + //side 4 + cv[0].mPosition = p[2]; + cv[1].mPosition = p[0]; + cv[2].mPosition = p[3]; + + tetrahedron_set_normal(cv); + + face.mVertices.push_back(cv[0]); + face.mVertices.push_back(cv[1]); + face.mVertices.push_back(cv[2]); + + //set index buffer + for (U32 i = 0; i < 12; i++) + { + face.mIndices.push_back(i); + } + + mVolumeFaces.push_back(face); + mSculptLevel = 0; +} + void LLVolume::copyVolumeFaces(LLVolume* volume) { mVolumeFaces = volume->mVolumeFaces; diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index d2727d8f21..bf2854ede9 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -969,6 +969,7 @@ protected: public: virtual BOOL createVolumeFacesFromFile(const std::string& file_name); virtual BOOL createVolumeFacesFromStream(std::istream& is); + virtual void makeTetrahedron(); protected: BOOL mUnique; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index c262e94ff4..3410ad6559 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -8976,6 +8976,9 @@ void LLPipeline::loadMesh(LLVOVolume* vobj, LLUUID mesh_id, S32 detail) group->derefLOD(lod); } } + + //nothing found, so make a tetrahedron + volume->makeTetrahedron(); } } @@ -9102,7 +9105,11 @@ void LLPipeline::notifyLoadedMeshes() if (valid) { - mesh->mTargetVolume->copyVolumeFaces(mesh->mVolume); + if (mesh->mVolume->getNumVolumeFaces() > 0) + { + mesh->mTargetVolume->copyVolumeFaces(mesh->mVolume); + } + for (std::set::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) { LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter); -- cgit v1.2.3 From 62233f22469cdc66042fc7bbbbd367dbb7212fde Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 24 Nov 2009 07:38:04 -0600 Subject: Fix for copying of tetrahedrons in place of mesh LODs. Fix for bad tetrahedron bounding box. Bad fix for simultaneous loading of multiple LODs. --- indra/llmath/llvolume.cpp | 31 +++++++++++++++++++++++++-- indra/llmath/llvolume.h | 5 ++++- indra/llmath/llvolumemgr.cpp | 13 ++++++++++++ indra/llmath/llvolumemgr.h | 1 + indra/newview/llvovolume.cpp | 31 ++++----------------------- indra/newview/llvovolume.h | 1 - indra/newview/pipeline.cpp | 50 +++++++++++++++++++++++++++++++++++--------- indra/newview/pipeline.h | 6 ++++-- 8 files changed, 95 insertions(+), 43 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 84da1b3c62..515b1061f9 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1676,6 +1676,7 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mFaceMask = 0x0; mDetail = detail; mSculptLevel = -2; + mIsTetrahedron = FALSE; mLODScaleBias.setVec(1,1,1); // set defaults @@ -1905,7 +1906,7 @@ BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name) BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) { mSculptLevel = -1; // default is an error occured - + LLSD header; { if (!LLSDSerialize::deserialize(header, is, 1024*1024*1024)) @@ -2048,6 +2049,11 @@ BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) { U32 face_count = mdl.size(); + if (face_count == 0) + { + llerrs << "WTF?" << llendl; + } + mVolumeFaces.resize(face_count); for (U32 i = 0; i < face_count; ++i) @@ -2063,8 +2069,9 @@ BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) //copy out indices face.mIndices.resize(idx.size()/2); - if (idx.empty()) + if (idx.empty() || face.mIndices.size() < 3) { //why is there an empty index list? + llerrs <<"WTF?" << llendl; continue; } @@ -2150,6 +2157,11 @@ void tetrahedron_set_normal(LLVolumeFace::VertexData* cv) cv[2].mNormal = nrm; } +BOOL LLVolume::isTetrahedron() +{ + return mIsTetrahedron; +} + void LLVolume::makeTetrahedron() { mVolumeFaces.clear(); @@ -2165,6 +2177,9 @@ void LLVolume::makeTetrahedron() LLVector3(x,-x,-x) }; + face.mExtents[0].setVec(-x,-x,-x); + face.mExtents[1].setVec(x,x,x); + LLVolumeFace::VertexData cv[3]; //set texture coordinates @@ -2225,12 +2240,19 @@ void LLVolume::makeTetrahedron() mVolumeFaces.push_back(face); mSculptLevel = 0; + mIsTetrahedron = TRUE; } void LLVolume::copyVolumeFaces(LLVolume* volume) { + if (volume->isTetrahedron()) + { + llerrs << "WTF?" << llendl; + } + mVolumeFaces = volume->mVolumeFaces; mSculptLevel = 0; + mIsTetrahedron = FALSE; } S32 const LL_SCULPT_MESH_MAX_FACES = 8; @@ -2615,6 +2637,11 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, LLMemType m1(LLMemType::MTYPE_VOLUME); U8 sculpt_type = mParams.getSculptType(); + if (sculpt_type & LL_SCULPT_TYPE_MASK == LL_SCULPT_TYPE_MESH) + { + llerrs << "WTF?" << llendl; + } + BOOL data_is_empty = FALSE; if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL) diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index bf2854ede9..8e57f2e280 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -904,7 +904,8 @@ public: BOOL isUnique() const { return mUnique; } S32 getSculptLevel() const { return mSculptLevel; } - + void setSculptLevel(S32 level) { mSculptLevel = level; } + S32 *getTriangleIndices(U32 &num_indices) const; // returns number of triangle indeces required for path/profile mesh @@ -970,11 +971,13 @@ public: virtual BOOL createVolumeFacesFromFile(const std::string& file_name); virtual BOOL createVolumeFacesFromStream(std::istream& is); virtual void makeTetrahedron(); + virtual BOOL isTetrahedron(); protected: BOOL mUnique; F32 mDetail; S32 mSculptLevel; + BOOL mIsTetrahedron; LLVolumeParams mParams; LLPath *mPathp; diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index 61c5a0adc9..419e0015ba 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -375,6 +375,19 @@ F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail) return mDetailScales[detail]; } +S32 LLVolumeLODGroup::getVolumeDetailFromScale(const F32 detail) +{ + for (S32 i = 1; i < 4; i++) + { + if (mDetailScales[i] > detail) + { + return i-1; + } + } + + return 3; +} + F32 LLVolumeLODGroup::dump() { F32 usage = 0.f; diff --git a/indra/llmath/llvolumemgr.h b/indra/llmath/llvolumemgr.h index a78ea76a1a..f5dc4cd748 100644 --- a/indra/llmath/llvolumemgr.h +++ b/indra/llmath/llvolumemgr.h @@ -59,6 +59,7 @@ public: static S32 getDetailFromTan(const F32 tan_angle); static void getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher); static F32 getVolumeScaleFromDetail(const S32 detail); + static S32 getVolumeDetailFromScale(F32 scale); LLVolume* refLOD(const S32 detail); BOOL derefLOD(LLVolume *volumep); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 4c126d8fd9..64c2e9e8ec 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -163,7 +163,6 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mRelativeXformInvTrans.setIdentity(); mLOD = MIN_LOD; - mMeshSculptLevel = -2; mTextureAnimp = NULL; mVObjRadius = LLVector3(1,1,0.5f).length(); mNumFaces = 0; @@ -682,25 +681,7 @@ void LLVOVolume::updateTextureVirtualSize() LLUUID id = sculpt_params->getSculptTexture(); U8 sculpt_type = sculpt_params->getSculptType(); - if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) - // mesh is a mesh - { - if (mMeshSculptLevel == -2) - { - // get the asset please - gPipeline.loadMesh(this, id); - /*gAssetStorage->getAssetData(id, LLAssetType::AT_MESH, (LLGetAssetCallback)NULL, NULL, TRUE); - - if (gAssetStorage->hasLocalAsset(id, LLAssetType::AT_MESH)) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE); - mSculptChanged = TRUE; - }*/ - } - } - - else - // mesh is a sculptie + if ((sculpt_type & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) { mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); @@ -902,14 +883,10 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms, const S32 detail, bool if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) { if (getVolume()->getNumVolumeFaces() == 0) - { - //mesh is not loaded, request pipeline load this mesh + { + //load request not yet issued, request pipeline load this mesh LLUUID asset_id = volume_params.getSculptID(); - gPipeline.loadMesh(this, asset_id, detail); - } - else - { - mMeshSculptLevel = 1; + gPipeline.loadMesh(this, asset_id, LLVolumeLODGroup::getVolumeDetailFromScale(getVolume()->getDetail())); } } else // otherwise is sculptie diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 4b247f3778..f14a71130b 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -298,7 +298,6 @@ private: LLFrameTimer mTextureUpdateTimer; S32 mLOD; BOOL mLODChanged; - S32 mMeshSculptLevel; BOOL mSculptChanged; F32 mSpotLightPriority; LLMatrix4 mRelativeXform; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 3410ad6559..0ee619244b 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -8913,23 +8913,29 @@ LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups() void LLPipeline::loadMesh(LLVOVolume* vobj, LLUUID mesh_id, S32 detail) { + + if (detail < 0 || detail > 4) + { + return; + } + { LLMutexLock lock(mMeshMutex); //add volume to list of loading meshes - mesh_load_map::iterator iter = mLoadingMeshes.find(mesh_id); - if (iter != mLoadingMeshes.end()) + mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_id); + if (iter != mLoadingMeshes[detail].end()) { //request pending for this mesh, append volume id to list iter->second.insert(vobj->getID()); return; } //first request for this mesh - mLoadingMeshes[mesh_id].insert(vobj->getID()); + mLoadingMeshes[detail][mesh_id].insert(vobj->getID()); } if (gAssetStorage->hasLocalAsset(mesh_id, LLAssetType::AT_MESH)) { //already have asset, load desired LOD in background - mPendingMeshes.push_back(new LLMeshThread(mesh_id, vobj->getVolume())); + mPendingMeshes.push_back(new LLMeshThread(mesh_id, vobj->getVolume(), detail)); } else { //fetch asset and load when done @@ -8952,7 +8958,7 @@ void LLPipeline::loadMesh(LLVOVolume* vobj, LLUUID mesh_id, S32 detail) for (S32 i = detail-1; i >= 0; --i) { LLVolume* lod = group->refLOD(i); - if (lod && lod->getNumVolumeFaces() > 0) + if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0) { volume->copyVolumeFaces(lod); group->derefLOD(lod); @@ -8966,7 +8972,7 @@ void LLPipeline::loadMesh(LLVOVolume* vobj, LLUUID mesh_id, S32 detail) for (S32 i = detail+1; i < 4; ++i) { LLVolume* lod = group->refLOD(i); - if (lod && lod->getNumVolumeFaces() > 0) + if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0) { volume->copyVolumeFaces(lod); group->derefLOD(lod); @@ -8976,6 +8982,10 @@ void LLPipeline::loadMesh(LLVOVolume* vobj, LLUUID mesh_id, S32 detail) group->derefLOD(lod); } } + else + { + llerrs << "WTF?" << llendl; + } //nothing found, so make a tetrahedron volume->makeTetrahedron(); @@ -8992,12 +9002,22 @@ void LLPipeline::getMeshAssetCallback(LLVFS *vfs, } -LLPipeline::LLMeshThread::LLMeshThread(LLUUID mesh_id, LLVolume* target) +LLPipeline::LLMeshThread::LLMeshThread(LLUUID mesh_id, LLVolume* target, S32 detail) : LLThread("mesh_loading_thread") { mMeshID = mesh_id; mVolume = NULL; mDetail = target->getDetail(); + + if (detail == -1) + { + mDetailIndex = LLVolumeLODGroup::getVolumeDetailFromScale(target->getDetail()); + } + else + { + mDetailIndex = detail; + } + mTargetVolume = target; } @@ -9073,6 +9093,10 @@ void LLPipeline::notifyLoadedMeshes() for (std::list::iterator iter = mLoadedMeshes.begin(); iter != mLoadedMeshes.end(); ++iter) { //for each mesh done loading + + + + LLMeshThread* mesh = *iter; if (!mesh->isStopped()) @@ -9081,10 +9105,12 @@ void LLPipeline::notifyLoadedMeshes() continue; } + S32 detail = mesh->mDetailIndex; + //get list of objects waiting to be notified this mesh is loaded - mesh_load_map::iterator obj_iter = mLoadingMeshes.find(mesh->mMeshID); + mesh_load_map::iterator obj_iter = mLoadingMeshes[detail].find(mesh->mMeshID); - if (mesh->mVolume && obj_iter != mLoadingMeshes.end()) + if (mesh->mVolume && obj_iter != mLoadingMeshes[detail].end()) { //make sure target volume is still valid BOOL valid = FALSE; @@ -9109,6 +9135,10 @@ void LLPipeline::notifyLoadedMeshes() { mesh->mTargetVolume->copyVolumeFaces(mesh->mVolume); } + else + { + llwarns << "Mesh loading returned empty volume." << llendl; + } for (std::set::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) { @@ -9120,7 +9150,7 @@ void LLPipeline::notifyLoadedMeshes() } } - mLoadingMeshes.erase(mesh->mMeshID); + mLoadingMeshes[detail].erase(mesh->mMeshID); } delete mesh; diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 23e98aa0d6..a31379a209 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -676,8 +676,9 @@ public: protected: std::vector mSelectedFaces; + typedef std::map > mesh_load_map; - mesh_load_map mLoadingMeshes; + mesh_load_map mLoadingMeshes[4]; LLMutex* mMeshMutex; @@ -688,7 +689,8 @@ protected: LLVolume* mTargetVolume; LLUUID mMeshID; F32 mDetail; - LLMeshThread(LLUUID mesh_id, LLVolume* target); + S32 mDetailIndex; + LLMeshThread(LLUUID mesh_id, LLVolume* target, S32 detail = -1); ~LLMeshThread(); void run(); }; -- cgit v1.2.3 From 6d66910c6e2fbb25bf8b5c7b90e795f350342104 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 25 Nov 2009 11:35:41 -0600 Subject: Fix for spam on invalid mesh asset. Fix for index buffer overflow spam and crash in llvertexbuffer. --- indra/llmath/llvolume.cpp | 5 ----- indra/newview/llvovolume.cpp | 5 +++-- indra/newview/pipeline.cpp | 18 ++++++------------ 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 515b1061f9..3e547aec6f 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2245,11 +2245,6 @@ void LLVolume::makeTetrahedron() void LLVolume::copyVolumeFaces(LLVolume* volume) { - if (volume->isTetrahedron()) - { - llerrs << "WTF?" << llendl; - } - mVolumeFaces = volume->mVolumeFaces; mSculptLevel = 0; mIsTetrahedron = FALSE; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 64c2e9e8ec..3e9db86cfa 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -882,7 +882,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms, const S32 detail, bool // if it's a mesh if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) { - if (getVolume()->getNumVolumeFaces() == 0) + if (getVolume()->getNumVolumeFaces() == 0 || getVolume()->isTetrahedron()) { //load request not yet issued, request pipeline load this mesh LLUUID asset_id = volume_params.getSculptID(); @@ -924,7 +924,8 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms, const S32 detail, bool void LLVOVolume::notifyMeshLoaded() { mSculptChanged = TRUE; - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); + dirtySpatialGroup(TRUE); } // sculpt replaces generate() for sculpted surfaces diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 0ee619244b..af3a35615c 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1807,8 +1807,6 @@ void LLPipeline::rebuildPriorityGroups() assertInitialized(); - notifyLoadedMeshes(); - // Iterate through all drawables on the priority build queue, for (LLSpatialGroup::sg_list_t::iterator iter = mGroupQ1.begin(); iter != mGroupQ1.end(); ++iter) @@ -1888,6 +1886,8 @@ void LLPipeline::updateGeom(F32 max_dtime) // for now, only LLVOVolume does this to throttle LOD changes LLVOVolume::preUpdateGeom(); + notifyLoadedMeshes(); + // Iterate through all drawables on the priority build queue, for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin(); iter != mBuildQ1.end();) @@ -8913,7 +8913,6 @@ LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups() void LLPipeline::loadMesh(LLVOVolume* vobj, LLUUID mesh_id, S32 detail) { - if (detail < 0 || detail > 4) { return; @@ -9093,10 +9092,6 @@ void LLPipeline::notifyLoadedMeshes() for (std::list::iterator iter = mLoadedMeshes.begin(); iter != mLoadedMeshes.end(); ++iter) { //for each mesh done loading - - - - LLMeshThread* mesh = *iter; if (!mesh->isStopped()) @@ -9131,14 +9126,13 @@ void LLPipeline::notifyLoadedMeshes() if (valid) { - if (mesh->mVolume->getNumVolumeFaces() > 0) - { - mesh->mTargetVolume->copyVolumeFaces(mesh->mVolume); - } - else + if (mesh->mVolume->getNumVolumeFaces() <= 0) { llwarns << "Mesh loading returned empty volume." << llendl; + mesh->mVolume->makeTetrahedron(); } + + mesh->mTargetVolume->copyVolumeFaces(mesh->mVolume); for (std::set::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) { -- cgit v1.2.3 From f31f817ee61fa0f8fc05d2caa24f7674852629e5 Mon Sep 17 00:00:00 2001 From: "Karl Stiefvater (qarl)" Date: Wed, 25 Nov 2009 13:10:09 -0600 Subject: retry asset upload failures. --- indra/newview/llassetuploadresponders.cpp | 17 +++++++++++++++++ indra/newview/llassetuploadresponders.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index dddc6fef1c..6e32a91078 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -256,6 +256,7 @@ void LLAssetUploadResponder::result(const LLSD& content) lldebugs << "LLAssetUploadResponder::result from capabilities" << llendl; std::string state = content["state"]; + if (state == "upload") { uploadUpload(content); @@ -330,6 +331,22 @@ LLNewAgentInventoryResponder::LLNewAgentInventoryResponder( { } +// virtual +void LLNewAgentInventoryResponder::error(U32 statusNum, const std::string& reason) +{ + LLAssetUploadResponder::error(statusNum, reason); + LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE); +} + + +//virtual +void LLNewAgentInventoryResponder::uploadFailure(const LLSD& content) +{ + LLAssetUploadResponder::uploadFailure(content); + + LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], FALSE); +} + //virtual void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) { diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index 929a7a5f74..c869988203 100644 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -74,7 +74,9 @@ public: const LLSD& post_data, const std::string& file_name, LLAssetType::EType asset_type); + virtual void error(U32 statusNum, const std::string& reason); virtual void uploadComplete(const LLSD& content); + virtual void uploadFailure(const LLSD& content); }; // A base class which goes through and performs some default -- cgit v1.2.3 From 062a2dd309ca5521d4045eb721496476f43d24dc Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 30 Nov 2009 15:32:10 -0600 Subject: Remove zero area triangles from meshes post-import. --- indra/llmath/llvolume.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 3e547aec6f..1d36da7f52 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1692,10 +1692,9 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mGenerateSingleFace = generate_single_face; - generate(); - if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE) { + generate(); createVolumeFaces(); } } -- cgit v1.2.3 From f039fa98efedc91965338ef53624279f99914205 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 30 Nov 2009 17:02:38 -0600 Subject: Fix for silly crash due to LLPrimitive having 0 texture entries. --- indra/llmath/llvolume.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 1d36da7f52..858bd9edea 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1692,9 +1692,10 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mGenerateSingleFace = generate_single_face; + generate(); + if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE) { - generate(); createVolumeFaces(); } } -- cgit v1.2.3 From bb2631180a85df343e6d816fc37d881af31d49fb Mon Sep 17 00:00:00 2001 From: "Karl Stiefvater (qarl)" Date: Tue, 1 Dec 2009 17:40:52 -0600 Subject: CTS-4 Only part of an uploaded mesh renders. --- indra/llmath/llvolume.cpp | 1 - indra/llmath/llvolume.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 858bd9edea..fb2de92e35 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2250,7 +2250,6 @@ void LLVolume::copyVolumeFaces(LLVolume* volume) mIsTetrahedron = FALSE; } -S32 const LL_SCULPT_MESH_MAX_FACES = 8; S32 LLVolume::getNumFaces() const { diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 8e57f2e280..59c60ccd92 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -192,6 +192,7 @@ const U8 LL_SCULPT_TYPE_MESH = 5; const U8 LL_SCULPT_FLAG_INVERT = 64; const U8 LL_SCULPT_FLAG_MIRROR = 128; +const S32 LL_SCULPT_MESH_MAX_FACES = 8; class LLProfileParams { -- cgit v1.2.3 From 00962a68e24c4b628716aaa4390468dc5cc6194e Mon Sep 17 00:00:00 2001 From: "Karl Stiefvater (qarl)" Date: Wed, 2 Dec 2009 11:56:21 -0600 Subject: CTS-37 Mesh-type assets can't be added to the inventory of a prim --- indra/newview/llpanelobjectinventory.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 0c2e87aa3d..7a7372af6e 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1593,6 +1593,11 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory* object->getUUID(), object->getName()); break; + case LLAssetType::AT_MESH: + new_bridge = new LLTaskMeshBridge(panel, + object->getUUID(), + object->getName()); + break; break; default: -- cgit v1.2.3 From 9d3968bb837828568bf58113b8315c8ca2e8dae1 Mon Sep 17 00:00:00 2001 From: "Karl Stiefvater (qarl)" Date: Thu, 3 Dec 2009 15:12:30 -0800 Subject: hopefully: linux libraries for colladadom (pcre, etc.) --- install.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.xml b/install.xml index 68562ca37a..5629682404 100644 --- a/install.xml +++ b/install.xml @@ -273,9 +273,9 @@ linux md5sum - 01d17182ecc6728edaa520b3c780d194 + dde909f84fd2b7c56138f8fd193664c4 url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/colladadom-2.1.1-linux-20090921.tar.bz2 + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/colladadom-2.1.1-linux-20091203.tar.bz2 windows -- cgit v1.2.3 From 1590f187cf4e33bbb44215ea65fdc291eefd7971 Mon Sep 17 00:00:00 2001 From: Palmer Date: Mon, 7 Dec 2009 16:58:05 -0800 Subject: Fixing merge borkasaurs. --- indra/newview/llassetuploadresponders.cpp | 16 ++++++++-------- indra/newview/lltooldraganddrop.cpp | 11 +---------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 6b1897d077..bc606c04a9 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -92,7 +92,7 @@ static void on_new_single_inventory_upload_complete( LLSD args; args["AMOUNT"] = llformat("%d", upload_price); - LLNotifications::instance().add("UploadPayment", args); + LLNotificationsUtil::add("UploadPayment", args); } // Actually add the upload to viewer inventory @@ -157,12 +157,12 @@ static void on_new_single_inventory_upload_complete( // Show the preview panel for textures and sounds to let // user know that the image (or snapshot) arrived intact. - LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); - if ( view ) + LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel(); + if ( panel ) { LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); - view->getPanel()->setSelection( + panel->setSelection( server_response["new_inventory_item"].asUUID(), TAKE_FOCUS_NO); @@ -172,7 +172,7 @@ static void on_new_single_inventory_upload_complete( (LLFilePicker::instance().getFileCount() <= FILE_COUNT_DISPLAY_THRESHOLD) ) { - view->getPanel()->openSelected(); + panel->openSelected(); } // restore keyboard focus @@ -775,7 +775,7 @@ public: args["REASON"] = reason; - LLNotifications::instance().add("CannotUploadReason", args); + LLNotificationsUtil::add("CannotUploadReason", args); LLUploadDialog::modalUploadFinished(); } @@ -917,7 +917,7 @@ public: S32 option; std::string confirmation_url; - option = LLNotification::getSelectedOption( + option = LLNotificationsUtil::getSelectedOption( notification, response); @@ -1141,7 +1141,7 @@ void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog( // when using plain ol' 'this', that this object // would be deleted before the callback is triggered // and cause sadness. - LLNotifications::instance().add( + LLNotificationsUtil::add( "UploadCostConfirmation", substitutions, payload, diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 03c3900235..b367d6aec5 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -385,18 +385,9 @@ LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary() addEntry(DAD_ANIMATION, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_GESTURE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dActivateGesture, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_LINK, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL)); + addEntry(DAD_MESH, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); // TODO: animation on self could play it? edit it? // TODO: gesture on self could play it? edit it? - - -// Source: DAD_MESH - { - &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE - &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF - &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR - &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT - &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND - }, }; LLToolDragAndDrop::LLToolDragAndDrop() -- cgit v1.2.3 From cd138869d5bfcf40d3d13d7b887e36263e2919d9 Mon Sep 17 00:00:00 2001 From: Palmer Truelson Date: Mon, 7 Dec 2009 17:38:45 -0800 Subject: fix of another merge borkasaurus --- indra/newview/llassetuploadresponders.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index bc606c04a9..f5d5559bda 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -380,7 +380,6 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) mPostData["description"], content, expected_upload_cost); - LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); // continue uploading for bulk uploads -- cgit v1.2.3 From 7a7eced4a619d98d808abba3f0bf951bcf4cd95a Mon Sep 17 00:00:00 2001 From: Palmer Date: Tue, 8 Dec 2009 16:06:18 -0800 Subject: Fix of last merge borkasaur. Left off a comma on defining the mesh array. Also switched our mesh icon code to sync with viewer 2 and cleared out extra notification --- indra/newview/llinventorybridge.cpp | 4 +-- indra/newview/llviewertexteditor.cpp | 2 +- indra/newview/skins/default/textures/textures.xml | 1 + .../xui/en/floater_inventory_view_finder.xml | 29 +++++++++++++++++----- .../newview/skins/default/xui/en/notifications.xml | 21 ++++------------ 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 59bfc77723..93cfbddc92 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -125,9 +125,9 @@ std::string ICON_NAME[ICON_NAME_COUNT] = "Inv_Gesture", "Inv_LinkItem", - "Inv_LinkFolder" + "Inv_LinkFolder", - "inv_item_mesh.tga" + "Inv_Mesh" }; // +=================================================+ diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 569ceea431..80b8999a7a 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -534,7 +534,7 @@ LLUIImagePtr LLEmbeddedItems::getItemImage(llwchar ext_char) const case LLAssetType::AT_BODYPART: img_name = "Inv_Skin"; break; case LLAssetType::AT_ANIMATION: img_name = "Inv_Animation"; break; case LLAssetType::AT_GESTURE: img_name = "Inv_Gesture"; break; - case LLAssetType::AT_MESH: img_name = "inv_item_mesh.tga"; break; + case LLAssetType::AT_MESH: img_name = "Inv_Mesh"; break; default: llassert(0); } diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index ac84042584..ff9da8c8a0 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -233,6 +233,7 @@ with the same filename but different name + diff --git a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml index 90fee857fb..388825d31a 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml @@ -102,6 +102,23 @@ name="icon_notecard" top="122" width="16" /> + + - diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml index 2dfcdf4a4c..d26e855e2f 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml @@ -153,19 +153,28 @@ layout="topleft" left="5" name="CreatorNameLabel" - top_pad="12" + top_pad="10" width="78"> Creator: + Erica Linden @@ -177,19 +186,28 @@ layout="topleft" left="5" name="Owner:" - top_pad="15" + top_pad="10" width="78"> Owner: + Erica Linden @@ -201,7 +219,7 @@ layout="topleft" left="5" name="Group_label" - top_pad="15" + top_pad="10" width="78"> Group: diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index fbdac7164d..bd868ef61e 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -67,7 +67,7 @@ Click to view this web page Click to view this location's information - Click to view this Resident's profile + Click to view this resident's profile Click to view this group's description Click to view this event's description Click to view this classified @@ -1609,11 +1609,11 @@ Sends an HTTP request to the specified url with the body of the request and para llResetLandBanList() -Removes all Residents from the land ban list +Removes all residents from the land ban list llResetLandPassList() -Removes all Residents from the land access/pass list +Removes all residents from the land access/pass list integer llGetObjectPrimCount(key object_id) @@ -1621,7 +1621,7 @@ Returns the total number of prims for an object in the region list llGetParcelPrimOwners(vector pos) -Returns a list of all Residents who own objects on the parcel at pos and with individual prim counts. +Returns a list of all residents who own objects on the parcel at pos and with individual prim counts. Requires owner-like permissions for the parcel. @@ -1808,7 +1808,7 @@ Clears (deletes) the media and all params from the given face. No matching items found in inventory. - Drag a landmark here to add it to your favorites. + Drag and drop a landmark here to add to your favorites. You do not have a copy of this texture in your inventory @@ -2040,7 +2040,7 @@ this texture in your inventory all estates that you manage for [OWNER] - Allowed Residents: ([ALLOWEDAGENTS], max [MAXACCESS]) + Allowed residents: ([ALLOWEDAGENTS], max [MAXACCESS]) Allowed groups: ([ALLOWEDGROUPS], max [MAXACCESS]) @@ -2111,7 +2111,7 @@ this texture in your inventory (by name) - (Resident) + (resident) (object) (group) @@ -2938,7 +2938,7 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. Click the [BUTTON NAME] button to accept/connect to this voice chat. - You have blocked this Resident. Sending a message will automatically unblock them. + You have blocked this resident. Sending a message will automatically unblock them. @@ -678,8 +684,6 @@ with the same filename but different name - - @@ -698,7 +702,6 @@ with the same filename but different name - @@ -719,27 +722,10 @@ with the same filename but different name - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/default/xui/de/floater_buy_currency.xml b/indra/newview/skins/default/xui/de/floater_buy_currency.xml index 3c336cc40b..c320e796c2 100644 --- a/indra/newview/skins/default/xui/de/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/de/floater_buy_currency.xml @@ -46,7 +46,7 @@ [AMT] L$ - [http://www.secondlife.com/ payment method] | [http://www.secondlife.com/ currency] | [http://www.secondlife.com exchange rate] + [http://www.secondlife.com/my/account/payment_method_management.php?lang=de-DE payment method] | [http://www.secondlife.com/my/account/currency.php?lang=de-DE currency] | [http://www.secondlife.com/my/account/exchange_rates.php?lang=de-DE exchange rate] Geben Sie den Betrag erneut ein, um die aktuellste Umtauschrate anzuzeigen. diff --git a/indra/newview/skins/default/xui/de/floater_help_browser.xml b/indra/newview/skins/default/xui/de/floater_help_browser.xml index 53bddcced1..2344d6f412 100644 --- a/indra/newview/skins/default/xui/de/floater_help_browser.xml +++ b/indra/newview/skins/default/xui/de/floater_help_browser.xml @@ -1,10 +1,10 @@ - http://www.secondlife.com + http://de.secondlife.com - http://support.secondlife.com + http://de.secondlife.com/support diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index 809ac33e15..e93a38f187 100644 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -166,7 +166,7 @@ Anklicken, um Befehl secondlife:// auszuführen - + Teleportieren nach @@ -821,46 +821,46 @@ Sie haben keine Kopie dieser Textur in Ihrem Inventar. - - - - - - + + + + + + Inhalte werden geladen... Keine Inhalte - + Ja Nein - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + Mein Inventar @@ -1239,13 +1239,13 @@ keine - + (unbekannt) - - - + + + Kontostand @@ -1324,8 +1324,8 @@ Zuletzt geändert: - - + + In Gruppenbesitz @@ -1616,7 +1616,7 @@ Falls der Fehler dann weiterhin auftritt, müssen Sie [APP_NAME] von Ihrem Syste Unbehebbarer Fehler - [APP_NAME] erfordert einen Prozessor mit AltiVec (G4 oder später). + [APP_NAME] erfordert einen Prozessor mit AltiVec (G4 oder später). [APP_NAME] läuft bereits. diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index 82ed1a7d7f..9806f45bc4 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -112,7 +112,7 @@ Packets Lost: [PACKETS_LOST,number,0]/[PACKETS_IN,number,0] ([PACKETS_PCT,number word_wrap="true"> Second Life is brought to you by Philip, Tessa, Andrew, Cory, James, Ben, Char, Charlie, Colin, Dan, Daniel, Doug, Eric, Hamlet, Haney, Eve, Hunter, Ian, Jeff, Jennifer, Jim, John, Lee, Mark, Peter, Phoenix, Richard, Robin, Xenon, Steve, Tanya, Eddie, Avi, Frank, Bruce, Aaron, Alice, Bob, Debra, Eileen, Helen, Janet, Louie, Leviathania, Stefan, Ray, Kevin, Tom, Mikeb, MikeT, Burgess, Elena, Tracy, Bill, Todd, Ryan, Zach, Sarah, Nova, Tim, Stephanie, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Magellan, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Ventrella, Jack, Vektor, Iris, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Altruima, Jesse, Teeny, Monroe, Icculus, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Satoko, Yuko, Makiko, Thomas, Harry, Seth, Alexei, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, beez, Milo, Hermia, Red, Thrax, Joe, Sally, Magenta, Mogura, Paul, Jose, Rejean, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Jean, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, dustin, George, Del, Matthew, Cat, Jacqui, Lightfoot, Adrian, Viola, Alfred, Noel, Irfan, Sunil, Yool, Rika, Jane, Xtreme, Frontier, a2, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Gulliver, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Anthony, Jeremy, JP, Jake, Maurice, Madhavi, Leopard, Kyle, Joon, Kari, Bert, Belinda, Jon, Kristi, Bridie, Pramod, KJ, Socrates, Maria, Ivan, Aric, Yamasaki, Adreanne, Jay, MitchK, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Rohn, Colossus, Zen, BigPapi, Brad, Pastrami, Kurz, Mani, Neuro, Jaime, MJ, Rowan, Sgt, Elvis, Gecko, Samuel, Sardonyx, Leo, Bryan, Niko, Soft, Poppy, Rachel, Aki, Angelo, Banzai, Alexa, Sue, CeeLo, Bender, CG, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Heidy, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Winnie, Stella, Milton, Rothman, Niall, Marin, Allison, Katie, Dawn, Katt, Dusty, Kalpana, Judy, Andrea, Ambroff, Infinity, Gail, Rico, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Vidtuts, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Austin, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Yang, T, Simone, Maestro, Scott, Charlene, Quixote, Amanda, Susan, Zed, Anne, Enkidu, Esbee, Joroan, Katelin, Roxie, Tay, Scarlet, Kevin, Johnny, Wolfgang, Andren, Bob, Howard, Merov, Rand, Ray, Michon, Newell, Galen, Dessie, Les and many others. -Thank you to the following residents for helping to ensure that this is the best version yet: (in progress) +Thank you to the following Residents for helping to ensure that this is the best version yet: (in progress) diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml index 33fdd923ad..900f4c5956 100644 --- a/indra/newview/skins/default/xui/en/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en/floater_about_land.xml @@ -1036,7 +1036,7 @@ Leyla Linden name="Autoreturn" top="164" width="294"> - Autoreturn other residents' objects (minutes, 0 for off): + Autoreturn other Residents' objects (minutes, 0 for off): - Allow other residents to: + Allow other Residents to: L$ @@ -123,7 +123,7 @@ label="L$" left_pad="3" name="currency_amt" - width="60"> + width="85"> 1234 - Put on a new shape by dragging one from your inventory -to your avatar. Alternately, you create a new one from -scratch and wear it. + Put on a new shape by dragging one from your inventory to your avatar. Alternately, you create a new one from scratch and wear it. You do not have permission to modify this wearable. @@ -300,7 +300,7 @@ scratch and wear it. left="10" name="Create New" top="104" - width="140" /> + width="160" /> + diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml index d26e855e2f..2dfcdf4a4c 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml @@ -153,28 +153,19 @@ layout="topleft" left="5" name="CreatorNameLabel" - top_pad="10" + top_pad="12" width="78"> Creator: - Erica Linden @@ -186,28 +177,19 @@ layout="topleft" left="5" name="Owner:" - top_pad="10" + top_pad="15" width="78"> Owner: - Erica Linden @@ -219,7 +201,7 @@ layout="topleft" left="5" name="Group_label" - top_pad="10" + top_pad="15" width="78"> Group: diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index bd868ef61e..fbdac7164d 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -67,7 +67,7 @@ Click to view this web page Click to view this location's information - Click to view this resident's profile + Click to view this Resident's profile Click to view this group's description Click to view this event's description Click to view this classified @@ -1609,11 +1609,11 @@ Sends an HTTP request to the specified url with the body of the request and para llResetLandBanList() -Removes all residents from the land ban list +Removes all Residents from the land ban list llResetLandPassList() -Removes all residents from the land access/pass list +Removes all Residents from the land access/pass list integer llGetObjectPrimCount(key object_id) @@ -1621,7 +1621,7 @@ Returns the total number of prims for an object in the region list llGetParcelPrimOwners(vector pos) -Returns a list of all residents who own objects on the parcel at pos and with individual prim counts. +Returns a list of all Residents who own objects on the parcel at pos and with individual prim counts. Requires owner-like permissions for the parcel. @@ -1808,7 +1808,7 @@ Clears (deletes) the media and all params from the given face. No matching items found in inventory. - Drag and drop a landmark here to add to your favorites. + Drag a landmark here to add it to your favorites. You do not have a copy of this texture in your inventory @@ -2040,7 +2040,7 @@ this texture in your inventory all estates that you manage for [OWNER] - Allowed residents: ([ALLOWEDAGENTS], max [MAXACCESS]) + Allowed Residents: ([ALLOWEDAGENTS], max [MAXACCESS]) Allowed groups: ([ALLOWEDGROUPS], max [MAXACCESS]) @@ -2111,7 +2111,7 @@ this texture in your inventory (by name) - (resident) + (Resident) (object) (group) @@ -2938,7 +2938,7 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. Click the [BUTTON NAME] button to accept/connect to this voice chat. - You have blocked this resident. Sending a message will automatically unblock them. + You have blocked this Resident. Sending a message will automatically unblock them. + + Model Preview: + + + + + + + + + Dimensions (meters): + + + X: + + + Y: + + + Z: + + + Note: +Advanced users familiar with 3d content creation tools may prefer to use the Advanced Mesh Import window. + + + + + Model Preview: + + + + + + Dimensions (meters): + + + X: [X] | Y: [Y] | Z: [Z] + + + Note: + Advanced users familiar with 3d content creation tools may prefer to use the Advanced Mesh Import window. + + + + High + + + Medium + + + Lowest + + + Low + + + + + + + + + + Optimize + + + + This wizard is optimizing your model. This may take several minutes. To stop the process click the back button + + + Generating Level of Detail + + + Generate Level of Detail: High + + Generate Level of Detail: Medium + + Generate Level of Detail: Low + + Generate Level of Detail: Lowest + + + + Model Preview: + + + + High + + + Medium + + + Lowest + + + Low + + + + + Performance Accuracy + + + | | | + + + + + + + + + + Physics + + + + The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used: + + + + + + + + + Review + + + + Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload. + + + + + + + + + + + Upload Complete! + + + + Congratulations! Your model has been sucessfully uploaded. You will find the model in the Objects folder in your inventory. + + + + text_color="White" + left_pad="19"> Model Preview: Dimensions (meters): - X: [X] | Y: [Y] | Z: [Z] + X: [X] |Y: [Y] |Z: [Z] Note: + + Advanced users familiar with 3d content creation tools may prefer to use the [secondlife:///app/floater/upload_model Advanced Mesh Import Window] . @@ -218,7 +229,7 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se height="388" top_delta="0" name="optimize_panel" - visible="false" + visible="true" width="530" left="0"> - + Model Preview: - Performance Accuracy + Performance + Faster rendering but less detailed; lowers Resource (prim) cost. + Accuracy + More detailed model but slower; increases Resource (prim) cost. - ' ' ' - + width="290" /> + ' ' ' + Resource Cost: + Upload Fee: + + Dimensions (meters): + + + X: [X] |Y: [Y] |Z: [Z] + @@ -429,7 +466,7 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se - - Model Preview: - - - - - - Dimensions (meters): - - - X: [X] |Y: [Y] |Z: [Z] - - - Note: - - -Advanced users familiar with 3d content creation tools may prefer to use the [secondlife:///app/floater/upload_model Advanced Mesh Import Window] . - - - - - - - - - Optimize - - - - This wizard is optimizing your model. This may take several minutes. To stop the process click the back button - - - Generating Level of Detail - - - Generate Level of Detail: High - - Generate Level of Detail: Medium - - Generate Level of Detail: Low - - Generate Level of Detail: Lowest - - - - Model Preview: - - - - High - - - Medium - - - Lowest - - - Low - - - - - Performance - Faster rendering but less detailed; lowers Resource (prim) cost. - Accuracy - More detailed model but slower; increases Resource (prim) cost. - - - ' ' ' - Resource Cost: - Upload Fee: - - Dimensions (meters): - - - X: [X] |Y: [Y] |Z: [Z] - - - - - - - - - - Physics - - - - The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used: - - - - - - - - - Review - - - - Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload. - - - - - - - - - - - Upload Complete! - - - - Congratulations! Your model has been sucessfully uploaded. You will find the model in the Objects folder in your inventory. - - - + + Model Preview: + + + + + + Dimensions (meters): + + + X: [X] |Y: [Y] |Z: [Z] + + + Note: + + +Advanced users familiar with 3d content creation tools may prefer to use the [secondlife:///app/floater/upload_model Advanced Mesh Import Window] . + + + + + + + + + Optimize + + + + This wizard is optimizing your model. This may take several minutes. To stop the process click the back button + + + Generating Level of Detail + + + Generate Level of Detail: High + + Generate Level of Detail: Medium + + Generate Level of Detail: Low + + Generate Level of Detail: Lowest + + + + Model Preview: + + + + High + + + Medium + + + Lowest + + + Low + + + + + Performance + Faster rendering but less detailed; lowers Resource (prim) cost. + Accuracy + More detailed model but slower; increases Resource (prim) cost. + + + ' ' ' + Resource Cost: + Upload Fee: + + Dimensions (meters): + + + X: [X] |Y: [Y] |Z: [Z] + + + + + + + + + + Physics + + + + The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used: + + + Performance + Faster rendering but less detailed; lowers Resource (prim) cost. + Accuracy + More detailed model but slower; increases Resource (prim) cost. + + + ' ' ' ' ' ' ' ' ' ' ' + Recommended for solid objects + Recommended for buildings + Recommended for vehicles + Resource Cost: + Physics Cost: + Upload Fee: + + + + + + + + + Review + + + + Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload. + + + + Model Preview: + + + + High + + + Medium + + + Lowest + + + Low + + + + + + Dimensions (meters): + + + X: [X] |Y: [Y] |Z: [Z] + + + Resource Cost: + This is the cost to your Region's prim/object limit, at default scale + Physics Cost: + This is the cost to your Region's prim/object limit, at default scale + Upload Fee: + This is the amount the upload will cost. + + I confirm that I have the appropriate rights to the material contained in this model. [secondlife:///app/floater/learn_more Learn more] + + + + + + + + + Upload Complete! + + + + Congratulations! Your model has been sucessfully uploaded. You will find the model in the Objects folder in your inventory. + + + + + + + Date: Wed, 12 Jan 2011 17:35:31 -0500 Subject: SH-717 Viewer crash on exit after Upload model dialog could not be spawned Took out unused function that was seen in crash report from this bug. No functionality change. --- indra/newview/llfloatermodelpreview.cpp | 15 --------------- indra/newview/llfloatermodelpreview.h | 1 - 2 files changed, 16 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 3ac7f12e4e..8dcb441b16 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2817,21 +2817,6 @@ void LLModelPreview::clearMaterials() refresh(); } -bool LLModelPreview::containsRiggedAsset( void ) -{ - //loop through the models and determine if any of them contained a rigged asset, and if so - //return true. - //This is used to cleanup the joint positions after a preview. - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - LLModel* pModel = *iter; - if ( pModel->mAlternateBindMatrix.size() > 0 ) - { - return true; - } - } - return false; -} void LLModelPreview::genLODs(S32 which_lod, U32 decimation) { if (mBaseModel.empty()) diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 04e5b9591c..3747abedd1 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -279,7 +279,6 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex void rebuildUploadData(); void clearIncompatible(S32 lod); void updateStatusMessages(); - bool containsRiggedAsset( void ); void clearGLODGroup(); -- cgit v1.2.3 From 53d03606f13d52b4282e91e391eb761dbd96a1ad Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Fri, 14 Jan 2011 13:23:14 -0500 Subject: SH-557 FIX meshes sometimes don't load in a region Found that we were storing an empty string as a getMesh capability in the case that we checked for the new url before getting the list of caps from the server after a teleport. Made sure we didn't overwrite the caps url until we have the list of caps for the new region after teleport. Will be post-reviewed by davep --- indra/newview/llmeshrepository.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index d2f76eceb0..b772999ee2 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2299,7 +2299,7 @@ void LLMeshRepository::notifyLoadedMeshes() if (gAgent.getRegion()) { //update capability url - if (gAgent.getRegion()->getName() != region_name) + if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived()) { region_name = gAgent.getRegion()->getName(); -- cgit v1.2.3 From a678ff80af6c48d4232c52aa505b633a1fc22663 Mon Sep 17 00:00:00 2001 From: prep linden Date: Fri, 14 Jan 2011 15:00:19 -0500 Subject: voice dot is positioned consistently --- indra/newview/llvoavatar.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index b667dc1af0..ffe61485d6 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -2446,9 +2446,19 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) // here we get the approximate head position and set as sound source for the voice symbol // (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing) //-------------------------------------------------------------------------------------------- - LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] ); - mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset ); + if ( mIsSitting ) + { + LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] ); + mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset ); + } + else + { + LLVector3 tagPos = mRoot.getWorldPosition(); + tagPos[VZ] -= mPelvisToFoot; + tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); + mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos ); + } }//if ( voiceEnabled ) } -- cgit v1.2.3 From 5364bb5a11aaae33127db3866f7a9bba6404773d Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Fri, 14 Jan 2011 15:16:17 -0500 Subject: Mesh-development work in progress --- indra/newview/llviewerobject.cpp | 30 ++++++++++++++++++++---------- indra/newview/llvocache.cpp | 1 - 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index f380d4b183..bf550e9c70 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -5600,6 +5600,26 @@ void LLViewerObject::setAttachmentItemID(const LLUUID &id) mAttachmentItemID = id; } +EObjectUpdateType LLViewerObject::getLastUpdateType() const +{ + return mLastUpdateType; +} + +void LLViewerObject::setLastUpdateType(EObjectUpdateType last_update_type) +{ + mLastUpdateType = last_update_type; +} + +BOOL LLViewerObject::getLastUpdateCached() const +{ + return mLastUpdateCached; +} + +void LLViewerObject::setLastUpdateCached(BOOL last_update_cached) +{ + mLastUpdateCached = last_update_cached; +} + const LLUUID &LLViewerObject::extractAttachmentItemID() { LLUUID item_id = LLUUID::null; @@ -5616,16 +5636,6 @@ const LLUUID &LLViewerObject::extractAttachmentItemID() return getAttachmentItemID(); } -EObjectUpdateType LLViewerObject::getLastUpdateType() const -{ - return mLastUpdateType; -} - -void LLViewerObject::setLastUpdateType(EObjectUpdateType last_update_type) -{ - mLastUpdateType = last_update_type; -} - //virtual LLVOAvatar* LLViewerObject::getAvatar() const { diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 2188b41a06..10d6b009ae 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -648,7 +648,6 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: HeaderEntryInfo* entry; handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; - U32 num_handle_entries = mHandleEntryMap.size(); if(iter == mHandleEntryMap.end()) //new entry { if(num_handle_entries >= mCacheSize) -- cgit v1.2.3 From 4f06f3dae6d35b142f57e07c41e0a8abcd296fcb Mon Sep 17 00:00:00 2001 From: Tofu Buzzard Date: Sun, 16 Jan 2011 13:36:44 +0000 Subject: FIX VWR-24509 Fix SSAO speckling artifacts at distance, re-enable distant SSAO (transplanted from ef938dea0504b12fcf802f38fcf5457ba566c468) --- doc/contributions.txt | 1 + indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index b5158b3792..313cc11341 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -752,6 +752,7 @@ tiamat bingyi Tofu Buzzard CTS-411 STORM-546 + VWR-24509 TraductoresAnonimos Alter CT-324 Tue Torok diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl index ad4d700b99..6859f72a9c 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl @@ -51,6 +51,9 @@ void main() vec2 defined_weight = kern[0].xy; // special case the first (centre) sample's weight in the blur; we have to sample it anyway so we get it for 'free' vec4 col = defined_weight.xyxx * ccol; + // relax tolerance according to distance to avoid speckling artifacts, as angles and distances are a lot more abrupt within a small screen area at larger distances + float pointplanedist_tolerance_pow2 = pos.z*pos.z*0.00005; + // perturb sampling origin slightly in screen-space to hide edge-ghosting artifacts where smoothing radius is quite large tc += ( (int(tc.x+tc.y)%2 - 0.5) * kern[1].z * dlt * 0.5 ); @@ -59,7 +62,7 @@ void main() vec2 samptc = tc + kern[i].z*dlt; vec3 samppos = getPosition(samptc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane - if (d*d <= 0.003) + if (d*d <= pointplanedist_tolerance_pow2) { col += texture2DRect(lightMap, samptc)*kern[i].xyxx; defined_weight += kern[i].xy; @@ -70,7 +73,7 @@ void main() vec2 samptc = tc - kern[i].z*dlt; vec3 samppos = getPosition(samptc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane - if (d*d <= 0.003) + if (d*d <= pointplanedist_tolerance_pow2) { col += texture2DRect(lightMap, samptc)*kern[i].xyxx; defined_weight += kern[i].xy; -- cgit v1.2.3 From 951f4af77dc21f7761cf9b9787f391e752e738ca Mon Sep 17 00:00:00 2001 From: Tofu Buzzard Date: Sun, 16 Jan 2011 13:37:26 +0000 Subject: local - nerf failing test (transplanted from 2ca6263676abac96c6982880fc6ee2fe182a206a) --- indra/llui/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 684e393cba..3e94a4738b 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -245,11 +245,11 @@ target_link_libraries(llui ) # Add tests -if (LL_TESTS) +if (0 AND LL_TESTS) include(LLAddBuildTest) SET(llui_TEST_SOURCE_FILES llurlmatch.cpp llurlentry.cpp ) LL_ADD_PROJECT_UNIT_TESTS(llui "${llui_TEST_SOURCE_FILES}") -endif (LL_TESTS) \ No newline at end of file +endif (0 AND LL_TESTS) -- cgit v1.2.3 From 1426bcbae4ff6fad8383b857a6697abcbe243116 Mon Sep 17 00:00:00 2001 From: Tofu Buzzard Date: Sun, 16 Jan 2011 13:47:15 +0000 Subject: FIX VWR-24509 Fix SSAO speckling artifacts at distance, re-enable distant SSAO followup - remove the distance limiting, re-enabling distant SSAO. (transplanted from d11eafacb2609537905718fa559e81b53e6740f8) --- .../shaders/class1/deferred/sunLightSSAOF.glsl | 74 ++++++++++----------- .../shaders/class2/deferred/sunLightSSAOF.glsl | 76 ++++++++++------------ 2 files changed, 67 insertions(+), 83 deletions(-) diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl index 1e0693d19f..25ff958107 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl @@ -53,57 +53,49 @@ float calcAmbientOcclusion(vec4 pos, vec3 norm) { float ret = 1.0; - float dist = dot(pos.xyz,pos.xyz); - - if (dist < 64.0*64.0) - { - vec2 kern[8]; - // exponentially (^2) distant occlusion samples spread around origin - kern[0] = vec2(-1.0, 0.0) * 0.125*0.125; - kern[1] = vec2(1.0, 0.0) * 0.250*0.250; - kern[2] = vec2(0.0, 1.0) * 0.375*0.375; - kern[3] = vec2(0.0, -1.0) * 0.500*0.500; - kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625; - kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750; - kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875; - kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000; + vec2 kern[8]; + // exponentially (^2) distant occlusion samples spread around origin + kern[0] = vec2(-1.0, 0.0) * 0.125*0.125; + kern[1] = vec2(1.0, 0.0) * 0.250*0.250; + kern[2] = vec2(0.0, 1.0) * 0.375*0.375; + kern[3] = vec2(0.0, -1.0) * 0.500*0.500; + kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625; + kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750; + kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875; + kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000; - vec2 pos_screen = vary_fragcoord.xy; - vec3 pos_world = pos.xyz; - vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; + vec2 pos_screen = vary_fragcoord.xy; + vec3 pos_world = pos.xyz; + vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; - float angle_hidden = 0.0; - int points = 0; + float angle_hidden = 0.0; + int points = 0; - float scale = min(ssao_radius / -pos_world.z, ssao_max_radius); + float scale = min(ssao_radius / -pos_world.z, ssao_max_radius); - // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) - for (int i = 0; i < 8; i++) - { - vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect); - vec3 samppos_world = getPosition(samppos_screen).xyz; + // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations unrolling?) + for (int i = 0; i < 8; i++) + { + vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect); + vec3 samppos_world = getPosition(samppos_screen).xyz; - vec3 diff = pos_world - samppos_world; - float dist2 = dot(diff, diff); + vec3 diff = pos_world - samppos_world; + float dist2 = dot(diff, diff); - // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area - // --> solid angle shrinking by the square of distance - //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2 - //(k should vary inversely with # of samples, but this is taken care of later) + // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area + // --> solid angle shrinking by the square of distance + //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2 + //(k should vary inversely with # of samples, but this is taken care of later) - //if (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) // -0.05*norm to shift sample point back slightly for flat surfaces - // angle_hidden += min(1.0/dist2, ssao_factor_inv); // dist != 0 follows from conditional. max of 1.0 (= ssao_factor_inv * ssao_factor) - angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv); + angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv); - // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" - points = points + int(diff.z > -1.0); - } + // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" + points = points + int(diff.z > -1.0); + } - angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0); + angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0); - ret = (1.0 - (float(points != 0) * angle_hidden)); - ret += max((dist-32.0*32.0)/(32.0*32.0), 0.0); - } + ret = (1.0 - (float(points != 0) * angle_hidden)); return min(ret, 1.0); } diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl index cc921f23d7..08b16d787f 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl @@ -62,58 +62,50 @@ vec4 getPosition(vec2 pos_screen) float calcAmbientOcclusion(vec4 pos, vec3 norm) { float ret = 1.0; - - float dist = dot(pos.xyz,pos.xyz); - - if (dist < 64.0*64.0) - { - vec2 kern[8]; - // exponentially (^2) distant occlusion samples spread around origin - kern[0] = vec2(-1.0, 0.0) * 0.125*0.125; - kern[1] = vec2(1.0, 0.0) * 0.250*0.250; - kern[2] = vec2(0.0, 1.0) * 0.375*0.375; - kern[3] = vec2(0.0, -1.0) * 0.500*0.500; - kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625; - kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750; - kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875; - kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000; - vec2 pos_screen = vary_fragcoord.xy; - vec3 pos_world = pos.xyz; - vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; + vec2 kern[8]; + // exponentially (^2) distant occlusion samples spread around origin + kern[0] = vec2(-1.0, 0.0) * 0.125*0.125; + kern[1] = vec2(1.0, 0.0) * 0.250*0.250; + kern[2] = vec2(0.0, 1.0) * 0.375*0.375; + kern[3] = vec2(0.0, -1.0) * 0.500*0.500; + kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625; + kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750; + kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875; + kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000; + + vec2 pos_screen = vary_fragcoord.xy; + vec3 pos_world = pos.xyz; + vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; - float angle_hidden = 0.0; - int points = 0; + float angle_hidden = 0.0; + int points = 0; - float scale = min(ssao_radius / -pos_world.z, ssao_max_radius); + float scale = min(ssao_radius / -pos_world.z, ssao_max_radius); - // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) - for (int i = 0; i < 8; i++) - { - vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect); - vec3 samppos_world = getPosition(samppos_screen).xyz; + // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) + for (int i = 0; i < 8; i++) + { + vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect); + vec3 samppos_world = getPosition(samppos_screen).xyz; - vec3 diff = pos_world - samppos_world; - float dist2 = dot(diff, diff); + vec3 diff = pos_world - samppos_world; + float dist2 = dot(diff, diff); - // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area - // --> solid angle shrinking by the square of distance - //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2 - //(k should vary inversely with # of samples, but this is taken care of later) + // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area + // --> solid angle shrinking by the square of distance + //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2 + //(k should vary inversely with # of samples, but this is taken care of later) - //if (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) // -0.05*norm to shift sample point back slightly for flat surfaces - // angle_hidden += min(1.0/dist2, ssao_factor_inv); // dist != 0 follows from conditional. max of 1.0 (= ssao_factor_inv * ssao_factor) - angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv); + angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv); - // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" - points = points + int(diff.z > -1.0); - } + // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" + points = points + int(diff.z > -1.0); + } - angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0); + angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0); - ret = (1.0 - (float(points != 0) * angle_hidden)); - ret += max((dist-32.0*32.0)/(32.0*32.0), 0.0); - } + ret = (1.0 - (float(points != 0) * angle_hidden)); return min(ret, 1.0); } -- cgit v1.2.3 From aeec987f565f916c9919f8cc861a82b4caab9a46 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 18 Jan 2011 14:49:14 -0600 Subject: SH-571 work in progress. --- indra/newview/llspatialpartition.cpp | 6 ++++-- indra/newview/llviewerobjectlist.cpp | 4 ++-- indra/newview/llvovolume.cpp | 8 +++++--- indra/newview/pipeline.cpp | 10 ++++++---- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 1b5800b8a5..ec9bc86ea0 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -2465,7 +2465,6 @@ void renderOctree(LLSpatialGroup* group) { //render solid object bounding box, color //coded by buffer usage and activity - LLGLDepthTest depth(GL_TRUE, GL_FALSE); gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); LLVector4 col; if (group->mBuilt > 0.f) @@ -2557,7 +2556,10 @@ void renderOctree(LLSpatialGroup* group) size.mul(1.01f); size.add(fudge); - drawBox(group->mObjectBounds[0], fudge); + { + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + drawBox(group->mObjectBounds[0], fudge); + } gGL.setSceneBlendType(LLRender::BT_ALPHA); diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 7682d71e7f..e4da9cca04 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1376,7 +1376,7 @@ void LLViewerObjectList::updateObjectCost(const LLUUID& object_id, F32 object_co void LLViewerObjectList::onObjectCostFetchFailure(const LLUUID& object_id) { - llwarns << "Failed to fetch object cost for object: " << object_id << llendl; + //llwarns << "Failed to fetch object cost for object: " << object_id << llendl; mPendingObjectCost.erase(object_id); } @@ -1415,7 +1415,7 @@ void LLViewerObjectList::updatePhysicsProperties(const LLUUID& object_id, void LLViewerObjectList::onPhysicsFlagsFetchFailure(const LLUUID& object_id) { - llwarns << "Failed to fetch physics flags for object: " << object_id << llendl; + //llwarns << "Failed to fetch physics flags for object: " << object_id << llendl; mPendingPhysicsFlags.erase(object_id); } diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 366213073e..71ebcf4c9f 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -931,9 +931,9 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline) return mDrawable; } -BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms, const S32 detail, bool unique_volume) +BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bool unique_volume) { - LLVolumeParams volume_params = params; + LLVolumeParams volume_params = params_in; S32 lod = mLOD; @@ -945,7 +945,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms, const S32 detail, bool if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) { //meshes might not have all LODs, get the force detail to best existing LOD - LLUUID mesh_id = params.getSculptID(); + LLUUID mesh_id = volume_params.getSculptID(); //profile and path params don't matter for meshes volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); @@ -1019,6 +1019,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms, const S32 detail, bool LLPrimitive::setVolume(volume_params, available_lod); } } + } else // otherwise is sculptie { @@ -1031,6 +1032,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms, const S32 detail, bool return TRUE; } + return FALSE; } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 24327bf535..2488e80bfb 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -7978,14 +7978,14 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera glLoadMatrixf(proj.m); glMatrixMode(GL_MODELVIEW); glPushMatrix(); - glLoadMatrixf(view.m); + glLoadMatrixd(gGLModelView); stop_glerror(); gGLLastMatrix = NULL; { - LLGLDepthTest depth(GL_TRUE); - glClear(GL_DEPTH_BUFFER_BIT); + //LLGLDepthTest depth(GL_TRUE); + //glClear(GL_DEPTH_BUFFER_BIT); } gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -9018,7 +9018,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera) mShadow[j].bindTarget(); mShadow[j].getViewport(gGLViewport); - + mShadow[j].clear(); + { static LLCullResult result[4]; @@ -9159,6 +9160,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera) mShadow[i+4].bindTarget(); mShadow[i+4].getViewport(gGLViewport); + mShadow[i+4].clear(); static LLCullResult result[2]; -- cgit v1.2.3 From e9fd322febba11fa29a06c36df5f5d17f43a9da4 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Wed, 19 Jan 2011 11:37:17 -0800 Subject: SH-820 selectively enable/disable mesh preferences options --- indra/newview/llfloaterpreference.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 456005f1fe..952643326a 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -656,6 +656,13 @@ void LLFloaterPreference::onOpen(const LLSD& key) getChildView("maturity_desired_combobox")->setVisible( false); } + bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled"); + + getChildView("UseLightShaders")->setVisible(enable_mesh); + getChildView("UseSSAO")->setVisible(enable_mesh); + getChildView("shadows_label")->setVisible(enable_mesh); + getChildView("ShadowDetail")->setVisible(enable_mesh); + if (LLStartUp::getStartupState() == STATE_STARTED) { mFavoritesRecordMayExist = gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"); -- cgit v1.2.3 From b5e67321c3fa1e60e0973547372a5425e9d82efc Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Wed, 19 Jan 2011 11:37:42 -0800 Subject: SH-821 Selectively show/hide mesh render info --- indra/newview/llviewerwindow.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 96ee3f6180..dcfac012f6 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -506,18 +506,21 @@ public: ypos += y_inc; - addText(xpos, ypos, llformat("%.3f MB Mesh Data Received", LLMeshRepository::sBytesReceived/(1024.f*1024.f))); - - ypos += y_inc; - - addText(xpos, ypos, llformat("%d/%d Mesh HTTP Requests/Retries", LLMeshRepository::sHTTPRequestCount, - LLMeshRepository::sHTTPRetryCount)); - - ypos += y_inc; + if (gSavedSettings.getBOOL("MeshEnabled")) + { + addText(xpos, ypos, llformat("%.3f MB Mesh Data Received", LLMeshRepository::sBytesReceived/(1024.f*1024.f))); + + ypos += y_inc; + + addText(xpos, ypos, llformat("%d/%d Mesh HTTP Requests/Retries", LLMeshRepository::sHTTPRequestCount, + LLMeshRepository::sHTTPRetryCount)); + + ypos += y_inc; - addText(xpos, ypos, llformat("%.3f/%.3f MB Mesh Cache Read/Write ", LLMeshRepository::sCacheBytesRead/(1024.f*1024.f), LLMeshRepository::sCacheBytesWritten/(1024.f*1024.f))); + addText(xpos, ypos, llformat("%.3f/%.3f MB Mesh Cache Read/Write ", LLMeshRepository::sCacheBytesRead/(1024.f*1024.f), LLMeshRepository::sCacheBytesWritten/(1024.f*1024.f))); - ypos += y_inc; + ypos += y_inc; + } addText(xpos, ypos, llformat("Selection Triangle Count: %.3f Ktris ", LLSelectMgr::getInstance()->getSelection()->getSelectedObjectTriangleCount()/1000.f)); -- cgit v1.2.3 From ca1c1eea78ff2ab83979a4308dd5a93ea0032fc8 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Wed, 19 Jan 2011 11:38:34 -0800 Subject: SH-808 Selectively enable/disable features in edit tools --- indra/llui/llcombobox.cpp | 4 ++++ indra/llui/llcombobox.h | 1 + indra/newview/llfloatertools.cpp | 7 +++++++ indra/newview/llpanelobject.cpp | 26 ++++++++++++++++++++++++++ 4 files changed, 38 insertions(+) diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 8b6a73af56..701d1ff706 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -231,6 +231,10 @@ void LLComboBox::resetDirty() } } +bool LLComboBox::itemExists(const std::string& name) +{ + return mList->getItemByLabel(name); +} // add item "name" to menu LLScrollListItem* LLComboBox::add(const std::string& name, EAddPosition pos, BOOL enabled) diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index 74d64269bd..59beba509c 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -134,6 +134,7 @@ public: LLScrollListItem* addSeparator(EAddPosition pos = ADD_BOTTOM); BOOL remove( S32 index ); // remove item by index, return TRUE if found and removed void removeall() { clearRows(); } + bool itemExists(const std::string& name); void sortByName(BOOL ascending = TRUE); // Sort the entries in the combobox by name diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 920bdef7f6..49e24f8e3d 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -463,6 +463,13 @@ void LLFloaterTools::refresh() childSetEnabled("linked_set_cost", have_selection); childSetEnabled("object_cost", have_selection); + bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled"); + + getChildView("linked_set_count")->setVisible(enable_mesh); + getChildView("linked_set_cost")->setVisible(enable_mesh); + getChildView("object_count")->setVisible(enable_mesh); + getChildView("object_cost")->setVisible(enable_mesh); + // Refresh child tabs mPanelPermissions->refresh(); mPanelObject->refresh(); diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 45e9a04fc2..73a8fbe3aa 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1910,6 +1910,32 @@ void LLPanelObject::refresh() { mRootObject = NULL; } + + bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled"); + + getChildView("label physicsshapetype")->setVisible(enable_mesh); + getChildView("Physics Shape Type Combo Ctrl")->setVisible(enable_mesh); + getChildView("Physics Gravity")->setVisible(enable_mesh); + getChildView("Physics Material Override")->setVisible(enable_mesh); + getChildView("Physics Friction")->setVisible(enable_mesh); + getChildView("Physics Density")->setVisible(enable_mesh); + getChildView("Physics Restitution")->setVisible(enable_mesh); + + // if mesh isn't enabled we want to the scale max to be 10 + getChild("Scale X")->setMaxValue(enable_mesh ? 64 : 10); + getChild("Scale Y")->setMaxValue(enable_mesh ? 64 : 10); + getChild("Scale Z")->setMaxValue(enable_mesh ? 64 : 10); + + LLComboBox* sculpt_combo = getChild("sculpt type control"); + BOOL found = sculpt_combo->itemExists("Mesh"); + if (enable_mesh && !found) + { + sculpt_combo->add("Mesh"); + } + else if (!enable_mesh && found) + { + sculpt_combo->remove("Mesh"); + } } -- cgit v1.2.3 From f3493d41655e357374e6a7122e19d463100bb27c Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 19 Jan 2011 23:14:41 -0600 Subject: SH-822 Fix for crash in cacheOptimize (U16 should have been a U32) --- indra/llmath/llvolume.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index f41cd1b4e8..d6dfb5c7a9 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -5762,7 +5762,7 @@ void LLVolumeFace::cacheOptimize() for (U32 i = 0; i < mNumIndices; i++) { //populate vertex data and triangle data arrays U16 idx = mIndices[i]; - U16 tri_idx = i/3; + U32 tri_idx = i/3; vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx])); vertex_data[idx].mIdx = idx; -- cgit v1.2.3 From 32c4a448b113731a8c9ae32613fe4aa50b5c9997 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 19 Jan 2011 23:16:53 -0600 Subject: SH-571 Fix for shadows disappearing for a frame whenever an object switches octree nodes. Regressed EXT-7155 so fix for regression included. --- indra/newview/lldrawable.cpp | 4 ++-- indra/newview/lldrawpoolbump.cpp | 7 +------ indra/newview/llviewerdisplay.cpp | 1 - indra/newview/llvovolume.cpp | 26 +++----------------------- indra/newview/pipeline.cpp | 15 ++++++--------- indra/newview/pipeline.h | 1 - 6 files changed, 12 insertions(+), 42 deletions(-) diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 086702de87..73c4cf94ef 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -763,7 +763,7 @@ void LLDrawable::updateTexture() if (getVOVolume()) { - if (isActive()) + /*if (isActive()) { if (isRoot()) { @@ -773,7 +773,7 @@ void LLDrawable::updateTexture() { getParent()->mQuietCount = 0; } - } + }*/ gPipeline.markRebuild(this, LLDrawable::REBUILD_MATERIAL, TRUE); } diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index bd2c6e1c63..0afa8b1794 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -145,12 +145,7 @@ void LLStandardBumpmap::addstandard() // llinfos << "Loading bumpmap: " << bump_image_id << " from viewerart" << llendl; gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mLabel = label; gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage = - LLViewerTextureManager::getFetchedTexture(LLUUID(bump_image_id), - TRUE, - LLViewerTexture::BOOST_NONE, - LLViewerTexture::LOD_TEXTURE, - 0, - 0); + LLViewerTextureManager::getFetchedTexture(LLUUID(bump_image_id)); gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setBoostLevel(LLViewerTexture::BOOST_BUMP) ; gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setLoadedCallback(LLBumpImageList::onSourceStandardLoaded, 0, TRUE, FALSE, NULL, NULL ); LLStandardBumpmap::sStandardBumpmapCount++; diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 527f400c03..8ad38c1789 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -755,7 +755,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) { LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; LLMemType mt_ss(LLMemType::MTYPE_DISPLAY_STATE_SORT); - gPipeline.sAllowRebuildPriorityGroup = TRUE ; gPipeline.stateSort(*LLViewerCamera::getInstance(), result); stop_glerror(); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 71ebcf4c9f..5277e073a3 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -857,7 +857,8 @@ void LLVOVolume::updateTextureVirtualSize() BOOL LLVOVolume::isActive() const { - return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive()); + return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive()) || + (mDrawable.notNull() && mDrawable->isActive()); } BOOL LLVOVolume::setMaterial(const U8 material) @@ -3281,28 +3282,6 @@ F32 LLVOVolume::getBinRadius() F32 scale = 1.f; - if (isSculpted()) - { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLUUID id = sculpt_params->getSculptTexture(); - U8 sculpt_type = sculpt_params->getSculptType(); - - if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) - // mesh is a mesh - { - LLVolume* volume = getVolume(); - U32 vert_count = 0; - - for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = volume->getVolumeFace(i); - vert_count += face.mNumVertices; - } - - scale = 1.f/llmax(vert_count/1024.f, 1.f); - } - } - const LLVector4a* ext = mDrawable->getSpatialExtents(); BOOL shrink_wrap = mDrawable->isAnimating(); @@ -4395,6 +4374,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) { LLVOVolume* vobj = drawablep->getVOVolume(); vobj->preRebuild(); + LLVolume* volume = vobj->getVolume(); for (S32 i = 0; i < drawablep->getNumFaces(); ++i) { diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 2488e80bfb..c1b3ad99b2 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -284,7 +284,6 @@ BOOL LLPipeline::sRenderFrameTest = FALSE; BOOL LLPipeline::sRenderAttachedLights = TRUE; BOOL LLPipeline::sRenderAttachedParticles = TRUE; BOOL LLPipeline::sRenderDeferred = FALSE; -BOOL LLPipeline::sAllowRebuildPriorityGroup = FALSE ; S32 LLPipeline::sVisibleLightCount = 0; F32 LLPipeline::sMinRenderSize = 0.f; @@ -2112,12 +2111,6 @@ void LLPipeline::updateGL() void LLPipeline::rebuildPriorityGroups() { - if(!sAllowRebuildPriorityGroup) - { - return ; - } - sAllowRebuildPriorityGroup = FALSE ; - LLTimer update_timer; LLMemType mt(LLMemType::MTYPE_PIPELINE); @@ -2502,6 +2495,11 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f { LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD); + if (drawablep) + { + LLVOVolume* volume = drawablep->getVOVolume(); + } + if (drawablep && !drawablep->isDead() && assertInitialized()) { if (!drawablep->isState(LLDrawable::BUILT)) @@ -2635,7 +2633,7 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera) { LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); - if (!sShadowRender && bridge->getSpatialGroup()->changeLOD()) + if (bridge->getSpatialGroup()->changeLOD()) { bool force_update = false; bridge->updateDistance(camera, force_update); @@ -6139,7 +6137,6 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) LLGLDisable blend(GL_BLEND); bindDeferredShader(*shader); - //depth of field focal plane calculations F32 subject_distance = 16.f; diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 61264d380a..7ae83e9816 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -506,7 +506,6 @@ public: static BOOL sRenderAttachedLights; static BOOL sRenderAttachedParticles; static BOOL sRenderDeferred; - static BOOL sAllowRebuildPriorityGroup; static S32 sVisibleLightCount; static F32 sMinRenderSize; -- cgit v1.2.3 From 32d3d2e0503ef81a7d1e40f7e7464ca6743d540f Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 20 Jan 2011 14:49:05 -0500 Subject: SH-749 FIX: check for zero-extent to avoid div by zero --- indra/llprimitive/llmodel.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 1869e1dd47..3d03209eaf 100755 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -950,6 +950,25 @@ void LLModel::normalizeVolumeFaces() LLVector4a size; size.setSub(max, min); + // Prevent division by zero. + F32 x = size[0]; + F32 y = size[1]; + F32 z = size[2]; + F32 w = size[3]; + if (fabs(x) Date: Thu, 20 Jan 2011 15:50:50 -0500 Subject: fixed build breakage on mac/linux - unused var --- indra/newview/pipeline.cpp | 5 ----- 1 file changed, 5 deletions(-) mode change 100644 => 100755 indra/newview/pipeline.cpp diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp old mode 100644 new mode 100755 index c1b3ad99b2..38711472a1 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -2495,11 +2495,6 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f { LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD); - if (drawablep) - { - LLVOVolume* volume = drawablep->getVOVolume(); - } - if (drawablep && !drawablep->isDead() && assertInitialized()) { if (!drawablep->isState(LLDrawable::BUILT)) -- cgit v1.2.3 From c2fe5b3e7b6b764247ec4f4b7595a1e73f307c77 Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Thu, 20 Jan 2011 13:46:42 -0800 Subject: SH-719 - nVidia Quadro 4000 unregonized in Mac client Added detection for Quadro cards as per http://en.wikipedia.org/wiki/Comparison_of_Nvidia_graphics_processing_units CR: davep --- indra/newview/gpu_table.txt | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt index bf604d6805..7023e07348 100644 --- a/indra/newview/gpu_table.txt +++ b/indra/newview/gpu_table.txt @@ -302,12 +302,45 @@ NVIDIA NV43 .*NVIDIA.*NV43.* 1 1 NVIDIA NV44 .*NVIDIA.*NV44.* 1 1 NVIDIA nForce .*NVIDIA.*nForce.* 0 0 NVIDIA MCP78 .*NVIDIA.*MCP78.* 1 1 -NVIDIA Quadro2 .*Quadro2.* 0 1 -NVIDIA Quadro4 .*Quadro4.* 0 1 -NVIDIA Quadro DCC .*Quadro DCC.* 0 1 -NVIDIA Quadro FX 4500 .*Quadro.*FX.*4500.* 3 1 -NVIDIA Quadro FX .*Quadro FX.* 1 1 -NVIDIA Quadro NVS .*Quadro NVS.* 0 1 +NVIDIA Quadro2 .*Quadro2.* 0 1 +NVIDIA Quadro4 .*Quadro4.* 0 1 +NVIDIA Quadro DCC .*Quadro DCC.* 0 1 +NVIDIA Quadro FX 1400 .*Quadro.*FX.*1400.* 1 1 +NVIDIA Quadro FX 1500 .*Quadro.*FX.*1500.* 1 1 +NVIDIA Quadro FX 1700 .*Quadro.*FX.*1700.* 2 1 +NVIDIA Quadro FX 1800 .*Quadro.*FX.*1800.* 2 1 +NVIDIA Quadro FX 3700 .*Quadro.*FX.*3700.* 2 1 +NVIDIA Quadro FX 3800 .*Quadro.*FX.*3800.* 2 1 +NVIDIA Quadro FX 3400 .*Quadro.*FX.*3400.* 1 1 +NVIDIA Quadro FX 3450 .*Quadro.*FX.*3450.* 1 1 +NVIDIA Quadro FX 3500 .*Quadro.*FX.*3500.* 1 1 +NVIDIA Quadro FX 3700 .*Quadro.*FX.*3700.* 2 1 +NVIDIA Quadro FX 3800 .*Quadro.*FX.*3800.* 2 1 +NVIDIA Quadro FX 370 .*Quadro.*FX.*370.* 2 1 +NVIDIA Quadro FX 380 .*Quadro.*FX.*380.* 2 1 +NVIDIA Quadro FX 4000 .*Quadro.*FX.*4000.* 1 1 +NVIDIA Quadro FX 4500 .*Quadro.*FX.*4500.* 1 1 +NVIDIA Quadro FX 4600 .*Quadro.*FX.*4600.* 2 1 +NVIDIA Quadro FX 4700 .*Quadro.*FX.*4700.* 2 1 +NVIDIA Quadro FX 4800 .*Quadro.*FX.*4800.* 2 1 +NVIDIA Quadro FX 470 .*Quadro.*FX.*470.* 2 1 +NVIDIA Quadro FX 5500 .*Quadro.*FX.*5500.* 1 1 +NVIDIA Quadro FX 5600 .*Quadro.*FX.*5600.* 2 1 +NVIDIA Quadro FX 5700 .*Quadro.*FX.*5700.* 2 1 +NVIDIA Quadro FX 5800 .*Quadro.*FX.*5800.* 2 1 +NVIDIA Quadro FX 540 .*Quadro.*FX.*540.* 1 1 +NVIDIA Quadro FX 550 .*Quadro.*FX.*550.* 1 1 +NVIDIA Quadro FX 560 .*Quadro.*FX.*560.* 1 1 +NVIDIA Quadro FX 570 .*Quadro.*FX.*570.* 2 1 +NVIDIA Quadro FX 580 .*Quadro.*FX.*580.* 2 1 +NVIDIA Quadro FX .*Quadro FX.* 0 1 +NVIDIA Quadro VX 200 .*Quadro VX.*200.* 2 1 +NVIDIA Quadro 2000 .*Quadro.*2000.* 2 1 +NVIDIA Quadro 4000 .*Quadro.*4000.* 2 1 +NVIDIA Quadro 5000 .*Quadro.*5000.* 2 1 +NVIDIA Quadro 6000 .*Quadro.*6000.* 2 1 +NVIDIA Quadro 600 .*Quadro.*600.* 2 1 +NVIDIA Quadro NVS .*Quadro NVS.* 0 1 NVIDIA RIVA TNT .*RIVA TNT.* 0 0 S3 .*S3 Graphics.* 0 0 SiS SiS.* 0 0 -- cgit v1.2.3 From c1db849c418d2cef8c321199ad1421b183aff9bf Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 20 Jan 2011 15:50:03 -0600 Subject: SH-635 Fix for changing one physics parameter changing all physics parameters. --- indra/newview/llpanelobject.cpp | 79 ++++++++++++----------- indra/newview/llpanelobject.h | 8 ++- indra/newview/llselectmgr.cpp | 136 ++++++++++++++++++++++++++++----------- indra/newview/llselectmgr.h | 7 +- indra/newview/llviewerobject.cpp | 6 +- 5 files changed, 152 insertions(+), 84 deletions(-) diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 73a8fbe3aa..f1fd47f50e 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -135,23 +135,24 @@ BOOL LLPanelObject::postBuild() // PhysicsShapeType combobox mComboPhysicsShapeType = getChild("Physics Shape Type Combo Ctrl"); - childSetCommitCallback("Physics Shape Type Combo Ctrl", onCommitPhysicsParam, this); - + mComboPhysicsShapeType->setCommitCallback(boost::bind(&LLPanelObject::sendPhysicsShapeType, this, _1, mComboPhysicsShapeType)); + // PhysicsGravity mSpinPhysicsGravity = getChild("Physics Gravity"); - childSetCommitCallback("Physics Gravity", onCommitPhysicsParam, this); + mSpinPhysicsGravity->setCommitCallback(boost::bind(&LLPanelObject::sendPhysicsGravity, this, _1, mSpinPhysicsGravity)); // PhysicsFriction mSpinPhysicsFriction = getChild("Physics Friction"); - childSetCommitCallback("Physics Friction", onCommitPhysicsParam, this); - + mSpinPhysicsFriction->setCommitCallback(boost::bind(&LLPanelObject::sendPhysicsFriction, this, _1, mSpinPhysicsFriction)); + // PhysicsDensity mSpinPhysicsDensity = getChild("Physics Density"); - childSetCommitCallback("Physics Density", onCommitPhysicsParam, this); + mSpinPhysicsDensity->setCommitCallback(boost::bind(&LLPanelObject::sendPhysicsDensity, this, _1, mSpinPhysicsDensity)); // PhysicsRestitution mSpinPhysicsRestitution = getChild("Physics Restitution"); - childSetCommitCallback("Physics Restitution", onCommitPhysicsParam, this); + mSpinPhysicsRestitution->setCommitCallback(boost::bind(&LLPanelObject::sendPhysicsRestitution, this, _1, mSpinPhysicsRestitution)); + // Position mLabelPosition = getChild("label position"); @@ -1281,35 +1282,46 @@ void LLPanelObject::sendIsPhantom() } } -#include "llsdutil.h" -class CostResponder : public LLHTTPClient::Responder +void LLPanelObject::sendPhysicsShapeType(LLUICtrl* ctrl, void* userdata) { -public: - CostResponder(U32 id) { mID = id; } - virtual void result(const LLSD& content) { llinfos << ll_pretty_print_sd(content) << llendl; } + U8 type = ctrl->getValue().asInteger(); + LLSelectMgr::getInstance()->selectionSetPhysicsType(type); - U32 mID; -}; + refreshCost(); +} -void LLPanelObject::sendPhysicsParam() +void LLPanelObject::sendPhysicsGravity(LLUICtrl* ctrl, void* userdata) { - LLSD physicsType = mComboPhysicsShapeType->getValue(); - - U8 type = physicsType.asInteger(); - F32 gravity = mSpinPhysicsGravity->get(); - F32 friction = mSpinPhysicsFriction->get(); - F32 density = mSpinPhysicsDensity->get(); - F32 restitution = mSpinPhysicsRestitution->get(); - - LLSelectMgr::getInstance()->selectionUpdatePhysicsParam(type, gravity, friction, - density, restitution); + F32 val = ctrl->getValue().asReal(); + LLSelectMgr::getInstance()->selectionSetGravity(val); +} - std::string url = gAgent.getRegion()->getCapability("GetObjectCost"); - LLSD body = LLSD::emptyArray(); - - body.append(LLSelectMgr::getInstance()->getSelection()->getFirstObject()->getID()); +void LLPanelObject::sendPhysicsFriction(LLUICtrl* ctrl, void* userdata) +{ + F32 val = ctrl->getValue().asReal(); + LLSelectMgr::getInstance()->selectionSetFriction(val); +} + +void LLPanelObject::sendPhysicsRestitution(LLUICtrl* ctrl, void* userdata) +{ + F32 val = ctrl->getValue().asReal(); + LLSelectMgr::getInstance()->selectionSetRestitution(val); +} + +void LLPanelObject::sendPhysicsDensity(LLUICtrl* ctrl, void* userdata) +{ + F32 val = ctrl->getValue().asReal(); + LLSelectMgr::getInstance()->selectionSetDensity(val); +} + +void LLPanelObject::refreshCost() +{ + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); - LLHTTPClient::post( url, body, new CostResponder(body[0].asInteger()) ); + if (obj) + { + obj->getObjectCost(); + } } void LLPanelObject::sendCastShadows() @@ -2120,13 +2132,6 @@ void LLPanelObject::onCommitPhantom( LLUICtrl* ctrl, void* userdata ) self->sendIsPhantom(); } -// static -void LLPanelObject::onCommitPhysicsParam(LLUICtrl* ctrl, void* userdata ) -{ - LLPanelObject* self = (LLPanelObject*) userdata; - self->sendPhysicsParam(); -} - // static void LLPanelObject::onCommitCastShadows( LLUICtrl* ctrl, void* userdata ) { diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index b43b1cc261..54bb5df8bf 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -81,6 +81,7 @@ public: protected: void getState(); + void refreshCost(); void sendRotation(BOOL btn_down); void sendScale(BOOL btn_down); @@ -88,7 +89,12 @@ protected: void sendIsPhysical(); void sendIsTemporary(); void sendIsPhantom(); - void sendPhysicsParam(); + void sendPhysicsShapeType(LLUICtrl* ctrl, void* userdata); + void sendPhysicsGravity(LLUICtrl* ctrl, void* userdata); + void sendPhysicsFriction(LLUICtrl* ctrl, void* userdata); + void sendPhysicsRestitution(LLUICtrl* ctrl, void* userdata); + void sendPhysicsDensity(LLUICtrl* ctrl, void* userdata); + void sendCastShadows(); void sendSculpt(); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 305b629cf7..44ccbe22f7 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1889,6 +1889,103 @@ BOOL LLSelectMgr::selectionGetGlow(F32 *glow) return identical; } + +void LLSelectMgr::selectionSetPhysicsType(U8 type) +{ + struct f : public LLSelectedObjectFunctor + { + U8 mType; + f(const U8& t) : mType(t) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsShapeType(mType); + object->updateFlags(); + } + return true; + } + } sendfunc(type); + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionSetFriction(F32 friction) +{ + struct f : public LLSelectedObjectFunctor + { + F32 mFriction; + f(const F32& friction) : mFriction(friction) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsFriction(mFriction); + object->updateFlags(); + } + return true; + } + } sendfunc(friction); + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionSetGravity(F32 gravity ) +{ + struct f : public LLSelectedObjectFunctor + { + F32 mGravity; + f(const F32& gravity) : mGravity(gravity) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsGravity(mGravity); + object->updateFlags(); + } + return true; + } + } sendfunc(gravity); + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionSetDensity(F32 density ) +{ + struct f : public LLSelectedObjectFunctor + { + F32 mDensity; + f(const F32& density ) : mDensity(density) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsDensity(mDensity); + object->updateFlags(); + } + return true; + } + } sendfunc(density); + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionSetRestitution(F32 restitution) +{ + struct f : public LLSelectedObjectFunctor + { + F32 mRestitution; + f(const F32& restitution ) : mRestitution(restitution) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsRestitution(mRestitution); + object->updateFlags(); + } + return true; + } + } sendfunc(restitution); + getSelection()->applyToObjects(&sendfunc); +} + + //----------------------------------------------------------------------------- // selectionSetMaterial() //----------------------------------------------------------------------------- @@ -3936,45 +4033,6 @@ void LLSelectMgr::selectionUpdateCastShadows(BOOL cast_shadows) getSelection()->applyToObjects(&func); } -struct LLSelectMgrApplyPhysicsParam : public LLSelectedObjectFunctor -{ - LLSelectMgrApplyPhysicsParam(U8 type, F32 gravity, F32 friction, - F32 density, F32 restitution) : - mType(type), - mGravity(gravity), - mFriction(friction), - mDensity(density), - mRestitution(restitution) - {} - U8 mType; - F32 mGravity; - F32 mFriction; - F32 mDensity; - F32 mRestitution; - virtual bool apply(LLViewerObject* object) - { - if ( object->permModify() ) // preemptive permissions check - { - object->setPhysicsShapeType( mType ); - object->setPhysicsGravity(mGravity); - object->setPhysicsFriction(mFriction); - object->setPhysicsDensity(mDensity); - object->setPhysicsRestitution(mRestitution); - object->updateFlags(); - } - return true; - } -}; - - -void LLSelectMgr::selectionUpdatePhysicsParam(U8 type, F32 gravity, F32 friction, - F32 density, F32 restitution) -{ - llwarns << "physics shape type ->" << (U32)type << llendl; - LLSelectMgrApplyPhysicsParam func(type, gravity, friction, density, restitution); - getSelection()->applyToObjects(&func); -} - //---------------------------------------------------------------------- // Helpful packing functions for sendObjectMessage() //---------------------------------------------------------------------- diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 0cf582062d..bb0afd74d0 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -489,8 +489,6 @@ public: void saveSelectedObjectTextures(); void selectionUpdatePhysics(BOOL use_physics); - void selectionUpdatePhysicsParam(U8 type, F32 gravity, F32 friction, - F32 density, F32 restitution); void selectionUpdateTemporary(BOOL is_temporary); void selectionUpdatePhantom(BOOL is_ghost); void selectionUpdateCastShadows(BOOL cast_shadows); @@ -501,6 +499,11 @@ public: bool selectionGetIncludeInSearch(bool* include_in_search_out); // true if all selected objects have same BOOL selectionGetGlow(F32 *glow); + void selectionSetPhysicsType(U8 type); + void selectionSetGravity(F32 gravity); + void selectionSetFriction(F32 friction); + void selectionSetDensity(F32 density); + void selectionSetRestitution(F32 restitution); void selectionSetMaterial(U8 material); void selectionSetImage(const LLUUID& imageid); // could be item or asset id void selectionSetColor(const LLColor4 &color); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index bf550e9c70..244de7fed3 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -5306,11 +5306,6 @@ void LLViewerObject::updateFlags() gMessageSystem->addF32("Restitution", getPhysicsRestitution() ); gMessageSystem->addF32("GravityMultiplier", getPhysicsGravity() ); gMessageSystem->sendReliable( regionp->getHost() ); - - if (getPhysicsShapeType() != 0) - { - llwarns << "sent non default physics rep " << (S32) getPhysicsShapeType() << llendl; - } } BOOL LLViewerObject::setFlags(U32 flags, BOOL state) @@ -5346,6 +5341,7 @@ void LLViewerObject::setPhysicsShapeType(U8 type) { mPhysicsShapeUnknown = false; mPhysicsShapeType = type; + mCostStale = true; } void LLViewerObject::setPhysicsGravity(F32 gravity) -- cgit v1.2.3 From ee66cb86274c53122d8bcaebb5cd822a88f92376 Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Thu, 20 Jan 2011 15:15:28 -0800 Subject: remove duplicates --- indra/newview/gpu_table.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt index 7023e07348..66b3b97f00 100644 --- a/indra/newview/gpu_table.txt +++ b/indra/newview/gpu_table.txt @@ -309,8 +309,6 @@ NVIDIA Quadro FX 1400 .*Quadro.*FX.*1400.* 1 1 NVIDIA Quadro FX 1500 .*Quadro.*FX.*1500.* 1 1 NVIDIA Quadro FX 1700 .*Quadro.*FX.*1700.* 2 1 NVIDIA Quadro FX 1800 .*Quadro.*FX.*1800.* 2 1 -NVIDIA Quadro FX 3700 .*Quadro.*FX.*3700.* 2 1 -NVIDIA Quadro FX 3800 .*Quadro.*FX.*3800.* 2 1 NVIDIA Quadro FX 3400 .*Quadro.*FX.*3400.* 1 1 NVIDIA Quadro FX 3450 .*Quadro.*FX.*3450.* 1 1 NVIDIA Quadro FX 3500 .*Quadro.*FX.*3500.* 1 1 -- cgit v1.2.3 From b94ddeaa46c1f754c6b0b900fd3094aabe66e084 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Fri, 21 Jan 2011 13:29:17 -0500 Subject: SH-823 Admin menu does not appear when in god mode Fixed this issue. Also, viewer-development has a duplicated "Region Debug Console" entry. I assume this duplication is a mistake / bad merge so I took out the duplicate. --- indra/newview/skins/default/xui/en/menu_viewer.xml | 34 +--------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 6211561a5d..cb2cbbe033 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2571,18 +2571,6 @@ function="ToggleControl" parameter="PingInterpolate" /> - - - - @@ -2781,26 +2769,6 @@ function="Floater.Toggle" parameter="region_debug_console" /> - - - - - - - - - - - Date: Fri, 21 Jan 2011 18:29:25 +0000 Subject: adjust SSAO towards a stronger, darker effect curve (transplanted from 4b7066a9a309fa82727c0b403cc6f20720077dc0) --- indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl index 6859f72a9c..8dc9e98e05 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl @@ -81,6 +81,7 @@ void main() } col /= defined_weight.xyxx; + col.y *= col.y; gl_FragColor = col; } -- cgit v1.2.3 From dedec6404ae3333e0b645b6e4c74c552b7e52937 Mon Sep 17 00:00:00 2001 From: Tofu Buzzard Date: Fri, 21 Jan 2011 18:33:27 +0000 Subject: possibly controversial - turn autoglow on, tweaked to only be red-responsive. (transplanted from 93837b880d479534b651ff5bd25e4779fa6ec9ea) --- indra/newview/app_settings/settings.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 304ba15d07..8af84ba7b4 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8283,9 +8283,9 @@ Vector3 Value - 0.299 - 0.587 - 0.114 + 1 + 0 + 0 RenderGlowMaxExtractAlpha @@ -8297,7 +8297,7 @@ Type F32 Value - 0.065 + 0.25 RenderGlowMinLuminance @@ -8308,7 +8308,7 @@ Type F32 Value - 2.5 + 0.74 RenderGlowResolutionPow -- cgit v1.2.3 From 3940b79b1a191f423002936dfcd7479be5383ea5 Mon Sep 17 00:00:00 2001 From: Tofu Buzzard Date: Sun, 30 Jan 2011 10:56:54 -0800 Subject: tweak autoglow to be less invasive --- indra/newview/app_settings/settings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 8af84ba7b4..f976a2170c 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8308,7 +8308,7 @@ Type F32 Value - 0.74 + 0.81 RenderGlowResolutionPow -- cgit v1.2.3 From cae8a075c40b734a37e7d4cce4faf5dcdb6ece0c Mon Sep 17 00:00:00 2001 From: Tofu Buzzard Date: Fri, 21 Jan 2011 18:37:43 +0000 Subject: tweak SSAO to be weaker now that it's been de-linearized, and totally nerf the shadow blur dist factor since it helps more than hinders now that the shadow-smoother is more relaxed about edges at great distances. (transplanted from e6227fac98097154c46454228825a5a1c0e8a63e) --- indra/newview/app_settings/settings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index f976a2170c..e679a04320 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7306,7 +7306,7 @@ Vector3 Value - 0.40 + 0.70 1.00 0.00 @@ -8063,7 +8063,7 @@ Type F32 Value - 0.1 + 0 RenderGIAmbiance -- cgit v1.2.3 From 3c053b3fdba8bcd86179578a5d492847c0b17458 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 21 Jan 2011 16:23:44 -0600 Subject: SH-534 Fix for various bump map glitches. --- indra/llmath/lloctree.h | 14 ++++++-------- indra/newview/llappviewer.cpp | 1 + indra/newview/llviewercontrol.cpp | 1 + 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index 276f7b0f06..fdfc24f8b7 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -294,10 +294,8 @@ public: //is it here? if (isInside(data->getPositionGroup())) { - if (getElementCount() < LL_OCTREE_MAX_CAPACITY && - (contains(data->getBinRadius()) || - (data->getBinRadius() > getSize()[0] && - parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY))) + if ((getElementCount() < LL_OCTREE_MAX_CAPACITY && contains(data->getBinRadius()) || + (data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY))) { //it belongs here #if LL_OCTREE_PARANOIA_CHECK //if this is a redundant insertion, error out (should never happen) @@ -359,7 +357,7 @@ public: //make sure no existing node matches this position for (U32 i = 0; i < getChildCount(); i++) { - if (mChild[i]->getCenter().equal3(center)) + if (mChild[i]->getCenter().equals3(center)) { OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl; return false; @@ -488,18 +486,18 @@ public: { #if LL_OCTREE_PARANOIA_CHECK - if (child->getSize().equal3(getSize())) + if (child->getSize().equals3(getSize())) { OCT_ERRS << "Child size is same as parent size!" << llendl; } for (U32 i = 0; i < getChildCount(); i++) { - if(!mChild[i]->getSize().equal3(child->getSize())) + if(!mChild[i]->getSize().equals3(child->getSize())) { OCT_ERRS <<"Invalid octree child size." << llendl; } - if (mChild[i]->getCenter().equal3(child->getCenter())) + if (mChild[i]->getCenter().equals3(child->getCenter())) { OCT_ERRS <<"Duplicate octree child position." << llendl; } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 7e8c68632d..e23b3732a8 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -482,6 +482,7 @@ static void settings_to_globals() static void settings_modify() { LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderDeferred"); + LLPipeline::sRenderDeferred = gSavedSettings.getBOOL("RenderDeferred"); LLVOAvatar::sUseImpostors = gSavedSettings.getBOOL("RenderUseImpostors"); LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor"); LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4] diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 444d5cb902..9bf0ae7c3e 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -380,6 +380,7 @@ static bool handleRenderDeferredChanged(const LLSD& newvalue) gPipeline.updateRenderDeferred(); gPipeline.releaseGLBuffers(); gPipeline.createGLBuffers(); + gPipeline.resetVertexBuffers(); if (LLPipeline::sRenderDeferred && LLRenderTarget::sUseFBO) { LLViewerShaderMgr::instance()->setShaders(); -- cgit v1.2.3 From d7db673dc7c8cc638aab66be07f08892e548f783 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 21 Jan 2011 18:25:57 -0600 Subject: Fix for leaking occlusion queries -- try not to hold onto so many stale occlusion query references. --- indra/newview/llspatialpartition.cpp | 59 +++++++++++++++++++++++++++++++++--- indra/newview/llspatialpartition.h | 1 + indra/newview/llviewerwindow.cpp | 6 ++++ 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index b9063b3c81..c53b7b3eb6 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -64,6 +64,12 @@ const F32 SG_OCCLUSION_FUDGE = 0.25f; static U32 sZombieGroups = 0; U32 LLSpatialGroup::sNodeCount = 0; + +#define LL_TRACK_PENDING_OCCLUSION_QUERIES 0 + +std::set LLSpatialGroup::sPendingQueries; + + BOOL LLSpatialGroup::sNoDelete = FALSE; static F32 sLastMaxTexPriority = 1.f; @@ -81,6 +87,9 @@ protected: virtual void releaseName(GLuint name) { +#if LL_TRACK_PENDING_OCCLUSION_QUERIES + LLSpatialGroup::sPendingQueries.erase(name); +#endif glDeleteQueriesARB(1, &name); } }; @@ -361,9 +370,15 @@ LLSpatialGroup::~LLSpatialGroup() sNodeCount--; - if (gGLManager.mHasOcclusionQuery && mOcclusionQuery[LLViewerCamera::sCurCameraID]) + if (gGLManager.mHasOcclusionQuery) { - sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); + for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i) + { + if (mOcclusionQuery[i]) + { + sQueryPool.release(mOcclusionQuery[i]); + } + } } mOcclusionVerts = NULL; @@ -1096,12 +1111,23 @@ void LLSpatialGroup::setOcclusionState(U32 state, S32 mode) for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) { mOcclusionState[i] |= state; + + if ((state & DISCARD_QUERY) && mOcclusionQuery[i]) + { + sQueryPool.release(mOcclusionQuery[i]); + mOcclusionQuery[i] = 0; + } } } } else { mOcclusionState[LLViewerCamera::sCurCameraID] |= state; + if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) + { + sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); + mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; + } } } @@ -1540,15 +1566,31 @@ void LLSpatialGroup::checkOcclusion() { //otherwise, if a query is pending, read it back GLuint available = 0; - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); + if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) + { + glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); + } + else + { + available = 1; + } + if (available) { //result is available, read it back, otherwise wait until next frame GLuint res = 1; if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) { glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res); +#if LL_TRACK_PENDING_OCCLUSION_QUERIES + sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]); +#endif } - + else if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) + { //delete the query to avoid holding onto hundreds of pending queries + sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); + mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; + } + if (isOcclusionState(DISCARD_QUERY)) { res = 2; @@ -1621,6 +1663,13 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) } #if !LL_DARWIN U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB; +#else + U32 mode = GL_SAMPLES_PASSED_ARB; +#endif + +#if LL_TRACK_PENDING_OCCLUSION_QUERIES + sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]); +#endif glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); @@ -1637,7 +1686,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) } glEndQueryARB(mode); -#endif + if (use_depth_clamp) { glDisable(GL_DEPTH_CLAMP); diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 85fd66b297..664d957e49 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -187,6 +187,7 @@ public: return *this; } + static std::set sPendingQueries; //pending occlusion queries static U32 sNodeCount; static BOOL sNoDelete; //deletion of spatial groups and draw info not allowed if TRUE diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index dcfac012f6..db48b769e4 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -497,6 +497,12 @@ public: ypos += y_inc; + if (!LLSpatialGroup::sPendingQueries.empty()) + { + addText(xpos,ypos, llformat("%d Queries pending", LLSpatialGroup::sPendingQueries.size())); + ypos += y_inc; + } + addText(xpos,ypos, llformat("%d Avatars visible", LLVOAvatar::sNumVisibleAvatars)); -- cgit v1.2.3 From dc918c66d1c843effdd71d664095109d3f7be066 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 21 Jan 2011 18:26:22 -0600 Subject: SH-704 Potential fix for crash in LLModelPreview::calcResourceCost. --- indra/newview/llfloatermodelpreview.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index cc2a8c8aac..dde470693c 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2205,9 +2205,12 @@ U32 LLModelPreview::calcResourceCost() rebuildUploadData(); - if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) + if (mFMP && mModelLoader) { - mFMP->childEnable("ok_btn"); + if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) + { + mFMP->childEnable("ok_btn"); + } } U32 cost = 0; @@ -2215,7 +2218,7 @@ U32 LLModelPreview::calcResourceCost() U32 num_points = 0; U32 num_hulls = 0; - F32 debug_scale = mFMP->childGetValue("import_scale").asReal(); + F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f; F32 streaming_cost = 0.f; F32 physics_cost = 0.f; @@ -2270,9 +2273,7 @@ U32 LLModelPreview::calcResourceCost() } } - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); - F32 scale = mFMP->childGetValue("import_scale").asReal()*2.f; + F32 scale = mFMP ? mFMP->childGetValue("import_scale").asReal()*2.f : 2.f; mDetailsSignal(mPreviewScale[0]*scale, mPreviewScale[1]*scale, mPreviewScale[2]*scale, streaming_cost, physics_cost); -- cgit v1.2.3 From 9ca57fdf9832ce6c114e1254d45f828b1312df25 Mon Sep 17 00:00:00 2001 From: Tofu Buzzard Date: Sat, 22 Jan 2011 00:55:14 +0000 Subject: HACK to make deferred imposters more-or-less work. (transplanted from e41d116728dd1e453273047ba7fde9455a1811d4) --- indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl index 7125d845d9..7829e9b72f 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl @@ -14,7 +14,7 @@ uniform sampler2D specularMap; void main() { vec4 col = texture2D(diffuseMap, gl_TexCoord[0].xy); - gl_FragData[0] = vec4(col.rgb, col.a <= 0.5 ? 0.0 : 0.005); + gl_FragData[0] = vec4(col.rgb, col != vec4(0,0,0,0)); gl_FragData[1] = texture2D(specularMap, gl_TexCoord[0].xy); - gl_FragData[2] = vec4(texture2D(normalMap, gl_TexCoord[0].xy).xyz, 0.0); + gl_FragData[2] = texture2D(normalMap, gl_TexCoord[0].xy); } -- cgit v1.2.3 From ef0b1b1564c469b526d0a62d8e4412a26571fb4f Mon Sep 17 00:00:00 2001 From: Tofu Buzzard Date: Sat, 22 Jan 2011 00:56:18 +0000 Subject: remove some unused depth samplings. (transplanted from a38a7ea07c52aafbd4305f96d715201a35d86726) --- indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl | 3 --- indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl | 3 --- 2 files changed, 6 deletions(-) diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl index b08c5dd295..28a38d4390 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl @@ -10,7 +10,6 @@ #extension GL_ARB_texture_rectangle : enable uniform sampler2D diffuseMap; -uniform sampler2D noiseMap; uniform sampler2DRect depthMap; uniform mat4 shadow_matrix[6]; @@ -45,8 +44,6 @@ void main() vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; frag *= screen_res; - vec3 samp_pos = getPosition(frag).xyz; - vec4 pos = vec4(vary_position, 1.0); vec4 col = vec4(vary_ambient + vary_directional.rgb, gl_Color.a); diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index 32aab152a3..1dd29bfc70 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -14,7 +14,6 @@ uniform sampler2DRectShadow shadowMap0; uniform sampler2DRectShadow shadowMap1; uniform sampler2DRectShadow shadowMap2; uniform sampler2DRectShadow shadowMap3; -uniform sampler2D noiseMap; uniform sampler2DRect depthMap; uniform mat4 shadow_matrix[6]; @@ -70,8 +69,6 @@ void main() vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; frag *= screen_res; - vec3 samp_pos = getPosition(frag).xyz; - float shadow = 1.0; vec4 pos = vec4(vary_position, 1.0); -- cgit v1.2.3 From 92018853e2c9d6151e342c0b483a02fd0599a41f Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Mon, 24 Jan 2011 16:58:10 -0800 Subject: SH-753 GHOST Mesh from a Mesh Sandbox 11 and 12 from 6 Raycast debug view was not translating by the agent origin --- indra/newview/llspatialpartition.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index b9063b3c81..5f23908eda 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -3580,6 +3580,8 @@ void renderRaycast(LLDrawable* drawablep) if (volume) { + LLVector3 trans = drawablep->getRegion()->getOriginAgent(); + for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) { const LLVolumeFace& face = volume->getVolumeFace(i); @@ -3589,6 +3591,7 @@ void renderRaycast(LLDrawable* drawablep) } gGL.pushMatrix(); + glTranslatef(trans.mV[0], trans.mV[1], trans.mV[2]); glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix); LLVector3 start, end; @@ -3613,7 +3616,7 @@ void renderRaycast(LLDrawable* drawablep) LLRenderOctreeRaycast render(starta, dir, &t); gGL.flush(); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); { //render face positions @@ -3672,7 +3675,7 @@ void renderRaycast(LLDrawable* drawablep) LLGLDepthTest depth(GL_FALSE, GL_TRUE); gGL.color4f(0,0.5f,0.5f,1); - drawBoxOutline(pos, size); + drawBoxOutline(pos, size); } } } -- cgit v1.2.3 From 96c6200f7271cadec83f8d55e30e3b4713c3f939 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 25 Jan 2011 15:29:45 -0600 Subject: SH-390 Fix for bad occlusion culling of some mesh objects. --- indra/newview/llvovolume.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 5277e073a3..e3b5e613d9 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1075,7 +1075,6 @@ void LLVOVolume::notifyMeshLoaded() { mSculptChanged = TRUE; gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); - dirtySpatialGroup(TRUE); } // sculpt replaces generate() for sculpted surfaces @@ -1608,6 +1607,17 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) regenFaces(); } genBBoxes(FALSE); + + if (mSculptChanged) + { //changes in sculpt maps can thrash an object bounding box without + //triggering a spatial group bounding box update -- force spatial group + //to update bounding boxes + LLSpatialGroup* group = mDrawable->getSpatialGroup(); + if (group) + { + group->unbound(); + } + } } } } @@ -1632,7 +1642,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) mLODChanged = FALSE; mSculptChanged = FALSE; mFaceMappingChanged = FALSE; - + return LLViewerObject::updateGeometry(drawable); } -- cgit v1.2.3 From f0be01bda92553a3e9e671c26c2905b47cacb0b5 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 26 Jan 2011 15:26:56 -0600 Subject: SH-641 Fix for some objects not properly switching LoD under some situations. Fix for redundant calls to stateSort(LLDrawable*...) Put back "Build Queue" info display. --- indra/newview/llspatialpartition.cpp | 15 +-- indra/newview/llviewermenu.cpp | 4 + indra/newview/llvoavatarself.cpp | 1 - indra/newview/llvovolume.cpp | 2 +- indra/newview/pipeline.cpp | 138 +++++++++++++-------- indra/newview/pipeline.h | 2 + indra/newview/skins/default/xui/en/menu_viewer.xml | 10 ++ 7 files changed, 112 insertions(+), 60 deletions(-) diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index be8f81fc62..af6064ad20 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -522,7 +522,7 @@ BOOL LLSpatialGroup::isRecentlyVisible() const BOOL LLSpatialGroup::isVisible() const { - return mVisible[LLViewerCamera::sCurCameraID] == LLDrawable::getCurrentFrame() ? TRUE : FALSE; + return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE; } void LLSpatialGroup::setVisible() @@ -1345,7 +1345,8 @@ F32 LLSpatialGroup::getUpdateUrgency() const } else { - return (gFrameTimeSeconds - mLastUpdateTime+4.f)/mDistance; + F32 time = gFrameTimeSeconds-mLastUpdateTime+4.f; + return time + (mObjectBounds[1].dot3(mObjectBounds[1]).getF32()+1.f)/mDistance; } } @@ -1356,8 +1357,8 @@ BOOL LLSpatialGroup::needsUpdate() BOOL LLSpatialGroup::changeLOD() { - if (isState(ALPHA_DIRTY)) - { ///an alpha sort is going to happen, update distance and LOD + if (isState(ALPHA_DIRTY | OBJECT_DIRTY)) + { ///a rebuild is going to happen, update distance and LoD return TRUE; } @@ -1370,7 +1371,7 @@ BOOL LLSpatialGroup::changeLOD() return TRUE; } - if (mDistance > mRadius) + if (mDistance > mRadius*2.f) { return FALSE; } @@ -4100,7 +4101,7 @@ void LLSpatialPartition::renderDebug() LLPipeline::RENDER_DEBUG_RAYCAST | LLPipeline::RENDER_DEBUG_AVATAR_VOLUME | LLPipeline::RENDER_DEBUG_AGENT_TARGET | - LLPipeline::RENDER_DEBUG_BUILD_QUEUE | + //LLPipeline::RENDER_DEBUG_BUILD_QUEUE | LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) { return; @@ -4140,7 +4141,7 @@ void LLSpatialGroup::drawObjectBox(LLColor4 col) { gGL.color4fv(col.mV); LLVector4a size; - size = mObjectBounds[0]; + size = mObjectBounds[1]; size.mul(1.01f); size.add(LLVector4a(0.001f)); drawBox(mObjectBounds[0], size); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index a152ab4aa0..e9e0268587 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -937,6 +937,10 @@ U32 info_display_from_string(std::string info_display) { return LLPipeline::RENDER_DEBUG_FACE_AREA; } + else if ("build queue" == info_display) + { + return LLPipeline::RENDER_DEBUG_BUILD_QUEUE; + } else if ("lights" == info_display) { return LLPipeline::RENDER_DEBUG_LIGHTS; diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 3c66c4860e..aca233d58d 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -625,7 +625,6 @@ BOOL LLVOAvatarSelf::updateCharacter(LLAgent &agent) mScreenp->updateWorldMatrixChildren(); resetHUDAttachments(); } - LLVOAvatar::rebuildRiggedAttachments(); return LLVOAvatar::updateCharacter(agent); } diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index e3b5e613d9..3dc82f5368 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1227,7 +1227,7 @@ BOOL LLVOVolume::updateLOD() mLODChanged = TRUE; } - lod_changed |= LLViewerObject::updateLOD(); + lod_changed = lod_changed || LLViewerObject::updateLOD(); return lod_changed; } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 38711472a1..510d22136b 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -330,6 +330,8 @@ LLPipeline::LLPipeline() : mRenderDebugFeatureMask(0), mRenderDebugMask(0), mOldRenderDebugMask(0), + mGroupQ1Locked(false), + mGroupQ2Locked(false), mLastRebuildPool(NULL), mAlphaPool(NULL), mSkyPool(NULL), @@ -2118,6 +2120,7 @@ void LLPipeline::rebuildPriorityGroups() gMeshRepo.notifyLoadedMeshes(); + mGroupQ1Locked = true; // Iterate through all drawables on the priority build queue, for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ1.begin(); iter != mGroupQ1.end(); ++iter) @@ -2128,11 +2131,18 @@ void LLPipeline::rebuildPriorityGroups() } mGroupQ1.clear(); + mGroupQ1Locked = false; } void LLPipeline::rebuildGroups() { + if (mGroupQ2.empty()) + { + return; + } + + mGroupQ2Locked = true; // Iterate through some drawables on the non-priority build queue S32 size = (S32) mGroupQ2.size(); S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size); @@ -2142,33 +2152,30 @@ void LLPipeline::rebuildGroups() std::sort(mGroupQ2.begin(), mGroupQ2.end(), LLSpatialGroup::CompareUpdateUrgency()); LLSpatialGroup::sg_vector_t::iterator iter; + LLSpatialGroup::sg_vector_t::iterator last_iter = mGroupQ2.begin(); + for (iter = mGroupQ2.begin(); - iter != mGroupQ2.end(); ++iter) + iter != mGroupQ2.end() && count <= min_count; ++iter) { LLSpatialGroup* group = *iter; + last_iter = iter; - if (group->isDead()) + if (!group->isDead()) { - continue; + group->rebuildGeom(); + + if (group->mSpatialPartition->mRenderByGroup) + { + count++; + } } - group->rebuildGeom(); - - if (group->mSpatialPartition->mRenderByGroup) - { - count++; - } - group->clearState(LLSpatialGroup::IN_BUILD_Q2); - - if (count > min_count) - { - ++iter; - break; - } } - mGroupQ2.erase(mGroupQ2.begin(), iter); + mGroupQ2.erase(mGroupQ2.begin(), ++last_iter); + + mGroupQ2Locked = false; updateMovedList(mMovedBridge); } @@ -2463,6 +2470,8 @@ void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority) { if (!group->isState(LLSpatialGroup::IN_BUILD_Q1)) { + llassert_always(!mGroupQ1Locked); + mGroupQ1.push_back(group); group->setState(LLSpatialGroup::IN_BUILD_Q1); @@ -2479,11 +2488,7 @@ void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority) } else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1)) { - //llerrs << "Non-priority updates not yet supported!" << llendl; - if (std::find(mGroupQ2.begin(), mGroupQ2.end(), group) != mGroupQ2.end()) - { - llerrs << "WTF?" << llendl; - } + llassert_always(!mGroupQ2Locked); mGroupQ2.push_back(group); group->setState(LLSpatialGroup::IN_BUILD_Q2); @@ -2563,6 +2568,42 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) } } } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + { + LLSpatialGroup* last_group = NULL; + for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) + { + LLCullResult::bridge_list_t::iterator cur_iter = i; + LLSpatialBridge* bridge = *cur_iter; + LLSpatialGroup* group = bridge->getSpatialGroup(); + + if (last_group == NULL) + { + last_group = group; + } + + if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { + stateSort(bridge, camera); + } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && + last_group != group && last_group->changeLOD()) + { + last_group->mLastUpdateDistance = last_group->mDistance; + } + + last_group = group; + } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && + last_group && last_group->changeLOD()) + { + last_group->mLastUpdateDistance = last_group->mDistance; + } + } + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) { LLSpatialGroup* group = *iter; @@ -2578,19 +2619,6 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) } } - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) - { - for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) - { - LLCullResult::bridge_list_t::iterator cur_iter = i; - LLSpatialBridge* bridge = *cur_iter; - LLSpatialGroup* group = bridge->getSpatialGroup(); - if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - stateSort(bridge, camera); - } - } - } { LLFastTimer ftm(FTM_STATESORT_DRAWABLE); for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); @@ -2621,6 +2649,11 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) LLDrawable* drawablep = *i; stateSort(drawablep, camera); } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + { //avoid redundant stateSort calls + group->mLastUpdateDistance = group->mDistance; + } } } @@ -2687,21 +2720,17 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) { - LLSpatialGroup* group = drawablep->getSpatialGroup(); - if (!group || group->changeLOD()) + if (drawablep->isVisible()) { - if (drawablep->isVisible()) + if (!drawablep->isActive()) { - if (!drawablep->isActive()) - { - bool force_update = false; - drawablep->updateDistance(camera, force_update); - } - else if (drawablep->isAvatar()) - { - bool force_update = false; - drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility() - } + bool force_update = false; + drawablep->updateDistance(camera, force_update); + } + else if (drawablep->isAvatar()) + { + bool force_update = false; + drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility() } } } @@ -4191,13 +4220,19 @@ void LLPipeline::renderDebug() if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_BUILD_QUEUE) { U32 count = 0; - U32 size = mBuildQ2.size(); + U32 size = mGroupQ2.size(); LLColor4 col; + LLVertexBuffer::unbind(); LLGLEnable blend(GL_BLEND); + gGL.setSceneBlendType(LLRender::BT_ALPHA); LLGLDepthTest depth(GL_TRUE, GL_FALSE); gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); + gGL.pushMatrix(); + glLoadMatrixd(gGLModelView); + gGLLastMatrix = NULL; + for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ2.begin(); iter != mGroupQ2.end(); ++iter) { LLSpatialGroup* group = *iter; @@ -4219,7 +4254,7 @@ void LLPipeline::renderDebug() glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); } - F32 alpha = (F32) (size-count)/size; + F32 alpha = llclamp((F32) (size-count)/size, 0.f, 1.f); LLVector2 c(1.f-alpha, alpha); @@ -4227,7 +4262,7 @@ void LLPipeline::renderDebug() ++count; - col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.1f); + col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.5f); group->drawObjectBox(col); if (bridge) @@ -4237,6 +4272,7 @@ void LLPipeline::renderDebug() } } + gGL.popMatrix(); gGL.flush(); gPipeline.renderPhysicsDisplay(); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 7ae83e9816..0eb020605e 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -632,6 +632,8 @@ protected: LLDrawable::drawable_list_t mBuildQ2; // non-priority LLSpatialGroup::sg_vector_t mGroupQ1; //priority LLSpatialGroup::sg_vector_t mGroupQ2; // non-priority + bool mGroupQ2Locked; + bool mGroupQ1Locked; LLViewerObject::vobj_list_t mCreateQ; diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index cb2cbbe033..dac238b84a 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2257,6 +2257,16 @@ function="Advanced.ToggleInfoDisplay" parameter="face area" /> + + + + -- cgit v1.2.3 From ae292e00bbd5612acbd092c1d045f491965e5cfa Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Wed, 26 Jan 2011 17:01:56 -0800 Subject: SH-842 Hide "Model" option in upload menu --- indra/newview/llviewermenufile.cpp | 10 ++++++++++ indra/newview/skins/default/xui/en/menu_inventory_add.xml | 2 +- indra/newview/skins/default/xui/en/menu_viewer.xml | 4 ++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 4ba1d007fe..d0bb93d1b6 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -53,6 +53,7 @@ #include "llvfs.h" #include "llviewerinventory.h" #include "llviewermenu.h" // gMenuHolder +#include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "llviewerstats.h" #include "llviewerwindow.h" @@ -102,6 +103,14 @@ class LLMeshEnabled : public view_listener_t } }; +class LLMeshUploadVisible : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + return LLViewerParcelMgr::getInstance()->allowAgentBuild() && !gAgent.getRegion()->getCapability("ObjectAdd").empty(); + } +}; + LLMutex* LLFilePickerThread::sMutex = NULL; std::queue LLFilePickerThread::sDeadQ; @@ -1390,6 +1399,7 @@ void init_menu_file() view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload"); view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel"); view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled"); + view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel"); // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled. } diff --git a/indra/newview/skins/default/xui/en/menu_inventory_add.xml b/indra/newview/skins/default/xui/en/menu_inventory_add.xml index e0e6567872..62db15d456 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory_add.xml @@ -52,7 +52,7 @@ + function="File.VisibleUploadModel"/> + function="File.VisibleUploadModel"/> + function="File.VisibleUploadModel"/> Date: Wed, 26 Jan 2011 17:02:11 -0800 Subject: SH-841 Hide physics parameters in build tools when connected --- indra/newview/llpanelobject.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index f1fd47f50e..3e2d903d58 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1923,7 +1923,8 @@ void LLPanelObject::refresh() mRootObject = NULL; } - bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled"); + bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && + !gAgent.getRegion()->getCapability("GetMesh").empty(); getChildView("label physicsshapetype")->setVisible(enable_mesh); getChildView("Physics Shape Type Combo Ctrl")->setVisible(enable_mesh); -- cgit v1.2.3 From 1b97777f1ac5505be698837d8c94a4f5ff3af786 Mon Sep 17 00:00:00 2001 From: prep linden Date: Thu, 27 Jan 2011 16:12:13 -0500 Subject: Rebuild attached rigs during attachObject --- indra/newview/llvoavatar.cpp | 2 +- indra/newview/llvoavatarself.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index feb6db4700..55c5c85c21 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -8163,7 +8163,7 @@ BOOL LLVOAvatar::updateLOD() mNeedsSkin = TRUE; mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY); } - + rebuildRiggedAttachments(); updateVisibility(); return res; diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index aca233d58d..1ba4f9ce2d 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -625,6 +625,7 @@ BOOL LLVOAvatarSelf::updateCharacter(LLAgent &agent) mScreenp->updateWorldMatrixChildren(); resetHUDAttachments(); } + return LLVOAvatar::updateCharacter(agent); } @@ -1138,6 +1139,7 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view LLAppearanceMgr::instance().registerAttachment(attachment_id); // Clear any pending requests once the attachment arrives. removeAttachmentRequest(attachment_id); + updateLOD(); } return attachment; -- cgit v1.2.3 From 2e8640c3b084d00b3fa5de93b75ccaf25f2126a6 Mon Sep 17 00:00:00 2001 From: prep linden Date: Thu, 27 Jan 2011 17:13:08 -0500 Subject: Optimization so that updateRiggedAttachments is not called every frame - still a WIP. --- indra/newview/llvoavatar.cpp | 6 +++++- indra/newview/llvoavatar.h | 1 + indra/newview/llvoavatarself.cpp | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 55c5c85c21..4a6d303cdd 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -8163,12 +8163,16 @@ BOOL LLVOAvatar::updateLOD() mNeedsSkin = TRUE; mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY); } - rebuildRiggedAttachments(); updateVisibility(); return res; } +void LLVOAvatar::updateLODRiggedAttachments( void ) +{ + updateLOD(); + rebuildRiggedAttachments(); +} U32 LLVOAvatar::getPartitionType() const { // Avatars merely exist as drawables in the bridge partition diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 7ef35178ca..99d0ed76e5 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -122,6 +122,7 @@ public: virtual BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); virtual BOOL updateLOD(); BOOL updateJointLODs(); + void updateLODRiggedAttachments( void ); virtual BOOL isActive() const; // Whether this object needs to do an idleUpdate. virtual void updateTextures(); virtual S32 setTETexture(const U8 te, const LLUUID& uuid); // If setting a baked texture, need to request it from a non-local sim. diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 1ba4f9ce2d..d27d7be21b 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -1139,7 +1139,7 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view LLAppearanceMgr::instance().registerAttachment(attachment_id); // Clear any pending requests once the attachment arrives. removeAttachmentRequest(attachment_id); - updateLOD(); + updateLODRiggedAttacmhments(); } return attachment; -- cgit v1.2.3 From 536b51c2bb8d3e94f1e979e0ab9a18918b01f4df Mon Sep 17 00:00:00 2001 From: prep linden Date: Thu, 27 Jan 2011 17:15:31 -0500 Subject: Renamed function --- indra/newview/llvoavatar.cpp | 2 +- indra/newview/llvoavatarself.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 4a6d303cdd..70e4a17141 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -8168,7 +8168,7 @@ BOOL LLVOAvatar::updateLOD() return res; } -void LLVOAvatar::updateLODRiggedAttachments( void ) +void LLVOAvatar::updateLODRiggedAttacmhments( void ) { updateLOD(); rebuildRiggedAttachments(); diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index d27d7be21b..75966a0f96 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -1139,7 +1139,7 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view LLAppearanceMgr::instance().registerAttachment(attachment_id); // Clear any pending requests once the attachment arrives. removeAttachmentRequest(attachment_id); - updateLODRiggedAttacmhments(); + updateLODRiggedAttachments(); } return attachment; -- cgit v1.2.3 From 9c58022a2e96cf97d42bf284f2cc97ad8e8d9882 Mon Sep 17 00:00:00 2001 From: prep linden Date: Thu, 27 Jan 2011 17:17:17 -0500 Subject: Renamed function --- indra/newview/llvoavatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 70e4a17141..4a6d303cdd 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -8168,7 +8168,7 @@ BOOL LLVOAvatar::updateLOD() return res; } -void LLVOAvatar::updateLODRiggedAttacmhments( void ) +void LLVOAvatar::updateLODRiggedAttachments( void ) { updateLOD(); rebuildRiggedAttachments(); -- cgit v1.2.3 From ba8fcdcd19c59e7b34bad87948a120f4ad67c4b8 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Fri, 28 Jan 2011 12:17:00 -0800 Subject: SH-887 Upload model options available when MeshEnabled set to False --- indra/newview/llviewermenufile.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index d0bb93d1b6..9ecb11d253 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -107,7 +107,9 @@ class LLMeshUploadVisible : public view_listener_t { bool handleEvent(const LLSD& userdata) { - return LLViewerParcelMgr::getInstance()->allowAgentBuild() && !gAgent.getRegion()->getCapability("ObjectAdd").empty(); + return gSavedSettings.getBOOL("MeshEnabled") && + LLViewerParcelMgr::getInstance()->allowAgentBuild() && + !gAgent.getRegion()->getCapability("ObjectAdd").empty(); } }; -- cgit v1.2.3 From ad54a46ba2bc3886f9663bcaa4a6757fac733af7 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Fri, 28 Jan 2011 12:22:51 -0800 Subject: SH-841 Hide physics parameters in build tools when connected to a region that doesn't support additional physics parameters. --- indra/newview/llfloatertools.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 49e24f8e3d..c9b99d83ff 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -32,6 +32,7 @@ #include "llcoord.h" //#include "llgl.h" +#include "llagent.h" #include "llagentcamera.h" #include "llbutton.h" #include "llcheckboxctrl.h" @@ -463,7 +464,8 @@ void LLFloaterTools::refresh() childSetEnabled("linked_set_cost", have_selection); childSetEnabled("object_cost", have_selection); - bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled"); + bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && + !gAgent.getRegion()->getCapability("GetMesh").empty(); getChildView("linked_set_count")->setVisible(enable_mesh); getChildView("linked_set_cost")->setVisible(enable_mesh); -- cgit v1.2.3 From c285dddcca63a901212e61335fba4429062a6c17 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 28 Jan 2011 17:42:02 -0500 Subject: SH-845 FIX - display a message before bailing out if CPU lacks SSE2 support --- indra/newview/llappviewer.cpp | 12 ++++++++++++ indra/newview/skins/default/xui/en/notifications.xml | 6 ++++++ 2 files changed, 18 insertions(+) mode change 100644 => 100755 indra/newview/llappviewer.cpp mode change 100644 => 100755 indra/newview/skins/default/xui/en/notifications.xml diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp old mode 100644 new mode 100755 index 2d4838814e..e74a7a84c3 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -897,6 +897,18 @@ bool LLAppViewer::init() return 0; } + // Without SSE2 support we will crash almost immediately, warn here. + if (!gSysCPU.hasSSE2()) + { + // can't use an alert here since we're exiting and + // all hell breaks lose. + OSMessageBox( + LLNotifications::instance().getGlobalString("UnsupportedCPUSSE2"), + LLStringUtil::null, + OSMB_OK); + return 0; + } + // alert the user if they are using unsupported hardware if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware")) { diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml old mode 100644 new mode 100755 index 4fbe7b564f..de13379099 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6737,6 +6737,12 @@ The site at '<nolink>[HOST_NAME]</nolink>' in realm ' - Your CPU speed does not meet the minimum requirements. + +Your CPU does not seem to have the required support for SSE2 operations. + +Please see http://www.secondlife.com/corporate/sysreqs.php for information about system requirements. + + You do not appear to have the proper hardware requirements for [APP_NAME]. [APP_NAME] requires an OpenGL graphics card that has multitexture support. If this is the case, you may want to make sure that you have the latest drivers for your graphics card, and service packs and patches for your operating system. -- cgit v1.2.3 From 159afd141d1a4de595084c70f2025e783e3defa8 Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Fri, 28 Jan 2011 16:37:27 -0800 Subject: SH-753 - Ghost meshes Fix the case where the silhouette shown when editing a mesh in an adjacent region was showing up in the wrong place. The silhouette was not being translated by the avs view with respect to the region. --- indra/newview/llselectmgr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 44ccbe22f7..8ffbd5510d 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -5490,13 +5490,15 @@ void LLSelectNode::renderOneWireframe(const LLColor4& color) glMatrixMode(GL_MODELVIEW); gGL.pushMatrix(); - + BOOL is_hud_object = objectp->isHUDAttachment(); if (!is_hud_object) { glLoadIdentity(); glMultMatrixd(gGLModelView); + LLVector3 trans = objectp->getRegion()->getOriginAgent(); + glTranslatef(trans.mV[0], trans.mV[1], trans.mV[2]); } if (drawable->isActive()) -- cgit v1.2.3 From fefc37e92fc5313e88fc7416e78fc2436abfffdb Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Fri, 28 Jan 2011 16:39:02 -0800 Subject: SH-808 making sure the 10m vs. 64m scale limit switch happens for both the spinner and the manipulation tools etc. --- indra/llmath/xform.h | 2 +- indra/newview/llmanipscale.cpp | 23 +++++++++++++++++------ indra/newview/llmanipscale.h | 3 +++ indra/newview/llpanelobject.cpp | 8 ++++---- indra/newview/llvoavatar.cpp | 3 ++- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/indra/llmath/xform.h b/indra/llmath/xform.h index 7a9f0f62cf..1b50749b3e 100644 --- a/indra/llmath/xform.h +++ b/indra/llmath/xform.h @@ -33,10 +33,10 @@ const F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f const F32 MIN_OBJECT_Z = -256.f; const F32 DEFAULT_MAX_PRIM_SCALE = 64.f; +const F32 DEFAULT_MAX_PRIM_SCALE_NO_MESH = 10.f; const F32 MIN_PRIM_SCALE = 0.01f; const F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX - class LLXform { protected: diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index 060677f9f3..67ab7ab462 100644 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -85,6 +85,17 @@ const LLManip::EManipPart MANIPULATOR_IDS[NUM_MANIPULATORS] = }; +F32 get_default_max_prim_scale() +{ + if (gSavedSettings.getBOOL("MeshEnabled")) + { + return DEFAULT_MAX_PRIM_SCALE; + } + else + { + return DEFAULT_MAX_PRIM_SCALE_NO_MESH; + } +} // static void LLManipScale::setUniform(BOOL b) @@ -950,8 +961,8 @@ void LLManipScale::dragCorner( S32 x, S32 y ) mInSnapRegime = FALSE; } - F32 max_scale_factor = DEFAULT_MAX_PRIM_SCALE / MIN_PRIM_SCALE; - F32 min_scale_factor = MIN_PRIM_SCALE / DEFAULT_MAX_PRIM_SCALE; + F32 max_scale_factor = get_default_max_prim_scale() / MIN_PRIM_SCALE; + F32 min_scale_factor = MIN_PRIM_SCALE / get_default_max_prim_scale(); // find max and min scale factors that will make biggest object hit max absolute scale and smallest object hit min absolute scale for (LLObjectSelection::iterator iter = mObjectSelection->begin(); @@ -963,7 +974,7 @@ void LLManipScale::dragCorner( S32 x, S32 y ) { const LLVector3& scale = selectNode->mSavedScale; - F32 cur_max_scale_factor = llmin( DEFAULT_MAX_PRIM_SCALE / scale.mV[VX], DEFAULT_MAX_PRIM_SCALE / scale.mV[VY], DEFAULT_MAX_PRIM_SCALE / scale.mV[VZ] ); + F32 cur_max_scale_factor = llmin( get_default_max_prim_scale() / scale.mV[VX], get_default_max_prim_scale() / scale.mV[VY], get_default_max_prim_scale() / scale.mV[VZ] ); max_scale_factor = llmin( max_scale_factor, cur_max_scale_factor ); F32 cur_min_scale_factor = llmax( MIN_PRIM_SCALE / scale.mV[VX], MIN_PRIM_SCALE / scale.mV[VY], MIN_PRIM_SCALE / scale.mV[VZ] ); @@ -1260,7 +1271,7 @@ void LLManipScale::stretchFace( const LLVector3& drag_start_agent, const LLVecto F32 denom = axis * dir_local; F32 desired_delta_size = is_approx_zero(denom) ? 0.f : (delta_local_mag / denom); // in meters - F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE); + F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, get_default_max_prim_scale()); // propagate scale constraint back to position offset desired_delta_size = desired_scale - selectNode->mSavedScale.mV[axis_index]; // propagate constraint back to position @@ -1960,7 +1971,7 @@ F32 LLManipScale::partToMaxScale( S32 part, const LLBBox &bbox ) const max_extent = bbox_extents.mV[i]; } } - max_scale_factor = bbox_extents.magVec() * DEFAULT_MAX_PRIM_SCALE / max_extent; + max_scale_factor = bbox_extents.magVec() * get_default_max_prim_scale() / max_extent; if (getUniform()) { @@ -1975,7 +1986,7 @@ F32 LLManipScale::partToMinScale( S32 part, const LLBBox &bbox ) const { LLVector3 bbox_extents = unitVectorToLocalBBoxExtent( partToUnitVector( part ), bbox ); bbox_extents.abs(); - F32 min_extent = DEFAULT_MAX_PRIM_SCALE; + F32 min_extent = get_default_max_prim_scale(); for (U32 i = VX; i <= VZ; i++) { if (bbox_extents.mV[i] > 0.f && bbox_extents.mV[i] < min_extent) diff --git a/indra/newview/llmanipscale.h b/indra/newview/llmanipscale.h index 5559f557c0..2762433abf 100644 --- a/indra/newview/llmanipscale.h +++ b/indra/newview/llmanipscale.h @@ -39,6 +39,9 @@ #include "llviewerobject.h" #include "llbbox.h" + +F32 get_default_max_prim_scale(); + class LLToolComposite; class LLColor4; diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 3e2d903d58..b60eb893c7 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1934,10 +1934,10 @@ void LLPanelObject::refresh() getChildView("Physics Density")->setVisible(enable_mesh); getChildView("Physics Restitution")->setVisible(enable_mesh); - // if mesh isn't enabled we want to the scale max to be 10 - getChild("Scale X")->setMaxValue(enable_mesh ? 64 : 10); - getChild("Scale Y")->setMaxValue(enable_mesh ? 64 : 10); - getChild("Scale Z")->setMaxValue(enable_mesh ? 64 : 10); + F32 max_scale = get_default_max_prim_scale(); + getChild("Scale X")->setMaxValue(max_scale); + getChild("Scale Y")->setMaxValue(max_scale); + getChild("Scale Z")->setMaxValue(max_scale); LLComboBox* sculpt_combo = getChild("sculpt type control"); BOOL found = sculpt_combo->itemExists("Mesh"); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 4a6d303cdd..dd6f7011a1 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -63,6 +63,7 @@ #include "llkeyframefallmotion.h" #include "llkeyframestandmotion.h" #include "llkeyframewalkmotion.h" +#include "llmanipscale.h" // for get_default_max_prim_scale() #include "llmeshrepository.h" #include "llmutelist.h" #include "llmoveview.h" @@ -1383,7 +1384,7 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) newMin.setSub(pos, buffer); newMax.setAdd(pos, buffer); - float max_attachment_span = DEFAULT_MAX_PRIM_SCALE * 5.0f; + float max_attachment_span = get_default_max_prim_scale() * 5.0f; //stretch bounding box by joint positions for (polymesh_map_t::iterator i = mMeshes.begin(); i != mMeshes.end(); ++i) -- cgit v1.2.3 From fe253e6ec6f77a7967cadd6efd76b2fbbef4e2da Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Fri, 28 Jan 2011 21:43:28 -0700 Subject: merge the changeset 4de3178c6c81 from viewer-development: fixed the major memory leaking for SH-723/SH-847: memoy leaking --- indra/newview/llfirstuse.cpp | 58 +++++++++++++++++++++++++------------------- indra/newview/llfirstuse.h | 9 ++++--- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp index 4c17199895..4d252dc662 100644 --- a/indra/newview/llfirstuse.cpp +++ b/indra/newview/llfirstuse.cpp @@ -41,35 +41,36 @@ // static -std::set LLFirstUse::sConfigVariables; +//std::set LLFirstUse::sConfigVariables; +std::set LLFirstUse::sConfigVariablesEnabled; // static -void LLFirstUse::addConfigVariable(const std::string& var) -{ - sConfigVariables.insert(var); -} +//void LLFirstUse::addConfigVariable(const std::string& var) +//{ +// sConfigVariables.insert(var); +//} // static -void LLFirstUse::disableFirstUse() -{ - // Set all first-use warnings to disabled - for (std::set::iterator iter = sConfigVariables.begin(); - iter != sConfigVariables.end(); ++iter) - { - gWarningSettings.setBOOL(*iter, FALSE); - } -} +//void LLFirstUse::disableFirstUse() +//{ +// // Set all first-use warnings to disabled +// for (std::set::iterator iter = sConfigVariables.begin(); +// iter != sConfigVariables.end(); ++iter) +// { +// gWarningSettings.setBOOL(*iter, FALSE); +// } +//} // static -void LLFirstUse::resetFirstUse() -{ - // Set all first-use warnings to disabled - for (std::set::iterator iter = sConfigVariables.begin(); - iter != sConfigVariables.end(); ++iter) - { - gWarningSettings.setBOOL(*iter, TRUE); - } -} +//void LLFirstUse::resetFirstUse() +//{ +// // Set all first-use warnings to disabled +// for (std::set::iterator iter = sConfigVariables.begin(); +// iter != sConfigVariables.end(); ++iter) +// { +// gWarningSettings.setBOOL(*iter, TRUE); +// } +//} // static void LLFirstUse::otherAvatarChatFirst(bool enable) @@ -151,13 +152,21 @@ void LLFirstUse::firstUseNotification(const std::string& control_var, bool enabl if (enable) { + if(sConfigVariablesEnabled.find(control_var) != sConfigVariablesEnabled.end()) + { + return ; //already added + } + if (gSavedSettings.getBOOL("EnableUIHints")) { LL_DEBUGS("LLFirstUse") << "Trigger first use notification " << notification_name << LL_ENDL; // if notification doesn't already exist and this notification hasn't been disabled... if (gWarningSettings.getBOOL(control_var)) - { // create new notification + { + sConfigVariablesEnabled.insert(control_var) ; + + // create new notification LLNotifications::instance().add(LLNotification::Params().name(notification_name).substitutions(args).payload(payload.with("control_var", control_var))); } } @@ -169,7 +178,6 @@ void LLFirstUse::firstUseNotification(const std::string& control_var, bool enabl // redundantly clear settings var here, in case there are no notifications to cancel gWarningSettings.setBOOL(control_var, FALSE); } - } // static diff --git a/indra/newview/llfirstuse.h b/indra/newview/llfirstuse.h index 81659988e6..489f58626a 100644 --- a/indra/newview/llfirstuse.h +++ b/indra/newview/llfirstuse.h @@ -78,11 +78,11 @@ class LLFirstUse public: // Add a config variable to be reset on resetFirstUse() - static void addConfigVariable(const std::string& var); + //static void addConfigVariable(const std::string& var); // Sets all controls back to show the dialogs. - static void disableFirstUse(); - static void resetFirstUse(); + //static void disableFirstUse(); + //static void resetFirstUse(); static void otherAvatarChatFirst(bool enable = true); static void sit(bool enable = true); @@ -98,7 +98,8 @@ public: protected: static void firstUseNotification(const std::string& control_var, bool enable, const std::string& notification_name, LLSD args = LLSD(), LLSD payload = LLSD()); - static std::set sConfigVariables; + //static std::set sConfigVariables; + static std::set sConfigVariablesEnabled; static void init(); static bool processNotification(const LLSD& notify); -- cgit v1.2.3 From 893518c7a0aeb4f05f7289532e1790a0120d2345 Mon Sep 17 00:00:00 2001 From: Tofu Buzzard Date: Sun, 30 Jan 2011 12:09:28 -0800 Subject: dither compat tweak --- indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl index 8dc9e98e05..d9f021b114 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl @@ -55,7 +55,7 @@ void main() float pointplanedist_tolerance_pow2 = pos.z*pos.z*0.00005; // perturb sampling origin slightly in screen-space to hide edge-ghosting artifacts where smoothing radius is quite large - tc += ( (int(tc.x+tc.y)%2 - 0.5) * kern[1].z * dlt * 0.5 ); + tc += ( (mod(tc.x+tc.y,2) - 0.5) * kern[1].z * dlt * 0.5 ); for (int i = 1; i < 4; i++) { -- cgit v1.2.3 From 09bfb95976b28b9d1f8d3cc0959381fcba389a4e Mon Sep 17 00:00:00 2001 From: prep Date: Mon, 31 Jan 2011 16:23:22 -0500 Subject: Fix for Sh-512: Scales use their previous maximum value --- indra/newview/llpanelobject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index b60eb893c7..8fa6beb474 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1934,7 +1934,7 @@ void LLPanelObject::refresh() getChildView("Physics Density")->setVisible(enable_mesh); getChildView("Physics Restitution")->setVisible(enable_mesh); - F32 max_scale = get_default_max_prim_scale(); + F32 max_scale = DEFAULT_MAX_PRIM_SCALE_NO_MESH; getChild("Scale X")->setMaxValue(max_scale); getChild("Scale Y")->setMaxValue(max_scale); getChild("Scale Z")->setMaxValue(max_scale); -- cgit v1.2.3 From 7205ad6d53224d5ade142c579d1c38b49f3d9885 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 31 Jan 2011 18:03:39 -0500 Subject: SH-872 WIP - temporarily disabling problematic log output to see if that fixes crash on test machine --- indra/newview/llagentpilot.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) mode change 100644 => 100755 indra/newview/llagentpilot.cpp diff --git a/indra/newview/llagentpilot.cpp b/indra/newview/llagentpilot.cpp old mode 100644 new mode 100755 index 13e1023185..afeba6bdf0 --- a/indra/newview/llagentpilot.cpp +++ b/indra/newview/llagentpilot.cpp @@ -178,6 +178,8 @@ void LLAgentPilot::stopPlayback() } } +#define SKIP_PILOT_LOGGING 1 + void LLAgentPilot::updateTarget() { if (mPlaying) @@ -195,7 +197,9 @@ void LLAgentPilot::updateTarget() { if (!mStarted) { +#if SKIP_PILOT_LOGGING llinfos << "At start, beginning playback" << llendl; +#endif mTimer.reset(); mStarted = TRUE; } @@ -218,17 +222,23 @@ void LLAgentPilot::updateTarget() { if ((mNumRuns < 0) || (mNumRuns > 0)) { +#if SKIP_PILOT_LOGGING llinfos << "Looping, restarting playback" << llendl; +#endif startPlayback(); } else if (mQuitAfterRuns) { +#if SKIP_PILOT_LOGGING llinfos << "Done with all runs, quitting viewer!" << llendl; +#endif LLAppViewer::instance()->forceQuit(); } else { +#if SKIP_PILOT_LOGGING llinfos << "Done with all runs, disabling pilot" << llendl; +#endif stopPlayback(); } } -- cgit v1.2.3 From 1a51db5b53b3783b002bfa870fa45244df8fafdc Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 1 Feb 2011 02:33:14 -0600 Subject: SH-641 Cosmetic fix -- keep showing last rendered mesh LoD if requested LoD is unavailable. --- indra/newview/llmeshrepository.cpp | 16 ++++++++++++++-- indra/newview/llmeshrepository.h | 2 +- indra/newview/llvovolume.cpp | 3 ++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index b772999ee2..edcf249a21 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2160,7 +2160,7 @@ S32 LLMeshRepository::update() return size ; } -S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail) +S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod) { if (detail < 0 || detail > 4) { @@ -2201,7 +2201,19 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para if (group) { - //first see what the next lowest LOD available might be + //first, see if last_lod is available (don't transition down to avoid funny popping a la SH-641) + if (last_lod >= 0) + { + LLVolume* lod = group->refLOD(last_lod); + if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0) + { + group->derefLOD(lod); + return last_lod; + } + group->derefLOD(lod); + } + + //next, see what the next lowest LOD available might be for (S32 i = detail-1; i >= 0; --i) { LLVolume* lod = group->refLOD(i); diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index eccb82b661..b642a89192 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -456,7 +456,7 @@ public: S32 update() ; //mesh management functions - S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0); + S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0, S32 last_lod = -1); void notifyLoadedMeshes(); void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 3dc82f5368..b296d21b2b 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -936,6 +936,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo { LLVolumeParams volume_params = params_in; + S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1; S32 lod = mLOD; BOOL is404 = FALSE; @@ -1014,7 +1015,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo { //load request not yet issued, request pipeline load this mesh LLUUID asset_id = volume_params.getSculptID(); - S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod); + S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod, last_lod); if (available_lod != lod) { LLPrimitive::setVolume(volume_params, available_lod); -- cgit v1.2.3 From ee39db49a38a626e72e1924e4c157b16d90e8ee6 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 1 Feb 2011 03:13:47 -0600 Subject: SH-831 Fix for local lights option not disabling local lights. --- indra/newview/llviewercontrol.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 9bf0ae7c3e..414036c597 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -372,6 +372,12 @@ static bool handleRenderDynamicLODChanged(const LLSD& newvalue) return true; } +static bool handleRenderLocalLightsChanged(const LLSD& newvalue) +{ + gPipeline.setLightingDetail(-1); + return true; +} + static bool handleRenderDeferredChanged(const LLSD& newvalue) { LLRenderTarget::sUseFBO = newvalue.asBoolean(); @@ -592,6 +598,7 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderFogRatio")->getSignal()->connect(boost::bind(&handleFogRatioChanged, _2)); gSavedSettings.getControl("RenderMaxPartCount")->getSignal()->connect(boost::bind(&handleMaxPartCountChanged, _2)); gSavedSettings.getControl("RenderDynamicLOD")->getSignal()->connect(boost::bind(&handleRenderDynamicLODChanged, _2)); + gSavedSettings.getControl("RenderLocalLights")->getSignal()->connect(boost::bind(&handleRenderLocalLightsChanged, _2)); gSavedSettings.getControl("RenderDebugTextureBind")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderAutoMaskAlphaDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); -- cgit v1.2.3 From c7d0fab7b9279c5f6a57ee3de103b8fb142fb747 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Tue, 1 Feb 2011 12:33:39 -0500 Subject: Fixes for merge up from viewer-development to mesh-development. Backed out SH-659 since merge was messy; this will be merged in manually later. --- indra/llmath/llvolume.cpp | 6557 ++++++++++++++++++++++++++--------------- indra/llmath/llvolume.h | 2212 +++++++------- indra/llmath/llvolumeoctree.h | 70 +- 3 files changed, 5280 insertions(+), 3559 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 316eed679d..617a8b4ca3 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1,4 +1,5 @@ /** + * @file llvolume.cpp * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ @@ -24,9 +25,13 @@ */ #include "linden_common.h" +#include "llmemory.h" #include "llmath.h" #include +#if !LL_WINDOWS +#include +#endif #include "llerror.h" #include "llmemtype.h" @@ -37,9 +42,15 @@ #include "v4math.h" #include "m4math.h" #include "m3math.h" +#include "llmatrix3a.h" +#include "lloctree.h" #include "lldarray.h" #include "llvolume.h" +#include "llvolumeoctree.h" #include "llstl.h" +#include "llsdserialize.h" +#include "llvector4a.h" +#include "llmatrix4a.h" #define DEBUG_SILHOUETTE_BINORMALS 0 #define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette @@ -80,7 +91,18 @@ const F32 SKEW_MAX = 0.95f; const F32 SCULPT_MIN_AREA = 0.002f; const S32 SCULPT_MIN_AREA_DETAIL = 1; -#define GEN_TRI_STRIP 0 +extern BOOL gDebugGL; + +void assert_aligned(void* ptr, uintptr_t alignment) +{ +#if 0 + uintptr_t t = (uintptr_t) ptr; + if (t%alignment != 0) + { + llerrs << "WTF?" << llendl; + } +#endif +} BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm) { @@ -99,128 +121,262 @@ BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLV BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size) { - float fAWdU[3]; - LLVector3 dir; - LLVector3 diff; + return LLLineSegmentBoxIntersect(start.mV, end.mV, center.mV, size.mV); +} + +BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size) +{ + F32 fAWdU[3]; + F32 dir[3]; + F32 diff[3]; for (U32 i = 0; i < 3; i++) { - dir.mV[i] = 0.5f * (end.mV[i] - start.mV[i]); - diff.mV[i] = (0.5f * (end.mV[i] + start.mV[i])) - center.mV[i]; - fAWdU[i] = fabsf(dir.mV[i]); - if(fabsf(diff.mV[i])>size.mV[i] + fAWdU[i]) return false; + dir[i] = 0.5f * (end[i] - start[i]); + diff[i] = (0.5f * (end[i] + start[i])) - center[i]; + fAWdU[i] = fabsf(dir[i]); + if(fabsf(diff[i])>size[i] + fAWdU[i]) return false; } float f; - f = dir.mV[1] * diff.mV[2] - dir.mV[2] * diff.mV[1]; if(fabsf(f)>size.mV[1]*fAWdU[2] + size.mV[2]*fAWdU[1]) return false; - f = dir.mV[2] * diff.mV[0] - dir.mV[0] * diff.mV[2]; if(fabsf(f)>size.mV[0]*fAWdU[2] + size.mV[2]*fAWdU[0]) return false; - f = dir.mV[0] * diff.mV[1] - dir.mV[1] * diff.mV[0]; if(fabsf(f)>size.mV[0]*fAWdU[1] + size.mV[1]*fAWdU[0]) return false; + f = dir[1] * diff[2] - dir[2] * diff[1]; if(fabsf(f)>size[1]*fAWdU[2] + size[2]*fAWdU[1]) return false; + f = dir[2] * diff[0] - dir[0] * diff[2]; if(fabsf(f)>size[0]*fAWdU[2] + size[2]*fAWdU[0]) return false; + f = dir[0] * diff[1] - dir[1] * diff[0]; if(fabsf(f)>size[0]*fAWdU[1] + size[1]*fAWdU[0]) return false; return true; } + // intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir. // returns TRUE if intersecting and returns barycentric coordinates in intersection_a, intersection_b, // and returns the intersection point along dir in intersection_t. // Moller-Trumbore algorithm -BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir, - F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided) +BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, + F32& intersection_a, F32& intersection_b, F32& intersection_t) { - F32 u, v, t; /* find vectors for two edges sharing vert0 */ - LLVector3 edge1 = vert1 - vert0; + LLVector4a edge1; + edge1.setSub(vert1, vert0); - LLVector3 edge2 = vert2 - vert0;; + LLVector4a edge2; + edge2.setSub(vert2, vert0); /* begin calculating determinant - also used to calculate U parameter */ - LLVector3 pvec = dir % edge2; - - /* if determinant is near zero, ray lies in plane of triangle */ - F32 det = edge1 * pvec; + LLVector4a pvec; + pvec.setCross3(dir, edge2); - if (!two_sided) + /* if determinant is near zero, ray lies in plane of triangle */ + LLVector4a det; + det.setAllDot3(edge1, pvec); + + if (det.greaterEqual(LLVector4a::getEpsilon()).getGatheredBits() & 0x7) { - if (det < F_APPROXIMATELY_ZERO) - { - return FALSE; - } - /* calculate distance from vert0 to ray origin */ - LLVector3 tvec = orig - vert0; + LLVector4a tvec; + tvec.setSub(orig, vert0); /* calculate U parameter and test bounds */ - u = tvec * pvec; + LLVector4a u; + u.setAllDot3(tvec,pvec); - if (u < 0.f || u > det) + if ((u.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7) && + (u.lessEqual(det).getGatheredBits() & 0x7)) { - return FALSE; + /* prepare to test V parameter */ + LLVector4a qvec; + qvec.setCross3(tvec, edge1); + + /* calculate V parameter and test bounds */ + LLVector4a v; + v.setAllDot3(dir, qvec); + + + //if (!(v < 0.f || u + v > det)) + + LLVector4a sum_uv; + sum_uv.setAdd(u, v); + + S32 v_gequal = v.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7; + S32 sum_lequal = sum_uv.lessEqual(det).getGatheredBits() & 0x7; + + if (v_gequal && sum_lequal) + { + /* calculate t, scale parameters, ray intersects triangle */ + LLVector4a t; + t.setAllDot3(edge2,qvec); + + t.div(det); + u.div(det); + v.div(det); + + intersection_a = u[0]; + intersection_b = v[0]; + intersection_t = t[0]; + return TRUE; + } } - - /* prepare to test V parameter */ - LLVector3 qvec = tvec % edge1; + } - /* calculate V parameter and test bounds */ - v = dir * qvec; - if (v < 0.f || u + v > det) - { - return FALSE; - } + return FALSE; +} - /* calculate t, scale parameters, ray intersects triangle */ - t = edge2 * qvec; - F32 inv_det = 1.0 / det; - t *= inv_det; - u *= inv_det; - v *= inv_det; - } +BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, + F32& intersection_a, F32& intersection_b, F32& intersection_t) +{ + F32 u, v, t; - else // two sided - { - if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO) - { - return FALSE; - } - F32 inv_det = 1.0 / det; + /* find vectors for two edges sharing vert0 */ + LLVector4a edge1; + edge1.setSub(vert1, vert0); + + + LLVector4a edge2; + edge2.setSub(vert2, vert0); - /* calculate distance from vert0 to ray origin */ - LLVector3 tvec = orig - vert0; - - /* calculate U parameter and test bounds */ - u = (tvec * pvec) * inv_det; - if (u < 0.f || u > 1.f) - { - return FALSE; - } + /* begin calculating determinant - also used to calculate U parameter */ + LLVector4a pvec; + pvec.setCross3(dir, edge2); - /* prepare to test V parameter */ - LLVector3 qvec = tvec - edge1; - - /* calculate V parameter and test bounds */ - v = (dir * qvec) * inv_det; - - if (v < 0.f || u + v > 1.f) - { - return FALSE; - } + /* if determinant is near zero, ray lies in plane of triangle */ + F32 det = edge1.dot3(pvec).getF32(); - /* calculate t, ray intersects triangle */ - t = (edge2 * qvec) * inv_det; + + if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO) + { + return FALSE; + } + + F32 inv_det = 1.f / det; + + /* calculate distance from vert0 to ray origin */ + LLVector4a tvec; + tvec.setSub(orig, vert0); + + /* calculate U parameter and test bounds */ + u = (tvec.dot3(pvec).getF32()) * inv_det; + if (u < 0.f || u > 1.f) + { + return FALSE; + } + + /* prepare to test V parameter */ + tvec.sub(edge1); + + /* calculate V parameter and test bounds */ + v = (dir.dot3(tvec).getF32()) * inv_det; + + if (v < 0.f || u + v > 1.f) + { + return FALSE; } + + /* calculate t, ray intersects triangle */ + t = (edge2.dot3(tvec).getF32()) * inv_det; - if (intersection_a != NULL) - *intersection_a = u; - if (intersection_b != NULL) - *intersection_b = v; - if (intersection_t != NULL) - *intersection_t = t; + intersection_a = u; + intersection_b = v; + intersection_t = t; return TRUE; } +//helper for non-aligned vectors +BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir, + F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided) +{ + LLVector4a vert0a, vert1a, vert2a, origa, dira; + vert0a.load3(vert0.mV); + vert1a.load3(vert1.mV); + vert2a.load3(vert2.mV); + origa.load3(orig.mV); + dira.load3(dir.mV); + + if (two_sided) + { + return LLTriangleRayIntersectTwoSided(vert0a, vert1a, vert2a, origa, dira, + intersection_a, intersection_b, intersection_t); + } + else + { + return LLTriangleRayIntersect(vert0a, vert1a, vert2a, origa, dira, + intersection_a, intersection_b, intersection_t); + } +} + +class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst +{ +public: + const LLVolumeFace* mFace; + + LLVolumeOctreeRebound(const LLVolumeFace* face) + { + mFace = face; + } + + virtual void visit(const LLOctreeNode* branch) + { //this is a depth first traversal, so it's safe to assum all children have complete + //bounding data + + LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0); + + LLVector4a& min = node->mExtents[0]; + LLVector4a& max = node->mExtents[1]; + + if (!branch->getData().empty()) + { //node has data, find AABB that binds data set + const LLVolumeTriangle* tri = *(branch->getData().begin()); + + //initialize min/max to first available vertex + min = *(tri->mV[0]); + max = *(tri->mV[0]); + + for (LLOctreeNode::const_element_iter iter = + branch->getData().begin(); iter != branch->getData().end(); ++iter) + { //for each triangle in node + + //stretch by triangles in node + tri = *iter; + + min.setMin(min, *tri->mV[0]); + min.setMin(min, *tri->mV[1]); + min.setMin(min, *tri->mV[2]); + + max.setMax(max, *tri->mV[0]); + max.setMax(max, *tri->mV[1]); + max.setMax(max, *tri->mV[2]); + } + } + else if (!branch->getChildren().empty()) + { //no data, but child nodes exist + LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0); + + //initialize min/max to extents of first child + min = child->mExtents[0]; + max = child->mExtents[1]; + } + else + { + llerrs << "WTF? Empty leaf" << llendl; + } + + for (S32 i = 0; i < branch->getChildCount(); ++i) + { //stretch by child extents + LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0); + min.setMin(min, child->mExtents[0]); + max.setMax(max, child->mExtents[1]); + } + + node->mBounds[0].setAdd(min, max); + node->mBounds[0].mul(0.5f); + + node->mBounds[1].setSub(max,min); + node->mBounds[1].mul(0.5f); + } +}; //------------------------------------------------------------------- // statics @@ -1669,7 +1825,13 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mFaceMask = 0x0; mDetail = detail; mSculptLevel = -2; - + mIsTetrahedron = FALSE; + mLODScaleBias.setVec(1,1,1); + mHullPoints = NULL; + mHullIndices = NULL; + mNumHullPoints = 0; + mNumHullIndices = 0; + // set defaults if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE) { @@ -1684,7 +1846,8 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mGenerateSingleFace = generate_single_face; generate(); - if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE) + + if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE) { createVolumeFaces(); } @@ -1719,6 +1882,11 @@ LLVolume::~LLVolume() mPathp = NULL; mProfilep = NULL; mVolumeFaces.clear(); + + free(mHullPoints); + mHullPoints = NULL; + free(mHullIndices); + mHullIndices = NULL; } BOOL LLVolume::generate() @@ -1835,815 +2003,1435 @@ BOOL LLVolume::generate() return FALSE; } - -void LLVolume::createVolumeFaces() +void LLVolumeFace::VertexData::init() { - LLMemType m1(LLMemType::MTYPE_VOLUME); - - if (mGenerateSingleFace) + if (!mData) { - // do nothing + mData = (LLVector4a*) malloc(sizeof(LLVector4a)*2); } - else - { - S32 num_faces = getNumFaces(); - BOOL partial_build = TRUE; - if (num_faces != mVolumeFaces.size()) - { - partial_build = FALSE; - mVolumeFaces.resize(num_faces); - } - // Initialize volume faces with parameter data - for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++) - { - LLVolumeFace& vf = mVolumeFaces[i]; - LLProfile::Face& face = mProfilep->mFaces[i]; - vf.mBeginS = face.mIndex; - vf.mNumS = face.mCount; - if (vf.mNumS < 0) - { - llerrs << "Volume face corruption detected." << llendl; - } - - vf.mBeginT = 0; - vf.mNumT= getPath().mPath.size(); - vf.mID = i; +} - // Set the type mask bits correctly - if (mParams.getProfileParams().getHollow() > 0) - { - vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK; - } - if (mProfilep->isOpen()) - { - vf.mTypeMask |= LLVolumeFace::OPEN_MASK; - } - if (face.mCap) - { - vf.mTypeMask |= LLVolumeFace::CAP_MASK; - if (face.mFaceID == LL_FACE_PATH_BEGIN) - { - vf.mTypeMask |= LLVolumeFace::TOP_MASK; - } - else - { - llassert(face.mFaceID == LL_FACE_PATH_END); - vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK; - } - } - else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END)) - { - vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK; - } - else - { - vf.mTypeMask |= LLVolumeFace::SIDE_MASK; - if (face.mFlat) - { - vf.mTypeMask |= LLVolumeFace::FLAT_MASK; - } - if (face.mFaceID & LL_FACE_INNER_SIDE) - { - vf.mTypeMask |= LLVolumeFace::INNER_MASK; - if (face.mFlat && vf.mNumS > 2) - { //flat inner faces have to copy vert normals - vf.mNumS = vf.mNumS*2; - if (vf.mNumS < 0) - { - llerrs << "Volume face corruption detected." << llendl; - } - } - } - else - { - vf.mTypeMask |= LLVolumeFace::OUTER_MASK; - } - } - } +LLVolumeFace::VertexData::VertexData() +{ + mData = NULL; + init(); +} + +LLVolumeFace::VertexData::VertexData(const VertexData& rhs) +{ + mData = NULL; + *this = rhs; +} - for (face_list_t::iterator iter = mVolumeFaces.begin(); - iter != mVolumeFaces.end(); ++iter) - { - (*iter).create(this, partial_build); - } +const LLVolumeFace::VertexData& LLVolumeFace::VertexData::operator=(const LLVolumeFace::VertexData& rhs) +{ + if (this != &rhs) + { + init(); + LLVector4a::memcpyNonAliased16((F32*) mData, (F32*) rhs.mData, 2*sizeof(LLVector4a)); + mTexCoord = rhs.mTexCoord; } + return *this; } - -inline LLVector3 sculpt_rgb_to_vector(U8 r, U8 g, U8 b) +LLVolumeFace::VertexData::~VertexData() { - // maps RGB values to vector values [0..255] -> [-0.5..0.5] - LLVector3 value; - value.mV[VX] = r / 255.f - 0.5f; - value.mV[VY] = g / 255.f - 0.5f; - value.mV[VZ] = b / 255.f - 0.5f; - - return value; + free(mData); + mData = NULL; } -inline U32 sculpt_xy_to_index(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components) +LLVector4a& LLVolumeFace::VertexData::getPosition() { - U32 index = (x + y * sculpt_width) * sculpt_components; - return index; + return mData[POSITION]; } +LLVector4a& LLVolumeFace::VertexData::getNormal() +{ + return mData[NORMAL]; +} -inline U32 sculpt_st_to_index(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components) +const LLVector4a& LLVolumeFace::VertexData::getPosition() const { - U32 x = (U32) ((F32)s/(size_s) * (F32) sculpt_width); - U32 y = (U32) ((F32)t/(size_t) * (F32) sculpt_height); + return mData[POSITION]; +} - return sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components); +const LLVector4a& LLVolumeFace::VertexData::getNormal() const +{ + return mData[NORMAL]; } -inline LLVector3 sculpt_index_to_vector(U32 index, const U8* sculpt_data) +void LLVolumeFace::VertexData::setPosition(const LLVector4a& pos) { - LLVector3 v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]); - - return v; + mData[POSITION] = pos; } -inline LLVector3 sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) +void LLVolumeFace::VertexData::setNormal(const LLVector4a& norm) { - U32 index = sculpt_st_to_index(s, t, size_s, size_t, sculpt_width, sculpt_height, sculpt_components); - - return sculpt_index_to_vector(index, sculpt_data); + mData[NORMAL] = norm; } -inline LLVector3 sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) +bool LLVolumeFace::VertexData::operator<(const LLVolumeFace::VertexData& rhs)const { - U32 index = sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components); + const F32* lp = this->getPosition().getF32ptr(); + const F32* rp = rhs.getPosition().getF32ptr(); - return sculpt_index_to_vector(index, sculpt_data); -} + if (lp[0] != rp[0]) + { + return lp[0] < rp[0]; + } + if (rp[1] != lp[1]) + { + return lp[1] < rp[1]; + } -F32 LLVolume::sculptGetSurfaceArea() -{ - // test to see if image has enough variation to create non-degenerate geometry + if (rp[2] != lp[2]) + { + return lp[2] < rp[2]; + } - F32 area = 0; + lp = getNormal().getF32ptr(); + rp = rhs.getNormal().getF32ptr(); - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); - - for (S32 s = 0; s < sizeS-1; s++) + if (lp[0] != rp[0]) { - for (S32 t = 0; t < sizeT-1; t++) - { - // get four corners of quad - LLVector3 p1 = mMesh[(s )*sizeT + (t )].mPos; - LLVector3 p2 = mMesh[(s+1)*sizeT + (t )].mPos; - LLVector3 p3 = mMesh[(s )*sizeT + (t+1)].mPos; - LLVector3 p4 = mMesh[(s+1)*sizeT + (t+1)].mPos; + return lp[0] < rp[0]; + } - // compute the area of the quad by taking the length of the cross product of the two triangles - LLVector3 cross1 = (p1 - p2) % (p1 - p3); - LLVector3 cross2 = (p4 - p2) % (p4 - p3); - area += (cross1.magVec() + cross2.magVec()) / 2.0; + if (rp[1] != lp[1]) + { + return lp[1] < rp[1]; + } + + if (rp[2] != lp[2]) + { + return lp[2] < rp[2]; + } + + if (mTexCoord.mV[0] != rhs.mTexCoord.mV[0]) + { + return mTexCoord.mV[0] < rhs.mTexCoord.mV[0]; + } + + return mTexCoord.mV[1] < rhs.mTexCoord.mV[1]; +} + +bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const +{ + return mData[POSITION].equals3(rhs.getPosition()) && + mData[NORMAL].equals3(rhs.getNormal()) && + mTexCoord == rhs.mTexCoord; +} + +bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const +{ + bool retval = false; + if (rhs.mData[POSITION].equals3(mData[POSITION]) && rhs.mTexCoord == mTexCoord) + { + if (angle_cutoff > 1.f) + { + retval = (mData[NORMAL].equals3(rhs.mData[NORMAL])); + } + else + { + F32 cur_angle = rhs.mData[NORMAL].dot3(mData[NORMAL]).getF32(); + retval = cur_angle > angle_cutoff; } } - return area; + return retval; } -// create placeholder shape -void LLVolume::sculptGeneratePlaceholder() +BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name) { - LLMemType m1(LLMemType::MTYPE_VOLUME); + std::ifstream is; - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); + is.open(file_name.c_str(), std::ifstream::in | std::ifstream::binary); + + BOOL success = createVolumeFacesFromStream(is); - S32 line = 0; + is.close(); - // for now, this is a sphere. - for (S32 s = 0; s < sizeS; s++) + return success; +} + +BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) +{ + mSculptLevel = -1; // default is an error occured + + LLSD header; { - for (S32 t = 0; t < sizeT; t++) + if (!LLSDSerialize::deserialize(header, is, 1024*1024*1024)) { - S32 i = t + line; - Point& pt = mMesh[i]; + llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl; + return FALSE; + } + } + + std::string nm[] = + { + "lowest_lod", + "low_lod", + "medium_lod", + "high_lod" + }; - - F32 u = (F32)s/(sizeS-1); - F32 v = (F32)t/(sizeT-1); + S32 lod = llclamp((S32) mDetail, 0, 3); - const F32 RADIUS = (F32) 0.3; - - pt.mPos.mV[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS); - pt.mPos.mV[1] = (F32)(sin(F_PI * v) * sin(2.0 * F_PI * u) * RADIUS); - pt.mPos.mV[2] = (F32)(cos(F_PI * v) * RADIUS); + while (lod < 4 && + (header[nm[lod]]["offset"].asInteger() == -1 || + header[nm[lod]]["size"].asInteger() == 0 )) + { + ++lod; + } + + if (lod >= 4) + { + lod = llclamp((S32) mDetail, 0, 3); + while (lod >= 0 && + (header[nm[lod]]["offset"].asInteger() == -1 || + header[nm[lod]]["size"].asInteger() == 0) ) + { + --lod; + } + + if (lod < 0) + { + llwarns << "Mesh header missing LOD offsets. Not a valid mesh asset!" << llendl; + return FALSE; } - line += sizeT; } + + is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur); + + return unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger()); } -// create the vertices from the map -void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type) +bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) { - U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; - BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; - BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; - BOOL reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR - - - LLMemType m1(LLMemType::MTYPE_VOLUME); - - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); + //input stream is now pointing at a zlib compressed block of LLSD + //decompress block + LLSD mdl; + if (!unzip_llsd(mdl, is, size)) + { + llwarns << "not a valid mesh asset!" << llendl; + return false; + } - S32 line = 0; - for (S32 s = 0; s < sizeS; s++) { - // Run along the profile. - for (S32 t = 0; t < sizeT; t++) + U32 face_count = mdl.size(); + + if (face_count == 0) { - S32 i = t + line; - Point& pt = mMesh[i]; + llerrs << "WTF?" << llendl; + } - S32 reversed_t = t; + mVolumeFaces.resize(face_count); - if (reverse_horizontal) - { - reversed_t = sizeT - t - 1; - } - - U32 x = (U32) ((F32)reversed_t/(sizeT-1) * (F32) sculpt_width); - U32 y = (U32) ((F32)s/(sizeS-1) * (F32) sculpt_height); + for (U32 i = 0; i < face_count; ++i) + { + LLSD::Binary pos = mdl[i]["Position"]; + LLSD::Binary norm = mdl[i]["Normal"]; + LLSD::Binary tc = mdl[i]["TexCoord0"]; + LLSD::Binary idx = mdl[i]["TriangleList"]; + + LLVolumeFace& face = mVolumeFaces[i]; + //copy out indices + face.resizeIndices(idx.size()/2); - if (y == 0) // top row stitching + if (idx.empty() || face.mNumIndices < 3) + { //why is there an empty index list? + llerrs <<"WTF?" << llendl; + continue; + } + + U16* indices = (U16*) &(idx[0]); + for (U32 j = 0; j < idx.size()/2; ++j) { - // pinch? - if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) - { - x = sculpt_width / 2; - } + face.mIndices[j] = indices[j]; } - if (y == sculpt_height) // bottom row stitching + //copy out vertices + U32 num_verts = pos.size()/(3*2); + face.resizeVertices(num_verts); + + if (mdl[i].has("Weights")) { - // wrap? - if (sculpt_stitching == LL_SCULPT_TYPE_TORUS) + face.allocateWeights(num_verts); + + LLSD::Binary weights = mdl[i]["Weights"]; + + U32 idx = 0; + + U32 cur_vertex = 0; + while (idx < weights.size() && cur_vertex < num_verts) { - y = 0; + const U8 END_INFLUENCES = 0xFF; + U8 joint = weights[idx++]; + + U32 cur_influence = 0; + LLVector4 wght(0,0,0,0); + + while (joint != END_INFLUENCES && idx < weights.size()) + { + U16 influence = weights[idx++]; + influence |= ((U16) weights[idx++] << 8); + + F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f); + wght.mV[cur_influence++] = (F32) joint + w; + + if (cur_influence >= 4) + { + joint = END_INFLUENCES; + } + else + { + joint = weights[idx++]; + } + } + + face.mWeights[cur_vertex].loadua(wght.mV); + + cur_vertex++; } - else + + if (cur_vertex != num_verts || idx != weights.size()) { - y = sculpt_height - 1; + llwarns << "Vertex weight count does not match vertex count!" << llendl; } + + } - // pinch? - if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) + LLVector3 minp; + LLVector3 maxp; + LLVector2 min_tc; + LLVector2 max_tc; + + minp.setValue(mdl[i]["PositionDomain"]["Min"]); + maxp.setValue(mdl[i]["PositionDomain"]["Max"]); + LLVector4a min_pos, max_pos; + min_pos.load3(minp.mV); + max_pos.load3(maxp.mV); + + min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]); + max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]); + + LLVector4a pos_range; + pos_range.setSub(max_pos, min_pos); + LLVector2 tc_range = max_tc - min_tc; + + LLVector4a* pos_out = face.mPositions; + LLVector4a* norm_out = face.mNormals; + LLVector2* tc_out = face.mTexCoords; + + for (U32 j = 0; j < num_verts; ++j) + { + U16* v = (U16*) &(pos[j*3*2]); + + pos_out->set((F32) v[0], (F32) v[1], (F32) v[2]); + pos_out->div(65535.f); + pos_out->mul(pos_range); + pos_out->add(min_pos); + + pos_out++; + + U16* n = (U16*) &(norm[j*3*2]); + + norm_out->set((F32) n[0], (F32) n[1], (F32) n[2]); + norm_out->div(65535.f); + norm_out->mul(2.f); + norm_out->sub(1.f); + norm_out++; + + U16* t = (U16*) &(tc[j*2*2]); + + tc_out->mV[0] = (F32) t[0] / 65535.f * tc_range.mV[0] + min_tc.mV[0]; + tc_out->mV[1] = (F32) t[1] / 65535.f * tc_range.mV[1] + min_tc.mV[1]; + + tc_out++; + } + + + // modifier flags? + bool do_mirror = (mParams.getSculptType() & LL_SCULPT_FLAG_MIRROR); + bool do_invert = (mParams.getSculptType() &LL_SCULPT_FLAG_INVERT); + + + // translate to actions: + bool do_reflect_x = false; + bool do_reverse_triangles = false; + bool do_invert_normals = false; + + if (do_mirror) + { + do_reflect_x = true; + do_reverse_triangles = !do_reverse_triangles; + } + + if (do_invert) + { + do_invert_normals = true; + do_reverse_triangles = !do_reverse_triangles; + } + + // now do the work + + if (do_reflect_x) + { + LLVector4a* p = (LLVector4a*) face.mPositions; + LLVector4a* n = (LLVector4a*) face.mNormals; + + for (S32 i = 0; i < face.mNumVertices; i++) { - x = sculpt_width / 2; + p[i].mul(-1.0f); + n[i].mul(-1.0f); } } - if (x == sculpt_width) // side stitching + if (do_invert_normals) { - // wrap? - if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) || - (sculpt_stitching == LL_SCULPT_TYPE_TORUS) || - (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER)) + LLVector4a* n = (LLVector4a*) face.mNormals; + + for (S32 i = 0; i < face.mNumVertices; i++) { - x = 0; + n[i].mul(-1.0f); } - - else + } + + if (do_reverse_triangles) + { + for (U32 j = 0; j < face.mNumIndices; j += 3) { - x = sculpt_width - 1; + // swap the 2nd and 3rd index + S32 swap = face.mIndices[j+1]; + face.mIndices[j+1] = face.mIndices[j+2]; + face.mIndices[j+2] = swap; } } - pt.mPos = sculpt_xy_to_vector(x, y, sculpt_width, sculpt_height, sculpt_components, sculpt_data); + //calculate bounding box + LLVector4a& min = face.mExtents[0]; + LLVector4a& max = face.mExtents[1]; - if (sculpt_mirror) + min.clear(); + max.clear(); + min = max = face.mPositions[0]; + + for (S32 i = 1; i < face.mNumVertices; ++i) { - pt.mPos.mV[VX] *= -1.f; + min.setMin(min, face.mPositions[i]); + max.setMax(max, face.mPositions[i]); } } - - line += sizeT; } + + mSculptLevel = 0; // success! + + cacheOptimize(); + + return true; } +void tetrahedron_set_normal(LLVolumeFace::VertexData* cv) +{ + LLVector4a v0; + v0.setSub(cv[1].getPosition(), cv[0].getNormal()); + LLVector4a v1; + v1.setSub(cv[2].getNormal(), cv[0].getPosition()); + + cv[0].getNormal().setCross3(v0,v1); + cv[0].getNormal().normalize3fast(); + cv[1].setNormal(cv[0].getNormal()); + cv[2].setNormal(cv[1].getNormal()); +} -const S32 SCULPT_REZ_1 = 6; // changed from 4 to 6 - 6 looks round whereas 4 looks square -const S32 SCULPT_REZ_2 = 8; -const S32 SCULPT_REZ_3 = 16; -const S32 SCULPT_REZ_4 = 32; +BOOL LLVolume::isTetrahedron() +{ + return mIsTetrahedron; +} -S32 sculpt_sides(F32 detail) +void LLVolume::makeTetrahedron() { + mVolumeFaces.clear(); - // detail is usually one of: 1, 1.5, 2.5, 4.0. + LLVolumeFace face; + + F32 x = 0.25f; + LLVector4a p[] = + { //unit tetrahedron corners + LLVector4a(x,x,x), + LLVector4a(-x,-x,x), + LLVector4a(-x,x,-x), + LLVector4a(x,-x,-x) + }; + + face.mExtents[0].splat(-x); + face.mExtents[1].splat(x); - if (detail <= 1.0) - { - return SCULPT_REZ_1; - } - if (detail <= 2.0) + LLVolumeFace::VertexData cv[3]; + + //set texture coordinates + cv[0].mTexCoord = LLVector2(0,0); + cv[1].mTexCoord = LLVector2(1,0); + cv[2].mTexCoord = LLVector2(0.5f, 0.5f*F_SQRT3); + + + //side 1 + cv[0].setPosition(p[1]); + cv[1].setPosition(p[0]); + cv[2].setPosition(p[2]); + + tetrahedron_set_normal(cv); + + face.resizeVertices(12); + face.resizeIndices(12); + + LLVector4a* v = (LLVector4a*) face.mPositions; + LLVector4a* n = (LLVector4a*) face.mNormals; + LLVector2* tc = (LLVector2*) face.mTexCoords; + + v[0] = cv[0].getPosition(); + v[1] = cv[1].getPosition(); + v[2] = cv[2].getPosition(); + v += 3; + + n[0] = cv[0].getNormal(); + n[1] = cv[1].getNormal(); + n[2] = cv[2].getNormal(); + n += 3; + + tc[0] = cv[0].mTexCoord; + tc[1] = cv[1].mTexCoord; + tc[2] = cv[2].mTexCoord; + tc += 3; + + + //side 2 + cv[0].setPosition(p[3]); + cv[1].setPosition(p[0]); + cv[2].setPosition(p[1]); + + tetrahedron_set_normal(cv); + + v[0] = cv[0].getPosition(); + v[1] = cv[1].getPosition(); + v[2] = cv[2].getPosition(); + v += 3; + + n[0] = cv[0].getNormal(); + n[1] = cv[1].getNormal(); + n[2] = cv[2].getNormal(); + n += 3; + + tc[0] = cv[0].mTexCoord; + tc[1] = cv[1].mTexCoord; + tc[2] = cv[2].mTexCoord; + tc += 3; + + //side 3 + cv[0].setPosition(p[3]); + cv[1].setPosition(p[1]); + cv[2].setPosition(p[2]); + + tetrahedron_set_normal(cv); + + v[0] = cv[0].getPosition(); + v[1] = cv[1].getPosition(); + v[2] = cv[2].getPosition(); + v += 3; + + n[0] = cv[0].getNormal(); + n[1] = cv[1].getNormal(); + n[2] = cv[2].getNormal(); + n += 3; + + tc[0] = cv[0].mTexCoord; + tc[1] = cv[1].mTexCoord; + tc[2] = cv[2].mTexCoord; + tc += 3; + + //side 4 + cv[0].setPosition(p[2]); + cv[1].setPosition(p[0]); + cv[2].setPosition(p[3]); + + tetrahedron_set_normal(cv); + + v[0] = cv[0].getPosition(); + v[1] = cv[1].getPosition(); + v[2] = cv[2].getPosition(); + v += 3; + + n[0] = cv[0].getNormal(); + n[1] = cv[1].getNormal(); + n[2] = cv[2].getNormal(); + n += 3; + + tc[0] = cv[0].mTexCoord; + tc[1] = cv[1].mTexCoord; + tc[2] = cv[2].mTexCoord; + tc += 3; + + //set index buffer + for (U16 i = 0; i < 12; i++) { - return SCULPT_REZ_2; + face.mIndices[i] = i; } - if (detail <= 3.0) + + mVolumeFaces.push_back(face); + mSculptLevel = 0; + mIsTetrahedron = TRUE; +} + +void LLVolume::copyVolumeFaces(const LLVolume* volume) +{ + mVolumeFaces = volume->mVolumeFaces; + mSculptLevel = 0; + mIsTetrahedron = FALSE; +} + +void LLVolume::cacheOptimize() +{ + for (S32 i = 0; i < mVolumeFaces.size(); ++i) { - return SCULPT_REZ_3; + mVolumeFaces[i].cacheOptimize(); } - else +} + + +S32 LLVolume::getNumFaces() const +{ + U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK); + + if (sculpt_type == LL_SCULPT_TYPE_MESH) { - return SCULPT_REZ_4; + return LL_SCULPT_MESH_MAX_FACES; } -} + return (S32)mProfilep->mFaces.size(); +} -// determine the number of vertices in both s and t direction for this sculpt -void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32& s, S32& t) -{ - // this code has the following properties: - // 1) the aspect ratio of the mesh is as close as possible to the ratio of the map - // while still using all available verts - // 2) the mesh cannot have more verts than is allowed by LOD - // 3) the mesh cannot have more verts than is allowed by the map - - S32 max_vertices_lod = (S32)pow((double)sculpt_sides(detail), 2.0); - S32 max_vertices_map = width * height / 4; - - S32 vertices; - if (max_vertices_map > 0) - vertices = llmin(max_vertices_lod, max_vertices_map); - else - vertices = max_vertices_lod; - - - F32 ratio; - if ((width == 0) || (height == 0)) - ratio = 1.f; - else - ratio = (F32) width / (F32) height; - - - s = (S32)fsqrtf(((F32)vertices / ratio)); - - s = llmax(s, 4); // no degenerate sizes, please - t = vertices / s; - - t = llmax(t, 4); // no degenerate sizes, please - s = vertices / t; -} - -// sculpt replaces generate() for sculpted surfaces -void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level) +void LLVolume::createVolumeFaces() { LLMemType m1(LLMemType::MTYPE_VOLUME); - U8 sculpt_type = mParams.getSculptType(); - - BOOL data_is_empty = FALSE; - if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL) + if (mGenerateSingleFace) { - sculpt_level = -1; - data_is_empty = TRUE; + // do nothing } - - S32 requested_sizeS = 0; - S32 requested_sizeT = 0; - - sculpt_calc_mesh_resolution(sculpt_width, sculpt_height, sculpt_type, mDetail, requested_sizeS, requested_sizeT); - - mPathp->generate(mParams.getPathParams(), mDetail, 0, TRUE, requested_sizeS); - mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(), mDetail, 0, TRUE, requested_sizeT); - - S32 sizeS = mPathp->mPath.size(); // we requested a specific size, now see what we really got - S32 sizeT = mProfilep->mProfile.size(); // we requested a specific size, now see what we really got - - // weird crash bug - DEV-11158 - trying to collect more data: - if ((sizeS == 0) || (sizeT == 0)) + else { - llwarns << "sculpt bad mesh size " << sizeS << " " << sizeT << llendl; - } - - sNumMeshPoints -= mMesh.size(); - mMesh.resize(sizeS * sizeT); - sNumMeshPoints += mMesh.size(); + S32 num_faces = getNumFaces(); + BOOL partial_build = TRUE; + if (num_faces != mVolumeFaces.size()) + { + partial_build = FALSE; + mVolumeFaces.resize(num_faces); + } + // Initialize volume faces with parameter data + for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++) + { + LLVolumeFace& vf = mVolumeFaces[i]; + LLProfile::Face& face = mProfilep->mFaces[i]; + vf.mBeginS = face.mIndex; + vf.mNumS = face.mCount; + if (vf.mNumS < 0) + { + llerrs << "Volume face corruption detected." << llendl; + } - //generate vertex positions - if (!data_is_empty) - { - sculptGenerateMapVertices(sculpt_width, sculpt_height, sculpt_components, sculpt_data, sculpt_type); + vf.mBeginT = 0; + vf.mNumT= getPath().mPath.size(); + vf.mID = i; - // don't test lowest LOD to support legacy content DEV-33670 - if (mDetail > SCULPT_MIN_AREA_DETAIL) - { - if (sculptGetSurfaceArea() < SCULPT_MIN_AREA) + // Set the type mask bits correctly + if (mParams.getProfileParams().getHollow() > 0) { - data_is_empty = TRUE; + vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK; + } + if (mProfilep->isOpen()) + { + vf.mTypeMask |= LLVolumeFace::OPEN_MASK; + } + if (face.mCap) + { + vf.mTypeMask |= LLVolumeFace::CAP_MASK; + if (face.mFaceID == LL_FACE_PATH_BEGIN) + { + vf.mTypeMask |= LLVolumeFace::TOP_MASK; + } + else + { + llassert(face.mFaceID == LL_FACE_PATH_END); + vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK; + } + } + else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END)) + { + vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK; + } + else + { + vf.mTypeMask |= LLVolumeFace::SIDE_MASK; + if (face.mFlat) + { + vf.mTypeMask |= LLVolumeFace::FLAT_MASK; + } + if (face.mFaceID & LL_FACE_INNER_SIDE) + { + vf.mTypeMask |= LLVolumeFace::INNER_MASK; + if (face.mFlat && vf.mNumS > 2) + { //flat inner faces have to copy vert normals + vf.mNumS = vf.mNumS*2; + if (vf.mNumS < 0) + { + llerrs << "Volume face corruption detected." << llendl; + } + } + } + else + { + vf.mTypeMask |= LLVolumeFace::OUTER_MASK; + } } } - } - if (data_is_empty) - { - sculptGeneratePlaceholder(); + for (face_list_t::iterator iter = mVolumeFaces.begin(); + iter != mVolumeFaces.end(); ++iter) + { + (*iter).create(this, partial_build); + } } +} - - for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++) - { - mFaceMask |= mProfilep->mFaces[i].mFaceID; - } - - mSculptLevel = sculpt_level; +inline LLVector3 sculpt_rgb_to_vector(U8 r, U8 g, U8 b) +{ + // maps RGB values to vector values [0..255] -> [-0.5..0.5] + LLVector3 value; + value.mV[VX] = r / 255.f - 0.5f; + value.mV[VY] = g / 255.f - 0.5f; + value.mV[VZ] = b / 255.f - 0.5f; - // Delete any existing faces so that they get regenerated - mVolumeFaces.clear(); - - createVolumeFaces(); + return value; } +inline U32 sculpt_xy_to_index(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components) +{ + U32 index = (x + y * sculpt_width) * sculpt_components; + return index; +} - -BOOL LLVolume::isCap(S32 face) +inline U32 sculpt_st_to_index(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components) { - return mProfilep->mFaces[face].mCap; + U32 x = (U32) ((F32)s/(size_s) * (F32) sculpt_width); + U32 y = (U32) ((F32)t/(size_t) * (F32) sculpt_height); + + return sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components); } -BOOL LLVolume::isFlat(S32 face) + +inline LLVector3 sculpt_index_to_vector(U32 index, const U8* sculpt_data) { - return mProfilep->mFaces[face].mFlat; -} + LLVector3 v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]); + return v; +} -bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const +inline LLVector3 sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) { - return ( (getPathParams() == params.getPathParams()) && - (getProfileParams() == params.getProfileParams()) && - (mSculptID == params.mSculptID) && - (mSculptType == params.mSculptType) ); + U32 index = sculpt_st_to_index(s, t, size_s, size_t, sculpt_width, sculpt_height, sculpt_components); + + return sculpt_index_to_vector(index, sculpt_data); } -bool LLVolumeParams::operator!=(const LLVolumeParams ¶ms) const +inline LLVector3 sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) { - return ( (getPathParams() != params.getPathParams()) || - (getProfileParams() != params.getProfileParams()) || - (mSculptID != params.mSculptID) || - (mSculptType != params.mSculptType) ); + U32 index = sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components); + + return sculpt_index_to_vector(index, sculpt_data); } -bool LLVolumeParams::operator<(const LLVolumeParams ¶ms) const + +F32 LLVolume::sculptGetSurfaceArea() { - if( getPathParams() != params.getPathParams() ) - { - return getPathParams() < params.getPathParams(); - } - - if (getProfileParams() != params.getProfileParams()) - { - return getProfileParams() < params.getProfileParams(); - } - - if (mSculptID != params.mSculptID) - { - return mSculptID < params.mSculptID; - } + // test to see if image has enough variation to create non-degenerate geometry + F32 area = 0; - return mSculptType < params.mSculptType; + S32 sizeS = mPathp->mPath.size(); + S32 sizeT = mProfilep->mProfile.size(); + + for (S32 s = 0; s < sizeS-1; s++) + { + for (S32 t = 0; t < sizeT-1; t++) + { + // get four corners of quad + LLVector3 p1 = mMesh[(s )*sizeT + (t )].mPos; + LLVector3 p2 = mMesh[(s+1)*sizeT + (t )].mPos; + LLVector3 p3 = mMesh[(s )*sizeT + (t+1)].mPos; + LLVector3 p4 = mMesh[(s+1)*sizeT + (t+1)].mPos; + // compute the area of the quad by taking the length of the cross product of the two triangles + LLVector3 cross1 = (p1 - p2) % (p1 - p3); + LLVector3 cross2 = (p4 - p2) % (p4 - p3); + area += (cross1.magVec() + cross2.magVec()) / 2.0; + } + } + return area; } -void LLVolumeParams::copyParams(const LLVolumeParams ¶ms) +// create placeholder shape +void LLVolume::sculptGeneratePlaceholder() { LLMemType m1(LLMemType::MTYPE_VOLUME); - mProfileParams.copyParams(params.mProfileParams); - mPathParams.copyParams(params.mPathParams); - mSculptID = params.getSculptID(); - mSculptType = params.getSculptType(); -} - -// Less restricitve approx 0 for volumes -const F32 APPROXIMATELY_ZERO = 0.001f; -bool approx_zero( F32 f, F32 tolerance = APPROXIMATELY_ZERO) -{ - return (f >= -tolerance) && (f <= tolerance); -} + + S32 sizeS = mPathp->mPath.size(); + S32 sizeT = mProfilep->mProfile.size(); + + S32 line = 0; -// return true if in range (or nearly so) -static bool limit_range(F32& v, F32 min, F32 max, F32 tolerance = APPROXIMATELY_ZERO) -{ - F32 min_delta = v - min; - if (min_delta < 0.f) - { - v = min; - if (!approx_zero(min_delta, tolerance)) - return false; - } - F32 max_delta = max - v; - if (max_delta < 0.f) + // for now, this is a sphere. + for (S32 s = 0; s < sizeS; s++) { - v = max; - if (!approx_zero(max_delta, tolerance)) - return false; - } - return true; -} - -bool LLVolumeParams::setBeginAndEndS(const F32 b, const F32 e) -{ - bool valid = true; - - // First, clamp to valid ranges. - F32 begin = b; - valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); - - F32 end = e; - if (end >= .0149f && end < MIN_CUT_DELTA) end = MIN_CUT_DELTA; // eliminate warning for common rounding error - valid &= limit_range(end, MIN_CUT_DELTA, 1.f); + for (S32 t = 0; t < sizeT; t++) + { + S32 i = t + line; + Point& pt = mMesh[i]; - valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f); + + F32 u = (F32)s/(sizeS-1); + F32 v = (F32)t/(sizeT-1); - // Now set them. - mProfileParams.setBegin(begin); - mProfileParams.setEnd(end); + const F32 RADIUS = (F32) 0.3; + + pt.mPos.mV[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS); + pt.mPos.mV[1] = (F32)(sin(F_PI * v) * sin(2.0 * F_PI * u) * RADIUS); + pt.mPos.mV[2] = (F32)(cos(F_PI * v) * RADIUS); - return valid; + } + line += sizeT; + } } -bool LLVolumeParams::setBeginAndEndT(const F32 b, const F32 e) +// create the vertices from the map +void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type) { - bool valid = true; + U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; + BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; + BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; + BOOL reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR + + + LLMemType m1(LLMemType::MTYPE_VOLUME); + + S32 sizeS = mPathp->mPath.size(); + S32 sizeT = mProfilep->mProfile.size(); + + S32 line = 0; + for (S32 s = 0; s < sizeS; s++) + { + // Run along the profile. + for (S32 t = 0; t < sizeT; t++) + { + S32 i = t + line; + Point& pt = mMesh[i]; - // First, clamp to valid ranges. - F32 begin = b; - valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); + S32 reversed_t = t; - F32 end = e; - valid &= limit_range(end, MIN_CUT_DELTA, 1.f); + if (reverse_horizontal) + { + reversed_t = sizeT - t - 1; + } + + U32 x = (U32) ((F32)reversed_t/(sizeT-1) * (F32) sculpt_width); + U32 y = (U32) ((F32)s/(sizeS-1) * (F32) sculpt_height); - valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f); + + if (y == 0) // top row stitching + { + // pinch? + if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) + { + x = sculpt_width / 2; + } + } - // Now set them. - mPathParams.setBegin(begin); - mPathParams.setEnd(end); + if (y == sculpt_height) // bottom row stitching + { + // wrap? + if (sculpt_stitching == LL_SCULPT_TYPE_TORUS) + { + y = 0; + } + else + { + y = sculpt_height - 1; + } - return valid; -} + // pinch? + if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) + { + x = sculpt_width / 2; + } + } -bool LLVolumeParams::setHollow(const F32 h) -{ - // Validate the hollow based on path and profile. - U8 profile = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - U8 hole_type = mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK; - - F32 max_hollow = HOLLOW_MAX; + if (x == sculpt_width) // side stitching + { + // wrap? + if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) || + (sculpt_stitching == LL_SCULPT_TYPE_TORUS) || + (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER)) + { + x = 0; + } + + else + { + x = sculpt_width - 1; + } + } - // Only square holes have trouble. - if (LL_PCODE_HOLE_SQUARE == hole_type) - { - switch(profile) - { - case LL_PCODE_PROFILE_CIRCLE: - case LL_PCODE_PROFILE_CIRCLE_HALF: - case LL_PCODE_PROFILE_EQUALTRI: - max_hollow = HOLLOW_MAX_SQUARE; + pt.mPos = sculpt_xy_to_vector(x, y, sculpt_width, sculpt_height, sculpt_components, sculpt_data); + + if (sculpt_mirror) + { + pt.mPos.mV[VX] *= -1.f; + } } + + line += sizeT; } +} - F32 hollow = h; - bool valid = limit_range(hollow, HOLLOW_MIN, max_hollow); - mProfileParams.setHollow(hollow); - return valid; -} +const S32 SCULPT_REZ_1 = 6; // changed from 4 to 6 - 6 looks round whereas 4 looks square +const S32 SCULPT_REZ_2 = 8; +const S32 SCULPT_REZ_3 = 16; +const S32 SCULPT_REZ_4 = 32; -bool LLVolumeParams::setTwistBegin(const F32 b) +S32 sculpt_sides(F32 detail) { - F32 twist_begin = b; - bool valid = limit_range(twist_begin, TWIST_MIN, TWIST_MAX); - mPathParams.setTwistBegin(twist_begin); - return valid; -} - -bool LLVolumeParams::setTwistEnd(const F32 e) -{ - F32 twist_end = e; - bool valid = limit_range(twist_end, TWIST_MIN, TWIST_MAX); - mPathParams.setTwistEnd(twist_end); - return valid; -} -bool LLVolumeParams::setRatio(const F32 x, const F32 y) -{ - F32 min_x = RATIO_MIN; - F32 max_x = RATIO_MAX; - F32 min_y = RATIO_MIN; - F32 max_y = RATIO_MAX; - // If this is a circular path (and not a sphere) then 'ratio' is actually hole size. - U8 path_type = mPathParams.getCurveType(); - U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - if ( LL_PCODE_PATH_CIRCLE == path_type && - LL_PCODE_PROFILE_CIRCLE_HALF != profile_type) + // detail is usually one of: 1, 1.5, 2.5, 4.0. + + if (detail <= 1.0) { - // Holes are more restricted... - min_x = HOLE_X_MIN; - max_x = HOLE_X_MAX; - min_y = HOLE_Y_MIN; - max_y = HOLE_Y_MAX; + return SCULPT_REZ_1; + } + if (detail <= 2.0) + { + return SCULPT_REZ_2; + } + if (detail <= 3.0) + { + return SCULPT_REZ_3; + } + else + { + return SCULPT_REZ_4; } - - F32 ratio_x = x; - bool valid = limit_range(ratio_x, min_x, max_x); - F32 ratio_y = y; - valid &= limit_range(ratio_y, min_y, max_y); - - mPathParams.setScale(ratio_x, ratio_y); - - return valid; } -bool LLVolumeParams::setShear(const F32 x, const F32 y) -{ - F32 shear_x = x; - bool valid = limit_range(shear_x, SHEAR_MIN, SHEAR_MAX); - F32 shear_y = y; - valid &= limit_range(shear_y, SHEAR_MIN, SHEAR_MAX); - mPathParams.setShear(shear_x, shear_y); - return valid; -} -bool LLVolumeParams::setTaperX(const F32 v) -{ - F32 taper = v; - bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX); - mPathParams.setTaperX(taper); - return valid; -} -bool LLVolumeParams::setTaperY(const F32 v) +// determine the number of vertices in both s and t direction for this sculpt +void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32& s, S32& t) { - F32 taper = v; - bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX); - mPathParams.setTaperY(taper); - return valid; -} + // this code has the following properties: + // 1) the aspect ratio of the mesh is as close as possible to the ratio of the map + // while still using all available verts + // 2) the mesh cannot have more verts than is allowed by LOD + // 3) the mesh cannot have more verts than is allowed by the map + + S32 max_vertices_lod = (S32)pow((double)sculpt_sides(detail), 2.0); + S32 max_vertices_map = width * height / 4; + + S32 vertices; + if (max_vertices_map > 0) + vertices = llmin(max_vertices_lod, max_vertices_map); + else + vertices = max_vertices_lod; + -bool LLVolumeParams::setRevolutions(const F32 r) -{ - F32 revolutions = r; - bool valid = limit_range(revolutions, REV_MIN, REV_MAX); - mPathParams.setRevolutions(revolutions); - return valid; + F32 ratio; + if ((width == 0) || (height == 0)) + ratio = 1.f; + else + ratio = (F32) width / (F32) height; + + + s = (S32)(F32) sqrt(((F32)vertices / ratio)); + + s = llmax(s, 4); // no degenerate sizes, please + t = vertices / s; + + t = llmax(t, 4); // no degenerate sizes, please + s = vertices / t; } -bool LLVolumeParams::setRadiusOffset(const F32 offset) +// sculpt replaces generate() for sculpted surfaces +void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level) { - bool valid = true; + LLMemType m1(LLMemType::MTYPE_VOLUME); + U8 sculpt_type = mParams.getSculptType(); - // If this is a sphere, just set it to 0 and get out. - U8 path_type = mPathParams.getCurveType(); - U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type || - LL_PCODE_PATH_CIRCLE != path_type ) + BOOL data_is_empty = FALSE; + + if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL) { - mPathParams.setRadiusOffset(0.f); - return true; + sculpt_level = -1; + data_is_empty = TRUE; } - // Limit radius offset, based on taper and hole size y. - F32 radius_offset = offset; - F32 taper_y = getTaperY(); - F32 radius_mag = fabs(radius_offset); - F32 hole_y_mag = fabs(getRatioY()); - F32 taper_y_mag = fabs(taper_y); - // Check to see if the taper effects us. - if ( (radius_offset > 0.f && taper_y < 0.f) || - (radius_offset < 0.f && taper_y > 0.f) ) + S32 requested_sizeS = 0; + S32 requested_sizeT = 0; + + sculpt_calc_mesh_resolution(sculpt_width, sculpt_height, sculpt_type, mDetail, requested_sizeS, requested_sizeT); + + mPathp->generate(mParams.getPathParams(), mDetail, 0, TRUE, requested_sizeS); + mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(), mDetail, 0, TRUE, requested_sizeT); + + S32 sizeS = mPathp->mPath.size(); // we requested a specific size, now see what we really got + S32 sizeT = mProfilep->mProfile.size(); // we requested a specific size, now see what we really got + + // weird crash bug - DEV-11158 - trying to collect more data: + if ((sizeS == 0) || (sizeT == 0)) { - // The taper does not help increase the radius offset range. - taper_y_mag = 0.f; + llwarns << "sculpt bad mesh size " << sizeS << " " << sizeT << llendl; } - F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag); + + sNumMeshPoints -= mMesh.size(); + mMesh.resize(sizeS * sizeT); + sNumMeshPoints += mMesh.size(); - // Enforce the maximum magnitude. - F32 delta = max_radius_mag - radius_mag; - if (delta < 0.f) + //generate vertex positions + if (!data_is_empty) { - // Check radius offset sign. - if (radius_offset < 0.f) - { - radius_offset = -max_radius_mag; - } - else + sculptGenerateMapVertices(sculpt_width, sculpt_height, sculpt_components, sculpt_data, sculpt_type); + + // don't test lowest LOD to support legacy content DEV-33670 + if (mDetail > SCULPT_MIN_AREA_DETAIL) { - radius_offset = max_radius_mag; + if (sculptGetSurfaceArea() < SCULPT_MIN_AREA) + { + data_is_empty = TRUE; + } } - valid = approx_zero(delta, .1f); } - mPathParams.setRadiusOffset(radius_offset); - return valid; + if (data_is_empty) + { + sculptGeneratePlaceholder(); + } + + + + for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++) + { + mFaceMask |= mProfilep->mFaces[i].mFaceID; + } + + mSculptLevel = sculpt_level; + + // Delete any existing faces so that they get regenerated + mVolumeFaces.clear(); + + createVolumeFaces(); } -bool LLVolumeParams::setSkew(const F32 skew_value) + + + +BOOL LLVolume::isCap(S32 face) { - bool valid = true; + return mProfilep->mFaces[face].mCap; +} - // Check the skew value against the revolutions. - F32 skew = llclamp(skew_value, SKEW_MIN, SKEW_MAX); - F32 skew_mag = fabs(skew); - F32 revolutions = getRevolutions(); - F32 scale_x = getRatioX(); - F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f); - // Discontinuity; A revolution of 1 allows skews below 0.5. - if ( fabs(revolutions - 1.0f) < 0.001) - min_skew_mag = 0.0f; +BOOL LLVolume::isFlat(S32 face) +{ + return mProfilep->mFaces[face].mFlat; +} - // Clip skew. - F32 delta = skew_mag - min_skew_mag; - if (delta < 0.f) - { - // Check skew sign. - if (skew < 0.0f) - { - skew = -min_skew_mag; - } - else - { - skew = min_skew_mag; - } - valid = approx_zero(delta, .01f); - } - mPathParams.setSkew(skew); - return valid; +bool LLVolumeParams::isSculpt() const +{ + return mSculptID.notNull(); } -bool LLVolumeParams::setSculptID(const LLUUID sculpt_id, U8 sculpt_type) +bool LLVolumeParams::isMeshSculpt() const { - mSculptID = sculpt_id; - mSculptType = sculpt_type; - return true; + return isSculpt() && ((mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH); } -bool LLVolumeParams::setType(U8 profile, U8 path) +bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const { - bool result = true; - // First, check profile and path for validity. - U8 profile_type = profile & LL_PCODE_PROFILE_MASK; - U8 hole_type = (profile & LL_PCODE_HOLE_MASK) >> 4; - U8 path_type = path >> 4; + return ( (getPathParams() == params.getPathParams()) && + (getProfileParams() == params.getProfileParams()) && + (mSculptID == params.mSculptID) && + (mSculptType == params.mSculptType) ); +} - if (profile_type > LL_PCODE_PROFILE_MAX) +bool LLVolumeParams::operator!=(const LLVolumeParams ¶ms) const +{ + return ( (getPathParams() != params.getPathParams()) || + (getProfileParams() != params.getProfileParams()) || + (mSculptID != params.mSculptID) || + (mSculptType != params.mSculptType) ); +} + +bool LLVolumeParams::operator<(const LLVolumeParams ¶ms) const +{ + if( getPathParams() != params.getPathParams() ) { - // Bad profile. Make it square. - profile = LL_PCODE_PROFILE_SQUARE; - result = false; - llwarns << "LLVolumeParams::setType changing bad profile type (" << profile_type - << ") to be LL_PCODE_PROFILE_SQUARE" << llendl; + return getPathParams() < params.getPathParams(); } - else if (hole_type > LL_PCODE_HOLE_MAX) + + if (getProfileParams() != params.getProfileParams()) { - // Bad hole. Make it the same. - profile = profile_type; - result = false; - llwarns << "LLVolumeParams::setType changing bad hole type (" << hole_type - << ") to be LL_PCODE_HOLE_SAME" << llendl; + return getProfileParams() < params.getProfileParams(); } - - if (path_type < LL_PCODE_PATH_MIN || - path_type > LL_PCODE_PATH_MAX) + + if (mSculptID != params.mSculptID) { - // Bad path. Make it linear. - result = false; - llwarns << "LLVolumeParams::setType changing bad path (" << path - << ") to be LL_PCODE_PATH_LINE" << llendl; - path = LL_PCODE_PATH_LINE; + return mSculptID < params.mSculptID; } - mProfileParams.setCurveType(profile); - mPathParams.setCurveType(path); - return result; + return mSculptType < params.mSculptType; + + } -// static -bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow, - U8 path_curve, F32 path_begin, F32 path_end, - F32 scx, F32 scy, F32 shx, F32 shy, - F32 twistend, F32 twistbegin, F32 radiusoffset, - F32 tx, F32 ty, F32 revolutions, F32 skew) +void LLVolumeParams::copyParams(const LLVolumeParams ¶ms) { - LLVolumeParams test_params; - if (!test_params.setType (prof_curve, path_curve)) + LLMemType m1(LLMemType::MTYPE_VOLUME); + mProfileParams.copyParams(params.mProfileParams); + mPathParams.copyParams(params.mPathParams); + mSculptID = params.getSculptID(); + mSculptType = params.getSculptType(); +} + +// Less restricitve approx 0 for volumes +const F32 APPROXIMATELY_ZERO = 0.001f; +bool approx_zero( F32 f, F32 tolerance = APPROXIMATELY_ZERO) +{ + return (f >= -tolerance) && (f <= tolerance); +} + +// return true if in range (or nearly so) +static bool limit_range(F32& v, F32 min, F32 max, F32 tolerance = APPROXIMATELY_ZERO) +{ + F32 min_delta = v - min; + if (min_delta < 0.f) { - return false; + v = min; + if (!approx_zero(min_delta, tolerance)) + return false; + } + F32 max_delta = max - v; + if (max_delta < 0.f) + { + v = max; + if (!approx_zero(max_delta, tolerance)) + return false; + } + return true; +} + +bool LLVolumeParams::setBeginAndEndS(const F32 b, const F32 e) +{ + bool valid = true; + + // First, clamp to valid ranges. + F32 begin = b; + valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); + + F32 end = e; + if (end >= .0149f && end < MIN_CUT_DELTA) end = MIN_CUT_DELTA; // eliminate warning for common rounding error + valid &= limit_range(end, MIN_CUT_DELTA, 1.f); + + valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f); + + // Now set them. + mProfileParams.setBegin(begin); + mProfileParams.setEnd(end); + + return valid; +} + +bool LLVolumeParams::setBeginAndEndT(const F32 b, const F32 e) +{ + bool valid = true; + + // First, clamp to valid ranges. + F32 begin = b; + valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); + + F32 end = e; + valid &= limit_range(end, MIN_CUT_DELTA, 1.f); + + valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f); + + // Now set them. + mPathParams.setBegin(begin); + mPathParams.setEnd(end); + + return valid; +} + +bool LLVolumeParams::setHollow(const F32 h) +{ + // Validate the hollow based on path and profile. + U8 profile = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; + U8 hole_type = mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK; + + F32 max_hollow = HOLLOW_MAX; + + // Only square holes have trouble. + if (LL_PCODE_HOLE_SQUARE == hole_type) + { + switch(profile) + { + case LL_PCODE_PROFILE_CIRCLE: + case LL_PCODE_PROFILE_CIRCLE_HALF: + case LL_PCODE_PROFILE_EQUALTRI: + max_hollow = HOLLOW_MAX_SQUARE; + } + } + + F32 hollow = h; + bool valid = limit_range(hollow, HOLLOW_MIN, max_hollow); + mProfileParams.setHollow(hollow); + + return valid; +} + +bool LLVolumeParams::setTwistBegin(const F32 b) +{ + F32 twist_begin = b; + bool valid = limit_range(twist_begin, TWIST_MIN, TWIST_MAX); + mPathParams.setTwistBegin(twist_begin); + return valid; +} + +bool LLVolumeParams::setTwistEnd(const F32 e) +{ + F32 twist_end = e; + bool valid = limit_range(twist_end, TWIST_MIN, TWIST_MAX); + mPathParams.setTwistEnd(twist_end); + return valid; +} + +bool LLVolumeParams::setRatio(const F32 x, const F32 y) +{ + F32 min_x = RATIO_MIN; + F32 max_x = RATIO_MAX; + F32 min_y = RATIO_MIN; + F32 max_y = RATIO_MAX; + // If this is a circular path (and not a sphere) then 'ratio' is actually hole size. + U8 path_type = mPathParams.getCurveType(); + U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; + if ( LL_PCODE_PATH_CIRCLE == path_type && + LL_PCODE_PROFILE_CIRCLE_HALF != profile_type) + { + // Holes are more restricted... + min_x = HOLE_X_MIN; + max_x = HOLE_X_MAX; + min_y = HOLE_Y_MIN; + max_y = HOLE_Y_MAX; + } + + F32 ratio_x = x; + bool valid = limit_range(ratio_x, min_x, max_x); + F32 ratio_y = y; + valid &= limit_range(ratio_y, min_y, max_y); + + mPathParams.setScale(ratio_x, ratio_y); + + return valid; +} + +bool LLVolumeParams::setShear(const F32 x, const F32 y) +{ + F32 shear_x = x; + bool valid = limit_range(shear_x, SHEAR_MIN, SHEAR_MAX); + F32 shear_y = y; + valid &= limit_range(shear_y, SHEAR_MIN, SHEAR_MAX); + mPathParams.setShear(shear_x, shear_y); + return valid; +} + +bool LLVolumeParams::setTaperX(const F32 v) +{ + F32 taper = v; + bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX); + mPathParams.setTaperX(taper); + return valid; +} + +bool LLVolumeParams::setTaperY(const F32 v) +{ + F32 taper = v; + bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX); + mPathParams.setTaperY(taper); + return valid; +} + +bool LLVolumeParams::setRevolutions(const F32 r) +{ + F32 revolutions = r; + bool valid = limit_range(revolutions, REV_MIN, REV_MAX); + mPathParams.setRevolutions(revolutions); + return valid; +} + +bool LLVolumeParams::setRadiusOffset(const F32 offset) +{ + bool valid = true; + + // If this is a sphere, just set it to 0 and get out. + U8 path_type = mPathParams.getCurveType(); + U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; + if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type || + LL_PCODE_PATH_CIRCLE != path_type ) + { + mPathParams.setRadiusOffset(0.f); + return true; + } + + // Limit radius offset, based on taper and hole size y. + F32 radius_offset = offset; + F32 taper_y = getTaperY(); + F32 radius_mag = fabs(radius_offset); + F32 hole_y_mag = fabs(getRatioY()); + F32 taper_y_mag = fabs(taper_y); + // Check to see if the taper effects us. + if ( (radius_offset > 0.f && taper_y < 0.f) || + (radius_offset < 0.f && taper_y > 0.f) ) + { + // The taper does not help increase the radius offset range. + taper_y_mag = 0.f; + } + F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag); + + // Enforce the maximum magnitude. + F32 delta = max_radius_mag - radius_mag; + if (delta < 0.f) + { + // Check radius offset sign. + if (radius_offset < 0.f) + { + radius_offset = -max_radius_mag; + } + else + { + radius_offset = max_radius_mag; + } + valid = approx_zero(delta, .1f); + } + + mPathParams.setRadiusOffset(radius_offset); + return valid; +} + +bool LLVolumeParams::setSkew(const F32 skew_value) +{ + bool valid = true; + + // Check the skew value against the revolutions. + F32 skew = llclamp(skew_value, SKEW_MIN, SKEW_MAX); + F32 skew_mag = fabs(skew); + F32 revolutions = getRevolutions(); + F32 scale_x = getRatioX(); + F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f); + // Discontinuity; A revolution of 1 allows skews below 0.5. + if ( fabs(revolutions - 1.0f) < 0.001) + min_skew_mag = 0.0f; + + // Clip skew. + F32 delta = skew_mag - min_skew_mag; + if (delta < 0.f) + { + // Check skew sign. + if (skew < 0.0f) + { + skew = -min_skew_mag; + } + else + { + skew = min_skew_mag; + } + valid = approx_zero(delta, .01f); + } + + mPathParams.setSkew(skew); + return valid; +} + +bool LLVolumeParams::setSculptID(const LLUUID sculpt_id, U8 sculpt_type) +{ + mSculptID = sculpt_id; + mSculptType = sculpt_type; + return true; +} + +bool LLVolumeParams::setType(U8 profile, U8 path) +{ + bool result = true; + // First, check profile and path for validity. + U8 profile_type = profile & LL_PCODE_PROFILE_MASK; + U8 hole_type = (profile & LL_PCODE_HOLE_MASK) >> 4; + U8 path_type = path >> 4; + + if (profile_type > LL_PCODE_PROFILE_MAX) + { + // Bad profile. Make it square. + profile = LL_PCODE_PROFILE_SQUARE; + result = false; + llwarns << "LLVolumeParams::setType changing bad profile type (" << profile_type + << ") to be LL_PCODE_PROFILE_SQUARE" << llendl; + } + else if (hole_type > LL_PCODE_HOLE_MAX) + { + // Bad hole. Make it the same. + profile = profile_type; + result = false; + llwarns << "LLVolumeParams::setType changing bad hole type (" << hole_type + << ") to be LL_PCODE_HOLE_SAME" << llendl; + } + + if (path_type < LL_PCODE_PATH_MIN || + path_type > LL_PCODE_PATH_MAX) + { + // Bad path. Make it linear. + result = false; + llwarns << "LLVolumeParams::setType changing bad path (" << path + << ") to be LL_PCODE_PATH_LINE" << llendl; + path = LL_PCODE_PATH_LINE; + } + + mProfileParams.setCurveType(profile); + mPathParams.setCurveType(path); + return result; +} + +// static +bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow, + U8 path_curve, F32 path_begin, F32 path_end, + F32 scx, F32 scy, F32 shx, F32 shy, + F32 twistend, F32 twistbegin, F32 radiusoffset, + F32 tx, F32 ty, F32 revolutions, F32 skew) +{ + LLVolumeParams test_params; + if (!test_params.setType (prof_curve, path_curve)) + { + return false; } if (!test_params.setBeginAndEndS (prof_begin, prof_end)) { @@ -2692,1768 +3480,2536 @@ bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 h return true; } -S32 *LLVolume::getTriangleIndices(U32 &num_indices) const -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - S32 expected_num_triangle_indices = getNumTriangleIndices(); - if (expected_num_triangle_indices > MAX_VOLUME_TRIANGLE_INDICES) - { - // we don't allow LLVolumes with this many vertices - llwarns << "Couldn't allocate triangle indices" << llendl; - num_indices = 0; - return NULL; - } +S32 *LLVolume::getTriangleIndices(U32 &num_indices) const +{ + LLMemType m1(LLMemType::MTYPE_VOLUME); + + S32 expected_num_triangle_indices = getNumTriangleIndices(); + if (expected_num_triangle_indices > MAX_VOLUME_TRIANGLE_INDICES) + { + // we don't allow LLVolumes with this many vertices + llwarns << "Couldn't allocate triangle indices" << llendl; + num_indices = 0; + return NULL; + } + + S32* index = new S32[expected_num_triangle_indices]; + S32 count = 0; + + // Let's do this totally diffently, as we don't care about faces... + // Counter-clockwise triangles are forward facing... + + BOOL open = getProfile().isOpen(); + BOOL hollow = (mParams.getProfileParams().getHollow() > 0); + BOOL path_open = getPath().isOpen(); + S32 size_s, size_s_out, size_t; + S32 s, t, i; + size_s = getProfile().getTotal(); + size_s_out = getProfile().getTotalOut(); + size_t = getPath().mPath.size(); + + // NOTE -- if the construction of the triangles below ever changes + // then getNumTriangleIndices() method may also have to be updated. + + if (open) /* Flawfinder: ignore */ + { + if (hollow) + { + // Open hollow -- much like the closed solid, except we + // we need to stitch up the gap between s=0 and s=size_s-1 + + for (t = 0; t < size_t - 1; t++) + { + // The outer face, first cut, and inner face + for (s = 0; s < size_s - 1; s++) + { + i = s + t*size_s; + index[count++] = i; // x,y + index[count++] = i + 1; // x+1,y + index[count++] = i + size_s; // x,y+1 + + index[count++] = i + size_s; // x,y+1 + index[count++] = i + 1; // x+1,y + index[count++] = i + size_s + 1; // x+1,y+1 + } + + // The other cut face + index[count++] = s + t*size_s; // x,y + index[count++] = 0 + t*size_s; // x+1,y + index[count++] = s + (t+1)*size_s; // x,y+1 + + index[count++] = s + (t+1)*size_s; // x,y+1 + index[count++] = 0 + t*size_s; // x+1,y + index[count++] = 0 + (t+1)*size_s; // x+1,y+1 + } + + // Do the top and bottom caps, if necessary + if (path_open) + { + // Top cap + S32 pt1 = 0; + S32 pt2 = size_s-1; + S32 i = (size_t - 1)*size_s; + + while (pt2 - pt1 > 1) + { + // Use the profile points instead of the mesh, since you want + // the un-transformed profile distances. + LLVector3 p1 = getProfile().mProfile[pt1]; + LLVector3 p2 = getProfile().mProfile[pt2]; + LLVector3 pa = getProfile().mProfile[pt1+1]; + LLVector3 pb = getProfile().mProfile[pt2-1]; + + p1.mV[VZ] = 0.f; + p2.mV[VZ] = 0.f; + pa.mV[VZ] = 0.f; + pb.mV[VZ] = 0.f; + + // Use area of triangle to determine backfacing + F32 area_1a2, area_1ba, area_21b, area_2ab; + area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + + (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + + (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - S32* index = new S32[expected_num_triangle_indices]; - S32 count = 0; + area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + + (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + + (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - // Let's do this totally diffently, as we don't care about faces... - // Counter-clockwise triangles are forward facing... + area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + + (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + + (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - BOOL open = getProfile().isOpen(); - BOOL hollow = (mParams.getProfileParams().getHollow() > 0); - BOOL path_open = getPath().isOpen(); - S32 size_s, size_s_out, size_t; - S32 s, t, i; - size_s = getProfile().getTotal(); - size_s_out = getProfile().getTotalOut(); - size_t = getPath().mPath.size(); + area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + + (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + + (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - // NOTE -- if the construction of the triangles below ever changes - // then getNumTriangleIndices() method may also have to be updated. + BOOL use_tri1a2 = TRUE; + BOOL tri_1a2 = TRUE; + BOOL tri_21b = TRUE; - if (open) /* Flawfinder: ignore */ - { - if (hollow) + if (area_1a2 < 0) + { + tri_1a2 = FALSE; + } + if (area_2ab < 0) + { + // Can't use, because it contains point b + tri_1a2 = FALSE; + } + if (area_21b < 0) + { + tri_21b = FALSE; + } + if (area_1ba < 0) + { + // Can't use, because it contains point b + tri_21b = FALSE; + } + + if (!tri_1a2) + { + use_tri1a2 = FALSE; + } + else if (!tri_21b) + { + use_tri1a2 = TRUE; + } + else + { + LLVector3 d1 = p1 - pa; + LLVector3 d2 = p2 - pb; + + if (d1.magVecSquared() < d2.magVecSquared()) + { + use_tri1a2 = TRUE; + } + else + { + use_tri1a2 = FALSE; + } + } + + if (use_tri1a2) + { + index[count++] = pt1 + i; + index[count++] = pt1 + 1 + i; + index[count++] = pt2 + i; + pt1++; + } + else + { + index[count++] = pt1 + i; + index[count++] = pt2 - 1 + i; + index[count++] = pt2 + i; + pt2--; + } + } + + // Bottom cap + pt1 = 0; + pt2 = size_s-1; + while (pt2 - pt1 > 1) + { + // Use the profile points instead of the mesh, since you want + // the un-transformed profile distances. + LLVector3 p1 = getProfile().mProfile[pt1]; + LLVector3 p2 = getProfile().mProfile[pt2]; + LLVector3 pa = getProfile().mProfile[pt1+1]; + LLVector3 pb = getProfile().mProfile[pt2-1]; + + p1.mV[VZ] = 0.f; + p2.mV[VZ] = 0.f; + pa.mV[VZ] = 0.f; + pb.mV[VZ] = 0.f; + + // Use area of triangle to determine backfacing + F32 area_1a2, area_1ba, area_21b, area_2ab; + area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + + (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + + (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); + + area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + + (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + + (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); + + area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + + (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + + (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + + area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + + (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + + (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + + BOOL use_tri1a2 = TRUE; + BOOL tri_1a2 = TRUE; + BOOL tri_21b = TRUE; + + if (area_1a2 < 0) + { + tri_1a2 = FALSE; + } + if (area_2ab < 0) + { + // Can't use, because it contains point b + tri_1a2 = FALSE; + } + if (area_21b < 0) + { + tri_21b = FALSE; + } + if (area_1ba < 0) + { + // Can't use, because it contains point b + tri_21b = FALSE; + } + + if (!tri_1a2) + { + use_tri1a2 = FALSE; + } + else if (!tri_21b) + { + use_tri1a2 = TRUE; + } + else + { + LLVector3 d1 = p1 - pa; + LLVector3 d2 = p2 - pb; + + if (d1.magVecSquared() < d2.magVecSquared()) + { + use_tri1a2 = TRUE; + } + else + { + use_tri1a2 = FALSE; + } + } + + if (use_tri1a2) + { + index[count++] = pt1; + index[count++] = pt2; + index[count++] = pt1 + 1; + pt1++; + } + else + { + index[count++] = pt1; + index[count++] = pt2; + index[count++] = pt2 - 1; + pt2--; + } + } + } + } + else { - // Open hollow -- much like the closed solid, except we - // we need to stitch up the gap between s=0 and s=size_s-1 + // Open solid for (t = 0; t < size_t - 1; t++) { - // The outer face, first cut, and inner face + // Outer face + 1 cut face for (s = 0; s < size_s - 1; s++) { i = s + t*size_s; + index[count++] = i; // x,y index[count++] = i + 1; // x+1,y index[count++] = i + size_s; // x,y+1 - + index[count++] = i + size_s; // x,y+1 index[count++] = i + 1; // x+1,y index[count++] = i + size_s + 1; // x+1,y+1 } - // The other cut face - index[count++] = s + t*size_s; // x,y - index[count++] = 0 + t*size_s; // x+1,y - index[count++] = s + (t+1)*size_s; // x,y+1 - - index[count++] = s + (t+1)*size_s; // x,y+1 - index[count++] = 0 + t*size_s; // x+1,y - index[count++] = 0 + (t+1)*size_s; // x+1,y+1 + // The other cut face + index[count++] = (size_s - 1) + (t*size_s); // x,y + index[count++] = 0 + t*size_s; // x+1,y + index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1 + + index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1 + index[count++] = 0 + (t*size_s); // x+1,y + index[count++] = 0 + (t+1)*size_s; // x+1,y+1 + } + + // Do the top and bottom caps, if necessary + if (path_open) + { + for (s = 0; s < size_s - 2; s++) + { + index[count++] = s+1; + index[count++] = s; + index[count++] = size_s - 1; + } + + // We've got a top cap + S32 offset = (size_t - 1)*size_s; + for (s = 0; s < size_s - 2; s++) + { + // Inverted ordering from bottom cap. + index[count++] = offset + size_s - 1; + index[count++] = offset + s; + index[count++] = offset + s + 1; + } + } + } + } + else if (hollow) + { + // Closed hollow + // Outer face + + for (t = 0; t < size_t - 1; t++) + { + for (s = 0; s < size_s_out - 1; s++) + { + i = s + t*size_s; + + index[count++] = i; // x,y + index[count++] = i + 1; // x+1,y + index[count++] = i + size_s; // x,y+1 + + index[count++] = i + size_s; // x,y+1 + index[count++] = i + 1; // x+1,y + index[count++] = i + 1 + size_s; // x+1,y+1 } + } - // Do the top and bottom caps, if necessary - if (path_open) + // Inner face + // Invert facing from outer face + for (t = 0; t < size_t - 1; t++) + { + for (s = size_s_out; s < size_s - 1; s++) { - // Top cap - S32 pt1 = 0; - S32 pt2 = size_s-1; - S32 i = (size_t - 1)*size_s; + i = s + t*size_s; - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; + index[count++] = i; // x,y + index[count++] = i + 1; // x+1,y + index[count++] = i + size_s; // x,y+1 - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; + index[count++] = i + size_s; // x,y+1 + index[count++] = i + 1; // x+1,y + index[count++] = i + 1 + size_s; // x+1,y+1 + } + } - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); + // Do the top and bottom caps, if necessary + if (path_open) + { + // Top cap + S32 pt1 = 0; + S32 pt2 = size_s-1; + S32 i = (size_t - 1)*size_s; - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); + while (pt2 - pt1 > 1) + { + // Use the profile points instead of the mesh, since you want + // the un-transformed profile distances. + LLVector3 p1 = getProfile().mProfile[pt1]; + LLVector3 p2 = getProfile().mProfile[pt2]; + LLVector3 pa = getProfile().mProfile[pt1+1]; + LLVector3 pb = getProfile().mProfile[pt2-1]; - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + p1.mV[VZ] = 0.f; + p2.mV[VZ] = 0.f; + pa.mV[VZ] = 0.f; + pb.mV[VZ] = 0.f; - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + // Use area of triangle to determine backfacing + F32 area_1a2, area_1ba, area_21b, area_2ab; + area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + + (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + + (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; + area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + + (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + + (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } + area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + + (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + + (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; + area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + + (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + + (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } + BOOL use_tri1a2 = TRUE; + BOOL tri_1a2 = TRUE; + BOOL tri_21b = TRUE; - if (use_tri1a2) + if (area_1a2 < 0) + { + tri_1a2 = FALSE; + } + if (area_2ab < 0) + { + // Can't use, because it contains point b + tri_1a2 = FALSE; + } + if (area_21b < 0) + { + tri_21b = FALSE; + } + if (area_1ba < 0) + { + // Can't use, because it contains point b + tri_21b = FALSE; + } + + if (!tri_1a2) + { + use_tri1a2 = FALSE; + } + else if (!tri_21b) + { + use_tri1a2 = TRUE; + } + else + { + LLVector3 d1 = p1 - pa; + LLVector3 d2 = p2 - pb; + + if (d1.magVecSquared() < d2.magVecSquared()) { - index[count++] = pt1 + i; - index[count++] = pt1 + 1 + i; - index[count++] = pt2 + i; - pt1++; + use_tri1a2 = TRUE; } else { - index[count++] = pt1 + i; - index[count++] = pt2 - 1 + i; - index[count++] = pt2 + i; - pt2--; + use_tri1a2 = FALSE; } } - // Bottom cap - pt1 = 0; - pt2 = size_s-1; - while (pt2 - pt1 > 1) + if (use_tri1a2) { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; + index[count++] = pt1 + i; + index[count++] = pt1 + 1 + i; + index[count++] = pt2 + i; + pt1++; + } + else + { + index[count++] = pt1 + i; + index[count++] = pt2 - 1 + i; + index[count++] = pt2 + i; + pt2--; + } + } - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; + // Bottom cap + pt1 = 0; + pt2 = size_s-1; + while (pt2 - pt1 > 1) + { + // Use the profile points instead of the mesh, since you want + // the un-transformed profile distances. + LLVector3 p1 = getProfile().mProfile[pt1]; + LLVector3 p2 = getProfile().mProfile[pt2]; + LLVector3 pa = getProfile().mProfile[pt1+1]; + LLVector3 pb = getProfile().mProfile[pt2-1]; - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); + p1.mV[VZ] = 0.f; + p2.mV[VZ] = 0.f; + pa.mV[VZ] = 0.f; + pb.mV[VZ] = 0.f; - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); + // Use area of triangle to determine backfacing + F32 area_1a2, area_1ba, area_21b, area_2ab; + area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + + (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + + (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + + (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + + (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + + (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + + (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + + area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + + (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + + (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; + BOOL use_tri1a2 = TRUE; + BOOL tri_1a2 = TRUE; + BOOL tri_21b = TRUE; - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } + if (area_1a2 < 0) + { + tri_1a2 = FALSE; + } + if (area_2ab < 0) + { + // Can't use, because it contains point b + tri_1a2 = FALSE; + } + if (area_21b < 0) + { + tri_21b = FALSE; + } + if (area_1ba < 0) + { + // Can't use, because it contains point b + tri_21b = FALSE; + } - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) + if (!tri_1a2) + { + use_tri1a2 = FALSE; + } + else if (!tri_21b) + { + use_tri1a2 = TRUE; + } + else + { + LLVector3 d1 = p1 - pa; + LLVector3 d2 = p2 - pb; + + if (d1.magVecSquared() < d2.magVecSquared()) { use_tri1a2 = TRUE; } else { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } + use_tri1a2 = FALSE; } + } - if (use_tri1a2) - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt1 + 1; - pt1++; - } - else - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt2 - 1; - pt2--; - } + if (use_tri1a2) + { + index[count++] = pt1; + index[count++] = pt2; + index[count++] = pt1 + 1; + pt1++; + } + else + { + index[count++] = pt1; + index[count++] = pt2; + index[count++] = pt2 - 1; + pt2--; } } + } + } + else + { + // Closed solid. Easy case. + for (t = 0; t < size_t - 1; t++) + { + for (s = 0; s < size_s - 1; s++) + { + // Should wrap properly, but for now... + i = s + t*size_s; + + index[count++] = i; // x,y + index[count++] = i + 1; // x+1,y + index[count++] = i + size_s; // x,y+1 + + index[count++] = i + size_s; // x,y+1 + index[count++] = i + 1; // x+1,y + index[count++] = i + size_s + 1; // x+1,y+1 + } } - else + + // Do the top and bottom caps, if necessary + if (path_open) { - // Open solid + // bottom cap + for (s = 1; s < size_s - 2; s++) + { + index[count++] = s+1; + index[count++] = s; + index[count++] = 0; + } - for (t = 0; t < size_t - 1; t++) + // top cap + S32 offset = (size_t - 1)*size_s; + for (s = 1; s < size_s - 2; s++) { - // Outer face + 1 cut face - for (s = 0; s < size_s - 1; s++) - { - i = s + t*size_s; + // Inverted ordering from bottom cap. + index[count++] = offset; + index[count++] = offset + s; + index[count++] = offset + s + 1; + } + } + } - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 +#ifdef LL_DEBUG + // assert that we computed the correct number of indices + if (count != expected_num_triangle_indices ) + { + llerrs << "bad index count prediciton:" + << " expected=" << expected_num_triangle_indices + << " actual=" << count << llendl; + } +#endif - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s + 1; // x+1,y+1 - } +#if 0 + // verify that each index does not point beyond the size of the mesh + S32 num_vertices = mMesh.size(); + for (i = 0; i < count; i+=3) + { + llinfos << index[i] << ":" << index[i+1] << ":" << index[i+2] << llendl; + llassert(index[i] < num_vertices); + llassert(index[i+1] < num_vertices); + llassert(index[i+2] < num_vertices); + } +#endif - // The other cut face - index[count++] = (size_s - 1) + (t*size_s); // x,y - index[count++] = 0 + t*size_s; // x+1,y - index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1 + num_indices = count; + return index; +} - index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1 - index[count++] = 0 + (t*size_s); // x+1,y - index[count++] = 0 + (t+1)*size_s; // x+1,y+1 - } +S32 LLVolume::getNumTriangleIndices() const +{ + BOOL profile_open = getProfile().isOpen(); + BOOL hollow = (mParams.getProfileParams().getHollow() > 0); + BOOL path_open = getPath().isOpen(); - // Do the top and bottom caps, if necessary - if (path_open) - { - for (s = 0; s < size_s - 2; s++) - { - index[count++] = s+1; - index[count++] = s; - index[count++] = size_s - 1; - } + S32 size_s, size_s_out, size_t; + size_s = getProfile().getTotal(); + size_s_out = getProfile().getTotalOut(); + size_t = getPath().mPath.size(); - // We've got a top cap - S32 offset = (size_t - 1)*size_s; - for (s = 0; s < size_s - 2; s++) - { - // Inverted ordering from bottom cap. - index[count++] = offset + size_s - 1; - index[count++] = offset + s; - index[count++] = offset + s + 1; - } - } + S32 count = 0; + if (profile_open) /* Flawfinder: ignore */ + { + if (hollow) + { + // Open hollow -- much like the closed solid, except we + // we need to stitch up the gap between s=0 and s=size_s-1 + count = (size_t - 1) * (((size_s -1) * 6) + 6); + } + else + { + count = (size_t - 1) * (((size_s -1) * 6) + 6); } } else if (hollow) { // Closed hollow // Outer face - - for (t = 0; t < size_t - 1; t++) + count = (size_t - 1) * (size_s_out - 1) * 6; + + // Inner face + count += (size_t - 1) * ((size_s - 1) - size_s_out) * 6; + } + else + { + // Closed solid. Easy case. + count = (size_t - 1) * (size_s - 1) * 6; + } + + if (path_open) + { + S32 cap_triangle_count = size_s - 3; + if ( profile_open + || hollow ) { - for (s = 0; s < size_s_out - 1; s++) - { - i = s + t*size_s; + cap_triangle_count = size_s - 2; + } + if ( cap_triangle_count > 0 ) + { + // top and bottom caps + count += cap_triangle_count * 2 * 3; + } + } + return count; +} - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + 1 + size_s; // x+1,y+1 - } - } +S32 LLVolume::getNumTriangles() const +{ + U32 triangle_count = 0; - // Inner face - // Invert facing from outer face - for (t = 0; t < size_t - 1; t++) - { - for (s = size_s_out; s < size_s - 1; s++) - { - i = s + t*size_s; + for (S32 i = 0; i < getNumVolumeFaces(); ++i) + { + triangle_count += getVolumeFace(i).mNumIndices/3; + } - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 + return triangle_count; +} - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + 1 + size_s; // x+1,y+1 - } - } - // Do the top and bottom caps, if necessary - if (path_open) - { - // Top cap - S32 pt1 = 0; - S32 pt2 = size_s-1; - S32 i = (size_t - 1)*size_s; +//----------------------------------------------------------------------------- +// generateSilhouetteVertices() +//----------------------------------------------------------------------------- +void LLVolume::generateSilhouetteVertices(std::vector &vertices, + std::vector &normals, + std::vector &segments, + const LLVector3& obj_cam_vec_in, + const LLMatrix4& mat_in, + const LLMatrix3& norm_mat_in, + S32 face_mask) +{ + LLMemType m1(LLMemType::MTYPE_VOLUME); - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; + LLMatrix4a mat; + mat.loadu(mat_in); - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; + LLMatrix4a norm_mat; + norm_mat.loadu(norm_mat_in); + + LLVector4a obj_cam_vec; + obj_cam_vec.load3(obj_cam_vec_in.mV); - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); + vertices.clear(); + normals.clear(); + segments.clear(); - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); + if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) + { + return; + } + + S32 cur_index = 0; + //for each face + for (face_list_t::iterator iter = mVolumeFaces.begin(); + iter != mVolumeFaces.end(); ++iter) + { + LLVolumeFace& face = *iter; + + if (!(face_mask & (0x1 << cur_index++)) || + face.mNumIndices == 0 || face.mEdge.empty()) + { + continue; + } - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) { + + } + else { - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + //============================================== + //DEBUG draw edge map instead of silhouette edge + //============================================== - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; +#if DEBUG_SILHOUETTE_EDGE_MAP - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } + //for each triangle + U32 count = face.mNumIndices; + for (U32 j = 0; j < count/3; j++) { + //get vertices + S32 v1 = face.mIndices[j*3+0]; + S32 v2 = face.mIndices[j*3+1]; + S32 v3 = face.mIndices[j*3+2]; - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; + //get current face center + LLVector3 cCenter = (face.mVertices[v1].getPosition() + + face.mVertices[v2].getPosition() + + face.mVertices[v3].getPosition()) / 3.0f; - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; + //for each edge + for (S32 k = 0; k < 3; k++) { + S32 nIndex = face.mEdge[j*3+k]; + if (nIndex <= -1) { + continue; } - else - { - use_tri1a2 = FALSE; + + if (nIndex >= (S32) count/3) { + continue; } - } + //get neighbor vertices + v1 = face.mIndices[nIndex*3+0]; + v2 = face.mIndices[nIndex*3+1]; + v3 = face.mIndices[nIndex*3+2]; - if (use_tri1a2) - { - index[count++] = pt1 + i; - index[count++] = pt1 + 1 + i; - index[count++] = pt2 + i; - pt1++; - } - else - { - index[count++] = pt1 + i; - index[count++] = pt2 - 1 + i; - index[count++] = pt2 + i; - pt2--; + //get neighbor face center + LLVector3 nCenter = (face.mVertices[v1].getPosition() + + face.mVertices[v2].getPosition() + + face.mVertices[v3].getPosition()) / 3.0f; + + //draw line + vertices.push_back(cCenter); + vertices.push_back(nCenter); + normals.push_back(LLVector3(1,1,1)); + normals.push_back(LLVector3(1,1,1)); + segments.push_back(vertices.size()); } } + + continue; - // Bottom cap - pt1 = 0; - pt2 = size_s-1; - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; + //============================================== + //DEBUG + //============================================== - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); + //============================================== + //DEBUG draw normals instead of silhouette edge + //============================================== +#elif DEBUG_SILHOUETTE_NORMALS - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); + //for each vertex + for (U32 j = 0; j < face.mNumVertices; j++) { + vertices.push_back(face.mVertices[j].getPosition()); + vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].getNormal()*0.1f); + normals.push_back(LLVector3(0,0,1)); + normals.push_back(LLVector3(0,0,1)); + segments.push_back(vertices.size()); +#if DEBUG_SILHOUETTE_BINORMALS + vertices.push_back(face.mVertices[j].getPosition()); + vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mBinormal*0.1f); + normals.push_back(LLVector3(0,0,1)); + normals.push_back(LLVector3(0,0,1)); + segments.push_back(vertices.size()); +#endif + } + + continue; +#else + //============================================== + //DEBUG + //============================================== - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + static const U8 AWAY = 0x01, + TOWARDS = 0x02; - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + //for each triangle + std::vector fFacing; + vector_append(fFacing, face.mNumIndices/3); - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; + LLVector4a* v = (LLVector4a*) face.mPositions; + LLVector4a* n = (LLVector4a*) face.mNormals; - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } + for (U32 j = 0; j < face.mNumIndices/3; j++) + { + //approximate normal + S32 v1 = face.mIndices[j*3+0]; + S32 v2 = face.mIndices[j*3+1]; + S32 v3 = face.mIndices[j*3+2]; - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) + LLVector4a c1,c2; + c1.setSub(v[v1], v[v2]); + c2.setSub(v[v2], v[v3]); + + LLVector4a norm; + + norm.setCross3(c1, c2); + + if (norm.dot3(norm) < 0.00000001f) { - use_tri1a2 = TRUE; + fFacing[j] = AWAY | TOWARDS; } - else + else { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) + //get view vector + LLVector4a view; + view.setSub(obj_cam_vec, v[v1]); + bool away = view.dot3(norm) > 0.0f; + if (away) { - use_tri1a2 = TRUE; + fFacing[j] = AWAY; } - else + else { - use_tri1a2 = FALSE; + fFacing[j] = TOWARDS; } } - - if (use_tri1a2) - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt1 + 1; - pt1++; - } - else - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt2 - 1; - pt2--; + } + + //for each triangle + for (U32 j = 0; j < face.mNumIndices/3; j++) + { + if (fFacing[j] == (AWAY | TOWARDS)) + { //this is a degenerate triangle + //take neighbor facing (degenerate faces get facing of one of their neighbors) + // *FIX IF NEEDED: this does not deal with neighboring degenerate faces + for (S32 k = 0; k < 3; k++) + { + S32 index = face.mEdge[j*3+k]; + if (index != -1) + { + fFacing[j] = fFacing[index]; + break; + } + } + continue; //skip degenerate face } + + //for each edge + for (S32 k = 0; k < 3; k++) { + S32 index = face.mEdge[j*3+k]; + if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) { + //our neighbor is degenerate, make him face our direction + fFacing[face.mEdge[j*3+k]] = fFacing[j]; + continue; + } + + if (index == -1 || //edge has no neighbor, MUST be a silhouette edge + (fFacing[index] & fFacing[j]) == 0) { //we found a silhouette edge + + S32 v1 = face.mIndices[j*3+k]; + S32 v2 = face.mIndices[j*3+((k+1)%3)]; + + LLVector4a t; + mat.affineTransform(v[v1], t); + vertices.push_back(LLVector3(t[0], t[1], t[2])); + + norm_mat.rotate(n[v1], t); + + t.normalize3fast(); + normals.push_back(LLVector3(t[0], t[1], t[2])); + + mat.affineTransform(v[v2], t); + vertices.push_back(LLVector3(t[0], t[1], t[2])); + + norm_mat.rotate(n[v2], t); + t.normalize3fast(); + normals.push_back(LLVector3(t[0], t[1], t[2])); + + segments.push_back(vertices.size()); + } + } } - } +#endif + } + } +} + +S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + S32 face, + LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) +{ + LLVector4a starta, enda; + starta.load3(start.mV); + enda.load3(end.mV); + + return lineSegmentIntersect(starta, enda, face, intersection, tex_coord, normal, bi_normal); + +} + + +S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + S32 face, + LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) +{ + S32 hit_face = -1; + + S32 start_face; + S32 end_face; + + if (face == -1) // ALL_SIDES + { + start_face = 0; + end_face = getNumVolumeFaces() - 1; } else { - // Closed solid. Easy case. - for (t = 0; t < size_t - 1; t++) - { - for (s = 0; s < size_s - 1; s++) - { - // Should wrap properly, but for now... - i = s + t*size_s; + start_face = face; + end_face = face; + } - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 + LLVector4a dir; + dir.setSub(end, start); - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s + 1; // x+1,y+1 - } - } + F32 closest_t = 2.f; // must be larger than 1 + + end_face = llmin(end_face, getNumVolumeFaces()-1); - // Do the top and bottom caps, if necessary - if (path_open) + for (S32 i = start_face; i <= end_face; i++) + { + LLVolumeFace &face = mVolumeFaces[i]; + + LLVector4a box_center; + box_center.setAdd(face.mExtents[0], face.mExtents[1]); + box_center.mul(0.5f); + + LLVector4a box_size; + box_size.setSub(face.mExtents[1], face.mExtents[0]); + + if (LLLineSegmentBoxIntersect(start, end, box_center, box_size)) { - // bottom cap - for (s = 1; s < size_s - 2; s++) + if (bi_normal != NULL) // if the caller wants binormals, we may need to generate them { - index[count++] = s+1; - index[count++] = s; - index[count++] = 0; + genBinormals(i); } - // top cap - S32 offset = (size_t - 1)*size_s; - for (s = 1; s < size_s - 2; s++) + if (!face.mOctree) { - // Inverted ordering from bottom cap. - index[count++] = offset; - index[count++] = offset + s; - index[count++] = offset + s + 1; + face.createOctree(); } - } - } + + //LLVector4a* p = (LLVector4a*) face.mPositions; -#ifdef LL_DEBUG - // assert that we computed the correct number of indices - if (count != expected_num_triangle_indices ) - { - llerrs << "bad index count prediciton:" - << " expected=" << expected_num_triangle_indices - << " actual=" << count << llendl; + LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal); + intersect.traverse(face.mOctree); + if (intersect.mHitFace) + { + hit_face = i; + } + } } -#endif + + + return hit_face; +} -#if 0 - // verify that each index does not point beyond the size of the mesh - S32 num_vertices = mMesh.size(); - for (i = 0; i < count; i+=3) - { - llinfos << index[i] << ":" << index[i+1] << ":" << index[i+2] << llendl; - llassert(index[i] < num_vertices); - llassert(index[i+1] < num_vertices); - llassert(index[i+2] < num_vertices); - } -#endif +class LLVertexIndexPair +{ +public: + LLVertexIndexPair(const LLVector3 &vertex, const S32 index); - num_indices = count; - return index; + LLVector3 mVertex; + S32 mIndex; +}; + +LLVertexIndexPair::LLVertexIndexPair(const LLVector3 &vertex, const S32 index) +{ + mVertex = vertex; + mIndex = index; } -S32 LLVolume::getNumTriangleIndices() const +const F32 VERTEX_SLOP = 0.00001f; +const F32 VERTEX_SLOP_SQRD = VERTEX_SLOP * VERTEX_SLOP; + +struct lessVertex { - BOOL profile_open = getProfile().isOpen(); - BOOL hollow = (mParams.getProfileParams().getHollow() > 0); - BOOL path_open = getPath().isOpen(); + bool operator()(const LLVertexIndexPair *a, const LLVertexIndexPair *b) + { + const F32 slop = VERTEX_SLOP; - S32 size_s, size_s_out, size_t; - size_s = getProfile().getTotal(); - size_s_out = getProfile().getTotalOut(); - size_t = getPath().mPath.size(); + if (a->mVertex.mV[0] + slop < b->mVertex.mV[0]) + { + return TRUE; + } + else if (a->mVertex.mV[0] - slop > b->mVertex.mV[0]) + { + return FALSE; + } + + if (a->mVertex.mV[1] + slop < b->mVertex.mV[1]) + { + return TRUE; + } + else if (a->mVertex.mV[1] - slop > b->mVertex.mV[1]) + { + return FALSE; + } + + if (a->mVertex.mV[2] + slop < b->mVertex.mV[2]) + { + return TRUE; + } + else if (a->mVertex.mV[2] - slop > b->mVertex.mV[2]) + { + return FALSE; + } + + return FALSE; + } +}; - S32 count = 0; - if (profile_open) /* Flawfinder: ignore */ +struct lessTriangle +{ + bool operator()(const S32 *a, const S32 *b) { - if (hollow) + if (*a < *b) + { + return TRUE; + } + else if (*a > *b) + { + return FALSE; + } + + if (*(a+1) < *(b+1)) { - // Open hollow -- much like the closed solid, except we - // we need to stitch up the gap between s=0 and s=size_s-1 - count = (size_t - 1) * (((size_s -1) * 6) + 6); + return TRUE; } - else + else if (*(a+1) > *(b+1)) { - count = (size_t - 1) * (((size_s -1) * 6) + 6); + return FALSE; } - } - else if (hollow) - { - // Closed hollow - // Outer face - count = (size_t - 1) * (size_s_out - 1) * 6; - - // Inner face - count += (size_t - 1) * ((size_s - 1) - size_s_out) * 6; - } - else - { - // Closed solid. Easy case. - count = (size_t - 1) * (size_s - 1) * 6; - } - if (path_open) - { - S32 cap_triangle_count = size_s - 3; - if ( profile_open - || hollow ) + if (*(a+2) < *(b+2)) { - cap_triangle_count = size_s - 2; + return TRUE; } - if ( cap_triangle_count > 0 ) + else if (*(a+2) > *(b+2)) { - // top and bottom caps - count += cap_triangle_count * 2 * 3; + return FALSE; } + + return FALSE; } - return count; +}; + +BOOL equalTriangle(const S32 *a, const S32 *b) +{ + if ((*a == *b) && (*(a+1) == *(b+1)) && (*(a+2) == *(b+2))) + { + return TRUE; + } + return FALSE; } -//----------------------------------------------------------------------------- -// generateSilhouetteVertices() -//----------------------------------------------------------------------------- -void LLVolume::generateSilhouetteVertices(std::vector &vertices, - std::vector &normals, - std::vector &segments, - const LLVector3& obj_cam_vec, - const LLMatrix4& mat, - const LLMatrix3& norm_mat, - S32 face_mask) +BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices, + const std::vector& input_vertices, + const S32 num_input_triangles, + S32 *input_triangles, + S32 &num_output_vertices, + LLVector3 **output_vertices, + S32 &num_output_triangles, + S32 **output_triangles) { LLMemType m1(LLMemType::MTYPE_VOLUME); - vertices.clear(); - normals.clear(); - segments.clear(); - - S32 cur_index = 0; - //for each face - for (face_list_t::iterator iter = mVolumeFaces.begin(); - iter != mVolumeFaces.end(); ++iter) + /* Testing: avoid any cleanup + static BOOL skip_cleanup = TRUE; + if ( skip_cleanup ) { - const LLVolumeFace& face = *iter; - - if (!(face_mask & (0x1 << cur_index++))) + num_output_vertices = num_input_vertices; + num_output_triangles = num_input_triangles; + + *output_vertices = new LLVector3[num_input_vertices]; + for (S32 index = 0; index < num_input_vertices; index++) { - continue; - } - if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) { - + (*output_vertices)[index] = input_vertices[index].mPos; } - else { - - //============================================== - //DEBUG draw edge map instead of silhouette edge - //============================================== - -#if DEBUG_SILHOUETTE_EDGE_MAP - - //for each triangle - U32 count = face.mIndices.size(); - for (U32 j = 0; j < count/3; j++) { - //get vertices - S32 v1 = face.mIndices[j*3+0]; - S32 v2 = face.mIndices[j*3+1]; - S32 v3 = face.mIndices[j*3+2]; - - //get current face center - LLVector3 cCenter = (face.mVertices[v1].mPosition + - face.mVertices[v2].mPosition + - face.mVertices[v3].mPosition) / 3.0f; - - //for each edge - for (S32 k = 0; k < 3; k++) { - S32 nIndex = face.mEdge[j*3+k]; - if (nIndex <= -1) { - continue; - } - - if (nIndex >= (S32) count/3) { - continue; - } - //get neighbor vertices - v1 = face.mIndices[nIndex*3+0]; - v2 = face.mIndices[nIndex*3+1]; - v3 = face.mIndices[nIndex*3+2]; - - //get neighbor face center - LLVector3 nCenter = (face.mVertices[v1].mPosition + - face.mVertices[v2].mPosition + - face.mVertices[v3].mPosition) / 3.0f; - //draw line - vertices.push_back(cCenter); - vertices.push_back(nCenter); - normals.push_back(LLVector3(1,1,1)); - normals.push_back(LLVector3(1,1,1)); - segments.push_back(vertices.size()); - } - } - - continue; + *output_triangles = new S32[num_input_triangles*3]; + memcpy(*output_triangles, input_triangles, 3*num_input_triangles*sizeof(S32)); // Flawfinder: ignore + return TRUE; + } + */ - //============================================== - //DEBUG - //============================================== + // Here's how we do this: + // Create a structure which contains the original vertex index and the + // LLVector3 data. + // "Sort" the data by the vectors + // Create an array the size of the old vertex list, with a mapping of + // old indices to new indices. + // Go through triangles, shift so the lowest index is first + // Sort triangles by first index + // Remove duplicate triangles + // Allocate and pack new triangle data. - //============================================== - //DEBUG draw normals instead of silhouette edge - //============================================== -#elif DEBUG_SILHOUETTE_NORMALS + //LLTimer cleanupTimer; + //llinfos << "In vertices: " << num_input_vertices << llendl; + //llinfos << "In triangles: " << num_input_triangles << llendl; - //for each vertex - for (U32 j = 0; j < face.mVertices.size(); j++) { - vertices.push_back(face.mVertices[j].mPosition); - vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mNormal*0.1f); - normals.push_back(LLVector3(0,0,1)); - normals.push_back(LLVector3(0,0,1)); - segments.push_back(vertices.size()); -#if DEBUG_SILHOUETTE_BINORMALS - vertices.push_back(face.mVertices[j].mPosition); - vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mBinormal*0.1f); - normals.push_back(LLVector3(0,0,1)); - normals.push_back(LLVector3(0,0,1)); - segments.push_back(vertices.size()); -#endif - } - - continue; -#else - //============================================== - //DEBUG - //============================================== + S32 i; + typedef std::multiset vertex_set_t; + vertex_set_t vertex_list; - static const U8 AWAY = 0x01, - TOWARDS = 0x02; + LLVertexIndexPair *pairp = NULL; + for (i = 0; i < num_input_vertices; i++) + { + LLVertexIndexPair *new_pairp = new LLVertexIndexPair(input_vertices[i].mPos, i); + vertex_list.insert(new_pairp); + } - //for each triangle - std::vector fFacing; - vector_append(fFacing, face.mIndices.size()/3); - for (U32 j = 0; j < face.mIndices.size()/3; j++) - { - //approximate normal - S32 v1 = face.mIndices[j*3+0]; - S32 v2 = face.mIndices[j*3+1]; - S32 v3 = face.mIndices[j*3+2]; + // Generate the vertex mapping and the list of vertices without + // duplicates. This will crash if there are no vertices. + llassert(num_input_vertices > 0); // check for no vertices! + S32 *vertex_mapping = new S32[num_input_vertices]; + LLVector3 *new_vertices = new LLVector3[num_input_vertices]; + LLVertexIndexPair *prev_pairp = NULL; - LLVector3 norm = (face.mVertices[v1].mPosition - face.mVertices[v2].mPosition) % - (face.mVertices[v2].mPosition - face.mVertices[v3].mPosition); - - if (norm.magVecSquared() < 0.00000001f) - { - fFacing[j] = AWAY | TOWARDS; - } - else - { - //get view vector - LLVector3 view = (obj_cam_vec-face.mVertices[v1].mPosition); - bool away = view * norm > 0.0f; - if (away) - { - fFacing[j] = AWAY; - } - else - { - fFacing[j] = TOWARDS; - } - } - } - - //for each triangle - for (U32 j = 0; j < face.mIndices.size()/3; j++) - { - if (fFacing[j] == (AWAY | TOWARDS)) - { //this is a degenerate triangle - //take neighbor facing (degenerate faces get facing of one of their neighbors) - // *FIX IF NEEDED: this does not deal with neighboring degenerate faces - for (S32 k = 0; k < 3; k++) - { - S32 index = face.mEdge[j*3+k]; - if (index != -1) - { - fFacing[j] = fFacing[index]; - break; - } - } - continue; //skip degenerate face - } + S32 new_num_vertices; - //for each edge - for (S32 k = 0; k < 3; k++) { - S32 index = face.mEdge[j*3+k]; - if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) { - //our neighbor is degenerate, make him face our direction - fFacing[face.mEdge[j*3+k]] = fFacing[j]; - continue; - } + new_num_vertices = 0; + for (vertex_set_t::iterator iter = vertex_list.begin(), + end = vertex_list.end(); + iter != end; iter++) + { + pairp = *iter; + if (!prev_pairp || ((pairp->mVertex - prev_pairp->mVertex).magVecSquared() >= VERTEX_SLOP_SQRD)) + { + new_vertices[new_num_vertices] = pairp->mVertex; + //llinfos << "Added vertex " << new_num_vertices << " : " << pairp->mVertex << llendl; + new_num_vertices++; + // Update the previous + prev_pairp = pairp; + } + else + { + //llinfos << "Removed duplicate vertex " << pairp->mVertex << ", distance magVecSquared() is " << (pairp->mVertex - prev_pairp->mVertex).magVecSquared() << llendl; + } + vertex_mapping[pairp->mIndex] = new_num_vertices - 1; + } - if (index == -1 || //edge has no neighbor, MUST be a silhouette edge - (fFacing[index] & fFacing[j]) == 0) { //we found a silhouette edge + // Iterate through triangles and remove degenerates, re-ordering vertices + // along the way. + S32 *new_triangles = new S32[num_input_triangles * 3]; + S32 new_num_triangles = 0; - S32 v1 = face.mIndices[j*3+k]; - S32 v2 = face.mIndices[j*3+((k+1)%3)]; - - vertices.push_back(face.mVertices[v1].mPosition*mat); - LLVector3 norm1 = face.mVertices[v1].mNormal * norm_mat; - norm1.normVec(); - normals.push_back(norm1); + for (i = 0; i < num_input_triangles; i++) + { + S32 v1 = i*3; + S32 v2 = v1 + 1; + S32 v3 = v1 + 2; - vertices.push_back(face.mVertices[v2].mPosition*mat); - LLVector3 norm2 = face.mVertices[v2].mNormal * norm_mat; - norm2.normVec(); - normals.push_back(norm2); + //llinfos << "Checking triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl; + input_triangles[v1] = vertex_mapping[input_triangles[v1]]; + input_triangles[v2] = vertex_mapping[input_triangles[v2]]; + input_triangles[v3] = vertex_mapping[input_triangles[v3]]; - segments.push_back(vertices.size()); - } - } + if ((input_triangles[v1] == input_triangles[v2]) + || (input_triangles[v1] == input_triangles[v3]) + || (input_triangles[v2] == input_triangles[v3])) + { + //llinfos << "Removing degenerate triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl; + // Degenerate triangle, skip + continue; + } + + if (input_triangles[v1] < input_triangles[v2]) + { + if (input_triangles[v1] < input_triangles[v3]) + { + // (0 < 1) && (0 < 2) + new_triangles[new_num_triangles*3] = input_triangles[v1]; + new_triangles[new_num_triangles*3+1] = input_triangles[v2]; + new_triangles[new_num_triangles*3+2] = input_triangles[v3]; + } + else + { + // (0 < 1) && (2 < 0) + new_triangles[new_num_triangles*3] = input_triangles[v3]; + new_triangles[new_num_triangles*3+1] = input_triangles[v1]; + new_triangles[new_num_triangles*3+2] = input_triangles[v2]; } -#endif } + else if (input_triangles[v2] < input_triangles[v3]) + { + // (1 < 0) && (1 < 2) + new_triangles[new_num_triangles*3] = input_triangles[v2]; + new_triangles[new_num_triangles*3+1] = input_triangles[v3]; + new_triangles[new_num_triangles*3+2] = input_triangles[v1]; + } + else + { + // (1 < 0) && (2 < 1) + new_triangles[new_num_triangles*3] = input_triangles[v3]; + new_triangles[new_num_triangles*3+1] = input_triangles[v1]; + new_triangles[new_num_triangles*3+2] = input_triangles[v2]; + } + new_num_triangles++; } -} -S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, - S32 face, - LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) -{ - S32 hit_face = -1; - - S32 start_face; - S32 end_face; - - if (face == -1) // ALL_SIDES - { - start_face = 0; - end_face = getNumVolumeFaces() - 1; - } - else + if (new_num_triangles == 0) { - start_face = face; - end_face = face; + llwarns << "Created volume object with 0 faces." << llendl; + delete[] new_triangles; + delete[] vertex_mapping; + delete[] new_vertices; + return FALSE; } - LLVector3 dir = end - start; + typedef std::set triangle_set_t; + triangle_set_t triangle_list; - F32 closest_t = 2.f; // must be larger than 1 - - for (S32 i = start_face; i <= end_face; i++) + for (i = 0; i < new_num_triangles; i++) { - const LLVolumeFace &face = getVolumeFace((U32)i); + triangle_list.insert(&new_triangles[i*3]); + } - LLVector3 box_center = (face.mExtents[0] + face.mExtents[1]) / 2.f; - LLVector3 box_size = face.mExtents[1] - face.mExtents[0]; + // Sort through the triangle list, and delete duplicates - if (LLLineSegmentBoxIntersect(start, end, box_center, box_size)) - { - if (bi_normal != NULL) // if the caller wants binormals, we may need to generate them - { - genBinormals(i); - } - - for (U32 tri = 0; tri < face.mIndices.size()/3; tri++) - { - S32 index1 = face.mIndices[tri*3+0]; - S32 index2 = face.mIndices[tri*3+1]; - S32 index3 = face.mIndices[tri*3+2]; + S32 *prevp = NULL; + S32 *curp = NULL; - F32 a, b, t; - - if (LLTriangleRayIntersect(face.mVertices[index1].mPosition, - face.mVertices[index2].mPosition, - face.mVertices[index3].mPosition, - start, dir, &a, &b, &t, FALSE)) - { - if ((t >= 0.f) && // if hit is after start - (t <= 1.f) && // and before end - (t < closest_t)) // and this hit is closer + S32 *sorted_tris = new S32[new_num_triangles*3]; + S32 cur_tri = 0; + for (triangle_set_t::iterator iter = triangle_list.begin(), + end = triangle_list.end(); + iter != end; iter++) + { + curp = *iter; + if (!prevp || !equalTriangle(prevp, curp)) { - closest_t = t; - hit_face = i; - - if (intersection != NULL) - { - *intersection = start + dir * closest_t; - } - - if (tex_coord != NULL) - { - *tex_coord = ((1.f - a - b) * face.mVertices[index1].mTexCoord + - a * face.mVertices[index2].mTexCoord + - b * face.mVertices[index3].mTexCoord); - - } + //llinfos << "Added triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl; + sorted_tris[cur_tri*3] = *curp; + sorted_tris[cur_tri*3+1] = *(curp+1); + sorted_tris[cur_tri*3+2] = *(curp+2); + cur_tri++; + prevp = curp; + } + else + { + //llinfos << "Skipped triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl; + } + } - if (normal != NULL) - { - *normal = ((1.f - a - b) * face.mVertices[index1].mNormal + - a * face.mVertices[index2].mNormal + - b * face.mVertices[index3].mNormal); - } + *output_vertices = new LLVector3[new_num_vertices]; + num_output_vertices = new_num_vertices; + for (i = 0; i < new_num_vertices; i++) + { + (*output_vertices)[i] = new_vertices[i]; + } - if (bi_normal != NULL) - { - *bi_normal = ((1.f - a - b) * face.mVertices[index1].mBinormal + - a * face.mVertices[index2].mBinormal + - b * face.mVertices[index3].mBinormal); - } + *output_triangles = new S32[cur_tri*3]; + num_output_triangles = cur_tri; + memcpy(*output_triangles, sorted_tris, 3*cur_tri*sizeof(S32)); /* Flawfinder: ignore */ - } - } - } - } + /* + llinfos << "Out vertices: " << num_output_vertices << llendl; + llinfos << "Out triangles: " << num_output_triangles << llendl; + for (i = 0; i < num_output_vertices; i++) + { + llinfos << i << ":" << (*output_vertices)[i] << llendl; } + for (i = 0; i < num_output_triangles; i++) + { + llinfos << i << ":" << (*output_triangles)[i*3] << ":" << (*output_triangles)[i*3+1] << ":" << (*output_triangles)[i*3+2] << llendl; + } + */ + + //llinfos << "Out vertices: " << num_output_vertices << llendl; + //llinfos << "Out triangles: " << num_output_triangles << llendl; + delete[] vertex_mapping; + vertex_mapping = NULL; + delete[] new_vertices; + new_vertices = NULL; + delete[] new_triangles; + new_triangles = NULL; + delete[] sorted_tris; + sorted_tris = NULL; + triangle_list.clear(); + std::for_each(vertex_list.begin(), vertex_list.end(), DeletePointer()); + vertex_list.clear(); - - return hit_face; + return TRUE; } -class LLVertexIndexPair -{ -public: - LLVertexIndexPair(const LLVector3 &vertex, const S32 index); - - LLVector3 mVertex; - S32 mIndex; -}; -LLVertexIndexPair::LLVertexIndexPair(const LLVector3 &vertex, const S32 index) +BOOL LLVolumeParams::importFile(LLFILE *fp) { - mVertex = vertex; - mIndex = index; -} - -const F32 VERTEX_SLOP = 0.00001f; -const F32 VERTEX_SLOP_SQRD = VERTEX_SLOP * VERTEX_SLOP; + LLMemType m1(LLMemType::MTYPE_VOLUME); + + //llinfos << "importing volume" << llendl; + const S32 BUFSIZE = 16384; + char buffer[BUFSIZE]; /* Flawfinder: ignore */ + // *NOTE: changing the size or type of this buffer will require + // changing the sscanf below. + char keyword[256]; /* Flawfinder: ignore */ + keyword[0] = 0; -struct lessVertex -{ - bool operator()(const LLVertexIndexPair *a, const LLVertexIndexPair *b) + while (!feof(fp)) { - const F32 slop = VERTEX_SLOP; - - if (a->mVertex.mV[0] + slop < b->mVertex.mV[0]) + if (fgets(buffer, BUFSIZE, fp) == NULL) { - return TRUE; + buffer[0] = '\0'; } - else if (a->mVertex.mV[0] - slop > b->mVertex.mV[0]) + + sscanf(buffer, " %255s", keyword); /* Flawfinder: ignore */ + if (!strcmp("{", keyword)) { - return FALSE; + continue; } - - if (a->mVertex.mV[1] + slop < b->mVertex.mV[1]) + if (!strcmp("}",keyword)) { - return TRUE; + break; } - else if (a->mVertex.mV[1] - slop > b->mVertex.mV[1]) + else if (!strcmp("profile", keyword)) { - return FALSE; + mProfileParams.importFile(fp); } - - if (a->mVertex.mV[2] + slop < b->mVertex.mV[2]) + else if (!strcmp("path",keyword)) { - return TRUE; + mPathParams.importFile(fp); } - else if (a->mVertex.mV[2] - slop > b->mVertex.mV[2]) + else { - return FALSE; + llwarns << "unknown keyword " << keyword << " in volume import" << llendl; } - - return FALSE; } -}; -struct lessTriangle + return TRUE; +} + +BOOL LLVolumeParams::exportFile(LLFILE *fp) const +{ + fprintf(fp,"\tshape 0\n"); + fprintf(fp,"\t{\n"); + mPathParams.exportFile(fp); + mProfileParams.exportFile(fp); + fprintf(fp, "\t}\n"); + return TRUE; +} + + +BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream) { - bool operator()(const S32 *a, const S32 *b) + LLMemType m1(LLMemType::MTYPE_VOLUME); + + //llinfos << "importing volume" << llendl; + const S32 BUFSIZE = 16384; + // *NOTE: changing the size or type of this buffer will require + // changing the sscanf below. + char buffer[BUFSIZE]; /* Flawfinder: ignore */ + char keyword[256]; /* Flawfinder: ignore */ + keyword[0] = 0; + + while (input_stream.good()) { - if (*a < *b) - { - return TRUE; - } - else if (*a > *b) + input_stream.getline(buffer, BUFSIZE); + sscanf(buffer, " %255s", keyword); + if (!strcmp("{", keyword)) { - return FALSE; + continue; } - - if (*(a+1) < *(b+1)) + if (!strcmp("}",keyword)) { - return TRUE; + break; } - else if (*(a+1) > *(b+1)) + else if (!strcmp("profile", keyword)) { - return FALSE; + mProfileParams.importLegacyStream(input_stream); } - - if (*(a+2) < *(b+2)) + else if (!strcmp("path",keyword)) { - return TRUE; + mPathParams.importLegacyStream(input_stream); } - else if (*(a+2) > *(b+2)) + else { - return FALSE; + llwarns << "unknown keyword " << keyword << " in volume import" << llendl; } - - return FALSE; } -}; -BOOL equalTriangle(const S32 *a, const S32 *b) -{ - if ((*a == *b) && (*(a+1) == *(b+1)) && (*(a+2) == *(b+2))) - { - return TRUE; - } - return FALSE; + return TRUE; } -BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices, - const std::vector& input_vertices, - const S32 num_input_triangles, - S32 *input_triangles, - S32 &num_output_vertices, - LLVector3 **output_vertices, - S32 &num_output_triangles, - S32 **output_triangles) +BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const { LLMemType m1(LLMemType::MTYPE_VOLUME); - /* Testing: avoid any cleanup - static BOOL skip_cleanup = TRUE; - if ( skip_cleanup ) - { - num_output_vertices = num_input_vertices; - num_output_triangles = num_input_triangles; + output_stream <<"\tshape 0\n"; + output_stream <<"\t{\n"; + mPathParams.exportLegacyStream(output_stream); + mProfileParams.exportLegacyStream(output_stream); + output_stream << "\t}\n"; + return TRUE; +} - *output_vertices = new LLVector3[num_input_vertices]; - for (S32 index = 0; index < num_input_vertices; index++) - { - (*output_vertices)[index] = input_vertices[index].mPos; - } +LLSD LLVolumeParams::sculptAsLLSD() const +{ + LLSD sd = LLSD(); + sd["id"] = getSculptID(); + sd["type"] = getSculptType(); - *output_triangles = new S32[num_input_triangles*3]; - memcpy(*output_triangles, input_triangles, 3*num_input_triangles*sizeof(S32)); // Flawfinder: ignore - return TRUE; - } - */ + return sd; +} - // Here's how we do this: - // Create a structure which contains the original vertex index and the - // LLVector3 data. - // "Sort" the data by the vectors - // Create an array the size of the old vertex list, with a mapping of - // old indices to new indices. - // Go through triangles, shift so the lowest index is first - // Sort triangles by first index - // Remove duplicate triangles - // Allocate and pack new triangle data. +bool LLVolumeParams::sculptFromLLSD(LLSD& sd) +{ + setSculptID(sd["id"].asUUID(), (U8)sd["type"].asInteger()); + return true; +} - //LLTimer cleanupTimer; - //llinfos << "In vertices: " << num_input_vertices << llendl; - //llinfos << "In triangles: " << num_input_triangles << llendl; +LLSD LLVolumeParams::asLLSD() const +{ + LLSD sd = LLSD(); + sd["path"] = mPathParams; + sd["profile"] = mProfileParams; + sd["sculpt"] = sculptAsLLSD(); + + return sd; +} - S32 i; - typedef std::multiset vertex_set_t; - vertex_set_t vertex_list; +bool LLVolumeParams::fromLLSD(LLSD& sd) +{ + mPathParams.fromLLSD(sd["path"]); + mProfileParams.fromLLSD(sd["profile"]); + sculptFromLLSD(sd["sculpt"]); + + return true; +} - LLVertexIndexPair *pairp = NULL; - for (i = 0; i < num_input_vertices; i++) +void LLVolumeParams::reduceS(F32 begin, F32 end) +{ + begin = llclampf(begin); + end = llclampf(end); + if (begin > end) { - LLVertexIndexPair *new_pairp = new LLVertexIndexPair(input_vertices[i].mPos, i); - vertex_list.insert(new_pairp); + F32 temp = begin; + begin = end; + end = temp; } + F32 a = mProfileParams.getBegin(); + F32 b = mProfileParams.getEnd(); + mProfileParams.setBegin(a + begin * (b - a)); + mProfileParams.setEnd(a + end * (b - a)); +} - // Generate the vertex mapping and the list of vertices without - // duplicates. This will crash if there are no vertices. - llassert(num_input_vertices > 0); // check for no vertices! - S32 *vertex_mapping = new S32[num_input_vertices]; - LLVector3 *new_vertices = new LLVector3[num_input_vertices]; - LLVertexIndexPair *prev_pairp = NULL; - - S32 new_num_vertices; - - new_num_vertices = 0; - for (vertex_set_t::iterator iter = vertex_list.begin(), - end = vertex_list.end(); - iter != end; iter++) +void LLVolumeParams::reduceT(F32 begin, F32 end) +{ + begin = llclampf(begin); + end = llclampf(end); + if (begin > end) { - pairp = *iter; - if (!prev_pairp || ((pairp->mVertex - prev_pairp->mVertex).magVecSquared() >= VERTEX_SLOP_SQRD)) - { - new_vertices[new_num_vertices] = pairp->mVertex; - //llinfos << "Added vertex " << new_num_vertices << " : " << pairp->mVertex << llendl; - new_num_vertices++; - // Update the previous - prev_pairp = pairp; - } - else - { - //llinfos << "Removed duplicate vertex " << pairp->mVertex << ", distance magVecSquared() is " << (pairp->mVertex - prev_pairp->mVertex).magVecSquared() << llendl; - } - vertex_mapping[pairp->mIndex] = new_num_vertices - 1; + F32 temp = begin; + begin = end; + end = temp; } + F32 a = mPathParams.getBegin(); + F32 b = mPathParams.getEnd(); + mPathParams.setBegin(a + begin * (b - a)); + mPathParams.setEnd(a + end * (b - a)); +} - // Iterate through triangles and remove degenerates, re-ordering vertices - // along the way. - S32 *new_triangles = new S32[num_input_triangles * 3]; - S32 new_num_triangles = 0; +const F32 MIN_CONCAVE_PROFILE_WEDGE = 0.125f; // 1/8 unity +const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity - for (i = 0; i < num_input_triangles; i++) +// returns TRUE if the shape can be approximated with a convex shape +// for collison purposes +BOOL LLVolumeParams::isConvex() const +{ + if (!getSculptID().isNull()) { - S32 v1 = i*3; - S32 v2 = v1 + 1; - S32 v3 = v1 + 2; - - //llinfos << "Checking triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl; - input_triangles[v1] = vertex_mapping[input_triangles[v1]]; - input_triangles[v2] = vertex_mapping[input_triangles[v2]]; - input_triangles[v3] = vertex_mapping[input_triangles[v3]]; - - if ((input_triangles[v1] == input_triangles[v2]) - || (input_triangles[v1] == input_triangles[v3]) - || (input_triangles[v2] == input_triangles[v3])) - { - //llinfos << "Removing degenerate triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl; - // Degenerate triangle, skip - continue; - } + // can't determine, be safe and say no: + return FALSE; + } + + F32 path_length = mPathParams.getEnd() - mPathParams.getBegin(); + F32 hollow = mProfileParams.getHollow(); + + U8 path_type = mPathParams.getCurveType(); + if ( path_length > MIN_CONCAVE_PATH_WEDGE + && ( mPathParams.getTwist() != mPathParams.getTwistBegin() + || (hollow > 0.f + && LL_PCODE_PATH_LINE != path_type) ) ) + { + // twist along a "not too short" path is concave + return FALSE; + } - if (input_triangles[v1] < input_triangles[v2]) - { - if (input_triangles[v1] < input_triangles[v3]) - { - // (0 < 1) && (0 < 2) - new_triangles[new_num_triangles*3] = input_triangles[v1]; - new_triangles[new_num_triangles*3+1] = input_triangles[v2]; - new_triangles[new_num_triangles*3+2] = input_triangles[v3]; - } - else - { - // (0 < 1) && (2 < 0) - new_triangles[new_num_triangles*3] = input_triangles[v3]; - new_triangles[new_num_triangles*3+1] = input_triangles[v1]; - new_triangles[new_num_triangles*3+2] = input_triangles[v2]; - } - } - else if (input_triangles[v2] < input_triangles[v3]) - { - // (1 < 0) && (1 < 2) - new_triangles[new_num_triangles*3] = input_triangles[v2]; - new_triangles[new_num_triangles*3+1] = input_triangles[v3]; - new_triangles[new_num_triangles*3+2] = input_triangles[v1]; - } - else - { - // (1 < 0) && (2 < 1) - new_triangles[new_num_triangles*3] = input_triangles[v3]; - new_triangles[new_num_triangles*3+1] = input_triangles[v1]; - new_triangles[new_num_triangles*3+2] = input_triangles[v2]; - } - new_num_triangles++; + F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin(); + BOOL same_hole = hollow == 0.f + || (mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK) == LL_PCODE_HOLE_SAME; + + F32 min_profile_wedge = MIN_CONCAVE_PROFILE_WEDGE; + U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; + if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) + { + // it is a sphere and spheres get twice the minimum profile wedge + min_profile_wedge = 2.f * MIN_CONCAVE_PROFILE_WEDGE; } - if (new_num_triangles == 0) + BOOL convex_profile = ( ( profile_length == 1.f + || profile_length <= 0.5f ) + && hollow == 0.f ) // trivially convex + || ( profile_length <= min_profile_wedge + && same_hole ); // effectvely convex (even when hollow) + + if (!convex_profile) { - llwarns << "Created volume object with 0 faces." << llendl; - delete[] new_triangles; - delete[] vertex_mapping; - delete[] new_vertices; + // profile is concave return FALSE; } - typedef std::set triangle_set_t; - triangle_set_t triangle_list; + if ( LL_PCODE_PATH_LINE == path_type ) + { + // straight paths with convex profile + return TRUE; + } - for (i = 0; i < new_num_triangles; i++) + BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f); + if (concave_path) { - triangle_list.insert(&new_triangles[i*3]); + return FALSE; } - // Sort through the triangle list, and delete duplicates + // we're left with spheres, toroids and tubes + if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) + { + // at this stage all spheres must be convex + return TRUE; + } - S32 *prevp = NULL; - S32 *curp = NULL; + // it's a toroid or tube + if ( path_length <= MIN_CONCAVE_PATH_WEDGE ) + { + // effectively convex + return TRUE; + } - S32 *sorted_tris = new S32[new_num_triangles*3]; - S32 cur_tri = 0; - for (triangle_set_t::iterator iter = triangle_list.begin(), - end = triangle_list.end(); - iter != end; iter++) + return FALSE; +} + +// debug +void LLVolumeParams::setCube() +{ + mProfileParams.setCurveType(LL_PCODE_PROFILE_SQUARE); + mProfileParams.setBegin(0.f); + mProfileParams.setEnd(1.f); + mProfileParams.setHollow(0.f); + + mPathParams.setBegin(0.f); + mPathParams.setEnd(1.f); + mPathParams.setScale(1.f, 1.f); + mPathParams.setShear(0.f, 0.f); + mPathParams.setCurveType(LL_PCODE_PATH_LINE); + mPathParams.setTwistBegin(0.f); + mPathParams.setTwistEnd(0.f); + mPathParams.setRadiusOffset(0.f); + mPathParams.setTaper(0.f, 0.f); + mPathParams.setRevolutions(0.f); + mPathParams.setSkew(0.f); +} + +LLFaceID LLVolume::generateFaceMask() +{ + LLFaceID new_mask = 0x0000; + + switch(mParams.getProfileParams().getCurveType() & LL_PCODE_PROFILE_MASK) { - curp = *iter; - if (!prevp || !equalTriangle(prevp, curp)) + case LL_PCODE_PROFILE_CIRCLE: + case LL_PCODE_PROFILE_CIRCLE_HALF: + new_mask |= LL_FACE_OUTER_SIDE_0; + break; + case LL_PCODE_PROFILE_SQUARE: { - //llinfos << "Added triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl; - sorted_tris[cur_tri*3] = *curp; - sorted_tris[cur_tri*3+1] = *(curp+1); - sorted_tris[cur_tri*3+2] = *(curp+2); - cur_tri++; - prevp = curp; + for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 4.f); side < llceil(mParams.getProfileParams().getEnd() * 4.f); side++) + { + new_mask |= LL_FACE_OUTER_SIDE_0 << side; + } } - else + break; + case LL_PCODE_PROFILE_ISOTRI: + case LL_PCODE_PROFILE_EQUALTRI: + case LL_PCODE_PROFILE_RIGHTTRI: { - //llinfos << "Skipped triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl; + for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 3.f); side < llceil(mParams.getProfileParams().getEnd() * 3.f); side++) + { + new_mask |= LL_FACE_OUTER_SIDE_0 << side; + } } + break; + default: + llerrs << "Unknown profile!" << llendl; + break; } - *output_vertices = new LLVector3[new_num_vertices]; - num_output_vertices = new_num_vertices; - for (i = 0; i < new_num_vertices; i++) + // handle hollow objects + if (mParams.getProfileParams().getHollow() > 0) { - (*output_vertices)[i] = new_vertices[i]; + new_mask |= LL_FACE_INNER_SIDE; } - *output_triangles = new S32[cur_tri*3]; - num_output_triangles = cur_tri; - memcpy(*output_triangles, sorted_tris, 3*cur_tri*sizeof(S32)); /* Flawfinder: ignore */ + // handle open profile curves + if (mProfilep->isOpen()) + { + new_mask |= LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END; + } - /* - llinfos << "Out vertices: " << num_output_vertices << llendl; - llinfos << "Out triangles: " << num_output_triangles << llendl; - for (i = 0; i < num_output_vertices; i++) + // handle open path curves + if (mPathp->isOpen()) { - llinfos << i << ":" << (*output_vertices)[i] << llendl; + new_mask |= LL_FACE_PATH_BEGIN | LL_FACE_PATH_END; } - for (i = 0; i < num_output_triangles; i++) + + return new_mask; +} + +BOOL LLVolume::isFaceMaskValid(LLFaceID face_mask) +{ + LLFaceID test_mask = 0; + for(S32 i = 0; i < getNumFaces(); i++) { - llinfos << i << ":" << (*output_triangles)[i*3] << ":" << (*output_triangles)[i*3+1] << ":" << (*output_triangles)[i*3+2] << llendl; + test_mask |= mProfilep->mFaces[i].mFaceID; } - */ - //llinfos << "Out vertices: " << num_output_vertices << llendl; - //llinfos << "Out triangles: " << num_output_triangles << llendl; - delete[] vertex_mapping; - vertex_mapping = NULL; - delete[] new_vertices; - new_vertices = NULL; - delete[] new_triangles; - new_triangles = NULL; - delete[] sorted_tris; - sorted_tris = NULL; - triangle_list.clear(); - std::for_each(vertex_list.begin(), vertex_list.end(), DeletePointer()); - vertex_list.clear(); - - return TRUE; + return test_mask == face_mask; +} + +BOOL LLVolume::isConvex() const +{ + // mParams.isConvex() may return FALSE even though the final + // geometry is actually convex due to LOD approximations. + // TODO -- provide LLPath and LLProfile with isConvex() methods + // that correctly determine convexity. -- Leviathan + return mParams.isConvex(); +} + + +std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params) +{ + s << "{type=" << (U32) profile_params.mCurveType; + s << ", begin=" << profile_params.mBegin; + s << ", end=" << profile_params.mEnd; + s << ", hollow=" << profile_params.mHollow; + s << "}"; + return s; +} + + +std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params) +{ + s << "{type=" << (U32) path_params.mCurveType; + s << ", begin=" << path_params.mBegin; + s << ", end=" << path_params.mEnd; + s << ", twist=" << path_params.mTwistEnd; + s << ", scale=" << path_params.mScale; + s << ", shear=" << path_params.mShear; + s << ", twist_begin=" << path_params.mTwistBegin; + s << ", radius_offset=" << path_params.mRadiusOffset; + s << ", taper=" << path_params.mTaper; + s << ", revolutions=" << path_params.mRevolutions; + s << ", skew=" << path_params.mSkew; + s << "}"; + return s; +} + + +std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params) +{ + s << "{profileparams = " << volume_params.mProfileParams; + s << ", pathparams = " << volume_params.mPathParams; + s << "}"; + return s; +} + + +std::ostream& operator<<(std::ostream &s, const LLProfile &profile) +{ + s << " {open=" << (U32) profile.mOpen; + s << ", dirty=" << profile.mDirty; + s << ", totalout=" << profile.mTotalOut; + s << ", total=" << profile.mTotal; + s << "}"; + return s; +} + + +std::ostream& operator<<(std::ostream &s, const LLPath &path) +{ + s << "{open=" << (U32) path.mOpen; + s << ", dirty=" << path.mDirty; + s << ", step=" << path.mStep; + s << ", total=" << path.mTotal; + s << "}"; + return s; +} + +std::ostream& operator<<(std::ostream &s, const LLVolume &volume) +{ + s << "{params = " << volume.getParams(); + s << ", path = " << *volume.mPathp; + s << ", profile = " << *volume.mProfilep; + s << "}"; + return s; +} + + +std::ostream& operator<<(std::ostream &s, const LLVolume *volumep) +{ + s << "{params = " << volumep->getParams(); + s << ", path = " << *(volumep->mPathp); + s << ", profile = " << *(volumep->mProfilep); + s << "}"; + return s; +} + +LLVolumeFace::LLVolumeFace() : + mID(0), + mTypeMask(0), + mBeginS(0), + mBeginT(0), + mNumS(0), + mNumT(0), + mNumVertices(0), + mNumIndices(0), + mPositions(NULL), + mNormals(NULL), + mBinormals(NULL), + mTexCoords(NULL), + mIndices(NULL), + mWeights(NULL), + mOctree(NULL) +{ + mExtents = (LLVector4a*) malloc(sizeof(LLVector4a)*3); + mCenter = mExtents+2; } +LLVolumeFace::LLVolumeFace(const LLVolumeFace& src) +: mID(0), + mTypeMask(0), + mBeginS(0), + mBeginT(0), + mNumS(0), + mNumT(0), + mNumVertices(0), + mNumIndices(0), + mPositions(NULL), + mNormals(NULL), + mBinormals(NULL), + mTexCoords(NULL), + mIndices(NULL), + mWeights(NULL), + mOctree(NULL) +{ + mExtents = (LLVector4a*) malloc(sizeof(LLVector4a)*3); + mCenter = mExtents+2; + *this = src; +} -BOOL LLVolumeParams::importFile(LLFILE *fp) +LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src) { - LLMemType m1(LLMemType::MTYPE_VOLUME); + if (&src == this) + { //self assignment, do nothing + return *this; + } + + mID = src.mID; + mTypeMask = src.mTypeMask; + mBeginS = src.mBeginS; + mBeginT = src.mBeginT; + mNumS = src.mNumS; + mNumT = src.mNumT; + + mExtents[0] = src.mExtents[0]; + mExtents[1] = src.mExtents[1]; + *mCenter = *src.mCenter; + + mNumVertices = 0; + mNumIndices = 0; + + freeData(); - //llinfos << "importing volume" << llendl; - const S32 BUFSIZE = 16384; - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - // *NOTE: changing the size or type of this buffer will require - // changing the sscanf below. - char keyword[256]; /* Flawfinder: ignore */ - keyword[0] = 0; + LLVector4a::memcpyNonAliased16((F32*) mExtents, (F32*) src.mExtents, 3*sizeof(LLVector4a)); - while (!feof(fp)) + resizeVertices(src.mNumVertices); + resizeIndices(src.mNumIndices); + + if (mNumVertices) { - if (fgets(buffer, BUFSIZE, fp) == NULL) - { - buffer[0] = '\0'; - } - - sscanf(buffer, " %255s", keyword); /* Flawfinder: ignore */ - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) + S32 vert_size = mNumVertices*sizeof(LLVector4a); + S32 tc_size = (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF; + + LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size); + LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size); + LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size); + + + if (src.mBinormals) { - break; + allocateBinormals(src.mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) src.mBinormals, vert_size); } - else if (!strcmp("profile", keyword)) + else { - mProfileParams.importFile(fp); + free(mBinormals); + mBinormals = NULL; } - else if (!strcmp("path",keyword)) + + if (src.mWeights) { - mPathParams.importFile(fp); + allocateWeights(src.mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size); } else { - llwarns << "unknown keyword " << keyword << " in volume import" << llendl; + free(mWeights); + mWeights = NULL; } } - return TRUE; + if (mNumIndices) + { + S32 idx_size = (mNumIndices*sizeof(U16)+0xF) & ~0xF; + + LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size); + } + + //delete + return *this; } -BOOL LLVolumeParams::exportFile(LLFILE *fp) const +LLVolumeFace::~LLVolumeFace() { - fprintf(fp,"\tshape 0\n"); - fprintf(fp,"\t{\n"); - mPathParams.exportFile(fp); - mProfileParams.exportFile(fp); - fprintf(fp, "\t}\n"); - return TRUE; + free(mExtents); + mExtents = NULL; + + freeData(); } +void LLVolumeFace::freeData() +{ + free(mPositions); + mPositions = NULL; + free( mNormals); + mNormals = NULL; + free(mTexCoords); + mTexCoords = NULL; + free(mIndices); + mIndices = NULL; + free(mBinormals); + mBinormals = NULL; + free(mWeights); + mWeights = NULL; + + delete mOctree; + mOctree = NULL; +} -BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream) +BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) { - LLMemType m1(LLMemType::MTYPE_VOLUME); - - //llinfos << "importing volume" << llendl; - const S32 BUFSIZE = 16384; - // *NOTE: changing the size or type of this buffer will require - // changing the sscanf below. - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - char keyword[256]; /* Flawfinder: ignore */ - keyword[0] = 0; + //tree for this face is no longer valid + delete mOctree; + mOctree = NULL; - while (input_stream.good()) + if (mTypeMask & CAP_MASK) { - input_stream.getline(buffer, BUFSIZE); - sscanf(buffer, " %255s", keyword); - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("profile", keyword)) - { - mProfileParams.importLegacyStream(input_stream); - } - else if (!strcmp("path",keyword)) - { - mPathParams.importLegacyStream(input_stream); - } - else - { - llwarns << "unknown keyword " << keyword << " in volume import" << llendl; - } + return createCap(volume, partial_build); + } + else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK)) + { + return createSide(volume, partial_build); + } + else + { + llerrs << "Unknown/uninitialized face type!" << llendl; + return FALSE; } - - return TRUE; -} - -BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - output_stream <<"\tshape 0\n"; - output_stream <<"\t{\n"; - mPathParams.exportLegacyStream(output_stream); - mProfileParams.exportLegacyStream(output_stream); - output_stream << "\t}\n"; - return TRUE; } -LLSD LLVolumeParams::asLLSD() const +void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv) { - LLSD sd = LLSD(); - sd["path"] = mPathParams; - sd["profile"] = mProfileParams; - return sd; + cv.setPosition(mPositions[index]); + cv.setNormal(mNormals[index]); + cv.mTexCoord = mTexCoords[index]; } -bool LLVolumeParams::fromLLSD(LLSD& sd) +bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const { - mPathParams.fromLLSD(sd["path"]); - mProfileParams.fromLLSD(sd["profile"]); - return true; + return getPosition().equals3(rhs.getPosition()) && + mTexCoord == rhs.mTexCoord && + getNormal().equals3(rhs.getNormal()); } -void LLVolumeParams::reduceS(F32 begin, F32 end) +bool LLVolumeFace::VertexMapData::ComparePosition::operator()(const LLVector3& a, const LLVector3& b) const { - begin = llclampf(begin); - end = llclampf(end); - if (begin > end) + if (a.mV[0] != b.mV[0]) { - F32 temp = begin; - begin = end; - end = temp; + return a.mV[0] < b.mV[0]; } - F32 a = mProfileParams.getBegin(); - F32 b = mProfileParams.getEnd(); - mProfileParams.setBegin(a + begin * (b - a)); - mProfileParams.setEnd(a + end * (b - a)); + + if (a.mV[1] != b.mV[1]) + { + return a.mV[1] < b.mV[1]; + } + + return a.mV[2] < b.mV[2]; } -void LLVolumeParams::reduceT(F32 begin, F32 end) +void LLVolumeFace::optimize(F32 angle_cutoff) { - begin = llclampf(begin); - end = llclampf(end); - if (begin > end) + LLVolumeFace new_face; + + //map of points to vector of vertices at that point + VertexMapData::PointMap point_map; + + //remove redundant vertices + for (U32 i = 0; i < mNumIndices; ++i) { - F32 temp = begin; - begin = end; - end = temp; + U16 index = mIndices[i]; + + LLVolumeFace::VertexData cv; + getVertexData(index, cv); + + BOOL found = FALSE; + VertexMapData::PointMap::iterator point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr())); + if (point_iter != point_map.end()) + { //duplicate point might exist + for (U32 j = 0; j < point_iter->second.size(); ++j) + { + LLVolumeFace::VertexData& tv = (point_iter->second)[j]; + if (tv.compareNormal(cv, angle_cutoff)) + { + found = TRUE; + new_face.pushIndex((point_iter->second)[j].mIndex); + break; + } + } + } + + if (!found) + { + new_face.pushVertex(cv); + U16 index = (U16) new_face.mNumVertices-1; + new_face.pushIndex(index); + + VertexMapData d; + d.setPosition(cv.getPosition()); + d.mTexCoord = cv.mTexCoord; + d.setNormal(cv.getNormal()); + d.mIndex = index; + if (point_iter != point_map.end()) + { + point_iter->second.push_back(d); + } + else + { + point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d); + } + } } - F32 a = mPathParams.getBegin(); - F32 b = mPathParams.getEnd(); - mPathParams.setBegin(a + begin * (b - a)); - mPathParams.setEnd(a + end * (b - a)); + + swapData(new_face); } -const F32 MIN_CONCAVE_PROFILE_WEDGE = 0.125f; // 1/8 unity -const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity +class LLVCacheTriangleData; -// returns TRUE if the shape can be approximated with a convex shape -// for collison purposes -BOOL LLVolumeParams::isConvex() const +class LLVCacheVertexData { - F32 path_length = mPathParams.getEnd() - mPathParams.getBegin(); - F32 hollow = mProfileParams.getHollow(); - - U8 path_type = mPathParams.getCurveType(); - if ( path_length > MIN_CONCAVE_PATH_WEDGE - && ( mPathParams.getTwist() != mPathParams.getTwistBegin() - || (hollow > 0.f - && LL_PCODE_PATH_LINE != path_type) ) ) +public: + S32 mIdx; + S32 mCacheTag; + F32 mScore; + U32 mActiveTriangles; + std::vector mTriangles; + + LLVCacheVertexData() { - // twist along a "not too short" path is concave - return FALSE; + mCacheTag = -1; + mScore = 0.f; + mActiveTriangles = 0; + mIdx = -1; } +}; - F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin(); - BOOL same_hole = hollow == 0.f - || (mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK) == LL_PCODE_HOLE_SAME; +class LLVCacheTriangleData +{ +public: + bool mActive; + F32 mScore; + LLVCacheVertexData* mVertex[3]; - F32 min_profile_wedge = MIN_CONCAVE_PROFILE_WEDGE; - U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) + LLVCacheTriangleData() { - // it is a sphere and spheres get twice the minimum profile wedge - min_profile_wedge = 2.f * MIN_CONCAVE_PROFILE_WEDGE; + mActive = true; + mScore = 0.f; + mVertex[0] = mVertex[1] = mVertex[2] = NULL; } - BOOL convex_profile = ( ( profile_length == 1.f - || profile_length <= 0.5f ) - && hollow == 0.f ) // trivially convex - || ( profile_length <= min_profile_wedge - && same_hole ); // effectvely convex (even when hollow) - - if (!convex_profile) + void complete() { - // profile is concave - return FALSE; + mActive = false; + for (S32 i = 0; i < 3; ++i) + { + if (mVertex[i]) + { + llassert_always(mVertex[i]->mActiveTriangles > 0); + mVertex[i]->mActiveTriangles--; + } + } } - if ( LL_PCODE_PATH_LINE == path_type ) - { - // straight paths with convex profile - return TRUE; + bool operator<(const LLVCacheTriangleData& rhs) const + { //highest score first + return rhs.mScore < mScore; } +}; - BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f); - if (concave_path) - { - return FALSE; +const F32 FindVertexScore_CacheDecayPower = 1.5f; +const F32 FindVertexScore_LastTriScore = 0.75f; +const F32 FindVertexScore_ValenceBoostScale = 2.0f; +const F32 FindVertexScore_ValenceBoostPower = 0.5f; +const U32 MaxSizeVertexCache = 32; + +F32 find_vertex_score(LLVCacheVertexData& data) +{ + if (data.mActiveTriangles == 0) + { //no triangle references this vertex + return -1.f; } - // we're left with spheres, toroids and tubes - if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) + F32 score = 0.f; + + S32 cache_idx = data.mCacheTag; + + if (cache_idx < 0) { - // at this stage all spheres must be convex - return TRUE; + //not in cache } - - // it's a toroid or tube - if ( path_length <= MIN_CONCAVE_PATH_WEDGE ) + else { - // effectively convex - return TRUE; + if (cache_idx < 3) + { //vertex was in the last triangle + score = FindVertexScore_LastTriScore; + } + else + { //more points for being higher in the cache + F32 scaler = 1.f/(MaxSizeVertexCache-3); + score = 1.f-((cache_idx-3)*scaler); + score = powf(score, FindVertexScore_CacheDecayPower); + } } - return FALSE; -} - -// debug -void LLVolumeParams::setCube() -{ - mProfileParams.setCurveType(LL_PCODE_PROFILE_SQUARE); - mProfileParams.setBegin(0.f); - mProfileParams.setEnd(1.f); - mProfileParams.setHollow(0.f); + //bonus points for having low valence + F32 valence_boost = powf(data.mActiveTriangles, -FindVertexScore_ValenceBoostPower); + score += FindVertexScore_ValenceBoostScale * valence_boost; - mPathParams.setBegin(0.f); - mPathParams.setEnd(1.f); - mPathParams.setScale(1.f, 1.f); - mPathParams.setShear(0.f, 0.f); - mPathParams.setCurveType(LL_PCODE_PATH_LINE); - mPathParams.setTwistBegin(0.f); - mPathParams.setTwistEnd(0.f); - mPathParams.setRadiusOffset(0.f); - mPathParams.setTaper(0.f, 0.f); - mPathParams.setRevolutions(0.f); - mPathParams.setSkew(0.f); + return score; } -LLFaceID LLVolume::generateFaceMask() +class LLVCacheFIFO { - LLFaceID new_mask = 0x0000; +public: + LLVCacheVertexData* mCache[MaxSizeVertexCache]; + U32 mMisses; - switch(mParams.getProfileParams().getCurveType() & LL_PCODE_PROFILE_MASK) + LLVCacheFIFO() { - case LL_PCODE_PROFILE_CIRCLE: - case LL_PCODE_PROFILE_CIRCLE_HALF: - new_mask |= LL_FACE_OUTER_SIDE_0; - break; - case LL_PCODE_PROFILE_SQUARE: + mMisses = 0; + for (U32 i = 0; i < MaxSizeVertexCache; ++i) { - for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 4.f); side < llceil(mParams.getProfileParams().getEnd() * 4.f); side++) - { - new_mask |= LL_FACE_OUTER_SIDE_0 << side; - } + mCache[i] = NULL; } - break; - case LL_PCODE_PROFILE_ISOTRI: - case LL_PCODE_PROFILE_EQUALTRI: - case LL_PCODE_PROFILE_RIGHTTRI: + } + + void addVertex(LLVCacheVertexData* data) + { + if (data->mCacheTag == -1) { - for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 3.f); side < llceil(mParams.getProfileParams().getEnd() * 3.f); side++) + mMisses++; + + S32 end = MaxSizeVertexCache-1; + + if (mCache[end]) { - new_mask |= LL_FACE_OUTER_SIDE_0 << side; + mCache[end]->mCacheTag = -1; + } + + for (S32 i = end; i > 0; --i) + { + mCache[i] = mCache[i-1]; + if (mCache[i]) + { + mCache[i]->mCacheTag = i; + } } + + mCache[0] = data; + data->mCacheTag = 0; } - break; - default: - llerrs << "Unknown profile!" << llendl; - break; } +}; - // handle hollow objects - if (mParams.getProfileParams().getHollow() > 0) +class LLVCacheLRU +{ +public: + LLVCacheVertexData* mCache[MaxSizeVertexCache+3]; + + LLVCacheTriangleData* mBestTriangle; + + U32 mMisses; + + LLVCacheLRU() { - new_mask |= LL_FACE_INNER_SIDE; + for (U32 i = 0; i < MaxSizeVertexCache+3; ++i) + { + mCache[i] = NULL; + } + + mBestTriangle = NULL; + mMisses = 0; } - // handle open profile curves - if (mProfilep->isOpen()) + void addVertex(LLVCacheVertexData* data) { - new_mask |= LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END; + S32 end = MaxSizeVertexCache+2; + if (data->mCacheTag != -1) + { //just moving a vertex to the front of the cache + end = data->mCacheTag; + } + else + { + mMisses++; + if (mCache[end]) + { //adding a new vertex, vertex at end of cache falls off + mCache[end]->mCacheTag = -1; + } + } + + for (S32 i = end; i > 0; --i) + { //adjust cache pointers and tags + mCache[i] = mCache[i-1]; + + if (mCache[i]) + { + mCache[i]->mCacheTag = i; + } + } + + mCache[0] = data; + mCache[0]->mCacheTag = 0; } - // handle open path curves - if (mPathp->isOpen()) + void addTriangle(LLVCacheTriangleData* data) { - new_mask |= LL_FACE_PATH_BEGIN | LL_FACE_PATH_END; + addVertex(data->mVertex[0]); + addVertex(data->mVertex[1]); + addVertex(data->mVertex[2]); } - return new_mask; -} - -BOOL LLVolume::isFaceMaskValid(LLFaceID face_mask) -{ - LLFaceID test_mask = 0; - for(S32 i = 0; i < getNumFaces(); i++) + void updateScores() { - test_mask |= mProfilep->mFaces[i].mFaceID; + for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i) + { //trailing 3 vertices aren't actually in the cache for scoring purposes + if (mCache[i]) + { + mCache[i]->mCacheTag = -1; + } + } + + for (U32 i = 0; i < MaxSizeVertexCache; ++i) + { //update scores of vertices in cache + if (mCache[i]) + { + mCache[i]->mScore = find_vertex_score(*(mCache[i])); + llassert_always(mCache[i]->mCacheTag == i); + } + } + + mBestTriangle = NULL; + //update triangle scores + for (U32 i = 0; i < MaxSizeVertexCache+3; ++i) + { + if (mCache[i]) + { + for (U32 j = 0; j < mCache[i]->mTriangles.size(); ++j) + { + LLVCacheTriangleData* tri = mCache[i]->mTriangles[j]; + if (tri->mActive) + { + tri->mScore = tri->mVertex[0]->mScore; + tri->mScore += tri->mVertex[1]->mScore; + tri->mScore += tri->mVertex[2]->mScore; + + if (!mBestTriangle || mBestTriangle->mScore < tri->mScore) + { + mBestTriangle = tri; + } + } + } + } + } + + //knock trailing 3 vertices off the cache + for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i) + { + if (mCache[i]) + { + llassert_always(mCache[i]->mCacheTag == -1); + mCache[i] = NULL; + } + } } +}; - return test_mask == face_mask; -} -BOOL LLVolume::isConvex() const -{ - // mParams.isConvex() may return FALSE even though the final - // geometry is actually convex due to LOD approximations. - // TODO -- provide LLPath and LLProfile with isConvex() methods - // that correctly determine convexity. -- Leviathan - return mParams.isConvex(); -} +void LLVolumeFace::cacheOptimize() +{ //optimize for vertex cache according to Forsyth method: + // http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html + + LLVCacheLRU cache; + + //mapping of vertices to triangles and indices + std::vector vertex_data; + //mapping of triangles do vertices + std::vector triangle_data; -std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params) -{ - s << "{type=" << (U32) profile_params.mCurveType; - s << ", begin=" << profile_params.mBegin; - s << ", end=" << profile_params.mEnd; - s << ", hollow=" << profile_params.mHollow; - s << "}"; - return s; -} + triangle_data.resize(mNumIndices/3); + vertex_data.resize(mNumVertices); + for (U32 i = 0; i < mNumIndices; i++) + { //populate vertex data and triangle data arrays + U16 idx = mIndices[i]; + U32 tri_idx = i/3; -std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params) -{ - s << "{type=" << (U32) path_params.mCurveType; - s << ", begin=" << path_params.mBegin; - s << ", end=" << path_params.mEnd; - s << ", twist=" << path_params.mTwistEnd; - s << ", scale=" << path_params.mScale; - s << ", shear=" << path_params.mShear; - s << ", twist_begin=" << path_params.mTwistBegin; - s << ", radius_offset=" << path_params.mRadiusOffset; - s << ", taper=" << path_params.mTaper; - s << ", revolutions=" << path_params.mRevolutions; - s << ", skew=" << path_params.mSkew; - s << "}"; - return s; -} + vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx])); + vertex_data[idx].mIdx = idx; + triangle_data[tri_idx].mVertex[i%3] = &(vertex_data[idx]); + } + /*F32 pre_acmr = 1.f; + //measure cache misses from before rebuild + { + LLVCacheFIFO test_cache; + for (U32 i = 0; i < mNumIndices; ++i) + { + test_cache.addVertex(&vertex_data[mIndices[i]]); + } -std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params) -{ - s << "{profileparams = " << volume_params.mProfileParams; - s << ", pathparams = " << volume_params.mPathParams; - s << "}"; - return s; -} + for (U32 i = 0; i < mNumVertices; i++) + { + vertex_data[i].mCacheTag = -1; + } + pre_acmr = (F32) test_cache.mMisses/(mNumIndices/3); + }*/ -std::ostream& operator<<(std::ostream &s, const LLProfile &profile) -{ - s << " {open=" << (U32) profile.mOpen; - s << ", dirty=" << profile.mDirty; - s << ", totalout=" << profile.mTotalOut; - s << ", total=" << profile.mTotal; - s << "}"; - return s; -} + for (U32 i = 0; i < mNumVertices; i++) + { //initialize score values (no cache -- might try a fifo cache here) + vertex_data[i].mScore = find_vertex_score(vertex_data[i]); + vertex_data[i].mActiveTriangles = vertex_data[i].mTriangles.size(); + for (U32 j = 0; j < vertex_data[i].mTriangles.size(); ++j) + { + vertex_data[i].mTriangles[j]->mScore += vertex_data[i].mScore; + } + } -std::ostream& operator<<(std::ostream &s, const LLPath &path) -{ - s << "{open=" << (U32) path.mOpen; - s << ", dirty=" << path.mDirty; - s << ", step=" << path.mStep; - s << ", total=" << path.mTotal; - s << "}"; - return s; -} + //sort triangle data by score + std::sort(triangle_data.begin(), triangle_data.end()); -std::ostream& operator<<(std::ostream &s, const LLVolume &volume) -{ - s << "{params = " << volume.getParams(); - s << ", path = " << *volume.mPathp; - s << ", profile = " << *volume.mProfilep; - s << "}"; - return s; -} + std::vector new_indices; + LLVCacheTriangleData* tri; -std::ostream& operator<<(std::ostream &s, const LLVolume *volumep) -{ - s << "{params = " << volumep->getParams(); - s << ", path = " << *(volumep->mPathp); - s << ", profile = " << *(volumep->mProfilep); - s << "}"; - return s; -} + //prime pump by adding first triangle to cache; + tri = &(triangle_data[0]); + cache.addTriangle(tri); + new_indices.push_back(tri->mVertex[0]->mIdx); + new_indices.push_back(tri->mVertex[1]->mIdx); + new_indices.push_back(tri->mVertex[2]->mIdx); + tri->complete(); + U32 breaks = 0; + for (U32 i = 1; i < mNumIndices/3; ++i) + { + cache.updateScores(); + tri = cache.mBestTriangle; + if (!tri) + { + breaks++; + for (U32 j = 0; j < triangle_data.size(); ++j) + { + if (triangle_data[j].mActive) + { + tri = &(triangle_data[j]); + break; + } + } + } + + cache.addTriangle(tri); + new_indices.push_back(tri->mVertex[0]->mIdx); + new_indices.push_back(tri->mVertex[1]->mIdx); + new_indices.push_back(tri->mVertex[2]->mIdx); + tri->complete(); + } -BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) -{ - BOOL ret = FALSE ; - if (mTypeMask & CAP_MASK) + for (U32 i = 0; i < mNumIndices; ++i) { - ret = createCap(volume, partial_build); + mIndices[i] = new_indices[i]; } - else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK)) + + /*F32 post_acmr = 1.f; + //measure cache misses from after rebuild + { + LLVCacheFIFO test_cache; + for (U32 i = 0; i < mNumVertices; i++) + { + vertex_data[i].mCacheTag = -1; + } + + for (U32 i = 0; i < mNumIndices; ++i) + { + test_cache.addVertex(&vertex_data[mIndices[i]]); + } + + post_acmr = (F32) test_cache.mMisses/(mNumIndices/3); + }*/ + + //optimize for pre-TnL cache + + //allocate space for new buffer + S32 num_verts = mNumVertices; + LLVector4a* pos = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); + LLVector4a* norm = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); + S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF; + LLVector2* tc = (LLVector2*) malloc(size); + + LLVector4a* wght = NULL; + if (mWeights) { - ret = createSide(volume, partial_build); + wght = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); } - else + + LLVector4a* binorm = NULL; + if (mBinormals) { - llerrs << "Unknown/uninitialized face type!" << llendl; + binorm = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); } - //update the range of the texture coordinates - if(ret) + //allocate mapping of old indices to new indices + std::vector new_idx; + new_idx.resize(mNumVertices, -1); + + S32 cur_idx = 0; + for (U32 i = 0; i < mNumIndices; ++i) { - mTexCoordExtents[0].setVec(1.f, 1.f) ; - mTexCoordExtents[1].setVec(0.f, 0.f) ; + U16 idx = mIndices[i]; + if (new_idx[idx] == -1) + { //this vertex hasn't been added yet + new_idx[idx] = cur_idx; - U32 end = mVertices.size() ; - for(U32 i = 0 ; i < end ; i++) - { - if(mTexCoordExtents[0].mV[0] > mVertices[i].mTexCoord.mV[0]) + //copy vertex data + pos[cur_idx] = mPositions[idx]; + norm[cur_idx] = mNormals[idx]; + tc[cur_idx] = mTexCoords[idx]; + if (mWeights) { - mTexCoordExtents[0].mV[0] = mVertices[i].mTexCoord.mV[0] ; + wght[cur_idx] = mWeights[idx]; } - if(mTexCoordExtents[1].mV[0] < mVertices[i].mTexCoord.mV[0]) + if (mBinormals) { - mTexCoordExtents[1].mV[0] = mVertices[i].mTexCoord.mV[0] ; + binorm[cur_idx] = mBinormals[idx]; } - if(mTexCoordExtents[0].mV[1] > mVertices[i].mTexCoord.mV[1]) - { - mTexCoordExtents[0].mV[1] = mVertices[i].mTexCoord.mV[1] ; - } - if(mTexCoordExtents[1].mV[1] < mVertices[i].mTexCoord.mV[1]) - { - mTexCoordExtents[1].mV[1] = mVertices[i].mTexCoord.mV[1] ; - } + cur_idx++; } - mTexCoordExtents[0].mV[0] = llmax(0.f, mTexCoordExtents[0].mV[0]) ; - mTexCoordExtents[0].mV[1] = llmax(0.f, mTexCoordExtents[0].mV[1]) ; - mTexCoordExtents[1].mV[0] = llmin(1.f, mTexCoordExtents[1].mV[0]) ; - mTexCoordExtents[1].mV[1] = llmin(1.f, mTexCoordExtents[1].mV[1]) ; } - return ret ; + for (U32 i = 0; i < mNumIndices; ++i) + { + mIndices[i] = new_idx[mIndices[i]]; + } + + free(mPositions); + free(mNormals); + free(mTexCoords); + free(mWeights); + free(mBinormals); + + mPositions = pos; + mNormals = norm; + mTexCoords = tc; + mWeights = wght; + mBinormals = binorm; + + //std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks); + //llinfos << result << llendl; + +} + +void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size) +{ + if (mOctree) + { + return; + } + + mOctree = new LLOctreeRoot(center, size, NULL); + new LLVolumeOctreeListener(mOctree); + + for (U32 i = 0; i < mNumIndices; i+= 3) + { //for each triangle + LLPointer tri = new LLVolumeTriangle(); + + const LLVector4a& v0 = mPositions[mIndices[i]]; + const LLVector4a& v1 = mPositions[mIndices[i+1]]; + const LLVector4a& v2 = mPositions[mIndices[i+2]]; + + //store pointers to vertex data + tri->mV[0] = &v0; + tri->mV[1] = &v1; + tri->mV[2] = &v2; + + //store indices + tri->mIndex[0] = mIndices[i]; + tri->mIndex[1] = mIndices[i+1]; + tri->mIndex[2] = mIndices[i+2]; + + //get minimum point + LLVector4a min = v0; + min.setMin(min, v1); + min.setMin(min, v2); + + //get maximum point + LLVector4a max = v0; + max.setMax(max, v1); + max.setMax(max, v2); + + //compute center + LLVector4a center; + center.setAdd(min, max); + center.mul(0.5f); + + tri->mPositionGroup = center; + + //compute "radius" + LLVector4a size; + size.setSub(max,min); + + tri->mRadius = size.getLength3().getF32() * scaler; + + //insert + mOctree->insert(tri); + } + + //remove unneeded octree layers + while (!mOctree->balance()) { } + + //calculate AABB for each node + LLVolumeOctreeRebound rebound(this); + rebound.traverse(mOctree); + + if (gDebugGL) + { + LLVolumeOctreeValidate validate; + validate.traverse(mOctree); + } +} + + +void LLVolumeFace::swapData(LLVolumeFace& rhs) +{ + llswap(rhs.mPositions, mPositions); + llswap(rhs.mNormals, mNormals); + llswap(rhs.mBinormals, mBinormals); + llswap(rhs.mTexCoords, mTexCoords); + llswap(rhs.mIndices,mIndices); + llswap(rhs.mNumVertices, mNumVertices); + llswap(rhs.mNumIndices, mNumIndices); } void LerpPlanarVertex(LLVolumeFace::VertexData& v0, @@ -4463,10 +6019,21 @@ void LerpPlanarVertex(LLVolumeFace::VertexData& v0, F32 coef01, F32 coef02) { - vout.mPosition = v0.mPosition + ((v1.mPosition-v0.mPosition)*coef01)+((v2.mPosition-v0.mPosition)*coef02); + + LLVector4a lhs; + lhs.setSub(v1.getPosition(), v0.getPosition()); + lhs.mul(coef01); + LLVector4a rhs; + rhs.setSub(v2.getPosition(), v0.getPosition()); + rhs.mul(coef02); + + rhs.add(lhs); + rhs.add(v0.getPosition()); + + vout.setPosition(rhs); + vout.mTexCoord = v0.mTexCoord + ((v1.mTexCoord-v0.mTexCoord)*coef01)+((v2.mTexCoord-v0.mTexCoord)*coef02); - vout.mNormal = v0.mNormal; - vout.mBinormal = v0.mBinormal; + vout.setNormal(v0.getNormal()); } BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) @@ -4486,84 +6053,113 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) num_vertices = (grid_size+1)*(grid_size+1); num_indices = quad_count * 4; - LLVector3& min = mExtents[0]; - LLVector3& max = mExtents[1]; + LLVector4a& min = mExtents[0]; + LLVector4a& max = mExtents[1]; S32 offset = 0; if (mTypeMask & TOP_MASK) + { offset = (max_t-1) * max_s; + } else + { offset = mBeginS; + } + + { + VertexData corners[4]; + VertexData baseVert; + for(S32 t = 0; t < 4; t++) + { + corners[t].getPosition().load3( mesh[offset + (grid_size*t)].mPos.mV); + corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f; + corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1]; + } + + { + LLVector4a lhs; + lhs.setSub(corners[1].getPosition(), corners[0].getPosition()); + LLVector4a rhs; + rhs.setSub(corners[2].getPosition(), corners[1].getPosition()); + baseVert.getNormal().setCross3(lhs, rhs); + baseVert.getNormal().normalize3fast(); + } + + if(!(mTypeMask & TOP_MASK)) + { + baseVert.getNormal().mul(-1.0f); + } + else + { + //Swap the UVs on the U(X) axis for top face + LLVector2 swap; + swap = corners[0].mTexCoord; + corners[0].mTexCoord=corners[3].mTexCoord; + corners[3].mTexCoord=swap; + swap = corners[1].mTexCoord; + corners[1].mTexCoord=corners[2].mTexCoord; + corners[2].mTexCoord=swap; + } - VertexData corners[4]; - VertexData baseVert; - for(int t = 0; t < 4; t++){ - corners[t].mPosition = mesh[offset + (grid_size*t)].mPos; - corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f; - corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1]; - } - baseVert.mNormal = - ((corners[1].mPosition-corners[0].mPosition) % - (corners[2].mPosition-corners[1].mPosition)); - baseVert.mNormal.normVec(); - if(!(mTypeMask & TOP_MASK)){ - baseVert.mNormal *= -1.0f; - }else{ - //Swap the UVs on the U(X) axis for top face - LLVector2 swap; - swap = corners[0].mTexCoord; - corners[0].mTexCoord=corners[3].mTexCoord; - corners[3].mTexCoord=swap; - swap = corners[1].mTexCoord; - corners[1].mTexCoord=corners[2].mTexCoord; - corners[2].mTexCoord=swap; - } - baseVert.mBinormal = calc_binormal_from_triangle( - corners[0].mPosition, corners[0].mTexCoord, - corners[1].mPosition, corners[1].mTexCoord, - corners[2].mPosition, corners[2].mTexCoord); - for(int t = 0; t < 4; t++){ - corners[t].mBinormal = baseVert.mBinormal; - corners[t].mNormal = baseVert.mNormal; - } - mHasBinormals = TRUE; + LLVector4a binormal; + + calc_binormal_from_triangle( binormal, + corners[0].getPosition(), corners[0].mTexCoord, + corners[1].getPosition(), corners[1].mTexCoord, + corners[2].getPosition(), corners[2].mTexCoord); + + binormal.normalize3fast(); - if (partial_build) - { - mVertices.clear(); - } + S32 size = (grid_size+1)*(grid_size+1); + resizeVertices(size); + allocateBinormals(size); - S32 vtop = mVertices.size(); - for(int gx = 0;gxsetAdd(min, max); + mCenter->mul(0.5f); + } if (!partial_build) { -#if GEN_TRI_STRIP - mTriStrip.clear(); -#endif + resizeIndices(grid_size*grid_size*6); + + U16* out = mIndices; + S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; for(S32 gx = 0;gx=0;i--) { - mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]); - } - -#if GEN_TRI_STRIP - if (gy == 0) - { - mTriStrip.push_back((gx+1)*(grid_size+1)); - mTriStrip.push_back((gx+1)*(grid_size+1)); - mTriStrip.push_back(gx*(grid_size+1)); - } - - mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1)); - mTriStrip.push_back(gy+1+gx*(grid_size+1)); - - - if (gy == grid_size-1) - { - mTriStrip.push_back(gy+1+gx*(grid_size+1)); - } -#endif + *out++ = ((gy*(grid_size+1))+gx+idxs[i]); + } } else { for(S32 i=0;i<6;i++) { - mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]); - } - -#if GEN_TRI_STRIP - if (gy == 0) - { - mTriStrip.push_back(gx*(grid_size+1)); - mTriStrip.push_back(gx*(grid_size+1)); - mTriStrip.push_back((gx+1)*(grid_size+1)); - } - - mTriStrip.push_back(gy+1+gx*(grid_size+1)); - mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1)); - - if (gy == grid_size-1) - { - mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1)); + *out++ = ((gy*(grid_size+1))+gx+idxs[i]); } -#endif } - } - - } - -#if GEN_TRI_STRIP - if (mTriStrip.size()%2 == 1) - { - mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); + } } -#endif } return TRUE; @@ -4658,17 +6211,31 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) num_vertices = profile.size(); num_indices = (profile.size() - 2)*3; - mVertices.resize(num_vertices); + if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) + { + resizeVertices(num_vertices+1); + allocateBinormals(num_vertices+1); - if (!partial_build) + if (!partial_build) + { + resizeIndices(num_indices+3); + } + } + else { - mIndices.resize(num_indices); + resizeVertices(num_vertices); + allocateBinormals(num_vertices); + + if (!partial_build) + { + resizeIndices(num_indices); + } } S32 max_s = volume->getProfile().getTotal(); S32 max_t = volume->getPath().mPath.size(); - mCenter.clearVec(); + mCenter->clear(); S32 offset = 0; if (mTypeMask & TOP_MASK) @@ -4686,82 +6253,91 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) LLVector2 cuv; LLVector2 min_uv, max_uv; - LLVector3& min = mExtents[0]; - LLVector3& max = mExtents[1]; + LLVector4a& min = mExtents[0]; + LLVector4a& max = mExtents[1]; + + LLVector2* tc = (LLVector2*) mTexCoords; + LLVector4a* pos = (LLVector4a*) mPositions; + LLVector4a* norm = (LLVector4a*) mNormals; + LLVector4a* binorm = (LLVector4a*) mBinormals; // Copy the vertices into the array for (S32 i = 0; i < num_vertices; i++) { if (mTypeMask & TOP_MASK) { - mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f; - mVertices[i].mTexCoord.mV[1] = profile[i].mV[1]+0.5f; + tc[i].mV[0] = profile[i].mV[0]+0.5f; + tc[i].mV[1] = profile[i].mV[1]+0.5f; } else { // Mirror for underside. - mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f; - mVertices[i].mTexCoord.mV[1] = 0.5f - profile[i].mV[1]; + tc[i].mV[0] = profile[i].mV[0]+0.5f; + tc[i].mV[1] = 0.5f - profile[i].mV[1]; } - mVertices[i].mPosition = mesh[i + offset].mPos; + pos[i].load3(mesh[i + offset].mPos.mV); if (i == 0) { - min = max = mVertices[i].mPosition; - min_uv = max_uv = mVertices[i].mTexCoord; + max = pos[i]; + min = max; + min_uv = max_uv = tc[i]; } else { - update_min_max(min,max, mVertices[i].mPosition); - update_min_max(min_uv, max_uv, mVertices[i].mTexCoord); + update_min_max(min,max,pos[i]); + update_min_max(min_uv, max_uv, tc[i]); } } - mCenter = (min+max)*0.5f; + mCenter->setAdd(min, max); + mCenter->mul(0.5f); + cuv = (min_uv + max_uv)*0.5f; - LLVector3 binormal = calc_binormal_from_triangle( - mCenter, cuv, - mVertices[0].mPosition, mVertices[0].mTexCoord, - mVertices[1].mPosition, mVertices[1].mTexCoord); - binormal.normVec(); + LLVector4a binormal; + calc_binormal_from_triangle(binormal, + *mCenter, cuv, + pos[0], tc[0], + pos[1], tc[1]); + binormal.normalize3fast(); + + LLVector4a normal; + LLVector4a d0, d1; + - LLVector3 d0; - LLVector3 d1; - LLVector3 normal; + d0.setSub(*mCenter, pos[0]); + d1.setSub(*mCenter, pos[1]); - d0 = mCenter-mVertices[0].mPosition; - d1 = mCenter-mVertices[1].mPosition; + if (mTypeMask & TOP_MASK) + { + normal.setCross3(d0, d1); + } + else + { + normal.setCross3(d1, d0); + } - normal = (mTypeMask & TOP_MASK) ? (d0%d1) : (d1%d0); - normal.normVec(); + normal.normalize3fast(); VertexData vd; - vd.mPosition = mCenter; - vd.mNormal = normal; - vd.mBinormal = binormal; + vd.setPosition(*mCenter); vd.mTexCoord = cuv; if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) { - mVertices.push_back(vd); + pos[num_vertices] = *mCenter; + tc[num_vertices] = cuv; num_vertices++; - if (!partial_build) - { - vector_append(mIndices, 3); - } } - for (S32 i = 0; i < num_vertices; i++) { - mVertices[i].mBinormal = binormal; - mVertices[i].mNormal = normal; + binorm[i].load4a(binormal.getF32ptr()); + norm[i].load4a(normal.getF32ptr()); } - mHasBinormals = TRUE; - if (partial_build) { return TRUE; @@ -4869,8 +6445,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) pt2--; } } - - makeTriStrip(); } else { @@ -4975,8 +6549,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) pt2--; } } - - makeTriStrip(); } } else @@ -4998,131 +6570,277 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) mIndices[3*i+v2] = i + 1; } -#if GEN_TRI_STRIP - //make tri strip - if (mTypeMask & OPEN_MASK) - { - makeTriStrip(); - } - else - { - S32 j = num_vertices-2; - if (mTypeMask & TOP_MASK) - { - mTriStrip.push_back(0); - for (S32 i = 0; i <= j; ++i) - { - mTriStrip.push_back(i); - if (i != j) - { - mTriStrip.push_back(j); - } - --j; - } - } - else - { - mTriStrip.push_back(j); - for (S32 i = 0; i <= j; ++i) - { - if (i != j) - { - mTriStrip.push_back(j); - } - mTriStrip.push_back(i); - --j; - } - } - - mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); - if (mTriStrip.size()%2 == 1) - { - mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); - } - } -#endif } return TRUE; } -void LLVolumeFace::makeTriStrip() +void LLVolumeFace::createBinormals() { -#if GEN_TRI_STRIP - for (U32 i = 0; i < mIndices.size(); i+=3) + LLMemType m1(LLMemType::MTYPE_VOLUME); + + if (!mBinormals) { - U16 i0 = mIndices[i]; - U16 i1 = mIndices[i+1]; - U16 i2 = mIndices[i+2]; + allocateBinormals(mNumVertices); - if ((i/3)%2 == 1) - { - mTriStrip.push_back(i0); - mTriStrip.push_back(i0); - mTriStrip.push_back(i1); - mTriStrip.push_back(i2); - mTriStrip.push_back(i2); - } - else + //generate binormals + LLVector4a* pos = mPositions; + LLVector2* tc = (LLVector2*) mTexCoords; + LLVector4a* binorm = (LLVector4a*) mBinormals; + + LLVector4a* end = mBinormals+mNumVertices; + while (binorm < end) { - mTriStrip.push_back(i2); - mTriStrip.push_back(i2); - mTriStrip.push_back(i1); - mTriStrip.push_back(i0); - mTriStrip.push_back(i0); + (*binorm++).clear(); } - } - if (mTriStrip.size()%2 == 1) - { - mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); - } -#endif -} + binorm = mBinormals; -void LLVolumeFace::createBinormals() -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - if (!mHasBinormals) - { - //generate binormals - for (U32 i = 0; i < mIndices.size()/3; i++) + for (U32 i = 0; i < mNumIndices/3; i++) { //for each triangle - const VertexData& v0 = mVertices[mIndices[i*3+0]]; - const VertexData& v1 = mVertices[mIndices[i*3+1]]; - const VertexData& v2 = mVertices[mIndices[i*3+2]]; + const U16& i0 = mIndices[i*3+0]; + const U16& i1 = mIndices[i*3+1]; + const U16& i2 = mIndices[i*3+2]; //calculate binormal - LLVector3 binorm = calc_binormal_from_triangle(v0.mPosition, v0.mTexCoord, - v1.mPosition, v1.mTexCoord, - v2.mPosition, v2.mTexCoord); + LLVector4a binormal; + calc_binormal_from_triangle(binormal, + pos[i0], tc[i0], + pos[i1], tc[i1], + pos[i2], tc[i2]); - for (U32 j = 0; j < 3; j++) - { //add triangle normal to vertices - mVertices[mIndices[i*3+j]].mBinormal += binorm; // * (weight_sum - d[j])/weight_sum; - } + + //add triangle normal to vertices + binorm[i0].add(binormal); + binorm[i1].add(binormal); + binorm[i2].add(binormal); //even out quad contributions if (i % 2 == 0) { - mVertices[mIndices[i*3+2]].mBinormal += binorm; + binorm[i2].add(binormal); } else { - mVertices[mIndices[i*3+1]].mBinormal += binorm; + binorm[i1].add(binormal); } } //normalize binormals - for (U32 i = 0; i < mVertices.size(); i++) + for (U32 i = 0; i < mNumVertices; i++) + { + binorm[i].normalize3fast(); + //bump map/planar projection code requires normals to be normalized + mNormals[i].normalize3fast(); + } + } +} + +void LLVolumeFace::resizeVertices(S32 num_verts) +{ + free(mPositions); + free(mNormals); + free(mBinormals); + free(mTexCoords); + + mBinormals = NULL; + + if (num_verts) + { + mPositions = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); + assert_aligned(mPositions, 16); + mNormals = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); + assert_aligned(mNormals, 16); + + //pad texture coordinate block end to allow for QWORD reads + S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF; + mTexCoords = (LLVector2*) malloc(size); + assert_aligned(mTexCoords, 16); + } + else + { + mPositions = NULL; + mNormals = NULL; + mTexCoords = NULL; + } + + mNumVertices = num_verts; +} + +void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv) +{ + pushVertex(cv.getPosition(), cv.getNormal(), cv.mTexCoord); +} + +void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc) +{ + S32 new_verts = mNumVertices+1; + S32 new_size = new_verts*16; +// S32 old_size = mNumVertices*16; + + //positions + mPositions = (LLVector4a*) realloc(mPositions, new_size); + + //normals + mNormals = (LLVector4a*) realloc(mNormals, new_size); + + //tex coords + new_size = ((new_verts*8)+0xF) & ~0xF; + mTexCoords = (LLVector2*) realloc(mTexCoords, new_size); + + + //just clear binormals + free(mBinormals); + mBinormals = NULL; + + mPositions[mNumVertices] = pos; + mNormals[mNumVertices] = norm; + mTexCoords[mNumVertices] = tc; + + mNumVertices++; +} + +void LLVolumeFace::allocateBinormals(S32 num_verts) +{ + free(mBinormals); + mBinormals = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); +} + +void LLVolumeFace::allocateWeights(S32 num_verts) +{ + free(mWeights); + mWeights = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); +} + +void LLVolumeFace::resizeIndices(S32 num_indices) +{ + free(mIndices); + + if (num_indices) + { + //pad index block end to allow for QWORD reads + S32 size = ((num_indices*sizeof(U16)) + 0xF) & ~0xF; + + mIndices = (U16*) malloc(size); + } + else + { + mIndices = NULL; + } + + mNumIndices = num_indices; +} + +void LLVolumeFace::pushIndex(const U16& idx) +{ + S32 new_count = mNumIndices + 1; + S32 new_size = ((new_count*2)+0xF) & ~0xF; + + S32 old_size = ((mNumIndices*2)+0xF) & ~0xF; + if (new_size != old_size) + { + mIndices = (U16*) realloc(mIndices, new_size); + } + + mIndices[mNumIndices++] = idx; +} + +void LLVolumeFace::fillFromLegacyData(std::vector& v, std::vector& idx) +{ + resizeVertices(v.size()); + resizeIndices(idx.size()); + + for (U32 i = 0; i < v.size(); ++i) + { + mPositions[i] = v[i].getPosition(); + mNormals[i] = v[i].getNormal(); + mTexCoords[i] = v[i].mTexCoord; + } + + for (U32 i = 0; i < idx.size(); ++i) + { + mIndices[i] = idx[i]; + } +} + +void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMatrix4& norm_mat_in) +{ + U16 offset = mNumVertices; + + S32 new_count = face.mNumVertices + mNumVertices; + + if (new_count > 65536) + { + llerrs << "Cannot append face -- 16-bit overflow will occur." << llendl; + } + + if (face.mNumVertices == 0) + { + llerrs << "Cannot append empty face." << llendl; + } + + //allocate new buffer space + mPositions = (LLVector4a*) realloc(mPositions, new_count*sizeof(LLVector4a)); + assert_aligned(mPositions, 16); + mNormals = (LLVector4a*) realloc(mNormals, new_count*sizeof(LLVector4a)); + assert_aligned(mNormals, 16); + mTexCoords = (LLVector2*) realloc(mTexCoords, (new_count*sizeof(LLVector2)+0xF) & ~0xF); + assert_aligned(mTexCoords, 16); + + mNumVertices = new_count; + + //get destination address of appended face + LLVector4a* dst_pos = mPositions+offset; + LLVector2* dst_tc = mTexCoords+offset; + LLVector4a* dst_norm = mNormals+offset; + + //get source addresses of appended face + const LLVector4a* src_pos = face.mPositions; + const LLVector2* src_tc = face.mTexCoords; + const LLVector4a* src_norm = face.mNormals; + + //load aligned matrices + LLMatrix4a mat, norm_mat; + mat.loadu(mat_in); + norm_mat.loadu(norm_mat_in); + + for (U32 i = 0; i < face.mNumVertices; ++i) + { + //transform appended face position and store + mat.affineTransform(src_pos[i], dst_pos[i]); + + //transform appended face normal and store + norm_mat.rotate(src_norm[i], dst_norm[i]); + dst_norm[i].normalize3fast(); + + //copy appended face texture coordinate + dst_tc[i] = src_tc[i]; + + if (offset == 0 && i == 0) + { //initialize bounding box + mExtents[0] = mExtents[1] = dst_pos[i]; + } + else { - mVertices[i].mBinormal.normVec(); - mVertices[i].mNormal.normVec(); + //stretch bounding box + update_min_max(mExtents[0], mExtents[1], dst_pos[i]); } + } + - mHasBinormals = TRUE; + new_count = mNumIndices + face.mNumIndices; + + //allocate new index buffer + mIndices = (U16*) realloc(mIndices, (new_count*sizeof(U16)+0xF) & ~0xF); + + //get destination address into new index buffer + U16* dst_idx = mIndices+mNumIndices; + mNumIndices = new_count; + + for (U32 i = 0; i < face.mNumIndices; ++i) + { //copy indices, offsetting by old vertex count + dst_idx[i] = face.mIndices[i]+offset; } } @@ -5152,18 +6870,20 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) num_vertices = mNumS*mNumT; num_indices = (mNumS-1)*(mNumT-1)*6; - mVertices.resize(num_vertices); - if (!partial_build) { - mIndices.resize(num_indices); - mEdge.resize(num_indices); - } - else - { - mHasBinormals = FALSE; + resizeVertices(num_vertices); + resizeIndices(num_indices); + + if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) + { + mEdge.resize(num_indices); + } } + LLVector4a* pos = (LLVector4a*) mPositions; + LLVector4a* norm = (LLVector4a*) mNormals; + LLVector2* tc = (LLVector2*) mTexCoords; S32 begin_stex = llfloor( profile[mBeginS].mV[2] ); S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS; @@ -5214,21 +6934,20 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) i = mBeginS + s + max_s*t; } - mVertices[cur_vertex].mPosition = mesh[i].mPos; - mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); + pos[cur_vertex].load3(mesh[i].mPos.mV); + tc[cur_vertex] = LLVector2(ss,tt); - mVertices[cur_vertex].mNormal = LLVector3(0,0,0); - mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); - + norm[cur_vertex].clear(); cur_vertex++; if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0) { - mVertices[cur_vertex].mPosition = mesh[i].mPos; - mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); + + pos[cur_vertex].load3(mesh[i].mPos.mV); + tc[cur_vertex] = LLVector2(ss,tt); - mVertices[cur_vertex].mNormal = LLVector3(0,0,0); - mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); + norm[cur_vertex].clear(); + cur_vertex++; } } @@ -5246,29 +6965,29 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) i = mBeginS + s + max_s*t; ss = profile[mBeginS + s].mV[2] - begin_stex; - mVertices[cur_vertex].mPosition = mesh[i].mPos; - mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); - - mVertices[cur_vertex].mNormal = LLVector3(0,0,0); - mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); - + pos[cur_vertex].load3(mesh[i].mPos.mV); + tc[cur_vertex] = LLVector2(ss,tt); + norm[cur_vertex].clear(); + cur_vertex++; } } //get bounding box for this side - LLVector3& face_min = mExtents[0]; - LLVector3& face_max = mExtents[1]; - mCenter.clearVec(); + LLVector4a& face_min = mExtents[0]; + LLVector4a& face_max = mExtents[1]; + mCenter->clear(); - face_min = face_max = mVertices[0].mPosition; - for (U32 i = 1; i < mVertices.size(); ++i) + face_min = face_max = pos[0]; + + for (U32 i = 1; i < mNumVertices; ++i) { - update_min_max(face_min, face_max, mVertices[i].mPosition); + update_min_max(face_min, face_max, pos[i]); } - mCenter = (face_min + face_max) * 0.5f; + mCenter->setAdd(face_min, face_max); + mCenter->mul(0.5f); S32 cur_index = 0; S32 cur_edge = 0; @@ -5276,18 +6995,9 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) if (!partial_build) { -#if GEN_TRI_STRIP - mTriStrip.clear(); -#endif - // Now we generate the indices. for (t = 0; t < (mNumT-1); t++) { -#if GEN_TRI_STRIP - //prepend terminating index to strip - mTriStrip.push_back(mNumS*t); -#endif - for (s = 0; s < (mNumS-1); s++) { mIndices[cur_index++] = s + mNumS*t; //bottom left @@ -5297,16 +7007,6 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) mIndices[cur_index++] = s+1 + mNumS*t; //bottom right mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right -#if GEN_TRI_STRIP - if (s == 0) - { - mTriStrip.push_back(s+mNumS*t); - mTriStrip.push_back(s+mNumS*(t+1)); - } - mTriStrip.push_back(s+1+mNumS*t); - mTriStrip.push_back(s+1+mNumS*(t+1)); -#endif - mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1; //bottom left/top right neighbor face if (t < mNumT-2) { //top right/top left neighbor face mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1; @@ -5347,52 +7047,61 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) } mEdge[cur_edge++] = (mNumS-1)*2*t+s*2; //top right/bottom left neighbor face } -#if GEN_TRI_STRIP - //append terminating vertex to strip - mTriStrip.push_back(mNumS-1+mNumS*(t+1)); -#endif } + } -#if GEN_TRI_STRIP - if (mTriStrip.size()%2 == 1) - { - mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); - } -#endif + //clear normals + for (U32 i = 0; i < mNumVertices; i++) + { + mNormals[i].clear(); } //generate normals - for (U32 i = 0; i < mIndices.size()/3; i++) //for each triangle + for (U32 i = 0; i < mNumIndices/3; i++) //for each triangle { const U16* idx = &(mIndices[i*3]); - - VertexData* v[] = - { &mVertices[idx[0]], &mVertices[idx[1]], &mVertices[idx[2]] }; - - //calculate triangle normal - LLVector3 norm = (v[0]->mPosition-v[1]->mPosition) % (v[0]->mPosition-v[2]->mPosition); + - v[0]->mNormal += norm; - v[1]->mNormal += norm; - v[2]->mNormal += norm; + LLVector4a* v[] = + { pos+idx[0], pos+idx[1], pos+idx[2] }; + + LLVector4a* n[] = + { norm+idx[0], norm+idx[1], norm+idx[2] }; + + //calculate triangle normal + LLVector4a a, b, c; + + a.setSub(*v[0], *v[1]); + b.setSub(*v[0], *v[2]); + c.setCross3(a,b); + n[0]->add(c); + n[1]->add(c); + n[2]->add(c); + //even out quad contributions - v[i%2+1]->mNormal += norm; + n[i%2+1]->add(c); } // adjust normals based on wrapping and stitching - BOOL s_bottom_converges = ((mVertices[0].mPosition - mVertices[mNumS*(mNumT-2)].mPosition).magVecSquared() < 0.000001f); - BOOL s_top_converges = ((mVertices[mNumS-1].mPosition - mVertices[mNumS*(mNumT-2)+mNumS-1].mPosition).magVecSquared() < 0.000001f); + LLVector4a top; + top.setSub(pos[0], pos[mNumS*(mNumT-2)]); + BOOL s_bottom_converges = (top.dot3(top) < 0.000001f); + + top.setSub(pos[mNumS-1], pos[mNumS*(mNumT-2)+mNumS-1]); + BOOL s_top_converges = (top.dot3(top) < 0.000001f); + if (sculpt_stitching == LL_SCULPT_TYPE_NONE) // logic for non-sculpt volumes { if (volume->getPath().isOpen() == FALSE) { //wrap normals on T for (S32 i = 0; i < mNumS; i++) { - LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal; - mVertices[i].mNormal = norm; - mVertices[mNumS*(mNumT-1)+i].mNormal = norm; + LLVector4a n; + n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]); + norm[i] = n; + norm[mNumS*(mNumT-1)+i] = n; } } @@ -5400,9 +7109,10 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { //wrap normals on S for (S32 i = 0; i < mNumT; i++) { - LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal; - mVertices[mNumS * i].mNormal = norm; - mVertices[mNumS * i+mNumS-1].mNormal = norm; + LLVector4a n; + n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]); + norm[mNumS * i] = n; + norm[mNumS * i+mNumS-1] = n; } } @@ -5413,7 +7123,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { //all lower S have same normal for (S32 i = 0; i < mNumT; i++) { - mVertices[mNumS*i].mNormal = LLVector3(1,0,0); + norm[mNumS*i].set(1,0,0); } } @@ -5421,12 +7131,11 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { //all upper S have same normal for (S32 i = 0; i < mNumT; i++) { - mVertices[mNumS*i+mNumS-1].mNormal = LLVector3(-1,0,0); + norm[mNumS*i+mNumS-1].set(-1,0,0); } } } } - else // logic for sculpt volumes { BOOL average_poles = FALSE; @@ -5449,30 +7158,33 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { // average normals for north pole - LLVector3 average(0.0, 0.0, 0.0); + LLVector4a average; + average.clear(); + for (S32 i = 0; i < mNumS; i++) { - average += mVertices[i].mNormal; + average.add(norm[i]); } // set average for (S32 i = 0; i < mNumS; i++) { - mVertices[i].mNormal = average; + norm[i] = average; } // average normals for south pole - average = LLVector3(0.0, 0.0, 0.0); + average.clear(); + for (S32 i = 0; i < mNumS; i++) { - average += mVertices[i + mNumS * (mNumT - 1)].mNormal; + average.add(norm[i + mNumS * (mNumT - 1)]); } // set average for (S32 i = 0; i < mNumS; i++) { - mVertices[i + mNumS * (mNumT - 1)].mNormal = average; + norm[i + mNumS * (mNumT - 1)] = average; } } @@ -5482,23 +7194,22 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { for (S32 i = 0; i < mNumT; i++) { - LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal; - mVertices[mNumS * i].mNormal = norm; - mVertices[mNumS * i+mNumS-1].mNormal = norm; + LLVector4a n; + n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]); + norm[mNumS * i] = n; + norm[mNumS * i+mNumS-1] = n; } } - - if (wrap_t) { for (S32 i = 0; i < mNumS; i++) { - LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal; - mVertices[i].mNormal = norm; - mVertices[mNumS*(mNumT-1)+i].mNormal = norm; + LLVector4a n; + n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]); + norm[i] = n; + norm[mNumS*(mNumT-1)+i] = n; } - } } @@ -5508,41 +7219,51 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) // Finds binormal based on three vertices with texture coordinates. // Fills in dummy values if the triangle has degenerate texture coordinates. -LLVector3 calc_binormal_from_triangle( - const LLVector3& pos0, +void calc_binormal_from_triangle(LLVector4a& binormal, + + const LLVector4a& pos0, const LLVector2& tex0, - const LLVector3& pos1, + const LLVector4a& pos1, const LLVector2& tex1, - const LLVector3& pos2, + const LLVector4a& pos2, const LLVector2& tex2) { - LLVector3 rx0( pos0.mV[VX], tex0.mV[VX], tex0.mV[VY] ); - LLVector3 rx1( pos1.mV[VX], tex1.mV[VX], tex1.mV[VY] ); - LLVector3 rx2( pos2.mV[VX], tex2.mV[VX], tex2.mV[VY] ); + LLVector4a rx0( pos0[VX], tex0.mV[VX], tex0.mV[VY] ); + LLVector4a rx1( pos1[VX], tex1.mV[VX], tex1.mV[VY] ); + LLVector4a rx2( pos2[VX], tex2.mV[VX], tex2.mV[VY] ); - LLVector3 ry0( pos0.mV[VY], tex0.mV[VX], tex0.mV[VY] ); - LLVector3 ry1( pos1.mV[VY], tex1.mV[VX], tex1.mV[VY] ); - LLVector3 ry2( pos2.mV[VY], tex2.mV[VX], tex2.mV[VY] ); + LLVector4a ry0( pos0[VY], tex0.mV[VX], tex0.mV[VY] ); + LLVector4a ry1( pos1[VY], tex1.mV[VX], tex1.mV[VY] ); + LLVector4a ry2( pos2[VY], tex2.mV[VX], tex2.mV[VY] ); - LLVector3 rz0( pos0.mV[VZ], tex0.mV[VX], tex0.mV[VY] ); - LLVector3 rz1( pos1.mV[VZ], tex1.mV[VX], tex1.mV[VY] ); - LLVector3 rz2( pos2.mV[VZ], tex2.mV[VX], tex2.mV[VY] ); + LLVector4a rz0( pos0[VZ], tex0.mV[VX], tex0.mV[VY] ); + LLVector4a rz1( pos1[VZ], tex1.mV[VX], tex1.mV[VY] ); + LLVector4a rz2( pos2[VZ], tex2.mV[VX], tex2.mV[VY] ); - LLVector3 r0 = (rx0 - rx1) % (rx0 - rx2); - LLVector3 r1 = (ry0 - ry1) % (ry0 - ry2); - LLVector3 r2 = (rz0 - rz1) % (rz0 - rz2); + LLVector4a lhs, rhs; + + LLVector4a r0; + lhs.setSub(rx0, rx1); rhs.setSub(rx0, rx2); + r0.setCross3(lhs, rhs); + + LLVector4a r1; + lhs.setSub(ry0, ry1); rhs.setSub(ry0, ry2); + r1.setCross3(lhs, rhs); + + LLVector4a r2; + lhs.setSub(rz0, rz1); rhs.setSub(rz0, rz2); + r2.setCross3(lhs, rhs); - if( r0.mV[VX] && r1.mV[VX] && r2.mV[VX] ) + if( r0[VX] && r1[VX] && r2[VX] ) { - LLVector3 binormal( - -r0.mV[VZ] / r0.mV[VX], - -r1.mV[VZ] / r1.mV[VX], - -r2.mV[VZ] / r2.mV[VX]); + binormal.set( + -r0[VZ] / r0[VX], + -r1[VZ] / r1[VX], + -r2[VZ] / r2[VX]); // binormal.normVec(); - return binormal; } else { - return LLVector3( 0, 1 , 0 ); + binormal.set( 0, 1 , 0 ); } } diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 4a25f586da..eceaced9e2 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -1,1106 +1,1106 @@ -/** - * @file llvolume.h - * @brief LLVolume base class. - * - * $LicenseInfo:firstyear=2002&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_LLVOLUME_H -#define LL_LLVOLUME_H - -#include - -class LLProfileParams; -class LLPathParams; -class LLVolumeParams; -class LLProfile; -class LLPath; - -template class LLOctreeNode; - -class LLVector4a; -class LLVolumeFace; -class LLVolume; -class LLVolumeTriangle; - -#include "lldarray.h" -#include "lluuid.h" -#include "v4color.h" -//#include "vmath.h" -#include "v2math.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v4math.h" -#include "llquaternion.h" -#include "llstrider.h" -#include "v4coloru.h" -#include "llrefcount.h" -#include "llfile.h" - -//============================================================================ - -const S32 MIN_DETAIL_FACES = 6; -const S32 MIN_LOD = 0; -const S32 MAX_LOD = 3; - -// These are defined here but are not enforced at this level, -// rather they are here for the convenience of code that uses -// the LLVolume class. -const F32 MIN_VOLUME_PROFILE_WIDTH = 0.05f; -const F32 MIN_VOLUME_PATH_WIDTH = 0.05f; - -const F32 CUT_QUANTA = 0.00002f; -const F32 SCALE_QUANTA = 0.01f; -const F32 SHEAR_QUANTA = 0.01f; -const F32 TAPER_QUANTA = 0.01f; -const F32 REV_QUANTA = 0.015f; -const F32 HOLLOW_QUANTA = 0.00002f; - -const S32 MAX_VOLUME_TRIANGLE_INDICES = 10000; - -//============================================================================ - -// useful masks -const LLPCode LL_PCODE_HOLLOW_MASK = 0x80; // has a thickness -const LLPCode LL_PCODE_SEGMENT_MASK = 0x40; // segments (1 angle) -const LLPCode LL_PCODE_PATCH_MASK = 0x20; // segmented segments (2 angles) -const LLPCode LL_PCODE_HEMI_MASK = 0x10; // half-primitives get their own type per PR's dictum -const LLPCode LL_PCODE_BASE_MASK = 0x0F; - - // primitive shapes -const LLPCode LL_PCODE_CUBE = 1; -const LLPCode LL_PCODE_PRISM = 2; -const LLPCode LL_PCODE_TETRAHEDRON = 3; -const LLPCode LL_PCODE_PYRAMID = 4; -const LLPCode LL_PCODE_CYLINDER = 5; -const LLPCode LL_PCODE_CONE = 6; -const LLPCode LL_PCODE_SPHERE = 7; -const LLPCode LL_PCODE_TORUS = 8; -const LLPCode LL_PCODE_VOLUME = 9; - - // surfaces -//const LLPCode LL_PCODE_SURFACE_TRIANGLE = 10; -//const LLPCode LL_PCODE_SURFACE_SQUARE = 11; -//const LLPCode LL_PCODE_SURFACE_DISC = 12; - -const LLPCode LL_PCODE_APP = 14; // App specific pcode (for viewer/sim side only objects) -const LLPCode LL_PCODE_LEGACY = 15; - -// Pcodes for legacy objects -//const LLPCode LL_PCODE_LEGACY_ATOR = 0x10 | LL_PCODE_LEGACY; // ATOR -const LLPCode LL_PCODE_LEGACY_AVATAR = 0x20 | LL_PCODE_LEGACY; // PLAYER -//const LLPCode LL_PCODE_LEGACY_BIRD = 0x30 | LL_PCODE_LEGACY; // BIRD -//const LLPCode LL_PCODE_LEGACY_DEMON = 0x40 | LL_PCODE_LEGACY; // DEMON -const LLPCode LL_PCODE_LEGACY_GRASS = 0x50 | LL_PCODE_LEGACY; // GRASS -const LLPCode LL_PCODE_TREE_NEW = 0x60 | LL_PCODE_LEGACY; // new trees -//const LLPCode LL_PCODE_LEGACY_ORACLE = 0x70 | LL_PCODE_LEGACY; // ORACLE -const LLPCode LL_PCODE_LEGACY_PART_SYS = 0x80 | LL_PCODE_LEGACY; // PART_SYS -const LLPCode LL_PCODE_LEGACY_ROCK = 0x90 | LL_PCODE_LEGACY; // ROCK -//const LLPCode LL_PCODE_LEGACY_SHOT = 0xA0 | LL_PCODE_LEGACY; // BASIC_SHOT -//const LLPCode LL_PCODE_LEGACY_SHOT_BIG = 0xB0 | LL_PCODE_LEGACY; -//const LLPCode LL_PCODE_LEGACY_SMOKE = 0xC0 | LL_PCODE_LEGACY; // SMOKE -//const LLPCode LL_PCODE_LEGACY_SPARK = 0xD0 | LL_PCODE_LEGACY;// SPARK -const LLPCode LL_PCODE_LEGACY_TEXT_BUBBLE = 0xE0 | LL_PCODE_LEGACY; // TEXTBUBBLE -const LLPCode LL_PCODE_LEGACY_TREE = 0xF0 | LL_PCODE_LEGACY; // TREE - - // hemis -const LLPCode LL_PCODE_CYLINDER_HEMI = LL_PCODE_CYLINDER | LL_PCODE_HEMI_MASK; -const LLPCode LL_PCODE_CONE_HEMI = LL_PCODE_CONE | LL_PCODE_HEMI_MASK; -const LLPCode LL_PCODE_SPHERE_HEMI = LL_PCODE_SPHERE | LL_PCODE_HEMI_MASK; -const LLPCode LL_PCODE_TORUS_HEMI = LL_PCODE_TORUS | LL_PCODE_HEMI_MASK; - - -// Volumes consist of a profile at the base that is swept around -// a path to make a volume. -// The profile code -const U8 LL_PCODE_PROFILE_MASK = 0x0f; -const U8 LL_PCODE_PROFILE_MIN = 0x00; -const U8 LL_PCODE_PROFILE_CIRCLE = 0x00; -const U8 LL_PCODE_PROFILE_SQUARE = 0x01; -const U8 LL_PCODE_PROFILE_ISOTRI = 0x02; -const U8 LL_PCODE_PROFILE_EQUALTRI = 0x03; -const U8 LL_PCODE_PROFILE_RIGHTTRI = 0x04; -const U8 LL_PCODE_PROFILE_CIRCLE_HALF = 0x05; -const U8 LL_PCODE_PROFILE_MAX = 0x05; - -// Stored in the profile byte -const U8 LL_PCODE_HOLE_MASK = 0xf0; -const U8 LL_PCODE_HOLE_MIN = 0x00; -const U8 LL_PCODE_HOLE_SAME = 0x00; // same as outside profile -const U8 LL_PCODE_HOLE_CIRCLE = 0x10; -const U8 LL_PCODE_HOLE_SQUARE = 0x20; -const U8 LL_PCODE_HOLE_TRIANGLE = 0x30; -const U8 LL_PCODE_HOLE_MAX = 0x03; // min/max needs to be >> 4 of real min/max - -const U8 LL_PCODE_PATH_IGNORE = 0x00; -const U8 LL_PCODE_PATH_MIN = 0x01; // min/max needs to be >> 4 of real min/max -const U8 LL_PCODE_PATH_LINE = 0x10; -const U8 LL_PCODE_PATH_CIRCLE = 0x20; -const U8 LL_PCODE_PATH_CIRCLE2 = 0x30; -const U8 LL_PCODE_PATH_TEST = 0x40; -const U8 LL_PCODE_PATH_FLEXIBLE = 0x80; -const U8 LL_PCODE_PATH_MAX = 0x08; - -//============================================================================ - -// face identifiers -typedef U16 LLFaceID; - -const LLFaceID LL_FACE_PATH_BEGIN = 0x1 << 0; -const LLFaceID LL_FACE_PATH_END = 0x1 << 1; -const LLFaceID LL_FACE_INNER_SIDE = 0x1 << 2; -const LLFaceID LL_FACE_PROFILE_BEGIN = 0x1 << 3; -const LLFaceID LL_FACE_PROFILE_END = 0x1 << 4; -const LLFaceID LL_FACE_OUTER_SIDE_0 = 0x1 << 5; -const LLFaceID LL_FACE_OUTER_SIDE_1 = 0x1 << 6; -const LLFaceID LL_FACE_OUTER_SIDE_2 = 0x1 << 7; -const LLFaceID LL_FACE_OUTER_SIDE_3 = 0x1 << 8; - -//============================================================================ - -// sculpt types + flags - -const U8 LL_SCULPT_TYPE_NONE = 0; -const U8 LL_SCULPT_TYPE_SPHERE = 1; -const U8 LL_SCULPT_TYPE_TORUS = 2; -const U8 LL_SCULPT_TYPE_PLANE = 3; -const U8 LL_SCULPT_TYPE_CYLINDER = 4; -const U8 LL_SCULPT_TYPE_MESH = 5; -const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | - LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH; - -const U8 LL_SCULPT_FLAG_INVERT = 64; -const U8 LL_SCULPT_FLAG_MIRROR = 128; - -const S32 LL_SCULPT_MESH_MAX_FACES = 8; - -class LLProfileParams -{ -public: - LLProfileParams() - : mCurveType(LL_PCODE_PROFILE_SQUARE), - mBegin(0.f), - mEnd(1.f), - mHollow(0.f), - mCRC(0) - { - } - - LLProfileParams(U8 curve, F32 begin, F32 end, F32 hollow) - : mCurveType(curve), - mBegin(begin), - mEnd(end), - mHollow(hollow), - mCRC(0) - { - } - - LLProfileParams(U8 curve, U16 begin, U16 end, U16 hollow) - { - mCurveType = curve; - F32 temp_f32 = begin * CUT_QUANTA; - if (temp_f32 > 1.f) - { - temp_f32 = 1.f; - } - mBegin = temp_f32; - temp_f32 = end * CUT_QUANTA; - if (temp_f32 > 1.f) - { - temp_f32 = 1.f; - } - mEnd = 1.f - temp_f32; - temp_f32 = hollow * HOLLOW_QUANTA; - if (temp_f32 > 1.f) - { - temp_f32 = 1.f; - } - mHollow = temp_f32; - mCRC = 0; - } - - bool operator==(const LLProfileParams ¶ms) const; - bool operator!=(const LLProfileParams ¶ms) const; - bool operator<(const LLProfileParams ¶ms) const; - - void copyParams(const LLProfileParams ¶ms); - - BOOL importFile(LLFILE *fp); - BOOL exportFile(LLFILE *fp) const; - - BOOL importLegacyStream(std::istream& input_stream); - BOOL exportLegacyStream(std::ostream& output_stream) const; - - LLSD asLLSD() const; - operator LLSD() const { return asLLSD(); } - bool fromLLSD(LLSD& sd); - - const F32& getBegin () const { return mBegin; } - const F32& getEnd () const { return mEnd; } - const F32& getHollow() const { return mHollow; } - const U8& getCurveType () const { return mCurveType; } - - void setCurveType(const U32 type) { mCurveType = type;} - void setBegin(const F32 begin) { mBegin = (begin >= 1.0f) ? 0.0f : ((int) (begin * 100000))/100000.0f;} - void setEnd(const F32 end) { mEnd = (end <= 0.0f) ? 1.0f : ((int) (end * 100000))/100000.0f;} - void setHollow(const F32 hollow) { mHollow = ((int) (hollow * 100000))/100000.0f;} - - friend std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params); - -protected: - // Profile params - U8 mCurveType; - F32 mBegin; - F32 mEnd; - F32 mHollow; - - U32 mCRC; -}; - -inline bool LLProfileParams::operator==(const LLProfileParams ¶ms) const -{ - return - (getCurveType() == params.getCurveType()) && - (getBegin() == params.getBegin()) && - (getEnd() == params.getEnd()) && - (getHollow() == params.getHollow()); -} - -inline bool LLProfileParams::operator!=(const LLProfileParams ¶ms) const -{ - return - (getCurveType() != params.getCurveType()) || - (getBegin() != params.getBegin()) || - (getEnd() != params.getEnd()) || - (getHollow() != params.getHollow()); -} - - -inline bool LLProfileParams::operator<(const LLProfileParams ¶ms) const -{ - if (getCurveType() != params.getCurveType()) - { - return getCurveType() < params.getCurveType(); - } - else - if (getBegin() != params.getBegin()) - { - return getBegin() < params.getBegin(); - } - else - if (getEnd() != params.getEnd()) - { - return getEnd() < params.getEnd(); - } - else - { - return getHollow() < params.getHollow(); - } -} - -#define U8_TO_F32(x) (F32)(*((S8 *)&x)) - -class LLPathParams -{ -public: - LLPathParams() - : - mCurveType(LL_PCODE_PATH_LINE), - mBegin(0.f), - mEnd(1.f), - mScale(1.f,1.f), - mShear(0.f,0.f), - mTwistBegin(0.f), - mTwistEnd(0.f), - mRadiusOffset(0.f), - mTaper(0.f,0.f), - mRevolutions(1.f), - mSkew(0.f), - mCRC(0) - { - } - - LLPathParams(U8 curve, F32 begin, F32 end, F32 scx, F32 scy, F32 shx, F32 shy, F32 twistend, F32 twistbegin, F32 radiusoffset, F32 tx, F32 ty, F32 revolutions, F32 skew) - : mCurveType(curve), - mBegin(begin), - mEnd(end), - mScale(scx,scy), - mShear(shx,shy), - mTwistBegin(twistbegin), - mTwistEnd(twistend), - mRadiusOffset(radiusoffset), - mTaper(tx,ty), - mRevolutions(revolutions), - mSkew(skew), - mCRC(0) - { - } - - LLPathParams(U8 curve, U16 begin, U16 end, U8 scx, U8 scy, U8 shx, U8 shy, U8 twistend, U8 twistbegin, U8 radiusoffset, U8 tx, U8 ty, U8 revolutions, U8 skew) - { - mCurveType = curve; - mBegin = (F32)(begin * CUT_QUANTA); - mEnd = (F32)(100.f - end) * CUT_QUANTA; - if (mEnd > 1.f) - mEnd = 1.f; - mScale.setVec((F32) (200 - scx) * SCALE_QUANTA,(F32) (200 - scy) * SCALE_QUANTA); - mShear.setVec(U8_TO_F32(shx) * SHEAR_QUANTA,U8_TO_F32(shy) * SHEAR_QUANTA); - mTwistBegin = U8_TO_F32(twistbegin) * SCALE_QUANTA; - mTwistEnd = U8_TO_F32(twistend) * SCALE_QUANTA; - mRadiusOffset = U8_TO_F32(radiusoffset) * SCALE_QUANTA; - mTaper.setVec(U8_TO_F32(tx) * TAPER_QUANTA,U8_TO_F32(ty) * TAPER_QUANTA); - mRevolutions = ((F32)revolutions) * REV_QUANTA + 1.0f; - mSkew = U8_TO_F32(skew) * SCALE_QUANTA; - - mCRC = 0; - } - - bool operator==(const LLPathParams ¶ms) const; - bool operator!=(const LLPathParams ¶ms) const; - bool operator<(const LLPathParams ¶ms) const; - - void copyParams(const LLPathParams ¶ms); - - BOOL importFile(LLFILE *fp); - BOOL exportFile(LLFILE *fp) const; - - BOOL importLegacyStream(std::istream& input_stream); - BOOL exportLegacyStream(std::ostream& output_stream) const; - - LLSD asLLSD() const; - operator LLSD() const { return asLLSD(); } - bool fromLLSD(LLSD& sd); - - const F32& getBegin() const { return mBegin; } - const F32& getEnd() const { return mEnd; } - const LLVector2 &getScale() const { return mScale; } - const F32& getScaleX() const { return mScale.mV[0]; } - const F32& getScaleY() const { return mScale.mV[1]; } - const LLVector2 getBeginScale() const; - const LLVector2 getEndScale() const; - const LLVector2 &getShear() const { return mShear; } - const F32& getShearX() const { return mShear.mV[0]; } - const F32& getShearY() const { return mShear.mV[1]; } - const U8& getCurveType () const { return mCurveType; } - - const F32& getTwistBegin() const { return mTwistBegin; } - const F32& getTwistEnd() const { return mTwistEnd; } - const F32& getTwist() const { return mTwistEnd; } // deprecated - const F32& getRadiusOffset() const { return mRadiusOffset; } - const LLVector2 &getTaper() const { return mTaper; } - const F32& getTaperX() const { return mTaper.mV[0]; } - const F32& getTaperY() const { return mTaper.mV[1]; } - const F32& getRevolutions() const { return mRevolutions; } - const F32& getSkew() const { return mSkew; } - - void setCurveType(const U8 type) { mCurveType = type; } - void setBegin(const F32 begin) { mBegin = begin; } - void setEnd(const F32 end) { mEnd = end; } - - void setScale(const F32 x, const F32 y) { mScale.setVec(x,y); } - void setScaleX(const F32 v) { mScale.mV[VX] = v; } - void setScaleY(const F32 v) { mScale.mV[VY] = v; } - void setShear(const F32 x, const F32 y) { mShear.setVec(x,y); } - void setShearX(const F32 v) { mShear.mV[VX] = v; } - void setShearY(const F32 v) { mShear.mV[VY] = v; } - - void setTwistBegin(const F32 twist_begin) { mTwistBegin = twist_begin; } - void setTwistEnd(const F32 twist_end) { mTwistEnd = twist_end; } - void setTwist(const F32 twist) { setTwistEnd(twist); } // deprecated - void setRadiusOffset(const F32 radius_offset){ mRadiusOffset = radius_offset; } - void setTaper(const F32 x, const F32 y) { mTaper.setVec(x,y); } - void setTaperX(const F32 v) { mTaper.mV[VX] = v; } - void setTaperY(const F32 v) { mTaper.mV[VY] = v; } - void setRevolutions(const F32 revolutions) { mRevolutions = revolutions; } - void setSkew(const F32 skew) { mSkew = skew; } - - friend std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params); - -protected: - // Path params - U8 mCurveType; - F32 mBegin; - F32 mEnd; - LLVector2 mScale; - LLVector2 mShear; - - F32 mTwistBegin; - F32 mTwistEnd; - F32 mRadiusOffset; - LLVector2 mTaper; - F32 mRevolutions; - F32 mSkew; - - U32 mCRC; -}; - -inline bool LLPathParams::operator==(const LLPathParams ¶ms) const -{ - return - (getCurveType() == params.getCurveType()) && - (getScale() == params.getScale()) && - (getBegin() == params.getBegin()) && - (getEnd() == params.getEnd()) && - (getShear() == params.getShear()) && - (getTwist() == params.getTwist()) && - (getTwistBegin() == params.getTwistBegin()) && - (getRadiusOffset() == params.getRadiusOffset()) && - (getTaper() == params.getTaper()) && - (getRevolutions() == params.getRevolutions()) && - (getSkew() == params.getSkew()); -} - -inline bool LLPathParams::operator!=(const LLPathParams ¶ms) const -{ - return - (getCurveType() != params.getCurveType()) || - (getScale() != params.getScale()) || - (getBegin() != params.getBegin()) || - (getEnd() != params.getEnd()) || - (getShear() != params.getShear()) || - (getTwist() != params.getTwist()) || - (getTwistBegin() !=params.getTwistBegin()) || - (getRadiusOffset() != params.getRadiusOffset()) || - (getTaper() != params.getTaper()) || - (getRevolutions() != params.getRevolutions()) || - (getSkew() != params.getSkew()); -} - - -inline bool LLPathParams::operator<(const LLPathParams ¶ms) const -{ - if( getCurveType() != params.getCurveType()) - { - return getCurveType() < params.getCurveType(); - } - else - if( getScale() != params.getScale()) - { - return getScale() < params.getScale(); - } - else - if( getBegin() != params.getBegin()) - { - return getBegin() < params.getBegin(); - } - else - if( getEnd() != params.getEnd()) - { - return getEnd() < params.getEnd(); - } - else - if( getShear() != params.getShear()) - { - return getShear() < params.getShear(); - } - else - if( getTwist() != params.getTwist()) - { - return getTwist() < params.getTwist(); - } - else - if( getTwistBegin() != params.getTwistBegin()) - { - return getTwistBegin() < params.getTwistBegin(); - } - else - if( getRadiusOffset() != params.getRadiusOffset()) - { - return getRadiusOffset() < params.getRadiusOffset(); - } - else - if( getTaper() != params.getTaper()) - { - return getTaper() < params.getTaper(); - } - else - if( getRevolutions() != params.getRevolutions()) - { - return getRevolutions() < params.getRevolutions(); - } - else - { - return getSkew() < params.getSkew(); - } -} - -typedef LLVolumeParams* LLVolumeParamsPtr; -typedef const LLVolumeParams* const_LLVolumeParamsPtr; - -class LLVolumeParams -{ -public: - LLVolumeParams() - : mSculptType(LL_SCULPT_TYPE_NONE) - { - } - - LLVolumeParams(LLProfileParams &profile, LLPathParams &path, - LLUUID sculpt_id = LLUUID::null, U8 sculpt_type = LL_SCULPT_TYPE_NONE) - : mProfileParams(profile), mPathParams(path), mSculptID(sculpt_id), mSculptType(sculpt_type) - { - } - - bool operator==(const LLVolumeParams ¶ms) const; - bool operator!=(const LLVolumeParams ¶ms) const; - bool operator<(const LLVolumeParams ¶ms) const; - - - void copyParams(const LLVolumeParams ¶ms); - - const LLProfileParams &getProfileParams() const {return mProfileParams;} - LLProfileParams &getProfileParams() {return mProfileParams;} - const LLPathParams &getPathParams() const {return mPathParams;} - LLPathParams &getPathParams() {return mPathParams;} - - BOOL importFile(LLFILE *fp); - BOOL exportFile(LLFILE *fp) const; - - BOOL importLegacyStream(std::istream& input_stream); - BOOL exportLegacyStream(std::ostream& output_stream) const; - - LLSD sculptAsLLSD() const; - bool sculptFromLLSD(LLSD& sd); - - LLSD asLLSD() const; - operator LLSD() const { return asLLSD(); } - bool fromLLSD(LLSD& sd); - - bool setType(U8 profile, U8 path); - - //void setBeginS(const F32 beginS) { mProfileParams.setBegin(beginS); } // range 0 to 1 - //void setBeginT(const F32 beginT) { mPathParams.setBegin(beginT); } // range 0 to 1 - //void setEndS(const F32 endS) { mProfileParams.setEnd(endS); } // range 0 to 1, must be greater than begin - //void setEndT(const F32 endT) { mPathParams.setEnd(endT); } // range 0 to 1, must be greater than begin - - bool setBeginAndEndS(const F32 begin, const F32 end); // both range from 0 to 1, begin must be less than end - bool setBeginAndEndT(const F32 begin, const F32 end); // both range from 0 to 1, begin must be less than end - - bool setHollow(const F32 hollow); // range 0 to 1 - bool setRatio(const F32 x) { return setRatio(x,x); } // 0 = point, 1 = same as base - bool setShear(const F32 x) { return setShear(x,x); } // 0 = no movement, - bool setRatio(const F32 x, const F32 y); // 0 = point, 1 = same as base - bool setShear(const F32 x, const F32 y); // 0 = no movement - - bool setTwistBegin(const F32 twist_begin); // range -1 to 1 - bool setTwistEnd(const F32 twist_end); // range -1 to 1 - bool setTwist(const F32 twist) { return setTwistEnd(twist); } // deprecated - bool setTaper(const F32 x, const F32 y) { bool pass_x = setTaperX(x); bool pass_y = setTaperY(y); return pass_x && pass_y; } - bool setTaperX(const F32 v); // -1 to 1 - bool setTaperY(const F32 v); // -1 to 1 - bool setRevolutions(const F32 revolutions); // 1 to 4 - bool setRadiusOffset(const F32 radius_offset); - bool setSkew(const F32 skew); - bool setSculptID(const LLUUID sculpt_id, U8 sculpt_type); - - static bool validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow, - U8 path_curve, F32 path_begin, F32 path_end, - F32 scx, F32 scy, F32 shx, F32 shy, - F32 twistend, F32 twistbegin, F32 radiusoffset, - F32 tx, F32 ty, F32 revolutions, F32 skew); - - const F32& getBeginS() const { return mProfileParams.getBegin(); } - const F32& getBeginT() const { return mPathParams.getBegin(); } - const F32& getEndS() const { return mProfileParams.getEnd(); } - const F32& getEndT() const { return mPathParams.getEnd(); } - - const F32& getHollow() const { return mProfileParams.getHollow(); } - const F32& getTwist() const { return mPathParams.getTwist(); } - const F32& getRatio() const { return mPathParams.getScaleX(); } - const F32& getRatioX() const { return mPathParams.getScaleX(); } - const F32& getRatioY() const { return mPathParams.getScaleY(); } - const F32& getShearX() const { return mPathParams.getShearX(); } - const F32& getShearY() const { return mPathParams.getShearY(); } - - const F32& getTwistBegin()const { return mPathParams.getTwistBegin(); } - const F32& getRadiusOffset() const { return mPathParams.getRadiusOffset(); } - const F32& getTaper() const { return mPathParams.getTaperX(); } - const F32& getTaperX() const { return mPathParams.getTaperX(); } - const F32& getTaperY() const { return mPathParams.getTaperY(); } - const F32& getRevolutions() const { return mPathParams.getRevolutions(); } - const F32& getSkew() const { return mPathParams.getSkew(); } - const LLUUID& getSculptID() const { return mSculptID; } - const U8& getSculptType() const { return mSculptType; } - bool isSculpt() const; - bool isMeshSculpt() const; - BOOL isConvex() const; - - // 'begin' and 'end' should be in range [0, 1] (they will be clamped) - // (begin, end) = (0, 1) will not change the volume - // (begin, end) = (0, 0.5) will reduce the volume to the first half of its profile/path (S/T) - void reduceS(F32 begin, F32 end); - void reduceT(F32 begin, F32 end); - - struct compare - { - bool operator()( const const_LLVolumeParamsPtr& first, const const_LLVolumeParamsPtr& second) const - { - return (*first < *second); - } - }; - - friend std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); - - // debug helper functions - void setCube(); - -protected: - LLProfileParams mProfileParams; - LLPathParams mPathParams; - LLUUID mSculptID; - U8 mSculptType; -}; - - -class LLProfile -{ -public: - LLProfile() - : mOpen(FALSE), - mConcave(FALSE), - mDirty(TRUE), - mTotalOut(0), - mTotal(2) - { - } - - ~LLProfile(); - - S32 getTotal() const { return mTotal; } - S32 getTotalOut() const { return mTotalOut; } // Total number of outside points - BOOL isFlat(S32 face) const { return (mFaces[face].mCount == 2); } - BOOL isOpen() const { return mOpen; } - void setDirty() { mDirty = TRUE; } - BOOL generate(const LLProfileParams& params, BOOL path_open, F32 detail = 1.0f, S32 split = 0, - BOOL is_sculpted = FALSE, S32 sculpt_size = 0); - BOOL isConcave() const { return mConcave; } -public: - struct Face - { - S32 mIndex; - S32 mCount; - F32 mScaleU; - BOOL mCap; - BOOL mFlat; - LLFaceID mFaceID; - }; - - std::vector mProfile; - std::vector mNormals; - std::vector mFaces; - std::vector mEdgeNormals; - std::vector mEdgeCenters; - - friend std::ostream& operator<<(std::ostream &s, const LLProfile &profile); - -protected: - void genNormals(const LLProfileParams& params); - void genNGon(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0); - - Face* addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split = 0); - Face* addCap (S16 faceID); - Face* addFace(S32 index, S32 count, F32 scaleU, S16 faceID, BOOL flat); - -protected: - BOOL mOpen; - BOOL mConcave; - BOOL mDirty; - - S32 mTotalOut; - S32 mTotal; -}; - -//------------------------------------------------------------------- -// SWEEP/EXTRUDE PATHS -//------------------------------------------------------------------- - -class LLPath -{ -public: - struct PathPt - { - LLVector3 mPos; - LLVector2 mScale; - LLQuaternion mRot; - F32 mTexT; - PathPt() { mPos.setVec(0,0,0); mTexT = 0; mScale.setVec(0,0); mRot.loadIdentity(); } - }; - -public: - LLPath() - : mOpen(FALSE), - mTotal(0), - mDirty(TRUE), - mStep(1) - { - } - - virtual ~LLPath(); - - void genNGon(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f); - virtual BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, - BOOL is_sculpted = FALSE, S32 sculpt_size = 0); - - BOOL isOpen() const { return mOpen; } - F32 getStep() const { return mStep; } - void setDirty() { mDirty = TRUE; } - - S32 getPathLength() const { return (S32)mPath.size(); } - - void resizePath(S32 length) { mPath.resize(length); } - - friend std::ostream& operator<<(std::ostream &s, const LLPath &path); - -public: - std::vector mPath; - -protected: - BOOL mOpen; - S32 mTotal; - BOOL mDirty; - F32 mStep; -}; - -class LLDynamicPath : public LLPath -{ -public: - LLDynamicPath() : LLPath() { } - /*virtual*/ BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, - BOOL is_sculpted = FALSE, S32 sculpt_size = 0); -}; - -// Yet another "face" class - caches volume-specific, but not instance-specific data for faces) -class LLVolumeFace -{ -public: - class VertexData - { - enum - { - POSITION = 0, - NORMAL = 1 - }; - - private: - void init(); - public: - VertexData(); - VertexData(const VertexData& rhs); - const VertexData& operator=(const VertexData& rhs); - - ~VertexData(); - LLVector4a& getPosition(); - LLVector4a& getNormal(); - const LLVector4a& getPosition() const; - const LLVector4a& getNormal() const; - void setPosition(const LLVector4a& pos); - void setNormal(const LLVector4a& norm); - - - LLVector2 mTexCoord; - - bool operator<(const VertexData& rhs) const; - bool operator==(const VertexData& rhs) const; - bool compareNormal(const VertexData& rhs, F32 angle_cutoff) const; - - private: - LLVector4a* mData; - }; - - LLVolumeFace(); - LLVolumeFace(const LLVolumeFace& src); - LLVolumeFace& operator=(const LLVolumeFace& rhs); - - ~LLVolumeFace(); -private: - void freeData(); -public: - - BOOL create(LLVolume* volume, BOOL partial_build = FALSE); - void createBinormals(); - - void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform); - - void resizeVertices(S32 num_verts); - void allocateBinormals(S32 num_verts); - void allocateWeights(S32 num_verts); - void resizeIndices(S32 num_indices); - void fillFromLegacyData(std::vector& v, std::vector& idx); - - void pushVertex(const VertexData& cv); - void pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc); - void pushIndex(const U16& idx); - - void swapData(LLVolumeFace& rhs); - - void getVertexData(U16 indx, LLVolumeFace::VertexData& cv); - - class VertexMapData : public LLVolumeFace::VertexData - { - public: - U16 mIndex; - - bool operator==(const LLVolumeFace::VertexData& rhs) const; - - struct ComparePosition - { - bool operator()(const LLVector3& a, const LLVector3& b) const; - }; - - typedef std::map, VertexMapData::ComparePosition > PointMap; - }; - - void optimize(F32 angle_cutoff = 2.f); - void cacheOptimize(); - - void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f)); - - enum - { - SINGLE_MASK = 0x0001, - CAP_MASK = 0x0002, - END_MASK = 0x0004, - SIDE_MASK = 0x0008, - INNER_MASK = 0x0010, - OUTER_MASK = 0x0020, - HOLLOW_MASK = 0x0040, - OPEN_MASK = 0x0080, - FLAT_MASK = 0x0100, - TOP_MASK = 0x0200, - BOTTOM_MASK = 0x0400 - }; - -public: - S32 mID; - U32 mTypeMask; - - // Only used for INNER/OUTER faces - S32 mBeginS; - S32 mBeginT; - S32 mNumS; - S32 mNumT; - - LLVector4a* mExtents; //minimum and maximum point of face - LLVector4a* mCenter; - LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face. - - S32 mNumVertices; - S32 mNumIndices; - - LLVector4a* mPositions; - LLVector4a* mNormals; - LLVector4a* mBinormals; - LLVector2* mTexCoords; - U16* mIndices; - - std::vector mEdge; - - //list of skin weights for rigged volumes - // format is mWeights[vertex_index].mV[influence] = . - // mWeights.size() should be empty or match mVertices.size() - LLVector4a* mWeights; - - LLOctreeNode* mOctree; - -private: - BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE); - BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE); - BOOL createSide(LLVolume* volume, BOOL partial_build = FALSE); -}; - -class LLVolume : public LLRefCount -{ - friend class LLVolumeLODGroup; - -protected: - ~LLVolume(); // use unref - -public: - struct Point - { - LLVector3 mPos; - }; - - struct FaceParams - { - LLFaceID mFaceID; - S32 mBeginS; - S32 mCountS; - S32 mBeginT; - S32 mCountT; - }; - - LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL generate_single_face = FALSE, const BOOL is_unique = FALSE); - - U8 getProfileType() const { return mParams.getProfileParams().getCurveType(); } - U8 getPathType() const { return mParams.getPathParams().getCurveType(); } - S32 getNumFaces() const; - S32 getNumVolumeFaces() const { return mVolumeFaces.size(); } - F32 getDetail() const { return mDetail; } - const LLVolumeParams& getParams() const { return mParams; } - LLVolumeParams getCopyOfParams() const { return mParams; } - const LLProfile& getProfile() const { return *mProfilep; } - LLPath& getPath() const { return *mPathp; } - void resizePath(S32 length); - const std::vector& getMesh() const { return mMesh; } - const LLVector3& getMeshPt(const U32 i) const { return mMesh[i].mPos; } - - void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); } - - void regen(); - void genBinormals(S32 face); - - BOOL isConvex() const; - BOOL isCap(S32 face); - BOOL isFlat(S32 face); - BOOL isUnique() const { return mUnique; } - - S32 getSculptLevel() const { return mSculptLevel; } - void setSculptLevel(S32 level) { mSculptLevel = level; } - - S32 *getTriangleIndices(U32 &num_indices) const; - - // returns number of triangle indeces required for path/profile mesh - S32 getNumTriangleIndices() const; - - S32 getNumTriangles() const; - - void generateSilhouetteVertices(std::vector &vertices, - std::vector &normals, - std::vector &segments, - const LLVector3& view_vec, - const LLMatrix4& mat, - const LLMatrix3& norm_mat, - S32 face_index); - - //get the face index of the face that intersects with the given line segment at the point - //closest to start. Moves end to the point of intersection. Returns -1 if no intersection. - //Line segment must be in volume space. - S32 lineSegmentIntersect(const LLVector3& start, const LLVector3& end, - S32 face = -1, // which face to check, -1 = ALL_SIDES - LLVector3* intersection = NULL, // return the intersection point - LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point - ); - - S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, - S32 face = 1, - LLVector3* intersection = NULL, - LLVector2* tex_coord = NULL, - LLVector3* normal = NULL, - LLVector3* bi_normal = NULL); - - // The following cleans up vertices and triangles, - // getting rid of degenerate triangles and duplicate vertices, - // and allocates new arrays with the clean data. - static BOOL cleanupTriangleData( const S32 num_input_vertices, - const std::vector &input_vertices, - const S32 num_input_triangles, - S32 *input_triangles, - S32 &num_output_vertices, - LLVector3 **output_vertices, - S32 &num_output_triangles, - S32 **output_triangles); - LLFaceID generateFaceMask(); - - BOOL isFaceMaskValid(LLFaceID face_mask); - static S32 sNumMeshPoints; - - friend std::ostream& operator<<(std::ostream &s, const LLVolume &volume); - friend std::ostream& operator<<(std::ostream &s, const LLVolume *volumep); // HACK to bypass Windoze confusion over - // conversion if *(LLVolume*) to LLVolume& - const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE - - U32 mFaceMask; // bit array of which faces exist in this volume - LLVector3 mLODScaleBias; // vector for biasing LOD based on scale - - void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level); - void copyVolumeFaces(const LLVolume* volume); - void cacheOptimize(); - -private: - void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type); - F32 sculptGetSurfaceArea(); - void sculptGeneratePlaceholder(); - void sculptCalcMeshResolution(U16 width, U16 height, U8 type, S32& s, S32& t); - - -protected: - BOOL generate(); - void createVolumeFaces(); -public: - virtual BOOL createVolumeFacesFromFile(const std::string& file_name); - virtual BOOL createVolumeFacesFromStream(std::istream& is); - virtual bool unpackVolumeFaces(std::istream& is, S32 size); - - virtual void makeTetrahedron(); - virtual BOOL isTetrahedron(); - - protected: - BOOL mUnique; - F32 mDetail; - S32 mSculptLevel; - BOOL mIsTetrahedron; - - LLVolumeParams mParams; - LLPath *mPathp; - LLProfile *mProfilep; - std::vector mMesh; - - BOOL mGenerateSingleFace; - typedef std::vector face_list_t; - face_list_t mVolumeFaces; - -public: - LLVector4a* mHullPoints; - U16* mHullIndices; - S32 mNumHullPoints; - S32 mNumHullIndices; -}; - -std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); - -void calc_binormal_from_triangle( - LLVector4a& binormal, - const LLVector4a& pos0, - const LLVector2& tex0, - const LLVector4a& pos1, - const LLVector2& tex1, - const LLVector4a& pos2, - const LLVector2& tex2); - -BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size); -BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size); -BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size); - -BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir, - F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided); - -BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, - F32& intersection_a, F32& intersection_b, F32& intersection_t); -BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, - F32& intersection_a, F32& intersection_b, F32& intersection_t); - - - -#endif +/** + * @file llvolume.h + * @brief LLVolume base class. + * + * $LicenseInfo:firstyear=2002&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_LLVOLUME_H +#define LL_LLVOLUME_H + +#include + +class LLProfileParams; +class LLPathParams; +class LLVolumeParams; +class LLProfile; +class LLPath; + +template class LLOctreeNode; + +class LLVector4a; +class LLVolumeFace; +class LLVolume; +class LLVolumeTriangle; + +#include "lldarray.h" +#include "lluuid.h" +#include "v4color.h" +//#include "vmath.h" +#include "v2math.h" +#include "v3math.h" +#include "v3dmath.h" +#include "v4math.h" +#include "llquaternion.h" +#include "llstrider.h" +#include "v4coloru.h" +#include "llrefcount.h" +#include "llfile.h" + +//============================================================================ + +const S32 MIN_DETAIL_FACES = 6; +const S32 MIN_LOD = 0; +const S32 MAX_LOD = 3; + +// These are defined here but are not enforced at this level, +// rather they are here for the convenience of code that uses +// the LLVolume class. +const F32 MIN_VOLUME_PROFILE_WIDTH = 0.05f; +const F32 MIN_VOLUME_PATH_WIDTH = 0.05f; + +const F32 CUT_QUANTA = 0.00002f; +const F32 SCALE_QUANTA = 0.01f; +const F32 SHEAR_QUANTA = 0.01f; +const F32 TAPER_QUANTA = 0.01f; +const F32 REV_QUANTA = 0.015f; +const F32 HOLLOW_QUANTA = 0.00002f; + +const S32 MAX_VOLUME_TRIANGLE_INDICES = 10000; + +//============================================================================ + +// useful masks +const LLPCode LL_PCODE_HOLLOW_MASK = 0x80; // has a thickness +const LLPCode LL_PCODE_SEGMENT_MASK = 0x40; // segments (1 angle) +const LLPCode LL_PCODE_PATCH_MASK = 0x20; // segmented segments (2 angles) +const LLPCode LL_PCODE_HEMI_MASK = 0x10; // half-primitives get their own type per PR's dictum +const LLPCode LL_PCODE_BASE_MASK = 0x0F; + + // primitive shapes +const LLPCode LL_PCODE_CUBE = 1; +const LLPCode LL_PCODE_PRISM = 2; +const LLPCode LL_PCODE_TETRAHEDRON = 3; +const LLPCode LL_PCODE_PYRAMID = 4; +const LLPCode LL_PCODE_CYLINDER = 5; +const LLPCode LL_PCODE_CONE = 6; +const LLPCode LL_PCODE_SPHERE = 7; +const LLPCode LL_PCODE_TORUS = 8; +const LLPCode LL_PCODE_VOLUME = 9; + + // surfaces +//const LLPCode LL_PCODE_SURFACE_TRIANGLE = 10; +//const LLPCode LL_PCODE_SURFACE_SQUARE = 11; +//const LLPCode LL_PCODE_SURFACE_DISC = 12; + +const LLPCode LL_PCODE_APP = 14; // App specific pcode (for viewer/sim side only objects) +const LLPCode LL_PCODE_LEGACY = 15; + +// Pcodes for legacy objects +//const LLPCode LL_PCODE_LEGACY_ATOR = 0x10 | LL_PCODE_LEGACY; // ATOR +const LLPCode LL_PCODE_LEGACY_AVATAR = 0x20 | LL_PCODE_LEGACY; // PLAYER +//const LLPCode LL_PCODE_LEGACY_BIRD = 0x30 | LL_PCODE_LEGACY; // BIRD +//const LLPCode LL_PCODE_LEGACY_DEMON = 0x40 | LL_PCODE_LEGACY; // DEMON +const LLPCode LL_PCODE_LEGACY_GRASS = 0x50 | LL_PCODE_LEGACY; // GRASS +const LLPCode LL_PCODE_TREE_NEW = 0x60 | LL_PCODE_LEGACY; // new trees +//const LLPCode LL_PCODE_LEGACY_ORACLE = 0x70 | LL_PCODE_LEGACY; // ORACLE +const LLPCode LL_PCODE_LEGACY_PART_SYS = 0x80 | LL_PCODE_LEGACY; // PART_SYS +const LLPCode LL_PCODE_LEGACY_ROCK = 0x90 | LL_PCODE_LEGACY; // ROCK +//const LLPCode LL_PCODE_LEGACY_SHOT = 0xA0 | LL_PCODE_LEGACY; // BASIC_SHOT +//const LLPCode LL_PCODE_LEGACY_SHOT_BIG = 0xB0 | LL_PCODE_LEGACY; +//const LLPCode LL_PCODE_LEGACY_SMOKE = 0xC0 | LL_PCODE_LEGACY; // SMOKE +//const LLPCode LL_PCODE_LEGACY_SPARK = 0xD0 | LL_PCODE_LEGACY;// SPARK +const LLPCode LL_PCODE_LEGACY_TEXT_BUBBLE = 0xE0 | LL_PCODE_LEGACY; // TEXTBUBBLE +const LLPCode LL_PCODE_LEGACY_TREE = 0xF0 | LL_PCODE_LEGACY; // TREE + + // hemis +const LLPCode LL_PCODE_CYLINDER_HEMI = LL_PCODE_CYLINDER | LL_PCODE_HEMI_MASK; +const LLPCode LL_PCODE_CONE_HEMI = LL_PCODE_CONE | LL_PCODE_HEMI_MASK; +const LLPCode LL_PCODE_SPHERE_HEMI = LL_PCODE_SPHERE | LL_PCODE_HEMI_MASK; +const LLPCode LL_PCODE_TORUS_HEMI = LL_PCODE_TORUS | LL_PCODE_HEMI_MASK; + + +// Volumes consist of a profile at the base that is swept around +// a path to make a volume. +// The profile code +const U8 LL_PCODE_PROFILE_MASK = 0x0f; +const U8 LL_PCODE_PROFILE_MIN = 0x00; +const U8 LL_PCODE_PROFILE_CIRCLE = 0x00; +const U8 LL_PCODE_PROFILE_SQUARE = 0x01; +const U8 LL_PCODE_PROFILE_ISOTRI = 0x02; +const U8 LL_PCODE_PROFILE_EQUALTRI = 0x03; +const U8 LL_PCODE_PROFILE_RIGHTTRI = 0x04; +const U8 LL_PCODE_PROFILE_CIRCLE_HALF = 0x05; +const U8 LL_PCODE_PROFILE_MAX = 0x05; + +// Stored in the profile byte +const U8 LL_PCODE_HOLE_MASK = 0xf0; +const U8 LL_PCODE_HOLE_MIN = 0x00; +const U8 LL_PCODE_HOLE_SAME = 0x00; // same as outside profile +const U8 LL_PCODE_HOLE_CIRCLE = 0x10; +const U8 LL_PCODE_HOLE_SQUARE = 0x20; +const U8 LL_PCODE_HOLE_TRIANGLE = 0x30; +const U8 LL_PCODE_HOLE_MAX = 0x03; // min/max needs to be >> 4 of real min/max + +const U8 LL_PCODE_PATH_IGNORE = 0x00; +const U8 LL_PCODE_PATH_MIN = 0x01; // min/max needs to be >> 4 of real min/max +const U8 LL_PCODE_PATH_LINE = 0x10; +const U8 LL_PCODE_PATH_CIRCLE = 0x20; +const U8 LL_PCODE_PATH_CIRCLE2 = 0x30; +const U8 LL_PCODE_PATH_TEST = 0x40; +const U8 LL_PCODE_PATH_FLEXIBLE = 0x80; +const U8 LL_PCODE_PATH_MAX = 0x08; + +//============================================================================ + +// face identifiers +typedef U16 LLFaceID; + +const LLFaceID LL_FACE_PATH_BEGIN = 0x1 << 0; +const LLFaceID LL_FACE_PATH_END = 0x1 << 1; +const LLFaceID LL_FACE_INNER_SIDE = 0x1 << 2; +const LLFaceID LL_FACE_PROFILE_BEGIN = 0x1 << 3; +const LLFaceID LL_FACE_PROFILE_END = 0x1 << 4; +const LLFaceID LL_FACE_OUTER_SIDE_0 = 0x1 << 5; +const LLFaceID LL_FACE_OUTER_SIDE_1 = 0x1 << 6; +const LLFaceID LL_FACE_OUTER_SIDE_2 = 0x1 << 7; +const LLFaceID LL_FACE_OUTER_SIDE_3 = 0x1 << 8; + +//============================================================================ + +// sculpt types + flags + +const U8 LL_SCULPT_TYPE_NONE = 0; +const U8 LL_SCULPT_TYPE_SPHERE = 1; +const U8 LL_SCULPT_TYPE_TORUS = 2; +const U8 LL_SCULPT_TYPE_PLANE = 3; +const U8 LL_SCULPT_TYPE_CYLINDER = 4; +const U8 LL_SCULPT_TYPE_MESH = 5; +const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | + LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH; + +const U8 LL_SCULPT_FLAG_INVERT = 64; +const U8 LL_SCULPT_FLAG_MIRROR = 128; + +const S32 LL_SCULPT_MESH_MAX_FACES = 8; + +class LLProfileParams +{ +public: + LLProfileParams() + : mCurveType(LL_PCODE_PROFILE_SQUARE), + mBegin(0.f), + mEnd(1.f), + mHollow(0.f), + mCRC(0) + { + } + + LLProfileParams(U8 curve, F32 begin, F32 end, F32 hollow) + : mCurveType(curve), + mBegin(begin), + mEnd(end), + mHollow(hollow), + mCRC(0) + { + } + + LLProfileParams(U8 curve, U16 begin, U16 end, U16 hollow) + { + mCurveType = curve; + F32 temp_f32 = begin * CUT_QUANTA; + if (temp_f32 > 1.f) + { + temp_f32 = 1.f; + } + mBegin = temp_f32; + temp_f32 = end * CUT_QUANTA; + if (temp_f32 > 1.f) + { + temp_f32 = 1.f; + } + mEnd = 1.f - temp_f32; + temp_f32 = hollow * HOLLOW_QUANTA; + if (temp_f32 > 1.f) + { + temp_f32 = 1.f; + } + mHollow = temp_f32; + mCRC = 0; + } + + bool operator==(const LLProfileParams ¶ms) const; + bool operator!=(const LLProfileParams ¶ms) const; + bool operator<(const LLProfileParams ¶ms) const; + + void copyParams(const LLProfileParams ¶ms); + + BOOL importFile(LLFILE *fp); + BOOL exportFile(LLFILE *fp) const; + + BOOL importLegacyStream(std::istream& input_stream); + BOOL exportLegacyStream(std::ostream& output_stream) const; + + LLSD asLLSD() const; + operator LLSD() const { return asLLSD(); } + bool fromLLSD(LLSD& sd); + + const F32& getBegin () const { return mBegin; } + const F32& getEnd () const { return mEnd; } + const F32& getHollow() const { return mHollow; } + const U8& getCurveType () const { return mCurveType; } + + void setCurveType(const U32 type) { mCurveType = type;} + void setBegin(const F32 begin) { mBegin = (begin >= 1.0f) ? 0.0f : ((int) (begin * 100000))/100000.0f;} + void setEnd(const F32 end) { mEnd = (end <= 0.0f) ? 1.0f : ((int) (end * 100000))/100000.0f;} + void setHollow(const F32 hollow) { mHollow = ((int) (hollow * 100000))/100000.0f;} + + friend std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params); + +protected: + // Profile params + U8 mCurveType; + F32 mBegin; + F32 mEnd; + F32 mHollow; + + U32 mCRC; +}; + +inline bool LLProfileParams::operator==(const LLProfileParams ¶ms) const +{ + return + (getCurveType() == params.getCurveType()) && + (getBegin() == params.getBegin()) && + (getEnd() == params.getEnd()) && + (getHollow() == params.getHollow()); +} + +inline bool LLProfileParams::operator!=(const LLProfileParams ¶ms) const +{ + return + (getCurveType() != params.getCurveType()) || + (getBegin() != params.getBegin()) || + (getEnd() != params.getEnd()) || + (getHollow() != params.getHollow()); +} + + +inline bool LLProfileParams::operator<(const LLProfileParams ¶ms) const +{ + if (getCurveType() != params.getCurveType()) + { + return getCurveType() < params.getCurveType(); + } + else + if (getBegin() != params.getBegin()) + { + return getBegin() < params.getBegin(); + } + else + if (getEnd() != params.getEnd()) + { + return getEnd() < params.getEnd(); + } + else + { + return getHollow() < params.getHollow(); + } +} + +#define U8_TO_F32(x) (F32)(*((S8 *)&x)) + +class LLPathParams +{ +public: + LLPathParams() + : + mCurveType(LL_PCODE_PATH_LINE), + mBegin(0.f), + mEnd(1.f), + mScale(1.f,1.f), + mShear(0.f,0.f), + mTwistBegin(0.f), + mTwistEnd(0.f), + mRadiusOffset(0.f), + mTaper(0.f,0.f), + mRevolutions(1.f), + mSkew(0.f), + mCRC(0) + { + } + + LLPathParams(U8 curve, F32 begin, F32 end, F32 scx, F32 scy, F32 shx, F32 shy, F32 twistend, F32 twistbegin, F32 radiusoffset, F32 tx, F32 ty, F32 revolutions, F32 skew) + : mCurveType(curve), + mBegin(begin), + mEnd(end), + mScale(scx,scy), + mShear(shx,shy), + mTwistBegin(twistbegin), + mTwistEnd(twistend), + mRadiusOffset(radiusoffset), + mTaper(tx,ty), + mRevolutions(revolutions), + mSkew(skew), + mCRC(0) + { + } + + LLPathParams(U8 curve, U16 begin, U16 end, U8 scx, U8 scy, U8 shx, U8 shy, U8 twistend, U8 twistbegin, U8 radiusoffset, U8 tx, U8 ty, U8 revolutions, U8 skew) + { + mCurveType = curve; + mBegin = (F32)(begin * CUT_QUANTA); + mEnd = (F32)(100.f - end) * CUT_QUANTA; + if (mEnd > 1.f) + mEnd = 1.f; + mScale.setVec((F32) (200 - scx) * SCALE_QUANTA,(F32) (200 - scy) * SCALE_QUANTA); + mShear.setVec(U8_TO_F32(shx) * SHEAR_QUANTA,U8_TO_F32(shy) * SHEAR_QUANTA); + mTwistBegin = U8_TO_F32(twistbegin) * SCALE_QUANTA; + mTwistEnd = U8_TO_F32(twistend) * SCALE_QUANTA; + mRadiusOffset = U8_TO_F32(radiusoffset) * SCALE_QUANTA; + mTaper.setVec(U8_TO_F32(tx) * TAPER_QUANTA,U8_TO_F32(ty) * TAPER_QUANTA); + mRevolutions = ((F32)revolutions) * REV_QUANTA + 1.0f; + mSkew = U8_TO_F32(skew) * SCALE_QUANTA; + + mCRC = 0; + } + + bool operator==(const LLPathParams ¶ms) const; + bool operator!=(const LLPathParams ¶ms) const; + bool operator<(const LLPathParams ¶ms) const; + + void copyParams(const LLPathParams ¶ms); + + BOOL importFile(LLFILE *fp); + BOOL exportFile(LLFILE *fp) const; + + BOOL importLegacyStream(std::istream& input_stream); + BOOL exportLegacyStream(std::ostream& output_stream) const; + + LLSD asLLSD() const; + operator LLSD() const { return asLLSD(); } + bool fromLLSD(LLSD& sd); + + const F32& getBegin() const { return mBegin; } + const F32& getEnd() const { return mEnd; } + const LLVector2 &getScale() const { return mScale; } + const F32& getScaleX() const { return mScale.mV[0]; } + const F32& getScaleY() const { return mScale.mV[1]; } + const LLVector2 getBeginScale() const; + const LLVector2 getEndScale() const; + const LLVector2 &getShear() const { return mShear; } + const F32& getShearX() const { return mShear.mV[0]; } + const F32& getShearY() const { return mShear.mV[1]; } + const U8& getCurveType () const { return mCurveType; } + + const F32& getTwistBegin() const { return mTwistBegin; } + const F32& getTwistEnd() const { return mTwistEnd; } + const F32& getTwist() const { return mTwistEnd; } // deprecated + const F32& getRadiusOffset() const { return mRadiusOffset; } + const LLVector2 &getTaper() const { return mTaper; } + const F32& getTaperX() const { return mTaper.mV[0]; } + const F32& getTaperY() const { return mTaper.mV[1]; } + const F32& getRevolutions() const { return mRevolutions; } + const F32& getSkew() const { return mSkew; } + + void setCurveType(const U8 type) { mCurveType = type; } + void setBegin(const F32 begin) { mBegin = begin; } + void setEnd(const F32 end) { mEnd = end; } + + void setScale(const F32 x, const F32 y) { mScale.setVec(x,y); } + void setScaleX(const F32 v) { mScale.mV[VX] = v; } + void setScaleY(const F32 v) { mScale.mV[VY] = v; } + void setShear(const F32 x, const F32 y) { mShear.setVec(x,y); } + void setShearX(const F32 v) { mShear.mV[VX] = v; } + void setShearY(const F32 v) { mShear.mV[VY] = v; } + + void setTwistBegin(const F32 twist_begin) { mTwistBegin = twist_begin; } + void setTwistEnd(const F32 twist_end) { mTwistEnd = twist_end; } + void setTwist(const F32 twist) { setTwistEnd(twist); } // deprecated + void setRadiusOffset(const F32 radius_offset){ mRadiusOffset = radius_offset; } + void setTaper(const F32 x, const F32 y) { mTaper.setVec(x,y); } + void setTaperX(const F32 v) { mTaper.mV[VX] = v; } + void setTaperY(const F32 v) { mTaper.mV[VY] = v; } + void setRevolutions(const F32 revolutions) { mRevolutions = revolutions; } + void setSkew(const F32 skew) { mSkew = skew; } + + friend std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params); + +protected: + // Path params + U8 mCurveType; + F32 mBegin; + F32 mEnd; + LLVector2 mScale; + LLVector2 mShear; + + F32 mTwistBegin; + F32 mTwistEnd; + F32 mRadiusOffset; + LLVector2 mTaper; + F32 mRevolutions; + F32 mSkew; + + U32 mCRC; +}; + +inline bool LLPathParams::operator==(const LLPathParams ¶ms) const +{ + return + (getCurveType() == params.getCurveType()) && + (getScale() == params.getScale()) && + (getBegin() == params.getBegin()) && + (getEnd() == params.getEnd()) && + (getShear() == params.getShear()) && + (getTwist() == params.getTwist()) && + (getTwistBegin() == params.getTwistBegin()) && + (getRadiusOffset() == params.getRadiusOffset()) && + (getTaper() == params.getTaper()) && + (getRevolutions() == params.getRevolutions()) && + (getSkew() == params.getSkew()); +} + +inline bool LLPathParams::operator!=(const LLPathParams ¶ms) const +{ + return + (getCurveType() != params.getCurveType()) || + (getScale() != params.getScale()) || + (getBegin() != params.getBegin()) || + (getEnd() != params.getEnd()) || + (getShear() != params.getShear()) || + (getTwist() != params.getTwist()) || + (getTwistBegin() !=params.getTwistBegin()) || + (getRadiusOffset() != params.getRadiusOffset()) || + (getTaper() != params.getTaper()) || + (getRevolutions() != params.getRevolutions()) || + (getSkew() != params.getSkew()); +} + + +inline bool LLPathParams::operator<(const LLPathParams ¶ms) const +{ + if( getCurveType() != params.getCurveType()) + { + return getCurveType() < params.getCurveType(); + } + else + if( getScale() != params.getScale()) + { + return getScale() < params.getScale(); + } + else + if( getBegin() != params.getBegin()) + { + return getBegin() < params.getBegin(); + } + else + if( getEnd() != params.getEnd()) + { + return getEnd() < params.getEnd(); + } + else + if( getShear() != params.getShear()) + { + return getShear() < params.getShear(); + } + else + if( getTwist() != params.getTwist()) + { + return getTwist() < params.getTwist(); + } + else + if( getTwistBegin() != params.getTwistBegin()) + { + return getTwistBegin() < params.getTwistBegin(); + } + else + if( getRadiusOffset() != params.getRadiusOffset()) + { + return getRadiusOffset() < params.getRadiusOffset(); + } + else + if( getTaper() != params.getTaper()) + { + return getTaper() < params.getTaper(); + } + else + if( getRevolutions() != params.getRevolutions()) + { + return getRevolutions() < params.getRevolutions(); + } + else + { + return getSkew() < params.getSkew(); + } +} + +typedef LLVolumeParams* LLVolumeParamsPtr; +typedef const LLVolumeParams* const_LLVolumeParamsPtr; + +class LLVolumeParams +{ +public: + LLVolumeParams() + : mSculptType(LL_SCULPT_TYPE_NONE) + { + } + + LLVolumeParams(LLProfileParams &profile, LLPathParams &path, + LLUUID sculpt_id = LLUUID::null, U8 sculpt_type = LL_SCULPT_TYPE_NONE) + : mProfileParams(profile), mPathParams(path), mSculptID(sculpt_id), mSculptType(sculpt_type) + { + } + + bool operator==(const LLVolumeParams ¶ms) const; + bool operator!=(const LLVolumeParams ¶ms) const; + bool operator<(const LLVolumeParams ¶ms) const; + + + void copyParams(const LLVolumeParams ¶ms); + + const LLProfileParams &getProfileParams() const {return mProfileParams;} + LLProfileParams &getProfileParams() {return mProfileParams;} + const LLPathParams &getPathParams() const {return mPathParams;} + LLPathParams &getPathParams() {return mPathParams;} + + BOOL importFile(LLFILE *fp); + BOOL exportFile(LLFILE *fp) const; + + BOOL importLegacyStream(std::istream& input_stream); + BOOL exportLegacyStream(std::ostream& output_stream) const; + + LLSD sculptAsLLSD() const; + bool sculptFromLLSD(LLSD& sd); + + LLSD asLLSD() const; + operator LLSD() const { return asLLSD(); } + bool fromLLSD(LLSD& sd); + + bool setType(U8 profile, U8 path); + + //void setBeginS(const F32 beginS) { mProfileParams.setBegin(beginS); } // range 0 to 1 + //void setBeginT(const F32 beginT) { mPathParams.setBegin(beginT); } // range 0 to 1 + //void setEndS(const F32 endS) { mProfileParams.setEnd(endS); } // range 0 to 1, must be greater than begin + //void setEndT(const F32 endT) { mPathParams.setEnd(endT); } // range 0 to 1, must be greater than begin + + bool setBeginAndEndS(const F32 begin, const F32 end); // both range from 0 to 1, begin must be less than end + bool setBeginAndEndT(const F32 begin, const F32 end); // both range from 0 to 1, begin must be less than end + + bool setHollow(const F32 hollow); // range 0 to 1 + bool setRatio(const F32 x) { return setRatio(x,x); } // 0 = point, 1 = same as base + bool setShear(const F32 x) { return setShear(x,x); } // 0 = no movement, + bool setRatio(const F32 x, const F32 y); // 0 = point, 1 = same as base + bool setShear(const F32 x, const F32 y); // 0 = no movement + + bool setTwistBegin(const F32 twist_begin); // range -1 to 1 + bool setTwistEnd(const F32 twist_end); // range -1 to 1 + bool setTwist(const F32 twist) { return setTwistEnd(twist); } // deprecated + bool setTaper(const F32 x, const F32 y) { bool pass_x = setTaperX(x); bool pass_y = setTaperY(y); return pass_x && pass_y; } + bool setTaperX(const F32 v); // -1 to 1 + bool setTaperY(const F32 v); // -1 to 1 + bool setRevolutions(const F32 revolutions); // 1 to 4 + bool setRadiusOffset(const F32 radius_offset); + bool setSkew(const F32 skew); + bool setSculptID(const LLUUID sculpt_id, U8 sculpt_type); + + static bool validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow, + U8 path_curve, F32 path_begin, F32 path_end, + F32 scx, F32 scy, F32 shx, F32 shy, + F32 twistend, F32 twistbegin, F32 radiusoffset, + F32 tx, F32 ty, F32 revolutions, F32 skew); + + const F32& getBeginS() const { return mProfileParams.getBegin(); } + const F32& getBeginT() const { return mPathParams.getBegin(); } + const F32& getEndS() const { return mProfileParams.getEnd(); } + const F32& getEndT() const { return mPathParams.getEnd(); } + + const F32& getHollow() const { return mProfileParams.getHollow(); } + const F32& getTwist() const { return mPathParams.getTwist(); } + const F32& getRatio() const { return mPathParams.getScaleX(); } + const F32& getRatioX() const { return mPathParams.getScaleX(); } + const F32& getRatioY() const { return mPathParams.getScaleY(); } + const F32& getShearX() const { return mPathParams.getShearX(); } + const F32& getShearY() const { return mPathParams.getShearY(); } + + const F32& getTwistBegin()const { return mPathParams.getTwistBegin(); } + const F32& getRadiusOffset() const { return mPathParams.getRadiusOffset(); } + const F32& getTaper() const { return mPathParams.getTaperX(); } + const F32& getTaperX() const { return mPathParams.getTaperX(); } + const F32& getTaperY() const { return mPathParams.getTaperY(); } + const F32& getRevolutions() const { return mPathParams.getRevolutions(); } + const F32& getSkew() const { return mPathParams.getSkew(); } + const LLUUID& getSculptID() const { return mSculptID; } + const U8& getSculptType() const { return mSculptType; } + bool isSculpt() const; + bool isMeshSculpt() const; + BOOL isConvex() const; + + // 'begin' and 'end' should be in range [0, 1] (they will be clamped) + // (begin, end) = (0, 1) will not change the volume + // (begin, end) = (0, 0.5) will reduce the volume to the first half of its profile/path (S/T) + void reduceS(F32 begin, F32 end); + void reduceT(F32 begin, F32 end); + + struct compare + { + bool operator()( const const_LLVolumeParamsPtr& first, const const_LLVolumeParamsPtr& second) const + { + return (*first < *second); + } + }; + + friend std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); + + // debug helper functions + void setCube(); + +protected: + LLProfileParams mProfileParams; + LLPathParams mPathParams; + LLUUID mSculptID; + U8 mSculptType; +}; + + +class LLProfile +{ +public: + LLProfile() + : mOpen(FALSE), + mConcave(FALSE), + mDirty(TRUE), + mTotalOut(0), + mTotal(2) + { + } + + ~LLProfile(); + + S32 getTotal() const { return mTotal; } + S32 getTotalOut() const { return mTotalOut; } // Total number of outside points + BOOL isFlat(S32 face) const { return (mFaces[face].mCount == 2); } + BOOL isOpen() const { return mOpen; } + void setDirty() { mDirty = TRUE; } + BOOL generate(const LLProfileParams& params, BOOL path_open, F32 detail = 1.0f, S32 split = 0, + BOOL is_sculpted = FALSE, S32 sculpt_size = 0); + BOOL isConcave() const { return mConcave; } +public: + struct Face + { + S32 mIndex; + S32 mCount; + F32 mScaleU; + BOOL mCap; + BOOL mFlat; + LLFaceID mFaceID; + }; + + std::vector mProfile; + std::vector mNormals; + std::vector mFaces; + std::vector mEdgeNormals; + std::vector mEdgeCenters; + + friend std::ostream& operator<<(std::ostream &s, const LLProfile &profile); + +protected: + void genNormals(const LLProfileParams& params); + void genNGon(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0); + + Face* addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split = 0); + Face* addCap (S16 faceID); + Face* addFace(S32 index, S32 count, F32 scaleU, S16 faceID, BOOL flat); + +protected: + BOOL mOpen; + BOOL mConcave; + BOOL mDirty; + + S32 mTotalOut; + S32 mTotal; +}; + +//------------------------------------------------------------------- +// SWEEP/EXTRUDE PATHS +//------------------------------------------------------------------- + +class LLPath +{ +public: + struct PathPt + { + LLVector3 mPos; + LLVector2 mScale; + LLQuaternion mRot; + F32 mTexT; + PathPt() { mPos.setVec(0,0,0); mTexT = 0; mScale.setVec(0,0); mRot.loadIdentity(); } + }; + +public: + LLPath() + : mOpen(FALSE), + mTotal(0), + mDirty(TRUE), + mStep(1) + { + } + + virtual ~LLPath(); + + void genNGon(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f); + virtual BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, + BOOL is_sculpted = FALSE, S32 sculpt_size = 0); + + BOOL isOpen() const { return mOpen; } + F32 getStep() const { return mStep; } + void setDirty() { mDirty = TRUE; } + + S32 getPathLength() const { return (S32)mPath.size(); } + + void resizePath(S32 length) { mPath.resize(length); } + + friend std::ostream& operator<<(std::ostream &s, const LLPath &path); + +public: + std::vector mPath; + +protected: + BOOL mOpen; + S32 mTotal; + BOOL mDirty; + F32 mStep; +}; + +class LLDynamicPath : public LLPath +{ +public: + LLDynamicPath() : LLPath() { } + /*virtual*/ BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, + BOOL is_sculpted = FALSE, S32 sculpt_size = 0); +}; + +// Yet another "face" class - caches volume-specific, but not instance-specific data for faces) +class LLVolumeFace +{ +public: + class VertexData + { + enum + { + POSITION = 0, + NORMAL = 1 + }; + + private: + void init(); + public: + VertexData(); + VertexData(const VertexData& rhs); + const VertexData& operator=(const VertexData& rhs); + + ~VertexData(); + LLVector4a& getPosition(); + LLVector4a& getNormal(); + const LLVector4a& getPosition() const; + const LLVector4a& getNormal() const; + void setPosition(const LLVector4a& pos); + void setNormal(const LLVector4a& norm); + + + LLVector2 mTexCoord; + + bool operator<(const VertexData& rhs) const; + bool operator==(const VertexData& rhs) const; + bool compareNormal(const VertexData& rhs, F32 angle_cutoff) const; + + private: + LLVector4a* mData; + }; + + LLVolumeFace(); + LLVolumeFace(const LLVolumeFace& src); + LLVolumeFace& operator=(const LLVolumeFace& rhs); + + ~LLVolumeFace(); +private: + void freeData(); +public: + + BOOL create(LLVolume* volume, BOOL partial_build = FALSE); + void createBinormals(); + + void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform); + + void resizeVertices(S32 num_verts); + void allocateBinormals(S32 num_verts); + void allocateWeights(S32 num_verts); + void resizeIndices(S32 num_indices); + void fillFromLegacyData(std::vector& v, std::vector& idx); + + void pushVertex(const VertexData& cv); + void pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc); + void pushIndex(const U16& idx); + + void swapData(LLVolumeFace& rhs); + + void getVertexData(U16 indx, LLVolumeFace::VertexData& cv); + + class VertexMapData : public LLVolumeFace::VertexData + { + public: + U16 mIndex; + + bool operator==(const LLVolumeFace::VertexData& rhs) const; + + struct ComparePosition + { + bool operator()(const LLVector3& a, const LLVector3& b) const; + }; + + typedef std::map, VertexMapData::ComparePosition > PointMap; + }; + + void optimize(F32 angle_cutoff = 2.f); + void cacheOptimize(); + + void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f)); + + enum + { + SINGLE_MASK = 0x0001, + CAP_MASK = 0x0002, + END_MASK = 0x0004, + SIDE_MASK = 0x0008, + INNER_MASK = 0x0010, + OUTER_MASK = 0x0020, + HOLLOW_MASK = 0x0040, + OPEN_MASK = 0x0080, + FLAT_MASK = 0x0100, + TOP_MASK = 0x0200, + BOTTOM_MASK = 0x0400 + }; + +public: + S32 mID; + U32 mTypeMask; + + // Only used for INNER/OUTER faces + S32 mBeginS; + S32 mBeginT; + S32 mNumS; + S32 mNumT; + + LLVector4a* mExtents; //minimum and maximum point of face + LLVector4a* mCenter; + LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face. + + S32 mNumVertices; + S32 mNumIndices; + + LLVector4a* mPositions; + LLVector4a* mNormals; + LLVector4a* mBinormals; + LLVector2* mTexCoords; + U16* mIndices; + + std::vector mEdge; + + //list of skin weights for rigged volumes + // format is mWeights[vertex_index].mV[influence] = . + // mWeights.size() should be empty or match mVertices.size() + LLVector4a* mWeights; + + LLOctreeNode* mOctree; + +private: + BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE); + BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE); + BOOL createSide(LLVolume* volume, BOOL partial_build = FALSE); +}; + +class LLVolume : public LLRefCount +{ + friend class LLVolumeLODGroup; + +protected: + ~LLVolume(); // use unref + +public: + struct Point + { + LLVector3 mPos; + }; + + struct FaceParams + { + LLFaceID mFaceID; + S32 mBeginS; + S32 mCountS; + S32 mBeginT; + S32 mCountT; + }; + + LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL generate_single_face = FALSE, const BOOL is_unique = FALSE); + + U8 getProfileType() const { return mParams.getProfileParams().getCurveType(); } + U8 getPathType() const { return mParams.getPathParams().getCurveType(); } + S32 getNumFaces() const; + S32 getNumVolumeFaces() const { return mVolumeFaces.size(); } + F32 getDetail() const { return mDetail; } + const LLVolumeParams& getParams() const { return mParams; } + LLVolumeParams getCopyOfParams() const { return mParams; } + const LLProfile& getProfile() const { return *mProfilep; } + LLPath& getPath() const { return *mPathp; } + void resizePath(S32 length); + const std::vector& getMesh() const { return mMesh; } + const LLVector3& getMeshPt(const U32 i) const { return mMesh[i].mPos; } + + void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); } + + void regen(); + void genBinormals(S32 face); + + BOOL isConvex() const; + BOOL isCap(S32 face); + BOOL isFlat(S32 face); + BOOL isUnique() const { return mUnique; } + + S32 getSculptLevel() const { return mSculptLevel; } + void setSculptLevel(S32 level) { mSculptLevel = level; } + + S32 *getTriangleIndices(U32 &num_indices) const; + + // returns number of triangle indeces required for path/profile mesh + S32 getNumTriangleIndices() const; + + S32 getNumTriangles() const; + + void generateSilhouetteVertices(std::vector &vertices, + std::vector &normals, + std::vector &segments, + const LLVector3& view_vec, + const LLMatrix4& mat, + const LLMatrix3& norm_mat, + S32 face_index); + + //get the face index of the face that intersects with the given line segment at the point + //closest to start. Moves end to the point of intersection. Returns -1 if no intersection. + //Line segment must be in volume space. + S32 lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + S32 face = -1, // which face to check, -1 = ALL_SIDES + LLVector3* intersection = NULL, // return the intersection point + LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point + LLVector3* normal = NULL, // return the surface normal at the intersection point + LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point + ); + + S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + S32 face = 1, + LLVector3* intersection = NULL, + LLVector2* tex_coord = NULL, + LLVector3* normal = NULL, + LLVector3* bi_normal = NULL); + + // The following cleans up vertices and triangles, + // getting rid of degenerate triangles and duplicate vertices, + // and allocates new arrays with the clean data. + static BOOL cleanupTriangleData( const S32 num_input_vertices, + const std::vector &input_vertices, + const S32 num_input_triangles, + S32 *input_triangles, + S32 &num_output_vertices, + LLVector3 **output_vertices, + S32 &num_output_triangles, + S32 **output_triangles); + LLFaceID generateFaceMask(); + + BOOL isFaceMaskValid(LLFaceID face_mask); + static S32 sNumMeshPoints; + + friend std::ostream& operator<<(std::ostream &s, const LLVolume &volume); + friend std::ostream& operator<<(std::ostream &s, const LLVolume *volumep); // HACK to bypass Windoze confusion over + // conversion if *(LLVolume*) to LLVolume& + const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE + + U32 mFaceMask; // bit array of which faces exist in this volume + LLVector3 mLODScaleBias; // vector for biasing LOD based on scale + + void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level); + void copyVolumeFaces(const LLVolume* volume); + void cacheOptimize(); + +private: + void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type); + F32 sculptGetSurfaceArea(); + void sculptGeneratePlaceholder(); + void sculptCalcMeshResolution(U16 width, U16 height, U8 type, S32& s, S32& t); + + +protected: + BOOL generate(); + void createVolumeFaces(); +public: + virtual BOOL createVolumeFacesFromFile(const std::string& file_name); + virtual BOOL createVolumeFacesFromStream(std::istream& is); + virtual bool unpackVolumeFaces(std::istream& is, S32 size); + + virtual void makeTetrahedron(); + virtual BOOL isTetrahedron(); + + protected: + BOOL mUnique; + F32 mDetail; + S32 mSculptLevel; + BOOL mIsTetrahedron; + + LLVolumeParams mParams; + LLPath *mPathp; + LLProfile *mProfilep; + std::vector mMesh; + + BOOL mGenerateSingleFace; + typedef std::vector face_list_t; + face_list_t mVolumeFaces; + +public: + LLVector4a* mHullPoints; + U16* mHullIndices; + S32 mNumHullPoints; + S32 mNumHullIndices; +}; + +std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); + +void calc_binormal_from_triangle( + LLVector4a& binormal, + const LLVector4a& pos0, + const LLVector2& tex0, + const LLVector4a& pos1, + const LLVector2& tex1, + const LLVector4a& pos2, + const LLVector2& tex2); + +BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size); +BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size); +BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size); + +BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir, + F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided); + +BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, + F32& intersection_a, F32& intersection_b, F32& intersection_t); +BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, + F32& intersection_a, F32& intersection_b, F32& intersection_t); + + + +#endif diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h index f696cbd976..688d91dc40 100644 --- a/indra/llmath/llvolumeoctree.h +++ b/indra/llmath/llvolumeoctree.h @@ -34,6 +34,41 @@ #include "llvolume.h" #include "llvector4a.h" +class LLVolumeTriangle : public LLRefCount +{ +public: + LLVolumeTriangle() + { + + } + + LLVolumeTriangle(const LLVolumeTriangle& rhs) + { + *this = rhs; + } + + const LLVolumeTriangle& operator=(const LLVolumeTriangle& rhs) + { + llerrs << "Illegal operation!" << llendl; + return *this; + } + + ~LLVolumeTriangle() + { + + } + + LLVector4a mPositionGroup; + + const LLVector4a* mV[3]; + U16 mIndex[3]; + + F32 mRadius; + + virtual const LLVector4a& getPositionGroup() const; + virtual const F32& getBinRadius() const; +}; + class LLVolumeOctreeListener : public LLOctreeListener { public: @@ -91,41 +126,6 @@ public: virtual void visit(const LLOctreeNode* node); }; -class LLVolumeTriangle : public LLRefCount -{ -public: - LLVolumeTriangle() - { - - } - - LLVolumeTriangle(const LLVolumeTriangle& rhs) - { - *this = rhs; - } - - const LLVolumeTriangle& operator=(const LLVolumeTriangle& rhs) - { - llerrs << "Illegal operation!" << llendl; - return *this; - } - - ~LLVolumeTriangle() - { - - } - - LLVector4a mPositionGroup; - - const LLVector4a* mV[3]; - U16 mIndex[3]; - - F32 mRadius; - - virtual const LLVector4a& getPositionGroup() const; - virtual const F32& getBinRadius() const; -}; - class LLVolumeOctreeValidate : public LLOctreeTraveler { virtual void visit(const LLOctreeNode* branch); -- cgit v1.2.3 From ea7c6b0afed51f34292e27aaba00c8f60fd4033b Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 1 Feb 2011 13:22:06 -0600 Subject: Line endings? --- indra/llmath/llvolume.cpp | 284 +++++++++++++++++++++++----------------------- 1 file changed, 142 insertions(+), 142 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index d6dfb5c7a9..244c4574e1 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2003,145 +2003,145 @@ BOOL LLVolume::generate() return FALSE; } -void LLVolumeFace::VertexData::init() -{ - if (!mData) - { - mData = (LLVector4a*) malloc(sizeof(LLVector4a)*2); - } -} - -LLVolumeFace::VertexData::VertexData() -{ - mData = NULL; - init(); -} - -LLVolumeFace::VertexData::VertexData(const VertexData& rhs) -{ - mData = NULL; - *this = rhs; -} - -const LLVolumeFace::VertexData& LLVolumeFace::VertexData::operator=(const LLVolumeFace::VertexData& rhs) -{ - if (this != &rhs) - { - init(); - LLVector4a::memcpyNonAliased16((F32*) mData, (F32*) rhs.mData, 2*sizeof(LLVector4a)); - mTexCoord = rhs.mTexCoord; - } - return *this; -} - -LLVolumeFace::VertexData::~VertexData() -{ - free(mData); - mData = NULL; -} - -LLVector4a& LLVolumeFace::VertexData::getPosition() -{ - return mData[POSITION]; -} - -LLVector4a& LLVolumeFace::VertexData::getNormal() -{ - return mData[NORMAL]; -} - -const LLVector4a& LLVolumeFace::VertexData::getPosition() const -{ - return mData[POSITION]; -} - -const LLVector4a& LLVolumeFace::VertexData::getNormal() const -{ - return mData[NORMAL]; -} - - -void LLVolumeFace::VertexData::setPosition(const LLVector4a& pos) -{ - mData[POSITION] = pos; -} - -void LLVolumeFace::VertexData::setNormal(const LLVector4a& norm) -{ - mData[NORMAL] = norm; -} - -bool LLVolumeFace::VertexData::operator<(const LLVolumeFace::VertexData& rhs)const -{ - const F32* lp = this->getPosition().getF32ptr(); - const F32* rp = rhs.getPosition().getF32ptr(); - - if (lp[0] != rp[0]) - { - return lp[0] < rp[0]; - } - - if (rp[1] != lp[1]) - { - return lp[1] < rp[1]; - } - - if (rp[2] != lp[2]) - { - return lp[2] < rp[2]; - } - - lp = getNormal().getF32ptr(); - rp = rhs.getNormal().getF32ptr(); - - if (lp[0] != rp[0]) - { - return lp[0] < rp[0]; - } - - if (rp[1] != lp[1]) - { - return lp[1] < rp[1]; - } - - if (rp[2] != lp[2]) - { - return lp[2] < rp[2]; - } - - if (mTexCoord.mV[0] != rhs.mTexCoord.mV[0]) - { - return mTexCoord.mV[0] < rhs.mTexCoord.mV[0]; - } - - return mTexCoord.mV[1] < rhs.mTexCoord.mV[1]; -} - -bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const -{ - return mData[POSITION].equals3(rhs.getPosition()) && - mData[NORMAL].equals3(rhs.getNormal()) && - mTexCoord == rhs.mTexCoord; -} - -bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const -{ - bool retval = false; - if (rhs.mData[POSITION].equals3(mData[POSITION]) && rhs.mTexCoord == mTexCoord) - { - if (angle_cutoff > 1.f) - { - retval = (mData[NORMAL].equals3(rhs.mData[NORMAL])); - } - else - { - F32 cur_angle = rhs.mData[NORMAL].dot3(mData[NORMAL]).getF32(); - retval = cur_angle > angle_cutoff; - } - } - - return retval; -} +void LLVolumeFace::VertexData::init() +{ + if (!mData) + { + mData = (LLVector4a*) malloc(sizeof(LLVector4a)*2); + } +} + +LLVolumeFace::VertexData::VertexData() +{ + mData = NULL; + init(); +} + +LLVolumeFace::VertexData::VertexData(const VertexData& rhs) +{ + mData = NULL; + *this = rhs; +} + +const LLVolumeFace::VertexData& LLVolumeFace::VertexData::operator=(const LLVolumeFace::VertexData& rhs) +{ + if (this != &rhs) + { + init(); + LLVector4a::memcpyNonAliased16((F32*) mData, (F32*) rhs.mData, 2*sizeof(LLVector4a)); + mTexCoord = rhs.mTexCoord; + } + return *this; +} + +LLVolumeFace::VertexData::~VertexData() +{ + free(mData); + mData = NULL; +} + +LLVector4a& LLVolumeFace::VertexData::getPosition() +{ + return mData[POSITION]; +} + +LLVector4a& LLVolumeFace::VertexData::getNormal() +{ + return mData[NORMAL]; +} + +const LLVector4a& LLVolumeFace::VertexData::getPosition() const +{ + return mData[POSITION]; +} + +const LLVector4a& LLVolumeFace::VertexData::getNormal() const +{ + return mData[NORMAL]; +} + + +void LLVolumeFace::VertexData::setPosition(const LLVector4a& pos) +{ + mData[POSITION] = pos; +} + +void LLVolumeFace::VertexData::setNormal(const LLVector4a& norm) +{ + mData[NORMAL] = norm; +} + +bool LLVolumeFace::VertexData::operator<(const LLVolumeFace::VertexData& rhs)const +{ + const F32* lp = this->getPosition().getF32ptr(); + const F32* rp = rhs.getPosition().getF32ptr(); + + if (lp[0] != rp[0]) + { + return lp[0] < rp[0]; + } + + if (rp[1] != lp[1]) + { + return lp[1] < rp[1]; + } + + if (rp[2] != lp[2]) + { + return lp[2] < rp[2]; + } + + lp = getNormal().getF32ptr(); + rp = rhs.getNormal().getF32ptr(); + + if (lp[0] != rp[0]) + { + return lp[0] < rp[0]; + } + + if (rp[1] != lp[1]) + { + return lp[1] < rp[1]; + } + + if (rp[2] != lp[2]) + { + return lp[2] < rp[2]; + } + + if (mTexCoord.mV[0] != rhs.mTexCoord.mV[0]) + { + return mTexCoord.mV[0] < rhs.mTexCoord.mV[0]; + } + + return mTexCoord.mV[1] < rhs.mTexCoord.mV[1]; +} + +bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const +{ + return mData[POSITION].equals3(rhs.getPosition()) && + mData[NORMAL].equals3(rhs.getNormal()) && + mTexCoord == rhs.mTexCoord; +} + +bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const +{ + bool retval = false; + if (rhs.mData[POSITION].equals3(mData[POSITION]) && rhs.mTexCoord == mTexCoord) + { + if (angle_cutoff > 1.f) + { + retval = (mData[NORMAL].equals3(rhs.mData[NORMAL])); + } + else + { + F32 cur_angle = rhs.mData[NORMAL].dot3(mData[NORMAL]).getF32(); + retval = cur_angle > angle_cutoff; + } + } + + return retval; +} BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name) { @@ -5546,9 +5546,9 @@ public: } }; -const F32 FindVertexScore_CacheDecayPower = 1.5f; -const F32 FindVertexScore_LastTriScore = 0.75f; -const F32 FindVertexScore_ValenceBoostScale = 2.0f; +const F32 FindVertexScore_CacheDecayPower = 1.5f; +const F32 FindVertexScore_LastTriScore = 0.75f; +const F32 FindVertexScore_ValenceBoostScale = 2.0f; const F32 FindVertexScore_ValenceBoostPower = 0.5f; const U32 MaxSizeVertexCache = 32; -- cgit v1.2.3 From d08372f71d575ebc3050806660655e1c7c7cff84 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 1 Feb 2011 12:43:12 -0700 Subject: merge fix for SH-659 from v-d to mesh: small textures not loaded --- indra/llmath/llvolume.cpp | 40 +++++++++++++++++++++++++++++++++++++--- indra/llmath/llvolume.h | 4 ++-- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 617a8b4ca3..2f662b757b 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -5393,19 +5393,53 @@ BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) delete mOctree; mOctree = NULL; + BOOL ret = FALSE ; if (mTypeMask & CAP_MASK) { - return createCap(volume, partial_build); + ret = createCap(volume, partial_build); } else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK)) { - return createSide(volume, partial_build); + ret = createSide(volume, partial_build); } else { llerrs << "Unknown/uninitialized face type!" << llendl; - return FALSE; } + + //update the range of the texture coordinates + if(ret) + { + mTexCoordExtents[0].setVec(1.f, 1.f) ; + mTexCoordExtents[1].setVec(0.f, 0.f) ; + + for(U32 i = 0 ; i < mNumVertices ; i++) + { + if(mTexCoordExtents[0].mV[0] > mTexCoords[i].mV[0]) + { + mTexCoordExtents[0].mV[0] = mTexCoords[i].mV[0] ; + } + if(mTexCoordExtents[1].mV[0] < mTexCoords[i].mV[0]) + { + mTexCoordExtents[1].mV[0] = mTexCoords[i].mV[0] ; + } + + if(mTexCoordExtents[0].mV[1] > mTexCoords[i].mV[1]) + { + mTexCoordExtents[0].mV[1] = mTexCoords[i].mV[1] ; + } + if(mTexCoordExtents[1].mV[1] < mTexCoords[i].mV[1]) + { + mTexCoordExtents[1].mV[1] = mTexCoords[i].mV[1] ; + } + } + mTexCoordExtents[0].mV[0] = llmax(0.f, mTexCoordExtents[0].mV[0]) ; + mTexCoordExtents[0].mV[1] = llmax(0.f, mTexCoordExtents[0].mV[1]) ; + mTexCoordExtents[1].mV[0] = llmin(1.f, mTexCoordExtents[1].mV[0]) ; + mTexCoordExtents[1].mV[1] = llmin(1.f, mTexCoordExtents[1].mV[1]) ; + } + + return ret ; } void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv) diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index eceaced9e2..5bd65c2bf2 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -901,7 +901,7 @@ public: LLVector4a* mExtents; //minimum and maximum point of face LLVector4a* mCenter; - LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face. + LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face. S32 mNumVertices; S32 mNumIndices; @@ -909,7 +909,7 @@ public: LLVector4a* mPositions; LLVector4a* mNormals; LLVector4a* mBinormals; - LLVector2* mTexCoords; + LLVector2* mTexCoords; U16* mIndices; std::vector mEdge; -- cgit v1.2.3 From 7662e5d4acb37ee28a8a22173bcf5c853c8a71b8 Mon Sep 17 00:00:00 2001 From: prep linden Date: Tue, 1 Feb 2011 14:59:05 -0500 Subject: SH-512: Inworld scale weights use previous maximum (10) --- indra/newview/llmanipscale.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index 67ab7ab462..d16c4c3bd0 100644 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -960,9 +960,9 @@ void LLManipScale::dragCorner( S32 x, S32 y ) { mInSnapRegime = FALSE; } - - F32 max_scale_factor = get_default_max_prim_scale() / MIN_PRIM_SCALE; - F32 min_scale_factor = MIN_PRIM_SCALE / get_default_max_prim_scale(); + + F32 max_scale_factor = DEFAULT_MAX_PRIM_SCALE_NO_MESH / MIN_PRIM_SCALE; + F32 min_scale_factor = MIN_PRIM_SCALE / DEFAULT_MAX_PRIM_SCALE_NO_MESH; // find max and min scale factors that will make biggest object hit max absolute scale and smallest object hit min absolute scale for (LLObjectSelection::iterator iter = mObjectSelection->begin(); @@ -974,7 +974,7 @@ void LLManipScale::dragCorner( S32 x, S32 y ) { const LLVector3& scale = selectNode->mSavedScale; - F32 cur_max_scale_factor = llmin( get_default_max_prim_scale() / scale.mV[VX], get_default_max_prim_scale() / scale.mV[VY], get_default_max_prim_scale() / scale.mV[VZ] ); + F32 cur_max_scale_factor = llmin( DEFAULT_MAX_PRIM_SCALE_NO_MESH / scale.mV[VX], DEFAULT_MAX_PRIM_SCALE_NO_MESH / scale.mV[VY], DEFAULT_MAX_PRIM_SCALE_NO_MESH / scale.mV[VZ] ); max_scale_factor = llmin( max_scale_factor, cur_max_scale_factor ); F32 cur_min_scale_factor = llmax( MIN_PRIM_SCALE / scale.mV[VX], MIN_PRIM_SCALE / scale.mV[VY], MIN_PRIM_SCALE / scale.mV[VZ] ); @@ -1271,7 +1271,7 @@ void LLManipScale::stretchFace( const LLVector3& drag_start_agent, const LLVecto F32 denom = axis * dir_local; F32 desired_delta_size = is_approx_zero(denom) ? 0.f : (delta_local_mag / denom); // in meters - F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, get_default_max_prim_scale()); + F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE_NO_MESH); // propagate scale constraint back to position offset desired_delta_size = desired_scale - selectNode->mSavedScale.mV[axis_index]; // propagate constraint back to position @@ -1971,7 +1971,7 @@ F32 LLManipScale::partToMaxScale( S32 part, const LLBBox &bbox ) const max_extent = bbox_extents.mV[i]; } } - max_scale_factor = bbox_extents.magVec() * get_default_max_prim_scale() / max_extent; + max_scale_factor = bbox_extents.magVec() * DEFAULT_MAX_PRIM_SCALE_NO_MESH / max_extent; if (getUniform()) { @@ -1986,7 +1986,7 @@ F32 LLManipScale::partToMinScale( S32 part, const LLBBox &bbox ) const { LLVector3 bbox_extents = unitVectorToLocalBBoxExtent( partToUnitVector( part ), bbox ); bbox_extents.abs(); - F32 min_extent = get_default_max_prim_scale(); + F32 min_extent = DEFAULT_MAX_PRIM_SCALE_NO_MESH; for (U32 i = VX; i <= VZ; i++) { if (bbox_extents.mV[i] > 0.f && bbox_extents.mV[i] < min_extent) -- cgit v1.2.3 From 40e1041871a41cbd944f702c271f818accbd9057 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 1 Feb 2011 14:46:20 -0600 Subject: SH-818 Fix for inability to disable anti-aliasing on ATI catalyst. --- indra/newview/pipeline.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index ec3d0c10ab..9342e07a1d 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -3141,7 +3141,7 @@ void render_hud_elements() gGL.color4f(1,1,1,1); if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { - LLGLEnable multisample(GL_MULTISAMPLE_ARB); + LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD version in render_ui_3d() // Draw the tracking overlays @@ -3385,7 +3385,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) glMatrixMode(GL_MODELVIEW); LLGLSPipeline gls_pipeline; - LLGLEnable multisample(GL_MULTISAMPLE_ARB); + LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2); @@ -3625,7 +3625,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) } } - LLGLEnable multisample(GL_MULTISAMPLE_ARB); + LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); LLVertexBuffer::unbind(); @@ -3714,7 +3714,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) LLGLEnable cull(GL_CULL_FACE); - LLGLEnable multisample(GL_MULTISAMPLE_ARB); + LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); calcNearbyLights(camera); setupHWLights(NULL); @@ -6298,7 +6298,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) gGL.getTexUnit(1)->bind(&mScreen); gGL.getTexUnit(1)->activate(); - LLGLEnable multisample(GL_MULTISAMPLE_ARB); + LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); buff->setBuffer(mask); buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3); @@ -6763,7 +6763,7 @@ void LLPipeline::renderDeferredLighting() 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); } - LLGLEnable multisample(GL_MULTISAMPLE_ARB); + LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) { -- cgit v1.2.3 From 1b366dfe72c5852904468aaf8ff66e8e7be88318 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Tue, 1 Feb 2011 15:34:00 -0800 Subject: SH-734 [REGRESSION] INTEGRATION_TEST_llsdmessage and _capabilitylistener failing in opensource environment --- indra/llmessage/tests/llsdmessage_test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/llmessage/tests/llsdmessage_test.cpp b/indra/llmessage/tests/llsdmessage_test.cpp index 9998a1b8bb..0f2c069303 100644 --- a/indra/llmessage/tests/llsdmessage_test.cpp +++ b/indra/llmessage/tests/llsdmessage_test.cpp @@ -61,6 +61,7 @@ namespace tut llsdmessage_data(): httpPump(pumps.obtain("LLHTTPClient")) { + LLCurl::initClass(); LLSDMessage::link(); } }; -- cgit v1.2.3 From 40f38c13a81fec9fcf1b0f98575d558801b33c0a Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Wed, 2 Feb 2011 14:46:19 -0800 Subject: SH-734 - also adding fix into the llcapabilitylistner test --- indra/newview/tests/llcapabilitylistener_test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/tests/llcapabilitylistener_test.cpp b/indra/newview/tests/llcapabilitylistener_test.cpp index d691bb6c44..2ad08dc1f3 100644 --- a/indra/newview/tests/llcapabilitylistener_test.cpp +++ b/indra/newview/tests/llcapabilitylistener_test.cpp @@ -114,6 +114,7 @@ namespace tut regionListener("testCapabilityListener", NULL, provider, LLUUID(), LLUUID()), regionPump(regionListener.getCapAPI()) { + LLCurl::initClass(); provider.setCapability("good", server + "capability-test"); provider.setCapability("fail", server + "fail"); } -- cgit v1.2.3 From 9e966bfe9fd15f9ffbc969fc41ef2306e9f9409c Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 2 Feb 2011 19:00:52 -0600 Subject: Tweak to physics shape display render to show convex decompositions. --- indra/newview/llspatialpartition.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index af6064ad20..a4c9b66e38 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -2948,10 +2948,10 @@ void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLCo { buff->setBuffer(data_mask); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + /* glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glColor4fv(line_color.mV); buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);*/ { glColor4fv(color.mV); @@ -2979,9 +2979,13 @@ void render_hull(LLVertexBuffer* buff, U32 data_mask, const LLColor4& color, con glColor4fv(color.mV); buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + LLGLEnable offset(GL_POLYGON_OFFSET_LINE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glPolygonOffset(3.f, 3.f); + glLineWidth(3.f); glColor4fv(line_color.mV); buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + glLineWidth(1.f); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } -- cgit v1.2.3 From bb113f75efefffc1f976267be6d722289929e596 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 2 Feb 2011 19:01:27 -0600 Subject: SH-900 Fix for only lowest LoD appearing for objects in neighboring regions. --- indra/newview/lldrawable.cpp | 8 ++------ indra/newview/llface.cpp | 3 +-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 73c4cf94ef..cbee800acb 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -709,11 +709,7 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) if (volume) { pos.set(getPositionGroup().getF32ptr()); - if (isStatic()) - { - pos += volume->getRegion()->getOriginAgent(); - } - + if (isState(LLDrawable::HAS_ALPHA)) { for (S32 i = 0; i < getNumFaces(); i++) @@ -733,7 +729,7 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) facep->mDistance = v * camera.getAtAxis(); } } - } + } } else { diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 15f59e84a6..bb1a46df5f 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -761,8 +761,7 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, mCenterLocal.set(t.getF32ptr()); t.setSub(newMax,newMin); - t.mul(0.5f); - mBoundingSphereRadius = t.getLength3().getF32(); + mBoundingSphereRadius = t.getLength3().getF32()*0.5f; updateCenterAgent(); } -- cgit v1.2.3 From aa9d9901e843135632b67af6b5641ab019a84d09 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 3 Feb 2011 17:49:19 -0500 Subject: SH-580 FIXED Crash in curl on exit New defensive programming added this llerrs trigger. This is worth investigating but not at the top of our priority at the moment. Reverting to llinfos for now as has been done for non-Windows builds already. --- indra/llmessage/llcurl.cpp | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 6473b23e80..2b9bfff536 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -90,13 +90,8 @@ void check_curl_code(CURLcode code) if (code != CURLE_OK) { // linux appears to throw a curl error once per session for a bad initialization - // at a pretty random time (when enabling cookies). Making curl errors non-asserts - // for non-windows platforms for now. - Nyx - #if LL_WINDOWS - llerrs << "curl error detected: " << curl_easy_strerror(code) << llendl; - #else - llinfos << "curl error detected: " << curl_easy_strerror(code) << llendl; - #endif + // at a pretty random time (when enabling cookies). + llinfos << "curl error detected: " << curl_easy_strerror(code) << llendl; } } @@ -105,13 +100,8 @@ void check_curl_multi_code(CURLMcode code) if (code != CURLM_OK) { // linux appears to throw a curl error once per session for a bad initialization - // at a pretty random time (when enabling cookies). Making curl errors non-asserts - // for non-windows platforms for now. - Nyx - #if LL_WINDOWS - llerrs << "curl multi error detected: " << curl_multi_strerror(code) << llendl; - #else - llinfos << "curl multi error detected: " << curl_multi_strerror(code) << llendl; - #endif + // at a pretty random time (when enabling cookies). + llinfos << "curl multi error detected: " << curl_multi_strerror(code) << llendl; } } -- cgit v1.2.3 From 04ddae45b284b8f535aa6cdc6b90af2088e82334 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 3 Feb 2011 17:52:45 -0500 Subject: SH-872 WIP - restored log statements, as removing them had no effect --- indra/newview/llagentpilot.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/indra/newview/llagentpilot.cpp b/indra/newview/llagentpilot.cpp index afeba6bdf0..13e1023185 100644 --- a/indra/newview/llagentpilot.cpp +++ b/indra/newview/llagentpilot.cpp @@ -178,8 +178,6 @@ void LLAgentPilot::stopPlayback() } } -#define SKIP_PILOT_LOGGING 1 - void LLAgentPilot::updateTarget() { if (mPlaying) @@ -197,9 +195,7 @@ void LLAgentPilot::updateTarget() { if (!mStarted) { -#if SKIP_PILOT_LOGGING llinfos << "At start, beginning playback" << llendl; -#endif mTimer.reset(); mStarted = TRUE; } @@ -222,23 +218,17 @@ void LLAgentPilot::updateTarget() { if ((mNumRuns < 0) || (mNumRuns > 0)) { -#if SKIP_PILOT_LOGGING llinfos << "Looping, restarting playback" << llendl; -#endif startPlayback(); } else if (mQuitAfterRuns) { -#if SKIP_PILOT_LOGGING llinfos << "Done with all runs, quitting viewer!" << llendl; -#endif LLAppViewer::instance()->forceQuit(); } else { -#if SKIP_PILOT_LOGGING llinfos << "Done with all runs, disabling pilot" << llendl; -#endif stopPlayback(); } } -- cgit v1.2.3 From fbfecd49c7f8f6dafc36cf56c0331a1207765f22 Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Thu, 3 Feb 2011 19:45:29 -0500 Subject: SH-861 FIX update render cost algorithm to use geometry triangle counts base cost is now geometry-based, for both meshes and prims Some of the previous weights have been recalibrated based on testing. Code reviewed by davep. Deferring QA for now until the other parts of the algorithm are updated, as re-generating the test takes time each time the algorithm changes. --- indra/newview/llvovolume.cpp | 224 ++++++++++++++++--------------------------- indra/newview/llvovolume.h | 2 +- 2 files changed, 84 insertions(+), 142 deletions(-) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 55e68d61f9..a388d2ef30 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -2933,44 +2933,32 @@ const LLMatrix4 LLVOVolume::getRenderMatrix() const // children, and cost should only be increased for unique textures -Nyx U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const { - // base cost of each prim should be 10 points - static const U32 ARC_PRIM_COST = 10; - // Get access to params we'll need at various points. // Skip if this is object doesn't have a volume (e.g. is an avatar). - const BOOL has_volume = (getVolume() != NULL); + BOOL has_volume = (getVolume() != NULL); LLVolumeParams volume_params; LLPathParams path_params; LLProfileParams profile_params; - if (has_volume) - { - volume_params = getVolume()->getParams(); - path_params = volume_params.getPathParams(); - profile_params = volume_params.getProfileParams(); - } - + U32 num_triangles = 0; + // per-prim costs - static const U32 ARC_INVISI_COST = 1; static const U32 ARC_PARTICLE_COST = 100; - static const U32 ARC_CUT_COST = 1; static const U32 ARC_TEXTURE_COST = 5; // per-prim multipliers - static const U32 ARC_HOLLOW_MULT = 2; - static const U32 ARC_CIRC_PROF_MULT = 2; - static const U32 ARC_CIRC_PATH_MULT = 2; - static const U32 ARC_GLOW_MULT = 2; - static const U32 ARC_BUMP_MULT = 2; - static const U32 ARC_FLEXI_MULT = 4; - static const U32 ARC_SHINY_MULT = 2; + static const F32 ARC_GLOW_MULT = 1.5f; // tested based on performance + static const F32 ARC_BUMP_MULT = 1.25f; // tested based on performance + static const F32 ARC_FLEXI_MULT = 4; + static const F32 ARC_SHINY_MULT = 1.6f; // tested based on performance + static const F32 ARC_INVISI_COST = 1.2f; // tested based on performance + static const F32 ARC_WEIGHTED_MESH = 1.2f; - // per-face costs - static const U32 ARC_PLANAR_COST = 1; - static const U32 ARC_ANIM_TEX_COST = 4; - static const U32 ARC_ALPHA_COST = 4; + static const F32 ARC_PLANAR_COST = 1.2f; // 1.2x max + static const F32 ARC_ANIM_TEX_COST = 1.4f; // 1.4x max + static const F32 ARC_ALPHA_COST = 4.f; // 4x max - U32 shame = ARC_PRIM_COST; + F32 shame = 0; U32 invisi = 0; U32 shiny = 0; @@ -2981,18 +2969,41 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const U32 particles = 0; U32 bump = 0; U32 planar = 0; - U32 cuts = 0; - U32 hollow = 0; - U32 circular_profile = 0; - U32 circular_path = 0; + U32 weighted_mesh = 0; // these multipliers are variable and can be floating point F32 scale = 0.f; - F32 twist = 0.f; - F32 revolutions = 0.f; - const LLDrawable* drawablep = mDrawable; + U32 num_faces = drawablep->getNumFaces(); + + if (has_volume) + { + volume_params = getVolume()->getParams(); + path_params = volume_params.getPathParams(); + profile_params = volume_params.getProfileParams(); + + F32 radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length(); + S32 default_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3); + if (default_detail == getLOD()) + { + num_triangles = getTriangleCount(); + } + else + { + LLVolume* default_volume = LLPrimitive::getVolumeManager()->refVolume(volume_params, default_detail); + if(default_volume != NULL) + { + num_triangles = default_volume->getNumTriangles(); + LLPrimitive::getVolumeManager()->unrefVolume(default_volume); + default_volume = NULL; + } + else + { + has_volume = false; + } + } + } if (isSculpted()) { @@ -3003,21 +3014,17 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const S32 size = gMeshRepo.getMeshSize(volume_params.getSculptID(),3); if ( size > 0) { + num_triangles = (U32)(size / 10.f); // avg 1 triangle per 10 bytes if (gMeshRepo.getSkinInfo(volume_params.getSculptID())) { // weighted attachment - 1 point for every 3 bytes - shame = (U32)(size / 3.f); - } - else - { - // non-weighted attachment - 1 point for every 4 bytes - shame = (U32)(size / 4.f); + weighted_mesh = 1; } - if (shame == 0) + if (num_triangles == 0) { - // someone made a really tiny mesh. - shame = 1; + // someone made a really tiny mesh. Approximate with a tetrahedron. + num_triangles = 4; } } else @@ -3052,70 +3059,12 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const } const LLVector3& sc = getScale(); - scale += sc.mV[0] + sc.mV[1] + sc.mV[2]; - if (scale > 4.f) - { - // scale is a multiplier, cap it at 4. - scale = 4.f; - } - - // add points for cut prims - if (path_params.getBegin() != 0.f || path_params.getEnd() != 1.f) - { - ++cuts; - } - - if (profile_params.getBegin() != 0.f || profile_params.getEnd() != 1.f) - { - ++cuts; - } - - // double cost for hollow prims / sculpties - if (volume_params.getHollow() != 0.f) - { - hollow = 1; - } - - F32 twist_mag = path_params.getTwistBegin() - path_params.getTwistEnd(); - if (twist_mag < 0) - { - twist_mag *= -1.f; - } - - // note magnitude of twist is [-1.f, 1.f]. which translates to [-180, 180] degrees. - // scale to degrees / 90 by multiplying by 2. - twist = twist_mag * 2.f; - - // multiply by the number of revolutions in the prim. cap at 4. - revolutions = path_params.getRevolutions(); - if (revolutions > 4.f) - { - revolutions = 4.f; - } - - // double cost for circular profiles / sculpties - if (profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE || - profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE_HALF) - { - circular_profile = 1; - } - - // double cost for circular paths / sculpties - if (path_params.getCurveType() == LL_PCODE_PATH_CIRCLE || - path_params.getCurveType() == LL_PCODE_PATH_CIRCLE2) - { - circular_path = 1; - } - - // treat sculpties as hollow prims with circular paths & profiles - if (isSculpted() && !isMesh()) - { - hollow = 1; - circular_profile = 1; - circular_path = 1; - } + scale += (sc.mV[0] + sc.mV[1] + sc.mV[2]) / 4.f; // scale to 1/4 the sum of the size + // enforce scale multiplier to be in the range [1,7] (7 was determined to experimentally be a reasonable max) + scale = scale > 7.f ? 7.f : scale; + scale = scale < 1.f ? 1.f : scale; - for (S32 i = 0; i < drawablep->getNumFaces(); ++i) + for (S32 i = 0; i < num_faces; ++i) { const LLFace* face = drawablep->getFace(i); const LLTextureEntry* te = face->getTextureEntry(); @@ -3132,11 +3081,11 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const if (face->getPoolType() == LLDrawPool::POOL_ALPHA) { - alpha++; + alpha = 1; } else if (img && img->getPrimaryFormat() == GL_ALPHA) { - invisi++; + invisi = 1; } if (te) @@ -3158,38 +3107,41 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const } if (face->mTextureMatrix != NULL) { - animtex++; + animtex = 1; } if (te->getTexGen()) { - planar++; + planar = 1; } } } - // shame currently has the "base" cost of 10 for normal prims, variable for mesh + // shame currently has the "base" cost of 1 point per 50 triangles, min 2. + shame = num_triangles / 50.f; + shame = shame < 2.f ? 2.f : shame; - // add modifier settings - shame += cuts * ARC_CUT_COST; - shame += planar * ARC_PLANAR_COST; - shame += animtex * ARC_ANIM_TEX_COST; - shame += alpha * ARC_ALPHA_COST; - shame += invisi * ARC_INVISI_COST; + // factor in scale + shame *= scale; - // multiply shame by multipliers - if (hollow) + // multiply by per-face modifiers + if (planar) + { + shame *= planar * ARC_PLANAR_COST; + } + + if (animtex) { - shame *= hollow * ARC_HOLLOW_MULT; + shame *= animtex * ARC_ANIM_TEX_COST; } - if (circular_profile) + if (alpha) { - shame *= circular_profile * ARC_CIRC_PROF_MULT; + shame *= alpha * ARC_ALPHA_COST; } - if (circular_path) + if(invisi) { - shame *= circular_path * ARC_CIRC_PATH_MULT; + shame *= invisi * ARC_INVISI_COST; } if (glow) @@ -3202,35 +3154,28 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const shame *= bump * ARC_BUMP_MULT; } - if (flexi) - { - shame *= flexi * ARC_FLEXI_MULT; - } - if (shiny) { shame *= shiny * ARC_SHINY_MULT; } - if (twist > 1.f) - { - shame = (U32)(shame * twist); - } - if (scale > 1.f) + // multiply shame by multipliers + if (weighted_mesh) { - shame = (U32)(shame *scale); + shame *= weighted_mesh * ARC_WEIGHTED_MESH; } - if (revolutions > 1.f) + if (flexi) { - shame = (U32)(shame * revolutions); + shame *= flexi * ARC_FLEXI_MULT; } + // add additional costs shame += particles * ARC_PARTICLE_COST; - return shame; + return (U32)shame; } F32 LLVOVolume::getStreamingCost() @@ -3247,16 +3192,13 @@ F32 LLVOVolume::getStreamingCost() return 0.f; } -U32 LLVOVolume::getTriangleCount() +U32 LLVOVolume::getTriangleCount() const { U32 count = 0; LLVolume* volume = getVolume(); if (volume) { - for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) - { - count += volume->getVolumeFace(i).mNumIndices/3; - } + count = volume->getNumTriangles(); } return count; diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 5af88c6cbd..e02a5d5675 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -132,7 +132,7 @@ public: typedef std::map texture_cost_t; U32 getRenderCost(texture_cost_t &textures) const; /*virtual*/ F32 getStreamingCost(); - /*virtual*/ U32 getTriangleCount(); + /*virtual*/ U32 getTriangleCount() const; /*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, -- cgit v1.2.3 From 44308a6693d1c79433db1dcad25f9846601f1c6c Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Mon, 7 Feb 2011 20:12:42 -0500 Subject: SH-923 FIX particle render cost does not appear to be functioning properly was checking the age of the particle system, not the individual particles. This appears to fix the problem. Deferring QA on the new algorithm until it is completed. --- indra/newview/llvovolume.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index a388d2ef30..c65b888bf9 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -2943,7 +2943,8 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const U32 num_triangles = 0; // per-prim costs - static const U32 ARC_PARTICLE_COST = 100; + static const U32 ARC_PARTICLE_COST = 1; + static const U32 ARC_PARTICLE_MAX = 2048; static const U32 ARC_TEXTURE_COST = 5; // per-prim multipliers @@ -3173,7 +3174,15 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const // add additional costs - shame += particles * ARC_PARTICLE_COST; + if (particles) + { + const LLPartSysData *part_sys_data = &(mPartSourcep->mPartSysData); + const LLPartData *part_data = &(part_sys_data->mPartData); + U32 num_particles = (U32)(part_sys_data->mBurstPartCount * llceil( part_data->mMaxAge / part_sys_data->mBurstRate)); + num_particles = num_particles > ARC_PARTICLE_MAX ? ARC_PARTICLE_MAX : num_particles; + F32 part_size = (llmax(part_data->mStartScale[0], part_data->mEndScale[0]) + llmax(part_data->mStartScale[1], part_data->mEndScale[1])) / 2.f; + shame += num_particles * part_size * ARC_PARTICLE_COST; + } return (U32)shame; } -- cgit v1.2.3 From 8b15ca8d6b9cf516670e66ee57591e79b898394d Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Mon, 7 Feb 2011 21:03:10 -0500 Subject: SH-930 FIX revert ARC algorithm for merge to viewer-development Reverting incomplete changes to ARC so that we don't change RC when we merge down. --- indra/newview/llfloatertools.cpp | 32 +++++- indra/newview/llfloatertools.h | 1 + indra/newview/llselectmgr.cpp | 4 +- indra/newview/llvoavatar.cpp | 16 +-- indra/newview/llvovolume.cpp | 237 +++++++++------------------------------ indra/newview/llvovolume.h | 5 +- 6 files changed, 97 insertions(+), 198 deletions(-) diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index c9b99d83ff..f5e3d160fc 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -451,8 +451,7 @@ void LLFloaterTools::refresh() if (sShowObjectCost) { std::string prim_cost_string; - S32 cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectRenderCost(); - LLResMgr::getInstance()->getIntegerString(prim_cost_string, cost); + LLResMgr::getInstance()->getIntegerString(prim_cost_string, calcRenderCost()); getChild("RenderingCost")->setTextArg("[COUNT]", prim_cost_string); } @@ -1010,6 +1009,35 @@ void LLFloaterTools::onClickGridOptions() //floaterp->addDependentFloater(LLFloaterBuildOptions::getInstance(), FALSE); } +S32 LLFloaterTools::calcRenderCost() +{ + S32 cost = 0; + std::set textures; + + for (LLObjectSelection::iterator selection_iter = LLSelectMgr::getInstance()->getSelection()->begin(); + selection_iter != LLSelectMgr::getInstance()->getSelection()->end(); + ++selection_iter) + { + LLSelectNode *select_node = *selection_iter; + if (select_node) + { + LLViewerObject *vobj = select_node->getObject(); + if (vobj->getVolume()) + { + LLVOVolume* volume = (LLVOVolume*) vobj; + + cost += volume->getRenderCost(textures); + cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST; + textures.clear(); + } + } + } + + + return cost; +} + + // static void LLFloaterTools::setEditTool(void* tool_pointer) { diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h index d5595445e0..87c3d2ab47 100644 --- a/indra/newview/llfloatertools.h +++ b/indra/newview/llfloatertools.h @@ -114,6 +114,7 @@ private: static bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response); static void setObjectType( LLPCode pcode ); void onClickGridOptions(); + S32 calcRenderCost(); public: LLButton *mBtnFocus; diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 8ffbd5510d..e0b9f1d736 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -6395,7 +6395,7 @@ U32 LLObjectSelection::getSelectedObjectTriangleCount() return count; } -S32 LLObjectSelection::getSelectedObjectRenderCost() +/*S32 LLObjectSelection::getSelectedObjectRenderCost() { S32 cost = 0; LLVOVolume::texture_cost_t textures; @@ -6419,7 +6419,7 @@ S32 LLObjectSelection::getSelectedObjectRenderCost() return cost; -} +}*/ //----------------------------------------------------------------------------- diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index dd6f7011a1..ec264b1f07 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -8241,7 +8241,7 @@ void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& d void LLVOAvatar::idleUpdateRenderCost() { - static const U32 ARC_BODY_PART_COST = 200; + static const U32 ARC_BODY_PART_COST = 20; static const U32 ARC_LIMIT = 2048; static std::set all_textures; @@ -8252,7 +8252,7 @@ void LLVOAvatar::idleUpdateRenderCost() } U32 cost = 0; - LLVOVolume::texture_cost_t textures; + std::set textures; for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { @@ -8293,21 +8293,15 @@ void LLVOAvatar::idleUpdateRenderCost() } - for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) - { - // add the cost of each individual texture in the linkset - cost += iter->second; - } - // Diagnostic output to identify all avatar-related textures. // Does not affect rendering cost calculation. // Could be wrapped in a debug option if output becomes problematic. if (isSelf()) { // print any attachment textures we didn't already know about. - for (LLVOVolume::texture_cost_t::iterator it = textures.begin(); it != textures.end(); ++it) + for (std::set::iterator it = textures.begin(); it != textures.end(); ++it) { - LLUUID image_id = it->first; + LLUUID image_id = *it; if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) continue; if (all_textures.find(image_id) == all_textures.end()) @@ -8339,6 +8333,8 @@ void LLVOAvatar::idleUpdateRenderCost() } } + cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST; + setDebugText(llformat("%d", cost)); F32 green = 1.f-llclamp(((F32) cost-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f); F32 red = llmin((F32) cost/(F32)ARC_LIMIT, 1.f); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index c65b888bf9..8f1a761549 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -2931,35 +2931,24 @@ const LLMatrix4 LLVOVolume::getRenderMatrix() const // total cost is returned value + 5 * size of the resulting set. // Cannot include cost of textures, as they may be re-used in linked // children, and cost should only be increased for unique textures -Nyx -U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const +U32 LLVOVolume::getRenderCost(std::set &textures) const { - // Get access to params we'll need at various points. - // Skip if this is object doesn't have a volume (e.g. is an avatar). - BOOL has_volume = (getVolume() != NULL); - LLVolumeParams volume_params; - LLPathParams path_params; - LLProfileParams profile_params; - - U32 num_triangles = 0; - + // base cost of each prim should be 10 points + static const U32 ARC_PRIM_COST = 10; // per-prim costs - static const U32 ARC_PARTICLE_COST = 1; - static const U32 ARC_PARTICLE_MAX = 2048; - static const U32 ARC_TEXTURE_COST = 5; + static const U32 ARC_INVISI_COST = 1; + static const U32 ARC_SHINY_COST = 1; + static const U32 ARC_GLOW_COST = 1; + static const U32 ARC_FLEXI_COST = 8; + static const U32 ARC_PARTICLE_COST = 16; + static const U32 ARC_BUMP_COST = 4; - // per-prim multipliers - static const F32 ARC_GLOW_MULT = 1.5f; // tested based on performance - static const F32 ARC_BUMP_MULT = 1.25f; // tested based on performance - static const F32 ARC_FLEXI_MULT = 4; - static const F32 ARC_SHINY_MULT = 1.6f; // tested based on performance - static const F32 ARC_INVISI_COST = 1.2f; // tested based on performance - static const F32 ARC_WEIGHTED_MESH = 1.2f; + // per-face costs + static const U32 ARC_PLANAR_COST = 1; + static const U32 ARC_ANIM_TEX_COST = 4; + static const U32 ARC_ALPHA_COST = 4; - static const F32 ARC_PLANAR_COST = 1.2f; // 1.2x max - static const F32 ARC_ANIM_TEX_COST = 1.4f; // 1.4x max - static const F32 ARC_ALPHA_COST = 4.f; // 4x max - - F32 shame = 0; + U32 shame = ARC_PRIM_COST; U32 invisi = 0; U32 shiny = 0; @@ -2968,87 +2957,9 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const U32 flexi = 0; U32 animtex = 0; U32 particles = 0; + U32 scale = 0; U32 bump = 0; U32 planar = 0; - U32 weighted_mesh = 0; - - // these multipliers are variable and can be floating point - F32 scale = 0.f; - - const LLDrawable* drawablep = mDrawable; - U32 num_faces = drawablep->getNumFaces(); - - if (has_volume) - { - volume_params = getVolume()->getParams(); - path_params = volume_params.getPathParams(); - profile_params = volume_params.getProfileParams(); - - F32 radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length(); - S32 default_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3); - if (default_detail == getLOD()) - { - num_triangles = getTriangleCount(); - } - else - { - LLVolume* default_volume = LLPrimitive::getVolumeManager()->refVolume(volume_params, default_detail); - if(default_volume != NULL) - { - num_triangles = default_volume->getNumTriangles(); - LLPrimitive::getVolumeManager()->unrefVolume(default_volume); - default_volume = NULL; - } - else - { - has_volume = false; - } - } - } - - if (isSculpted()) - { - if (isMesh()) - { - // base cost is dependent on mesh complexity - // note that 3 is the highest LOD as of the time of this coding. - S32 size = gMeshRepo.getMeshSize(volume_params.getSculptID(),3); - if ( size > 0) - { - num_triangles = (U32)(size / 10.f); // avg 1 triangle per 10 bytes - if (gMeshRepo.getSkinInfo(volume_params.getSculptID())) - { - // weighted attachment - 1 point for every 3 bytes - weighted_mesh = 1; - } - - if (num_triangles == 0) - { - // someone made a really tiny mesh. Approximate with a tetrahedron. - num_triangles = 4; - } - } - else - { - // something went wrong - user should know their content isn't render-free - return 0; - } - } - else - { - const LLSculptParams *sculpt_params = (LLSculptParams *) getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLUUID sculpt_id = sculpt_params->getSculptTexture(); - if (textures.find(sculpt_id) == textures.end()) - { - LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(sculpt_id); - if (texture) - { - S32 texture_cost = (S32)(ARC_TEXTURE_COST * (texture->getFullHeight() / 128.f + texture->getFullWidth() / 128.f + 1)); - textures.insert(texture_cost_t::value_type(sculpt_id, texture_cost)); - } - } - } - } if (isFlexible()) { @@ -3060,12 +2971,18 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const } const LLVector3& sc = getScale(); - scale += (sc.mV[0] + sc.mV[1] + sc.mV[2]) / 4.f; // scale to 1/4 the sum of the size - // enforce scale multiplier to be in the range [1,7] (7 was determined to experimentally be a reasonable max) - scale = scale > 7.f ? 7.f : scale; - scale = scale < 1.f ? 1.f : scale; + scale += (U32) sc.mV[0] + (U32) sc.mV[1] + (U32) sc.mV[2]; + + const LLDrawable* drawablep = mDrawable; - for (S32 i = 0; i < num_faces; ++i) + if (isSculpted()) + { + const LLSculptParams *sculpt_params = (LLSculptParams *) getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLUUID sculpt_id = sculpt_params->getSculptTexture(); + textures.insert(sculpt_id); + } + + for (S32 i = 0; i < drawablep->getNumFaces(); ++i) { const LLFace* face = drawablep->getFace(i); const LLTextureEntry* te = face->getTextureEntry(); @@ -3073,16 +2990,12 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const if (img) { - if (textures.find(img->getID()) == textures.end()) - { - S32 texture_cost = (S32)(ARC_TEXTURE_COST * (img->getFullHeight() / 128.f + img->getFullWidth() / 128.f + 1)); - textures.insert(texture_cost_t::value_type(img->getID(), texture_cost)); - } + textures.insert(img->getID()); } if (face->getPoolType() == LLDrawPool::POOL_ALPHA) { - alpha = 1; + alpha++; } else if (img && img->getPrimaryFormat() == GL_ALPHA) { @@ -3093,98 +3006,58 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const { if (te->getBumpmap()) { - // bump is a multiplier, don't add per-face bump = 1; } if (te->getShiny()) { - // shiny is a multiplier, don't add per-face shiny = 1; } if (te->getGlow() > 0.f) { - // glow is a multiplier, don't add per-face glow = 1; } if (face->mTextureMatrix != NULL) { - animtex = 1; + animtex++; } if (te->getTexGen()) { - planar = 1; + planar++; } } } - // shame currently has the "base" cost of 1 point per 50 triangles, min 2. - shame = num_triangles / 50.f; - shame = shame < 2.f ? 2.f : shame; - - // factor in scale - shame *= scale; - - // multiply by per-face modifiers - if (planar) - { - shame *= planar * ARC_PLANAR_COST; - } - - if (animtex) - { - shame *= animtex * ARC_ANIM_TEX_COST; - } - - if (alpha) - { - shame *= alpha * ARC_ALPHA_COST; - } - - if(invisi) - { - shame *= invisi * ARC_INVISI_COST; - } - - if (glow) - { - shame *= glow * ARC_GLOW_MULT; - } - - if (bump) - { - shame *= bump * ARC_BUMP_MULT; - } - - if (shiny) - { - shame *= shiny * ARC_SHINY_MULT; - } + shame += invisi * ARC_INVISI_COST; + shame += shiny * ARC_SHINY_COST; + shame += glow * ARC_GLOW_COST; + shame += alpha * ARC_ALPHA_COST; + shame += flexi * ARC_FLEXI_COST; + shame += animtex * ARC_ANIM_TEX_COST; + shame += particles * ARC_PARTICLE_COST; + shame += bump * ARC_BUMP_COST; + shame += planar * ARC_PLANAR_COST; + shame += scale; - // multiply shame by multipliers - if (weighted_mesh) + LLViewerObject::const_child_list_t& child_list = getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); + ++iter) { - shame *= weighted_mesh * ARC_WEIGHTED_MESH; - } - - if (flexi) - { - shame *= flexi * ARC_FLEXI_MULT; + const LLViewerObject* child_objectp = *iter; + const LLDrawable* child_drawablep = child_objectp->mDrawable; + if (child_drawablep) + { + const LLVOVolume* child_volumep = child_drawablep->getVOVolume(); + if (child_volumep) + { + shame += child_volumep->getRenderCost(textures); + } + } } + return shame; - // add additional costs - if (particles) - { - const LLPartSysData *part_sys_data = &(mPartSourcep->mPartSysData); - const LLPartData *part_data = &(part_sys_data->mPartData); - U32 num_particles = (U32)(part_sys_data->mBurstPartCount * llceil( part_data->mMaxAge / part_sys_data->mBurstRate)); - num_particles = num_particles > ARC_PARTICLE_MAX ? ARC_PARTICLE_MAX : num_particles; - F32 part_size = (llmax(part_data->mStartScale[0], part_data->mEndScale[0]) + llmax(part_data->mStartScale[1], part_data->mEndScale[1])) / 2.f; - shame += num_particles * part_size * ARC_PARTICLE_COST; - } - - return (U32)shame; } F32 LLVOVolume::getStreamingCost() diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index e02a5d5675..0c12f14832 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -129,8 +129,7 @@ public: const LLMatrix4& getRelativeXform() const { return mRelativeXform; } const LLMatrix3& getRelativeXformInvTrans() const { return mRelativeXformInvTrans; } /*virtual*/ const LLMatrix4 getRenderMatrix() const; - typedef std::map texture_cost_t; - U32 getRenderCost(texture_cost_t &textures) const; + U32 getRenderCost(std::set &textures) const; /*virtual*/ F32 getStreamingCost(); /*virtual*/ U32 getTriangleCount() const; /*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, @@ -359,6 +358,8 @@ public: static LLPointer sObjectMediaClient; static LLPointer sObjectMediaNavigateClient; + static const U32 ARC_TEXTURE_COST = 5; + protected: static S32 sNumLODChanges; -- cgit v1.2.3 From 854a0fe1c0a5dccb86d5c4e492af78a311b447a8 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 8 Feb 2011 15:52:32 -0600 Subject: Reduce number of potential joints in a rigged mesh to 32 for backwards compatibility with ATI X1950 --- indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl index eef6556fba..ef823c28b1 100644 --- a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl +++ b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl @@ -9,7 +9,7 @@ attribute vec4 object_weight; -uniform mat4 matrixPalette[64]; +uniform mat4 matrixPalette[32]; mat4 getObjectSkinnedTransform() { -- cgit v1.2.3 From a242129b571daa8c6137c79931e31f9d43422abc Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 8 Feb 2011 15:53:50 -0600 Subject: SH-523 Fix for non-finite values in silhouette rendering resulting in silhouette segments pointing at center of screen. --- indra/llmath/llvolume.cpp | 4 -- indra/llmath/llvolume.h | 1 - indra/newview/llselectmgr.cpp | 94 +++++++++++++++++++++---------------------- indra/newview/llselectmgr.h | 1 - indra/newview/llvovolume.cpp | 2 +- 5 files changed, 46 insertions(+), 56 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 2f662b757b..c4be176353 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -4179,7 +4179,6 @@ S32 LLVolume::getNumTriangles() const //----------------------------------------------------------------------------- void LLVolume::generateSilhouetteVertices(std::vector &vertices, std::vector &normals, - std::vector &segments, const LLVector3& obj_cam_vec_in, const LLMatrix4& mat_in, const LLMatrix3& norm_mat_in, @@ -4198,7 +4197,6 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, vertices.clear(); normals.clear(); - segments.clear(); if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) { @@ -4399,8 +4397,6 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, norm_mat.rotate(n[v2], t); t.normalize3fast(); normals.push_back(LLVector3(t[0], t[1], t[2])); - - segments.push_back(vertices.size()); } } } diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 5bd65c2bf2..60b64b1285 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -986,7 +986,6 @@ public: void generateSilhouetteVertices(std::vector &vertices, std::vector &normals, - std::vector &segments, const LLVector3& view_vec, const LLMatrix4& mat, const LLMatrix3& norm_mat, diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 8ffbd5510d..29a16ccc97 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -5204,7 +5204,6 @@ LLSelectNode::LLSelectNode(const LLSelectNode& nodep) mSilhouetteVertices = nodep.mSilhouetteVertices; mSilhouetteNormals = nodep.mSilhouetteNormals; - mSilhouetteSegments = nodep.mSilhouetteSegments; mSilhouetteExists = nodep.mSilhouetteExists; mObject = nodep.mObject; @@ -5628,17 +5627,15 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); gGL.begin(LLRender::LINES); { - S32 i = 0; - for (S32 seg_num = 0; seg_num < (S32)mSilhouetteSegments.size(); seg_num++) + for(S32 i = 0; i < mSilhouetteVertices.size(); i += 2) { - for(; i < mSilhouetteSegments[seg_num]; i++) - { - u_coord += u_divisor * LLSelectMgr::sHighlightUScale; - - gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f); - gGL.texCoord2f( u_coord, v_coord ); - gGL.vertex3fv( mSilhouetteVertices[i].mV ); - } + u_coord += u_divisor * LLSelectMgr::sHighlightUScale; + gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f); + gGL.texCoord2f( u_coord, v_coord ); + gGL.vertex3fv( mSilhouetteVertices[i].mV); + u_coord += u_divisor * LLSelectMgr::sHighlightUScale; + gGL.texCoord2f( u_coord, v_coord ); + gGL.vertex3fv(mSilhouetteVertices[i+1].mV); } } gGL.end(); @@ -5649,51 +5646,50 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) gGL.setSceneBlendType(LLRender::BT_ALPHA); gGL.begin(LLRender::TRIANGLES); { - S32 i = 0; - for (S32 seg_num = 0; seg_num < (S32)mSilhouetteSegments.size(); seg_num++) + for(S32 i = 0; i < mSilhouetteVertices.size(); i+=2) { - S32 first_i = i; - LLVector3 v; - LLVector2 t; + if (!mSilhouetteNormals[i].isFinite() || + !mSilhouetteNormals[i+1].isFinite()) + { //skip skewed segments + continue; + } - for(; i < mSilhouetteSegments[seg_num]; i++) - { + LLVector3 v[4]; + LLVector2 tc[4]; + v[0] = mSilhouetteVertices[i] + (mSilhouetteNormals[i] * silhouette_thickness); + tc[0].set(u_coord, v_coord + LLSelectMgr::sHighlightVScale); - if (i == first_i) { - LLVector3 vert = (mSilhouetteNormals[i]) * silhouette_thickness; - vert += mSilhouetteVertices[i]; + v[1] = mSilhouetteVertices[i]; + tc[1].set(u_coord, v_coord); - gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha); - gGL.texCoord2f( u_coord, v_coord + LLSelectMgr::sHighlightVScale ); - gGL.vertex3fv( vert.mV ); - - u_coord += u_divisor * LLSelectMgr::sHighlightUScale; + u_coord += u_divisor * LLSelectMgr::sHighlightUScale; - gGL.color4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2); - gGL.texCoord2f( u_coord, v_coord ); - gGL.vertex3fv( mSilhouetteVertices[i].mV ); + v[2] = mSilhouetteVertices[i+1] + (mSilhouetteNormals[i+1] * silhouette_thickness); + tc[2].set(u_coord, v_coord + LLSelectMgr::sHighlightVScale); + + v[3] = mSilhouetteVertices[i+1]; + tc[3].set(u_coord,v_coord); - v = mSilhouetteVertices[i]; - t = LLVector2(u_coord, v_coord); - } - else { - LLVector3 vert = (mSilhouetteNormals[i]) * silhouette_thickness; - vert += mSilhouetteVertices[i]; - - gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha); - gGL.texCoord2f( u_coord, v_coord + LLSelectMgr::sHighlightVScale ); - gGL.vertex3fv( vert.mV ); - gGL.vertex3fv( vert.mV ); - - gGL.texCoord2fv(t.mV); - u_coord += u_divisor * LLSelectMgr::sHighlightUScale; - gGL.color4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2); - gGL.vertex3fv(v.mV); - gGL.texCoord2f( u_coord, v_coord ); - gGL.vertex3fv( mSilhouetteVertices[i].mV ); + gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha); + gGL.texCoord2fv(tc[0].mV); + gGL.vertex3fv( v[0].mV ); + + gGL.color4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2); + gGL.texCoord2fv( tc[1].mV ); + gGL.vertex3fv( v[1].mV ); - } - } + gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha); + gGL.texCoord2fv( tc[2].mV ); + gGL.vertex3fv( v[2].mV ); + + gGL.vertex3fv( v[2].mV ); + + gGL.color4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2); + gGL.texCoord2fv( tc[1].mV ); + gGL.vertex3fv( v[1].mV ); + + gGL.texCoord2fv( tc[3].mV ); + gGL.vertex3fv( v[3].mV ); } } gGL.end(); diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 85d8d3212d..1b354f983a 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -182,7 +182,6 @@ public: std::vector mTextureScaleRatios; std::vector mSilhouetteVertices; // array of vertices to render silhouette of object std::vector mSilhouetteNormals; // array of normals to render silhouette of object - std::vector mSilhouetteSegments; // array of normals to render silhouette of object BOOL mSilhouetteExists; // need to generate silhouette? protected: diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 55e68d61f9..d18e848e34 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -2874,7 +2874,7 @@ void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_p trans_mat.translate(getRegion()->getOriginAgent()); } - volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, nodep->mSilhouetteSegments, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask()); + volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask()); nodep->mSilhouetteExists = TRUE; } -- cgit v1.2.3 From 44119c512f7eca7caa7a521090914624c502a9b1 Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Tue, 8 Feb 2011 17:40:07 -0500 Subject: SH-940 FIX crash on startup Setting the lighting detail happens when we force a graphics level on startup. This got added with handleRenderLocalLightsChanged, which got added recently. setLightingDetail is safe to call with the pipeline uninitialized. Removing the assert to stop the crash. Fix verified to be safe by davep. --- indra/newview/pipeline.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index ca58d8275b..69173d26f4 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1021,7 +1021,6 @@ S32 LLPipeline::getMaxLightingDetail() const S32 LLPipeline::setLightingDetail(S32 level) { LLMemType mt_ld(LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL); - assertInitialized(); if (level < 0) { -- cgit v1.2.3 From 9cd092544f6f4183af19132ed68111bd8d31a89f Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Tue, 8 Feb 2011 15:00:42 -0800 Subject: SH-545 [REGRESSION] Enabled Basic Shaders Can Cause an Unrecoverable System Lock Up originally done in http://bitbucket.org/leyla/leyla-mesh-development --- indra/llrender/llgl.cpp | 8 ++++++++ indra/newview/llfloaterpreference.cpp | 9 ++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 9022026248..f91584b5e4 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -671,7 +671,15 @@ void LLGLManager::initExtensions() mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts); mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts); // mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad +#ifdef GL_ARB_framebuffer_object mHasFramebufferObject = ExtensionExists("GL_ARB_framebuffer_object", gGLHExts.mSysExts); +#else + mHasFramebufferObject = ExtensionExists("GL_EXT_framebuffer_object", gGLHExts.mSysExts) && + ExtensionExists("GL_EXT_framebuffer_blit", gGLHExts.mSysExts) && + ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts) && + ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts); +#endif + mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts); mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts); mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 92d6d9a486..3673a28163 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1043,8 +1043,10 @@ void LLFloaterPreference::refreshEnabledState() //Deferred/SSAO/Shadows LLCheckBoxCtrl* ctrl_deferred = getChild("UseLightShaders"); - if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && - shaders) + + if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && + shaders && + gGLManager.mHasFramebufferObject) { BOOL enabled = (ctrl_wind_light->get()) ? TRUE : FALSE; @@ -1127,7 +1129,8 @@ void LLFloaterPreference::disableUnavailableSettings() } // disabled deferred - if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred")) + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") || + !gGLManager.mHasFramebufferObject) { ctrl_shadows->setEnabled(FALSE); ctrl_shadows->setValue(0); -- cgit v1.2.3 From 8f9edd3874823fccf9f78e45c758bee951b56e1d Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 8 Feb 2011 17:19:54 -0600 Subject: SH-534 Don't allow deferred rendering to be enabled on windows PC's with GL version less than 3.0. --- indra/newview/featuretable.txt | 6 +++++- indra/newview/featuretable_xp.txt | 5 ++++- indra/newview/llfeaturemanager.cpp | 4 ++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index 729132b638..afc268d7a5 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -1,4 +1,4 @@ -version 25 +version 26 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences // Should be combined into one table @@ -275,6 +275,9 @@ RenderObjectBump 0 0 list OpenGLPre15 RenderVBOEnable 1 0 +list OpenGLPre30 +RenderDeferred 0 0 + list Intel RenderAnisotropic 1 0 @@ -561,3 +564,4 @@ list NVIDIA_GeForce_Go_7800 RenderShaderLightingMaxLevel 1 2 list NVIDIA_GeForce_Go_7900 RenderShaderLightingMaxLevel 1 2 + diff --git a/indra/newview/featuretable_xp.txt b/indra/newview/featuretable_xp.txt index 755910f54a..38299c32bc 100644 --- a/indra/newview/featuretable_xp.txt +++ b/indra/newview/featuretable_xp.txt @@ -1,4 +1,4 @@ -version 25 +version 26 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences // Should be combined into one table @@ -267,6 +267,9 @@ RenderObjectBump 0 0 list OpenGLPre15 RenderVBOEnable 1 0 +list OpenGLPre30 +RenderDeferred 0 0 + list Intel RenderAnisotropic 1 0 diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 4e16cc4217..edfc4538a1 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -745,6 +745,10 @@ void LLFeatureManager::applyBaseMasks() { maskFeatures("OpenGLPre15"); } + if (gGLManager.mGLVersion < 3.f) + { + maskFeatures("OpenGLPre30"); + } // now mask by gpu string // Replaces ' ' with '_' in mGPUString to deal with inability for parser to handle spaces -- cgit v1.2.3 From d0bf3079d78df386bbac8676ee3e3264323e7e24 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Wed, 9 Feb 2011 10:53:38 -0800 Subject: SH-840 Convert resource cost physics cost to prim count --- indra/newview/llfloatertools.cpp | 154 +++++++++++++-------- .../newview/skins/default/xui/en/floater_tools.xml | 29 +++- 2 files changed, 128 insertions(+), 55 deletions(-) diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index f5e3d160fc..a404aa0b1c 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -414,62 +414,96 @@ void LLFloaterTools::refresh() // Refresh object and prim count labels LLLocale locale(LLLocale::USER_LOCALE); - // Get the number of objects selected - std::string root_object_count_string; - std::string object_count_string; - - LLResMgr::getInstance()->getIntegerString( - root_object_count_string, - LLSelectMgr::getInstance()->getSelection()->getRootObjectCount()); - LLResMgr::getInstance()->getIntegerString( - object_count_string, - LLSelectMgr::getInstance()->getSelection()->getObjectCount()); - - F32 obj_cost = - LLSelectMgr::getInstance()->getSelection()->getSelectedObjectCost(); - F32 link_cost = - LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetCost(); - F32 obj_physics_cost = - LLSelectMgr::getInstance()->getSelection()->getSelectedPhysicsCost(); - F32 link_physics_cost = - LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetPhysicsCost(); - - // Update the text for the counts - childSetTextArg( - "linked_set_count", - "[COUNT]", - root_object_count_string); - childSetTextArg("object_count", "[COUNT]", object_count_string); - - // Update the text for the resource costs - childSetTextArg("linked_set_cost","[COST]",llformat("%.1f", link_cost)); - childSetTextArg("object_cost", "[COST]", llformat("%.1f", obj_cost)); - childSetTextArg("linked_set_cost","[PHYSICS]",llformat("%.1f", link_physics_cost)); - childSetTextArg("object_cost", "[PHYSICS]", llformat("%.1f", obj_physics_cost)); - - // Display rendering cost if needed - if (sShowObjectCost) - { - std::string prim_cost_string; - LLResMgr::getInstance()->getIntegerString(prim_cost_string, calcRenderCost()); - getChild("RenderingCost")->setTextArg("[COUNT]", prim_cost_string); + if ((gAgent.getRegion() && gAgent.getRegion()->getCapability("GetMesh").empty()) || !gSavedSettings.getBOOL("MeshEnabled")) + { + std::string obj_count_string; + LLResMgr::getInstance()->getIntegerString(obj_count_string, LLSelectMgr::getInstance()->getSelection()->getRootObjectCount()); + getChild("obj_count")->setTextArg("[COUNT]", obj_count_string); + std::string prim_count_string; + LLResMgr::getInstance()->getIntegerString(prim_count_string, LLSelectMgr::getInstance()->getSelection()->getObjectCount()); + getChild("prim_count")->setTextArg("[COUNT]", prim_count_string); + + // calculate selection rendering cost + if (sShowObjectCost) + { + std::string prim_cost_string; + LLResMgr::getInstance()->getIntegerString(prim_cost_string, calcRenderCost()); + getChild("RenderingCost")->setTextArg("[COUNT]", prim_cost_string); + } + + getChildView("linked_set_count")->setVisible(false); + getChildView("linked_set_cost")->setVisible(false); + getChildView("object_count")->setVisible(false); + getChildView("object_cost")->setVisible(false); + getChildView("obj_count")->setVisible(true); + getChildView("prim_count")->setVisible(true); + + // disable the object and prim counts if nothing selected + bool have_selection = ! LLSelectMgr::getInstance()->getSelection()->isEmpty(); + getChildView("obj_count")->setEnabled(have_selection); + getChildView("prim_count")->setEnabled(have_selection); + getChildView("RenderingCost")->setEnabled(have_selection && sShowObjectCost); } + else + { + // Get the number of objects selected + std::string root_object_count_string; + std::string object_count_string; + + LLResMgr::getInstance()->getIntegerString( + root_object_count_string, + LLSelectMgr::getInstance()->getSelection()->getRootObjectCount()); + LLResMgr::getInstance()->getIntegerString( + object_count_string, + LLSelectMgr::getInstance()->getSelection()->getObjectCount()); + + F32 obj_cost = + LLSelectMgr::getInstance()->getSelection()->getSelectedObjectCost(); + F32 link_cost = + LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetCost(); + F32 obj_physics_cost = + LLSelectMgr::getInstance()->getSelection()->getSelectedPhysicsCost(); + F32 link_physics_cost = + LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetPhysicsCost(); + + // Update the text for the counts + childSetTextArg( + "linked_set_count", + "[COUNT]", + root_object_count_string); + childSetTextArg("object_count", "[COUNT]", object_count_string); + + // Update the text for the resource costs + childSetTextArg("linked_set_cost","[COST]",llformat("%.1f", link_cost)); + childSetTextArg("object_cost", "[COST]", llformat("%.1f", obj_cost)); + childSetTextArg("linked_set_cost","[PHYSICS]",llformat("%.1f", link_physics_cost)); + childSetTextArg("object_cost", "[PHYSICS]", llformat("%.1f", obj_physics_cost)); + + // Display rendering cost if needed + if (sShowObjectCost) + { + std::string prim_cost_string; + LLResMgr::getInstance()->getIntegerString(prim_cost_string, calcRenderCost()); + getChild("RenderingCost")->setTextArg("[COUNT]", prim_cost_string); + } - // disable the object and prim counts if nothing selected - bool have_selection = ! LLSelectMgr::getInstance()->getSelection()->isEmpty(); - childSetEnabled("linked_set_count", have_selection); - childSetEnabled("object_count", have_selection); - childSetEnabled("linked_set_cost", have_selection); - childSetEnabled("object_cost", have_selection); - - bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && - !gAgent.getRegion()->getCapability("GetMesh").empty(); + // disable the object and prim counts if nothing selected + bool have_selection = ! LLSelectMgr::getInstance()->getSelection()->isEmpty(); + childSetEnabled("linked_set_count", have_selection); + childSetEnabled("object_count", have_selection); + childSetEnabled("linked_set_cost", have_selection); + childSetEnabled("object_cost", have_selection); + getChildView("RenderingCost")->setEnabled(have_selection && sShowObjectCost); + + getChildView("linked_set_count")->setVisible(true); + getChildView("linked_set_cost")->setVisible(true); + getChildView("object_count")->setVisible(true); + getChildView("object_cost")->setVisible(true); + getChildView("obj_count")->setVisible(false); + getChildView("prim_count")->setVisible(false); + } - getChildView("linked_set_count")->setVisible(enable_mesh); - getChildView("linked_set_cost")->setVisible(enable_mesh); - getChildView("object_count")->setVisible(enable_mesh); - getChildView("object_cost")->setVisible(enable_mesh); // Refresh child tabs mPanelPermissions->refresh(); @@ -753,8 +787,20 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) getChildView("Strength:")->setVisible( land_visible); } - getChildView("obj_count")->setVisible( !land_visible); - getChildView("prim_count")->setVisible( !land_visible); + if (gAgent.getRegion()->getCapability("GetMesh").empty()) + { + getChildView("obj_count")->setVisible( !land_visible); + getChildView("prim_count")->setVisible( !land_visible); + getChildView("RenderingCost")->setVisible( !land_visible && sShowObjectCost); + } + else + { + getChildView("linked_set_count")->setVisible( !land_visible); + getChildView("linked_set_cost")->setVisible( !land_visible); + getChildView("object_count")->setVisible( !land_visible); + getChildView("object_cost")->setVisible( !land_visible); + getChildView("RenderingCost")->setVisible( !land_visible && sShowObjectCost); + } mTab->setVisible(!land_visible); mPanelLandInfo->setVisible(land_visible); } diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index cce833b1ea..53cc808e70 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -722,6 +722,33 @@ + + Objects: [COUNT] + + + Prims: [COUNT] + Linked Sets: [COUNT] -- cgit v1.2.3 From 64e017fc6b19006c893b4766be05c18ddb3b5593 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 9 Feb 2011 15:04:25 -0500 Subject: SH-915 WIP - allow flycam control in autopilot record/playback --- indra/newview/llagent.cpp | 8 ++++- indra/newview/llagentpilot.cpp | 70 ++++++++++++++++++++++++++++++++++++++++-- indra/newview/llagentpilot.h | 14 +++++++++ indra/newview/llappviewer.cpp | 11 +++++-- 4 files changed, 98 insertions(+), 5 deletions(-) mode change 100644 => 100755 indra/newview/llagent.cpp mode change 100644 => 100755 indra/newview/llagentpilot.cpp mode change 100644 => 100755 indra/newview/llagentpilot.h mode change 100644 => 100755 indra/newview/llappviewer.cpp diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp old mode 100644 new mode 100755 index de7073be24..3f1bf4c5c2 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -1213,7 +1213,13 @@ BOOL LLAgent::getBusy() const //----------------------------------------------------------------------------- // startAutoPilotGlobal() //----------------------------------------------------------------------------- -void LLAgent::startAutoPilotGlobal(const LLVector3d &target_global, const std::string& behavior_name, const LLQuaternion *target_rotation, void (*finish_callback)(BOOL, void *), void *callback_data, F32 stop_distance, F32 rot_threshold) +void LLAgent::startAutoPilotGlobal( + const LLVector3d &target_global, + const std::string& behavior_name, + const LLQuaternion *target_rotation, + void (*finish_callback)(BOOL, void *), + void *callback_data, + F32 stop_distance, F32 rot_threshold) { if (!isAgentAvatarValid()) { diff --git a/indra/newview/llagentpilot.cpp b/indra/newview/llagentpilot.cpp old mode 100644 new mode 100755 index 13e1023185..92e0180b46 --- a/indra/newview/llagentpilot.cpp +++ b/indra/newview/llagentpilot.cpp @@ -34,6 +34,8 @@ #include "llagent.h" #include "llappviewer.h" #include "llviewercontrol.h" +#include "llviewercamera.h" +#include "llviewerjoystick.h" LLAgentPilot gAgentPilot; @@ -47,7 +49,8 @@ LLAgentPilot::LLAgentPilot() : mLastRecordTime(0.f), mStarted(FALSE), mPlaying(FALSE), - mCurrentAction(0) + mCurrentAction(0), + mOverrideCamera(FALSE) { } @@ -55,6 +58,8 @@ LLAgentPilot::~LLAgentPilot() { } +#define CAM_FIELDS 1 + void LLAgentPilot::load(const std::string& filename) { if(filename.empty()) @@ -85,10 +90,30 @@ void LLAgentPilot::load(const std::string& filename) Action new_action; file >> new_action.mTime >> action_type; file >> new_action.mTarget.mdV[VX] >> new_action.mTarget.mdV[VY] >> new_action.mTarget.mdV[VZ]; +#if CAM_FIELDS + file >> new_action.mCameraView; + file >> new_action.mCameraOrigin.mV[VX] + >> new_action.mCameraOrigin.mV[VY] + >> new_action.mCameraOrigin.mV[VZ]; + + file >> new_action.mCameraXAxis.mV[VX] + >> new_action.mCameraXAxis.mV[VY] + >> new_action.mCameraXAxis.mV[VZ]; + + file >> new_action.mCameraYAxis.mV[VX] + >> new_action.mCameraYAxis.mV[VY] + >> new_action.mCameraYAxis.mV[VZ]; + + file >> new_action.mCameraZAxis.mV[VX] + >> new_action.mCameraZAxis.mV[VY] + >> new_action.mCameraZAxis.mV[VZ]; +#endif new_action.mType = (EActionType)action_type; mActions.put(new_action); } + mOverrideCamera = true; + file.close(); } @@ -108,7 +133,27 @@ void LLAgentPilot::save(const std::string& filename) for (i = 0; i < mActions.count(); i++) { file << mActions[i].mTime << "\t" << mActions[i].mType << "\t"; - file << std::setprecision(32) << mActions[i].mTarget.mdV[VX] << "\t" << mActions[i].mTarget.mdV[VY] << "\t" << mActions[i].mTarget.mdV[VZ] << '\n'; + file << std::setprecision(32) << mActions[i].mTarget.mdV[VX] << "\t" << mActions[i].mTarget.mdV[VY] << "\t" << mActions[i].mTarget.mdV[VZ]; +#if CAM_FIELDS + file << "\t" << mActions[i].mCameraView; + + file << "\t" << mActions[i].mCameraOrigin[VX] + << "\t" << mActions[i].mCameraOrigin[VY] + << "\t" << mActions[i].mCameraOrigin[VZ]; + + file << "\t" << mActions[i].mCameraXAxis[VX] + << "\t" << mActions[i].mCameraXAxis[VY] + << "\t" << mActions[i].mCameraXAxis[VZ]; + + file << "\t" << mActions[i].mCameraYAxis[VX] + << "\t" << mActions[i].mCameraYAxis[VY] + << "\t" << mActions[i].mCameraYAxis[VZ]; + + file << "\t" << mActions[i].mCameraZAxis[VX] + << "\t" << mActions[i].mCameraZAxis[VY] + << "\t" << mActions[i].mCameraZAxis[VZ]; +#endif + file << '\n'; } file.close(); @@ -136,6 +181,12 @@ void LLAgentPilot::addAction(enum EActionType action_type) action.mType = action_type; action.mTarget = gAgent.getPositionGlobal(); action.mTime = mTimer.getElapsedTimeF32(); + LLViewerCamera *cam = LLViewerCamera::getInstance(); + action.mCameraView = cam->getView(); + action.mCameraOrigin = cam->getOrigin(); + action.mCameraXAxis = cam->getXAxis(); + action.mCameraYAxis = cam->getYAxis(); + action.mCameraZAxis = cam->getZAxis(); mLastRecordTime = (F32)action.mTime; mActions.put(action); } @@ -151,7 +202,12 @@ void LLAgentPilot::startPlayback() if (mActions.count()) { llinfos << "Starting playback, moving to waypoint 0" << llendl; + if (!LLViewerJoystick::getInstance()->getOverrideCamera()) + { + LLViewerJoystick::getInstance()->toggleFlycam(); + } gAgent.startAutoPilotGlobal(mActions[0].mTarget); + moveCamera(mActions[0]); mStarted = FALSE; } else @@ -178,6 +234,15 @@ void LLAgentPilot::stopPlayback() } } +void LLAgentPilot::moveCamera(Action& action) +{ + LLViewerCamera::getInstance()->setView(action.mCameraView); + LLViewerCamera::getInstance()->setOrigin(action.mCameraOrigin); + LLViewerCamera::getInstance()->mXAxis = LLVector3(action.mCameraXAxis); + LLViewerCamera::getInstance()->mYAxis = LLVector3(action.mCameraYAxis); + LLViewerCamera::getInstance()->mZAxis = LLVector3(action.mCameraZAxis); +} + void LLAgentPilot::updateTarget() { if (mPlaying) @@ -209,6 +274,7 @@ void LLAgentPilot::updateTarget() if (mCurrentAction < mActions.count()) { gAgent.startAutoPilotGlobal(mActions[mCurrentAction].mTarget); + moveCamera(mActions[mCurrentAction]); } else { diff --git a/indra/newview/llagentpilot.h b/indra/newview/llagentpilot.h old mode 100644 new mode 100755 index f3d34246ae..fd2cb7ee32 --- a/indra/newview/llagentpilot.h +++ b/indra/newview/llagentpilot.h @@ -56,6 +56,11 @@ public: void startPlayback(); void stopPlayback(); + + bool isRecording() { return mRecording; } + bool isPlaying() { return mPlaying; } + bool getOverrideCamera() { return mOverrideCamera; } + void updateTarget(); static void startRecord(void *); @@ -78,6 +83,8 @@ private: BOOL mPlaying; S32 mCurrentAction; + BOOL mOverrideCamera; + class Action { public: @@ -85,10 +92,17 @@ private: EActionType mType; LLVector3d mTarget; F64 mTime; + F32 mCameraView; + LLVector3 mCameraOrigin; + LLVector3 mCameraXAxis; + LLVector3 mCameraYAxis; + LLVector3 mCameraZAxis; }; LLDynamicArray mActions; LLTimer mTimer; + + void moveCamera(Action& action); }; extern LLAgentPilot gAgentPilot; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp old mode 100644 new mode 100755 index c1a311b170..ec3d775dc7 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4221,8 +4221,15 @@ void LLAppViewer::idle() } if (LLViewerJoystick::getInstance()->getOverrideCamera()) - { - LLViewerJoystick::getInstance()->moveFlycam(); + { + if (gAgentPilot.isPlaying() && gAgentPilot.getOverrideCamera()) + { + // camera positioning handled inside gAgentPilot. + } + else + { + LLViewerJoystick::getInstance()->moveFlycam(); + } } else { -- cgit v1.2.3 From 42404a89a3966b1f8d1d85c81c7e550f2adb11cc Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 9 Feb 2011 15:10:22 -0600 Subject: Line endings. --- indra/newview/featuretable_xp.txt | 1116 ++++++++++++++++++------------------- 1 file changed, 558 insertions(+), 558 deletions(-) diff --git a/indra/newview/featuretable_xp.txt b/indra/newview/featuretable_xp.txt index 38299c32bc..d87c3db111 100644 --- a/indra/newview/featuretable_xp.txt +++ b/indra/newview/featuretable_xp.txt @@ -1,560 +1,560 @@ -version 26 - -// NOTE: This is mostly identical to featuretable_mac.txt with a few differences -// Should be combined into one table - -// -// Generates lists of feature mask that can be applied on top of each other. -// -// // Begin comments -// list -// Starts a feature list named -// -// is the name of a feature -// is 0 or 1, whether the feature is available -// is an F32 which is the recommended value -// -// For now, the first list read sets up all of the default values -// - - -// -// All contains everything at their default settings for high end machines -// NOTE: All settings are set to the MIN of applied values, including 'all'! -// -list all -RenderAnisotropic 1 1 -RenderAvatarCloth 1 1 -RenderAvatarLODFactor 1 1.0 -RenderAvatarMaxVisible 1 12 -RenderAvatarVP 1 1 -RenderCubeMap 1 1 -RenderDelayVBUpdate 1 0 -RenderFarClip 1 256 -RenderFlexTimeFactor 1 1.0 -RenderFogRatio 1 4.0 -RenderGamma 1 0 -RenderGlowResolutionPow 1 9 -RenderGround 1 1 -RenderMaxPartCount 1 8192 -RenderNightBrightness 1 1.0 -RenderObjectBump 1 1 -RenderReflectionDetail 1 4 -RenderTerrainDetail 1 1 -RenderTerrainLODFactor 1 2.0 -RenderTransparentWater 1 1 -RenderTreeLODFactor 1 1.0 -RenderUseImpostors 1 1 -RenderVBOEnable 1 1 -RenderVolumeLODFactor 1 2.0 -UseStartScreen 1 1 -UseOcclusion 1 1 -VertexShaderEnable 1 1 -WindLightUseAtmosShaders 1 1 -WLSkyDetail 1 128 -Disregard128DefaultDrawDistance 1 1 -Disregard96DefaultDrawDistance 1 1 -RenderTextureMemoryMultiple 1 1.0 -RenderShaderLightingMaxLevel 1 3 -SkyUseClassicClouds 1 1 -RenderDeferred 1 0 -RenderDeferredSSAO 1 0 -RenderShadowDetail 1 0 -WatchdogDisabled 1 1 -RenderUseStreamVBO 1 1 - -// -// Low Graphics Settings -// -list Low -RenderAnisotropic 1 0 -RenderAvatarCloth 1 0 -RenderAvatarLODFactor 1 0 -RenderAvatarMaxVisible 1 3 -RenderAvatarVP 1 0 -RenderFarClip 1 64 -RenderFlexTimeFactor 1 0 -RenderGlowResolutionPow 1 8 -RenderMaxPartCount 1 0 -RenderObjectBump 1 0 -RenderReflectionDetail 1 0 -RenderTerrainDetail 1 0 -RenderTerrainLODFactor 1 1 -RenderTransparentWater 1 0 -RenderTreeLODFactor 1 0 -RenderUseImpostors 1 1 -RenderVolumeLODFactor 1 0.5 -VertexShaderEnable 1 0 -WindLightUseAtmosShaders 1 0 -WLSkyDetail 1 48 -SkyUseClassicClouds 1 0 -RenderDeferred 1 0 -RenderDeferredSSAO 1 0 -RenderShadowDetail 1 0 - -// -// Mid Graphics Settings -// -list Mid -RenderAnisotropic 1 0 -RenderAvatarCloth 1 0 -RenderAvatarLODFactor 1 0.5 -RenderAvatarVP 1 1 -RenderFarClip 1 96 -RenderFlexTimeFactor 1 1.0 -RenderGlowResolutionPow 1 8 -RenderMaxPartCount 1 2048 -RenderObjectBump 1 1 -RenderReflectionDetail 1 0 -RenderTerrainDetail 1 1 -RenderTerrainLODFactor 1 1.0 -RenderTransparentWater 1 1 -RenderTreeLODFactor 1 0.5 -RenderUseImpostors 1 1 -RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 -WindLightUseAtmosShaders 1 0 -WLSkyDetail 1 48 -RenderDeferred 1 0 -RenderDeferredSSAO 1 0 -RenderShadowDetail 1 0 - -// -// High Graphics Settings (purty) -// -list High -RenderAnisotropic 1 1 -RenderAvatarCloth 1 0 -RenderAvatarLODFactor 1 1.0 -RenderAvatarVP 1 1 -RenderFarClip 1 128 -RenderFlexTimeFactor 1 1.0 -RenderGlowResolutionPow 1 9 -RenderMaxPartCount 1 4096 -RenderObjectBump 1 1 -RenderReflectionDetail 1 0 -RenderTerrainDetail 1 1 -RenderTerrainLODFactor 1 2.0 -RenderTransparentWater 1 1 -RenderTreeLODFactor 1 0.5 -RenderUseImpostors 1 1 -RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 -WindLightUseAtmosShaders 1 1 -WLSkyDetail 1 48 -RenderDeferred 1 0 -RenderDeferredSSAO 1 0 -RenderShadowDetail 1 0 - -// -// Ultra graphics (REALLY PURTY!) -// -list Ultra -RenderAnisotropic 1 1 -RenderAvatarCloth 1 1 -RenderAvatarLODFactor 1 1.0 -RenderAvatarVP 1 1 -RenderFarClip 1 256 -RenderFlexTimeFactor 1 1.0 -RenderGlowResolutionPow 1 9 -RenderMaxPartCount 1 8192 -RenderObjectBump 1 1 -RenderReflectionDetail 1 4 -RenderTerrainDetail 1 1 -RenderTerrainLODFactor 1 2.0 -RenderTransparentWater 1 1 -RenderTreeLODFactor 1 1.0 -RenderUseImpostors 1 1 -RenderVolumeLODFactor 1 2.0 -VertexShaderEnable 1 1 -WindLightUseAtmosShaders 1 1 -WLSkyDetail 1 128 -RenderDeferred 1 0 -RenderDeferredSSAO 1 0 -RenderShadowDetail 1 0 - -// -// Class Unknown Hardware (unknown) -// -list Unknown -RenderVBOEnable 1 0 - -// -// Class 0 Hardware (just old) -// -list Class0 -RenderVBOEnable 1 1 - -// -// Class 1 Hardware -// -list Class1 -RenderVBOEnable 1 1 - -// -// Class 2 Hardware (make it purty) -// -list Class2 -RenderVBOEnable 1 1 - -// -// Class 3 Hardware (make it purty) -// -list Class3 -RenderVBOEnable 1 1 - -// -// No Pixel Shaders available -// -list NoPixelShaders -RenderAvatarVP 0 0 -RenderAvatarCloth 0 0 -RenderReflectionDetail 0 0 -VertexShaderEnable 0 0 -WindLightUseAtmosShaders 0 0 -RenderDeferred 0 0 -RenderDeferredSSAO 0 0 -RenderShadowDetail 0 0 - -// -// No Vertex Shaders available -// -list NoVertexShaders -RenderAvatarVP 0 0 -RenderAvatarCloth 0 0 -RenderReflectionDetail 0 0 -VertexShaderEnable 0 0 -WindLightUseAtmosShaders 0 0 -RenderDeferred 0 0 -RenderDeferredSSAO 0 0 -RenderShadowDetail 0 0 - -// -// "Default" setups for safe, low, medium, high -// -list safe -RenderAnisotropic 1 0 -RenderAvatarCloth 0 0 -RenderAvatarVP 0 0 -RenderObjectBump 0 0 -RenderMaxPartCount 1 1024 -RenderTerrainDetail 1 0 -RenderUseImpostors 0 0 -RenderVBOEnable 1 0 -RenderReflectionDetail 0 0 -WindLightUseAtmosShaders 0 0 -RenderDeferred 0 0 -RenderDeferredSSAO 0 0 -RenderShadowDetail 0 0 - -// -// CPU based feature masks -// - -// 1Ghz or less (equiv) -list CPUSlow -RenderMaxPartCount 1 1024 - -// -// RAM based feature masks -// -list RAM256MB -RenderObjectBump 0 0 - -// -// Graphics card based feature masks -// -list OpenGLPre15 -RenderVBOEnable 1 0 - +version 26 + +// NOTE: This is mostly identical to featuretable_mac.txt with a few differences +// Should be combined into one table + +// +// Generates lists of feature mask that can be applied on top of each other. +// +// // Begin comments +// list +// Starts a feature list named +// +// is the name of a feature +// is 0 or 1, whether the feature is available +// is an F32 which is the recommended value +// +// For now, the first list read sets up all of the default values +// + + +// +// All contains everything at their default settings for high end machines +// NOTE: All settings are set to the MIN of applied values, including 'all'! +// +list all +RenderAnisotropic 1 1 +RenderAvatarCloth 1 1 +RenderAvatarLODFactor 1 1.0 +RenderAvatarMaxVisible 1 12 +RenderAvatarVP 1 1 +RenderCubeMap 1 1 +RenderDelayVBUpdate 1 0 +RenderFarClip 1 256 +RenderFlexTimeFactor 1 1.0 +RenderFogRatio 1 4.0 +RenderGamma 1 0 +RenderGlowResolutionPow 1 9 +RenderGround 1 1 +RenderMaxPartCount 1 8192 +RenderNightBrightness 1 1.0 +RenderObjectBump 1 1 +RenderReflectionDetail 1 4 +RenderTerrainDetail 1 1 +RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 +RenderTreeLODFactor 1 1.0 +RenderUseImpostors 1 1 +RenderVBOEnable 1 1 +RenderVolumeLODFactor 1 2.0 +UseStartScreen 1 1 +UseOcclusion 1 1 +VertexShaderEnable 1 1 +WindLightUseAtmosShaders 1 1 +WLSkyDetail 1 128 +Disregard128DefaultDrawDistance 1 1 +Disregard96DefaultDrawDistance 1 1 +RenderTextureMemoryMultiple 1 1.0 +RenderShaderLightingMaxLevel 1 3 +SkyUseClassicClouds 1 1 +RenderDeferred 1 0 +RenderDeferredSSAO 1 0 +RenderShadowDetail 1 0 +WatchdogDisabled 1 1 +RenderUseStreamVBO 1 1 + +// +// Low Graphics Settings +// +list Low +RenderAnisotropic 1 0 +RenderAvatarCloth 1 0 +RenderAvatarLODFactor 1 0 +RenderAvatarMaxVisible 1 3 +RenderAvatarVP 1 0 +RenderFarClip 1 64 +RenderFlexTimeFactor 1 0 +RenderGlowResolutionPow 1 8 +RenderMaxPartCount 1 0 +RenderObjectBump 1 0 +RenderReflectionDetail 1 0 +RenderTerrainDetail 1 0 +RenderTerrainLODFactor 1 1 +RenderTransparentWater 1 0 +RenderTreeLODFactor 1 0 +RenderUseImpostors 1 1 +RenderVolumeLODFactor 1 0.5 +VertexShaderEnable 1 0 +WindLightUseAtmosShaders 1 0 +WLSkyDetail 1 48 +SkyUseClassicClouds 1 0 +RenderDeferred 1 0 +RenderDeferredSSAO 1 0 +RenderShadowDetail 1 0 + +// +// Mid Graphics Settings +// +list Mid +RenderAnisotropic 1 0 +RenderAvatarCloth 1 0 +RenderAvatarLODFactor 1 0.5 +RenderAvatarVP 1 1 +RenderFarClip 1 96 +RenderFlexTimeFactor 1 1.0 +RenderGlowResolutionPow 1 8 +RenderMaxPartCount 1 2048 +RenderObjectBump 1 1 +RenderReflectionDetail 1 0 +RenderTerrainDetail 1 1 +RenderTerrainLODFactor 1 1.0 +RenderTransparentWater 1 1 +RenderTreeLODFactor 1 0.5 +RenderUseImpostors 1 1 +RenderVolumeLODFactor 1 1.125 +VertexShaderEnable 1 1 +WindLightUseAtmosShaders 1 0 +WLSkyDetail 1 48 +RenderDeferred 1 0 +RenderDeferredSSAO 1 0 +RenderShadowDetail 1 0 + +// +// High Graphics Settings (purty) +// +list High +RenderAnisotropic 1 1 +RenderAvatarCloth 1 0 +RenderAvatarLODFactor 1 1.0 +RenderAvatarVP 1 1 +RenderFarClip 1 128 +RenderFlexTimeFactor 1 1.0 +RenderGlowResolutionPow 1 9 +RenderMaxPartCount 1 4096 +RenderObjectBump 1 1 +RenderReflectionDetail 1 0 +RenderTerrainDetail 1 1 +RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 +RenderTreeLODFactor 1 0.5 +RenderUseImpostors 1 1 +RenderVolumeLODFactor 1 1.125 +VertexShaderEnable 1 1 +WindLightUseAtmosShaders 1 1 +WLSkyDetail 1 48 +RenderDeferred 1 0 +RenderDeferredSSAO 1 0 +RenderShadowDetail 1 0 + +// +// Ultra graphics (REALLY PURTY!) +// +list Ultra +RenderAnisotropic 1 1 +RenderAvatarCloth 1 1 +RenderAvatarLODFactor 1 1.0 +RenderAvatarVP 1 1 +RenderFarClip 1 256 +RenderFlexTimeFactor 1 1.0 +RenderGlowResolutionPow 1 9 +RenderMaxPartCount 1 8192 +RenderObjectBump 1 1 +RenderReflectionDetail 1 4 +RenderTerrainDetail 1 1 +RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 +RenderTreeLODFactor 1 1.0 +RenderUseImpostors 1 1 +RenderVolumeLODFactor 1 2.0 +VertexShaderEnable 1 1 +WindLightUseAtmosShaders 1 1 +WLSkyDetail 1 128 +RenderDeferred 1 0 +RenderDeferredSSAO 1 0 +RenderShadowDetail 1 0 + +// +// Class Unknown Hardware (unknown) +// +list Unknown +RenderVBOEnable 1 0 + +// +// Class 0 Hardware (just old) +// +list Class0 +RenderVBOEnable 1 1 + +// +// Class 1 Hardware +// +list Class1 +RenderVBOEnable 1 1 + +// +// Class 2 Hardware (make it purty) +// +list Class2 +RenderVBOEnable 1 1 + +// +// Class 3 Hardware (make it purty) +// +list Class3 +RenderVBOEnable 1 1 + +// +// No Pixel Shaders available +// +list NoPixelShaders +RenderAvatarVP 0 0 +RenderAvatarCloth 0 0 +RenderReflectionDetail 0 0 +VertexShaderEnable 0 0 +WindLightUseAtmosShaders 0 0 +RenderDeferred 0 0 +RenderDeferredSSAO 0 0 +RenderShadowDetail 0 0 + +// +// No Vertex Shaders available +// +list NoVertexShaders +RenderAvatarVP 0 0 +RenderAvatarCloth 0 0 +RenderReflectionDetail 0 0 +VertexShaderEnable 0 0 +WindLightUseAtmosShaders 0 0 +RenderDeferred 0 0 +RenderDeferredSSAO 0 0 +RenderShadowDetail 0 0 + +// +// "Default" setups for safe, low, medium, high +// +list safe +RenderAnisotropic 1 0 +RenderAvatarCloth 0 0 +RenderAvatarVP 0 0 +RenderObjectBump 0 0 +RenderMaxPartCount 1 1024 +RenderTerrainDetail 1 0 +RenderUseImpostors 0 0 +RenderVBOEnable 1 0 +RenderReflectionDetail 0 0 +WindLightUseAtmosShaders 0 0 +RenderDeferred 0 0 +RenderDeferredSSAO 0 0 +RenderShadowDetail 0 0 + +// +// CPU based feature masks +// + +// 1Ghz or less (equiv) +list CPUSlow +RenderMaxPartCount 1 1024 + +// +// RAM based feature masks +// +list RAM256MB +RenderObjectBump 0 0 + +// +// Graphics card based feature masks +// +list OpenGLPre15 +RenderVBOEnable 1 0 + list OpenGLPre30 RenderDeferred 0 0 - -list Intel -RenderAnisotropic 1 0 - -list GeForce2 -RenderAnisotropic 1 0 -RenderMaxPartCount 1 2048 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 1 - -list SiS -UseOcclusion 0 0 - - -list Intel_830M -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 -RenderUseImpostors 0 0 - -list Intel_845G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 -RenderUseImpostors 0 0 - -list Intel_855GM -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 -RenderUseImpostors 0 0 - -list Intel_865G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 -RenderUseImpostors 0 0 - -list Intel_900 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 -RenderUseImpostors 0 0 - -list Intel_915GM -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 -RenderUseImpostors 0 0 - -list Intel_915G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 -RenderUseImpostors 0 0 - -list Intel_945GM -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_945G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_950 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_965 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 -RenderUseImpostors 1 0 -UseOcclusion 0 0 - -list Intel_G33 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_G45 -WindLightUseAtmosShaders 0 0 - -list Intel_Bear_Lake -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Broadwater -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Brookdale -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Eaglelake -WindLightUseAtmosShaders 0 0 - -list Intel_Montara -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Springdale -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - - -list ATI_FireGL_5200 -RenderVBOEnable 1 0 -WindLightUseAtmosShaders 0 0 - - -list ATI_Mobility_Radeon_7xxx -RenderVBOEnable 0 0 - -list ATI_Radeon_7xxx -RenderVBOEnable 0 0 - -list ATI_All-in-Wonder_Radeon -RenderVBOEnable 0 0 - -list ATI_All-in-Wonder_7500 -RenderVBOEnable 0 0 - -list ATI_Mobility_Radeon_9600 -Disregard96DefaultDrawDistance 1 0 - - -/// tweaked ATI to 96 Draw distance - -list ATI_Radeon_9000 -Disregard96DefaultDrawDistance 1 0 -list ATI_Radeon_9200 -Disregard96DefaultDrawDistance 1 0 -list ATI_Radeon_9500 -Disregard96DefaultDrawDistance 1 0 -list ATI_Radeon_9600 -Disregard96DefaultDrawDistance 1 0 - -/// tweaked ATI to 128 draw distance - -list ATI_Radeon_X300 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Radeon_X400 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Radeon_X500 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Radeon_X600 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Radeon_X700 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Radeon_X1300 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -UseStartScreen 0 0 -list ATI_Radeon_X1400 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Radeon_X1500 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -UseStartScreen 0 0 -list ATI_Radeon_X1600 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Radeon_X1700 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Mobility_Radeon_X1xxx -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 - -list ATI_Radeon_HD_2300 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_HD_2400 -Disregard128DefaultDrawDistance 1 0 -list ATI_ASUS_AH24xx -Disregard128DefaultDrawDistance 1 0 - - -// Avatar hardware skinning causes invisible avatars -// on various ATI chipsets on drivers before 8.2 - -list ATIOldDriver -RenderAvatarVP 0 0 -RenderAvatarCloth 0 0 - -// ATI cards generally perform better when not using VBOs for streaming data - -list ATI -RenderUseStreamVBO 1 0 -RenderAvatarVP 1 0 - -/// Tweaked NVIDIA - -list NVIDIA_GeForce_FX_5100 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_5200 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_5500 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_5600 -Disregard96DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_FX_Go5100 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5200 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5300 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5500 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5600 -Disregard96DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_6100 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_6200 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_6500 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_6600 -Disregard128DefaultDrawDistance 1 0 - -list NVIDIA_G73 -Disregard128DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_Go_6100 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6200 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6500 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6600 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6700 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6800 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_7000 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7100 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7200 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7300 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7400 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7500 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7600 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7700 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7800 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7900 -RenderShaderLightingMaxLevel 1 2 - -list NVIDIA_GeForce_Go_7200 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7300 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7300_LE -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7400 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7600 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7700 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7800 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7900 -RenderShaderLightingMaxLevel 1 2 - + +list Intel +RenderAnisotropic 1 0 + +list GeForce2 +RenderAnisotropic 1 0 +RenderMaxPartCount 1 2048 +RenderTerrainDetail 1 0 +RenderVBOEnable 1 1 + +list SiS +UseOcclusion 0 0 + + +list Intel_830M +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 +RenderUseImpostors 0 0 + +list Intel_845G +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 +RenderUseImpostors 0 0 + +list Intel_855GM +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 +RenderUseImpostors 0 0 + +list Intel_865G +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 +RenderUseImpostors 0 0 + +list Intel_900 +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 +RenderUseImpostors 0 0 + +list Intel_915GM +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 +RenderUseImpostors 0 0 + +list Intel_915G +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 +RenderUseImpostors 0 0 + +list Intel_945GM +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 + +list Intel_945G +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 + +list Intel_950 +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 + +list Intel_965 +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 +RenderUseImpostors 1 0 +UseOcclusion 0 0 + +list Intel_G33 +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 + +list Intel_G45 +WindLightUseAtmosShaders 0 0 + +list Intel_Bear_Lake +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 + +list Intel_Broadwater +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 + +list Intel_Brookdale +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 + +list Intel_Eaglelake +WindLightUseAtmosShaders 0 0 + +list Intel_Montara +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 + +list Intel_Springdale +RenderTerrainDetail 1 0 +RenderVBOEnable 1 0 + + +list ATI_FireGL_5200 +RenderVBOEnable 1 0 +WindLightUseAtmosShaders 0 0 + + +list ATI_Mobility_Radeon_7xxx +RenderVBOEnable 0 0 + +list ATI_Radeon_7xxx +RenderVBOEnable 0 0 + +list ATI_All-in-Wonder_Radeon +RenderVBOEnable 0 0 + +list ATI_All-in-Wonder_7500 +RenderVBOEnable 0 0 + +list ATI_Mobility_Radeon_9600 +Disregard96DefaultDrawDistance 1 0 + + +/// tweaked ATI to 96 Draw distance + +list ATI_Radeon_9000 +Disregard96DefaultDrawDistance 1 0 +list ATI_Radeon_9200 +Disregard96DefaultDrawDistance 1 0 +list ATI_Radeon_9500 +Disregard96DefaultDrawDistance 1 0 +list ATI_Radeon_9600 +Disregard96DefaultDrawDistance 1 0 + +/// tweaked ATI to 128 draw distance + +list ATI_Radeon_X300 +Disregard128DefaultDrawDistance 1 0 +RenderVBOEnable 1 0 +list ATI_Radeon_X400 +Disregard128DefaultDrawDistance 1 0 +RenderVBOEnable 1 0 +list ATI_Radeon_X500 +Disregard128DefaultDrawDistance 1 0 +RenderVBOEnable 1 0 +list ATI_Radeon_X600 +Disregard128DefaultDrawDistance 1 0 +RenderVBOEnable 1 0 +list ATI_Radeon_X700 +Disregard128DefaultDrawDistance 1 0 +RenderVBOEnable 1 0 +list ATI_Radeon_X1300 +Disregard128DefaultDrawDistance 1 0 +RenderVBOEnable 1 0 +UseStartScreen 0 0 +list ATI_Radeon_X1400 +Disregard128DefaultDrawDistance 1 0 +RenderVBOEnable 1 0 +list ATI_Radeon_X1500 +Disregard128DefaultDrawDistance 1 0 +RenderVBOEnable 1 0 +UseStartScreen 0 0 +list ATI_Radeon_X1600 +Disregard128DefaultDrawDistance 1 0 +RenderVBOEnable 1 0 +list ATI_Radeon_X1700 +Disregard128DefaultDrawDistance 1 0 +RenderVBOEnable 1 0 +list ATI_Mobility_Radeon_X1xxx +Disregard128DefaultDrawDistance 1 0 +RenderVBOEnable 1 0 + +list ATI_Radeon_HD_2300 +Disregard128DefaultDrawDistance 1 0 +list ATI_Radeon_HD_2400 +Disregard128DefaultDrawDistance 1 0 +list ATI_ASUS_AH24xx +Disregard128DefaultDrawDistance 1 0 + + +// Avatar hardware skinning causes invisible avatars +// on various ATI chipsets on drivers before 8.2 + +list ATIOldDriver +RenderAvatarVP 0 0 +RenderAvatarCloth 0 0 + +// ATI cards generally perform better when not using VBOs for streaming data + +list ATI +RenderUseStreamVBO 1 0 +RenderAvatarVP 1 0 + +/// Tweaked NVIDIA + +list NVIDIA_GeForce_FX_5100 +Disregard96DefaultDrawDistance 1 0 +list NVIDIA_GeForce_FX_5200 +Disregard96DefaultDrawDistance 1 0 +list NVIDIA_GeForce_FX_5500 +Disregard96DefaultDrawDistance 1 0 +list NVIDIA_GeForce_FX_5600 +Disregard96DefaultDrawDistance 1 0 + +list NVIDIA_GeForce_FX_Go5100 +Disregard96DefaultDrawDistance 1 0 +list NVIDIA_GeForce_FX_Go5200 +Disregard96DefaultDrawDistance 1 0 +list NVIDIA_GeForce_FX_Go5300 +Disregard96DefaultDrawDistance 1 0 +list NVIDIA_GeForce_FX_Go5500 +Disregard96DefaultDrawDistance 1 0 +list NVIDIA_GeForce_FX_Go5600 +Disregard96DefaultDrawDistance 1 0 + +list NVIDIA_GeForce_6100 +Disregard128DefaultDrawDistance 1 0 +list NVIDIA_GeForce_6200 +Disregard128DefaultDrawDistance 1 0 +list NVIDIA_GeForce_6500 +Disregard128DefaultDrawDistance 1 0 +list NVIDIA_GeForce_6600 +Disregard128DefaultDrawDistance 1 0 + +list NVIDIA_G73 +Disregard128DefaultDrawDistance 1 0 + +list NVIDIA_GeForce_Go_6100 +RenderVBOEnable 1 0 +Disregard128DefaultDrawDistance 1 0 +list NVIDIA_GeForce_Go_6200 +RenderVBOEnable 1 0 +Disregard128DefaultDrawDistance 1 0 +list NVIDIA_GeForce_Go_6500 +RenderVBOEnable 1 0 +Disregard128DefaultDrawDistance 1 0 +list NVIDIA_GeForce_Go_6600 +RenderVBOEnable 1 0 +Disregard128DefaultDrawDistance 1 0 +list NVIDIA_GeForce_Go_6700 +RenderVBOEnable 1 0 +Disregard128DefaultDrawDistance 1 0 +list NVIDIA_GeForce_Go_6800 +RenderVBOEnable 1 0 +Disregard128DefaultDrawDistance 1 0 +list NVIDIA_GeForce_Go_6 +RenderVBOEnable 1 0 +Disregard128DefaultDrawDistance 1 0 + +list NVIDIA_GeForce_7000 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_7100 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_7200 +Disregard128DefaultDrawDistance 1 0 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_7300 +Disregard128DefaultDrawDistance 1 0 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_7400 +Disregard128DefaultDrawDistance 1 0 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_7500 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_7600 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_7700 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_7800 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_7900 +RenderShaderLightingMaxLevel 1 2 + +list NVIDIA_GeForce_Go_7200 +Disregard128DefaultDrawDistance 1 0 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_Go_7300 +Disregard128DefaultDrawDistance 1 0 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_Go_7300_LE +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_Go_7400 +Disregard128DefaultDrawDistance 1 0 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_Go_7600 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_Go_7700 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_Go_7800 +RenderShaderLightingMaxLevel 1 2 +list NVIDIA_GeForce_Go_7900 +RenderShaderLightingMaxLevel 1 2 + -- cgit v1.2.3 From 068822b18d4e62381a25c833cfa2639eddd4c24d Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 9 Feb 2011 15:28:46 -0600 Subject: SH-874 Fix for bad performance on cards without GL_ARB_depth_clamp in cases where water and terrain should be occluded. --- indra/newview/lldrawpool.h | 8 +++--- indra/newview/llspatialpartition.cpp | 49 +++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index 9d944ee213..d3fd9ead0d 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -47,14 +47,14 @@ public: { // Correspond to LLPipeline render type POOL_SIMPLE = 1, + POOL_GROUND, + POOL_FULLBRIGHT, + POOL_BUMP, POOL_TERRAIN, - POOL_TREE, POOL_SKY, POOL_WL_SKY, - POOL_GROUND, + POOL_TREE, POOL_GRASS, - POOL_FULLBRIGHT, - POOL_BUMP, POOL_INVISIBLE, // see below * POOL_AVATAR, POOL_VOIDWATER, diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index a4c9b66e38..40f1596139 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -273,12 +273,6 @@ void LLSpatialGroup::buildOcclusion() LLVector4a r; r.setAdd(mBounds[1], fudge); - LLVector4a r2; - r2.splat(0.25f); - r2.add(mBounds[1]); - - r.setMin(r, r2); - LLStrider pos; mOcclusionVerts->getVertexStrider(pos); @@ -1627,8 +1621,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1) { // Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension - if ((mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER && !gGLManager.mHasDepthClamp) || - earlyFail(camera, this)) + if (earlyFail(camera, this)) { setOcclusionState(LLSpatialGroup::DISCARD_QUERY); assert_states_valid(this); @@ -1656,12 +1649,11 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) // behind the far clip plane, and in the case of edge water to avoid // it being culled while still visible. bool const use_depth_clamp = gGLManager.mHasDepthClamp && - (mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER || + (mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER || mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER); - if (use_depth_clamp) - { - glEnable(GL_DEPTH_CLAMP); - } + + LLGLEnable clamp(use_depth_clamp ? GL_DEPTH_CLAMP : 0); + #if !LL_DARWIN U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB; #else @@ -1676,22 +1668,33 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); - if (camera->getOrigin().isExactlyZero()) - { //origin is invalid, draw entire box - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); + if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER) + { + LLGLSquashToFarClip squash(glh_get_current_projection()); + if (camera->getOrigin().isExactlyZero()) + { //origin is invalid, draw entire box + mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); + mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); + } + else + { + mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); + } } else { - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); + if (camera->getOrigin().isExactlyZero()) + { //origin is invalid, draw entire box + mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); + mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); + } + else + { + mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); + } } glEndQueryARB(mode); - - if (use_depth_clamp) - { - glDisable(GL_DEPTH_CLAMP); - } } setOcclusionState(LLSpatialGroup::QUERY_PENDING); -- cgit v1.2.3 From 3ae3a4a6cb2b23e78493ae04f365188b95efcd64 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 9 Feb 2011 17:07:13 -0500 Subject: SH-915 WIP - support pilot.xml with extended camera info --- indra/newview/app_settings/settings.xml | 11 ++++ indra/newview/llagentpilot.cpp | 111 ++++++++++++++++++++++++++++++-- indra/newview/llagentpilot.h | 8 ++- indra/newview/llstartup.cpp | 2 +- 4 files changed, 123 insertions(+), 9 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 6f47d9c019..d71b84739c 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -10207,6 +10207,17 @@ Value pilot.txt + StatsPilotXMLFile + + Comment + Filename for stats logging extended autopilot path + Persist + 1 + Type + String + Value + pilot.xml + StatsQuitAfterRuns Comment diff --git a/indra/newview/llagentpilot.cpp b/indra/newview/llagentpilot.cpp index 92e0180b46..1a443e62a4 100755 --- a/indra/newview/llagentpilot.cpp +++ b/indra/newview/llagentpilot.cpp @@ -36,6 +36,8 @@ #include "llviewercontrol.h" #include "llviewercamera.h" #include "llviewerjoystick.h" +#include "llsdserialize.h" +#include "llsdutil_math.h" LLAgentPilot gAgentPilot; @@ -58,9 +60,28 @@ LLAgentPilot::~LLAgentPilot() { } -#define CAM_FIELDS 1 +#define CAM_FIELDS 0 -void LLAgentPilot::load(const std::string& filename) +void LLAgentPilot::load() +{ + std::string txt_filename = gSavedSettings.getString("StatsPilotFile"); + std::string xml_filename = gSavedSettings.getString("StatsPilotXMLFile"); + if (LLFile::isfile(xml_filename)) + { + loadXML(xml_filename); + } + else if (LLFile::isfile(txt_filename)) + { + loadTxt(txt_filename); + } + else + { + lldebugs << "no autopilot file found" << llendl; + return; + } +} + +void LLAgentPilot::loadTxt(const std::string& filename) { if(filename.empty()) { @@ -112,12 +133,58 @@ void LLAgentPilot::load(const std::string& filename) mActions.put(new_action); } - mOverrideCamera = true; + mOverrideCamera = false; file.close(); } -void LLAgentPilot::save(const std::string& filename) +void LLAgentPilot::loadXML(const std::string& filename) +{ + if(filename.empty()) + { + return; + } + + llifstream file(filename); + + if (!file) + { + lldebugs << "Couldn't open " << filename + << ", aborting agentpilot load!" << llendl; + return; + } + else + { + llinfos << "Opening pilot file " << filename << llendl; + } + + LLSD record; + while (!file.eof() && LLSDSerialize::fromXML(record, file)) + { + Action action; + action.mTime = record["time"].asReal(); + action.mType = (EActionType)record["type"].asInteger(); + action.mCameraView = record["camera_view"].asReal(); + action.mTarget = ll_vector3d_from_sd(record["target"]); + action.mCameraOrigin = ll_vector3_from_sd(record["camera_origin"]); + action.mCameraXAxis = ll_vector3_from_sd(record["camera_xaxis"]); + action.mCameraYAxis = ll_vector3_from_sd(record["camera_yaxis"]); + action.mCameraZAxis = ll_vector3_from_sd(record["camera_zaxis"]); + mActions.put(action); + } + mOverrideCamera = true; + file.close(); +} + +void LLAgentPilot::save() +{ + std::string txt_filename = gSavedSettings.getString("StatsPilotFile"); + std::string xml_filename = gSavedSettings.getString("StatsPilotXMLFile"); + saveTxt(txt_filename); + saveXML(xml_filename); +} + +void LLAgentPilot::saveTxt(const std::string& filename) { llofstream file; file.open(filename); @@ -159,6 +226,34 @@ void LLAgentPilot::save(const std::string& filename) file.close(); } +void LLAgentPilot::saveXML(const std::string& filename) +{ + llofstream file; + file.open(filename); + + if (!file) + { + llinfos << "Couldn't open " << filename << ", aborting agentpilot save!" << llendl; + } + + S32 i; + for (i = 0; i < mActions.count(); i++) + { + Action& action = mActions[i]; + LLSD record; + record["time"] = (LLSD::Real)action.mTime; + record["type"] = (LLSD::Integer)action.mType; + record["camera_view"] = (LLSD::Real)action.mCameraView; + record["target"] = ll_sd_from_vector3d(action.mTarget); + record["camera_origin"] = ll_sd_from_vector3(action.mCameraOrigin); + record["camera_xaxis"] = ll_sd_from_vector3(action.mCameraXAxis); + record["camera_yaxis"] = ll_sd_from_vector3(action.mCameraYAxis); + record["camera_zaxis"] = ll_sd_from_vector3(action.mCameraZAxis); + LLSDSerialize::toXML(record, file); + } + file.close(); +} + void LLAgentPilot::startRecord() { mActions.reset(); @@ -170,7 +265,7 @@ void LLAgentPilot::startRecord() void LLAgentPilot::stopRecord() { gAgentPilot.addAction(STRAIGHT); - gAgentPilot.save(gSavedSettings.getString("StatsPilotFile")); + gAgentPilot.save(); mRecording = FALSE; } @@ -202,7 +297,8 @@ void LLAgentPilot::startPlayback() if (mActions.count()) { llinfos << "Starting playback, moving to waypoint 0" << llendl; - if (!LLViewerJoystick::getInstance()->getOverrideCamera()) + if (getOverrideCamera() && + !LLViewerJoystick::getInstance()->getOverrideCamera()) { LLViewerJoystick::getInstance()->toggleFlycam(); } @@ -236,6 +332,9 @@ void LLAgentPilot::stopPlayback() void LLAgentPilot::moveCamera(Action& action) { + if (!getOverrideCamera()) + return; + LLViewerCamera::getInstance()->setView(action.mCameraView); LLViewerCamera::getInstance()->setOrigin(action.mCameraOrigin); LLViewerCamera::getInstance()->mXAxis = LLVector3(action.mCameraXAxis); diff --git a/indra/newview/llagentpilot.h b/indra/newview/llagentpilot.h index fd2cb7ee32..5e045fa695 100755 --- a/indra/newview/llagentpilot.h +++ b/indra/newview/llagentpilot.h @@ -46,8 +46,12 @@ public: LLAgentPilot(); virtual ~LLAgentPilot(); - void load(const std::string& filename); - void save(const std::string& filename); + void load(); + void loadTxt(const std::string& filename); + void loadXML(const std::string& filename); + void save(); + void saveTxt(const std::string& filename); + void saveXML(const std::string& filename); void startRecord(); void stopRecord(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index c6efaf4afe..db7e0149cc 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -424,7 +424,7 @@ bool idle_startup() // // Load autopilot and stats stuff - gAgentPilot.load(gSavedSettings.getString("StatsPilotFile")); + gAgentPilot.load(); //gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps")); -- cgit v1.2.3 From 10518eaaaef51f6d5a23a4c8fa15267bf9aa0821 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 9 Feb 2011 16:53:47 -0600 Subject: SH-874 Revert much of the bad water bounding box and distortion texture usage changes from SNOW-643 and properly occlusion cull void water patches for machines without depth clamp. --- indra/llrender/llgl.cpp | 7 +- indra/llrender/llgl.h | 2 +- indra/newview/llspatialpartition.cpp | 2 +- indra/newview/llworld.cpp | 454 +++++++++++------------------------ 4 files changed, 148 insertions(+), 317 deletions(-) diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index f91584b5e4..9354373dba 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -2071,11 +2071,14 @@ void LLGLDepthTest::checkState() } } -LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f P) +LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f P, U32 layer) { + + F32 depth = 0.99999f - 0.0001f * layer; + for (U32 i = 0; i < 4; i++) { - P.element(2, i) = P.element(3, i) * 0.99999f; + P.element(2, i) = P.element(3, i) * depth; } glMatrixMode(GL_PROJECTION); diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index ff4e6078c9..df110613e3 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -320,7 +320,7 @@ private: class LLGLSquashToFarClip { public: - LLGLSquashToFarClip(glh::matrix4f projection); + LLGLSquashToFarClip(glh::matrix4f projection, U32 layer = 0); ~LLGLSquashToFarClip(); }; diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 40f1596139..5dd1b5ba7e 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -1670,7 +1670,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER) { - LLGLSquashToFarClip squash(glh_get_current_projection()); + LLGLSquashToFarClip squash(glh_get_current_projection(), 1); if (camera->getOrigin().isExactlyZero()) { //origin is invalid, draw entire box mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index fa9b9d5bc3..146bab0c0a 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -870,320 +870,148 @@ void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_heigh } } -// There are three types of water objects: -// Region water objects: the water in a region. -// Hole water objects: water in the void but within current draw distance. -// Edge water objects: the water outside the draw distance, up till the horizon. -// -// For example: -// -// -----------------------horizon------------------------- -// | | | | -// | Edge Water | | | -// | | | | -// | | | | -// | | | | -// | | | | -// | | rwidth | | -// | | <-----> | | -// ------------------------------------------------------- -// | |Hole |other| | | -// | |Water|reg. | | | -// | |-----------------| | -// | |other|cur. |<--> | | -// | |reg. | reg.| \__|_ draw distance | -// | |-----------------| | -// | | | |<--->| | -// | | | | \__|_ range | -// ------------------------------------------------------- -// | |<----width------>|<--horizon ext.->| -// | | | | -// | | | | -// | | | | -// | | | | -// | | | | -// | | | | -// | | | | -// ------------------------------------------------------- -// -void LLWorld::updateWaterObjects() -{ - if (!gAgent.getRegion()) - { - return; - } - if (mRegionList.empty()) - { - llwarns << "No regions!" << llendl; - return; - } - - // Region width in meters. - S32 const rwidth = (S32)REGION_WIDTH_U32; - - // The distance we might see into the void - // when standing on the edge of a region, in meters. - S32 const draw_distance = llceil(mLandFarClip); - - // We can only have "holes" in the water (where there no region) if we - // can have existing regions around it. Taking into account that this - // code is only executed when we enter a region, and not when we walk - // around in it, we (only) need to take into account regions that fall - // within the draw_distance. - // - // Set 'range' to draw_distance, rounded up to the nearest multiple of rwidth. - S32 const nsims = (draw_distance + rwidth - 1) / rwidth; - S32 const range = nsims * rwidth; - - // Get South-West corner of current region. - LLViewerRegion const* regionp = gAgent.getRegion(); - U32 region_x, region_y; - from_region_handle(regionp->getHandle(), ®ion_x, ®ion_y); - - // The min. and max. coordinates of the South-West corners of the Hole water objects. - S32 const min_x = (S32)region_x - range; - S32 const min_y = (S32)region_y - range; - S32 const max_x = (S32)region_x + range; - S32 const max_y = (S32)region_y + range; - - // Attempt to determine a sensible water height for all the - // Hole Water objects. - // - // It make little sense to try to guess what the best water - // height should be when that isn't completely obvious: if it's - // impossible to satisfy every region's water height without - // getting a jump in the water height. - // - // In order to keep the reasoning simple, we assume something - // logical as a group of connected regions, where the coastline - // is at the outer edge. Anything more complex that would "break" - // under such an assumption would probably break anyway (would - // depend on terrain editing and existing mega prims, say, if - // anything would make sense at all). - // - // So, what we do is find all connected regions within the - // draw distance that border void, and then pick the lowest - // water height of those (coast) regions. - S32 const n = 2 * nsims + 1; - S32 const origin = nsims + nsims * n; - std::vector water_heights(n * n); - std::vector checked(n * n, 0); // index = nx + ny * n + origin; - U8 const region_bit = 1; - U8 const hole_bit = 2; - U8 const bordering_hole_bit = 4; - U8 const bordering_edge_bit = 8; - // Use the legacy waterheight for the Edge water in the case - // that we don't find any Hole water at all. - F32 water_height = DEFAULT_WATER_HEIGHT; - int max_count = 0; - LL_DEBUGS("WaterHeight") << "Current region: " << regionp->getName() << "; water height: " << regionp->getWaterHeight() << " m." << LL_ENDL; - std::map water_height_counts; - typedef std::queue, std::deque > > nxny_pairs_type; - nxny_pairs_type nxny_pairs; - nxny_pairs.push(nxny_pairs_type::value_type(0, 0)); - water_heights[origin] = regionp->getWaterHeight(); - checked[origin] = region_bit; - // For debugging purposes. - int number_of_connected_regions = 1; - int uninitialized_regions = 0; - int bordering_hole = 0; - int bordering_edge = 0; - while(!nxny_pairs.empty()) - { - S32 const nx = nxny_pairs.front().first; - S32 const ny = nxny_pairs.front().second; - LL_DEBUGS("WaterHeight") << "nx,ny = " << nx << "," << ny << LL_ENDL; - S32 const index = nx + ny * n + origin; - nxny_pairs.pop(); - for (S32 dir = 0; dir < 4; ++dir) - { - S32 const cnx = nx + gDirAxes[dir][0]; - S32 const cny = ny + gDirAxes[dir][1]; - LL_DEBUGS("WaterHeight") << "dir = " << dir << "; cnx,cny = " << cnx << "," << cny << LL_ENDL; - S32 const cindex = cnx + cny * n + origin; - bool is_hole = false; - bool is_edge = false; - LLViewerRegion* new_region_found = NULL; - if (cnx < -nsims || cnx > nsims || - cny < -nsims || cny > nsims) - { - LL_DEBUGS("WaterHeight") << " Edge Water!" << LL_ENDL; - // Bumped into Edge water object. - is_edge = true; - } - else if (checked[cindex]) - { - LL_DEBUGS("WaterHeight") << " Already checked before!" << LL_ENDL; - // Already checked. - is_hole = (checked[cindex] & hole_bit); - } - else - { - S32 x = (S32)region_x + cnx * rwidth; - S32 y = (S32)region_y + cny * rwidth; - U64 region_handle = to_region_handle(x, y); - new_region_found = getRegionFromHandle(region_handle); - is_hole = !new_region_found; - checked[cindex] = is_hole ? hole_bit : region_bit; - } - if (is_hole) - { - // This was a region that borders at least one 'hole'. - // Count the found coastline. - F32 new_water_height = water_heights[index]; - LL_DEBUGS("WaterHeight") << " This is void; counting coastline with water height of " << new_water_height << LL_ENDL; - S32 new_water_height_cm = llround(new_water_height * 100); - int count = (water_height_counts[new_water_height_cm] += 1); - // Just use the lowest water height: this is mainly about the horizon water, - // and whatever we do, we don't want it to be possible to look under the water - // when looking in the distance: it is better to make a step downwards in water - // height when going away from the avie than a step upwards. However, since - // everyone is used to DEFAULT_WATER_HEIGHT, don't allow a single region - // to drag the water level below DEFAULT_WATER_HEIGHT on it's own. - if (bordering_hole == 0 || // First time we get here. - (new_water_height >= DEFAULT_WATER_HEIGHT && - new_water_height < water_height) || - (new_water_height < DEFAULT_WATER_HEIGHT && - count > max_count) - ) - { - water_height = new_water_height; - } - if (count > max_count) - { - max_count = count; - } - if (!(checked[index] & bordering_hole_bit)) - { - checked[index] |= bordering_hole_bit; - ++bordering_hole; - } - } - else if (is_edge && !(checked[index] & bordering_edge_bit)) - { - checked[index] |= bordering_edge_bit; - ++bordering_edge; - } - if (!new_region_found) - { - // Dead end, there is no region here. - continue; - } - // Found a new connected region. - ++number_of_connected_regions; - if (new_region_found->getName().empty()) - { - // Uninitialized LLViewerRegion, don't use it's water height. - LL_DEBUGS("WaterHeight") << " Uninitialized region." << LL_ENDL; - ++uninitialized_regions; - continue; - } - nxny_pairs.push(nxny_pairs_type::value_type(cnx, cny)); - water_heights[cindex] = new_region_found->getWaterHeight(); - LL_DEBUGS("WaterHeight") << " Found a new region (name: " << new_region_found->getName() << "; water height: " << water_heights[cindex] << " m)!" << LL_ENDL; - } - } - llinfos << "Number of connected regions: " << number_of_connected_regions << " (" << uninitialized_regions << - " uninitialized); number of regions bordering Hole water: " << bordering_hole << - "; number of regions bordering Edge water: " << bordering_edge << llendl; - llinfos << "Coastline count (height, count): "; - bool first = true; - for (std::map::iterator iter = water_height_counts.begin(); iter != water_height_counts.end(); ++iter) - { - if (!first) llcont << ", "; - llcont << "(" << (iter->first / 100.f) << ", " << iter->second << ")"; - first = false; - } - llcont << llendl; - llinfos << "Water height used for Hole and Edge water objects: " << water_height << llendl; - - // Update all Region water objects. - for (region_list_t::iterator iter = mRegionList.begin(); iter != mRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - LLVOWater* waterp = regionp->getLand().getWaterObj(); - if (waterp) - { - gObjectList.updateActive(waterp); - } - } - - // Clean up all existing Hole water objects. - for (std::list::iterator iter = mHoleWaterObjects.begin(); - iter != mHoleWaterObjects.end(); ++iter) - { - LLVOWater* waterp = *iter; - gObjectList.killObject(waterp); - } - mHoleWaterObjects.clear(); +void LLWorld::updateWaterObjects() +{ + if (!gAgent.getRegion()) + { + return; + } + if (mRegionList.empty()) + { + llwarns << "No regions!" << llendl; + return; + } + + // First, determine the min and max "box" of water objects + S32 min_x = 0; + S32 min_y = 0; + S32 max_x = 0; + S32 max_y = 0; + U32 region_x, region_y; + + S32 rwidth = 256; + + // We only want to fill in water for stuff that's near us, say, within 256 or 512m + S32 range = LLViewerCamera::getInstance()->getFar() > 256.f ? 512 : 256; + + LLViewerRegion* regionp = gAgent.getRegion(); + from_region_handle(regionp->getHandle(), ®ion_x, ®ion_y); + + min_x = (S32)region_x - range; + min_y = (S32)region_y - range; + max_x = (S32)region_x + range; + max_y = (S32)region_y + range; + + F32 height = 0.f; + + for (region_list_t::iterator iter = mRegionList.begin(); + iter != mRegionList.end(); ++iter) + { + LLViewerRegion* regionp = *iter; + LLVOWater* waterp = regionp->getLand().getWaterObj(); + height += regionp->getWaterHeight(); + if (waterp) + { + gObjectList.updateActive(waterp); + } + } + + for (std::list::iterator iter = mHoleWaterObjects.begin(); + iter != mHoleWaterObjects.end(); ++ iter) + { + LLVOWater* waterp = *iter; + gObjectList.killObject(waterp); + } + mHoleWaterObjects.clear(); + + // Now, get a list of the holes + S32 x, y; + for (x = min_x; x <= max_x; x += rwidth) + { + for (y = min_y; y <= max_y; y += rwidth) + { + U64 region_handle = to_region_handle(x, y); + if (!getRegionFromHandle(region_handle)) + { + LLVOWater* waterp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, gAgent.getRegion()); + waterp->setUseTexture(FALSE); + waterp->setPositionGlobal(LLVector3d(x + rwidth/2, + y + rwidth/2, + 256.f+DEFAULT_WATER_HEIGHT)); + waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, 512.f)); + gPipeline.createObject(waterp); + mHoleWaterObjects.push_back(waterp); + } + } + } + + // Update edge water objects + S32 wx, wy; + S32 center_x, center_y; + wx = (max_x - min_x) + rwidth; + wy = (max_y - min_y) + rwidth; + center_x = min_x + (wx >> 1); + center_y = min_y + (wy >> 1); + + S32 add_boundary[4] = { + 512 - (max_x - region_x), + 512 - (max_y - region_y), + 512 - (region_x - min_x), + 512 - (region_y - min_y) }; + + S32 dir; + for (dir = 0; dir < 8; dir++) + { + S32 dim[2] = { 0 }; + switch (gDirAxes[dir][0]) + { + case -1: dim[0] = add_boundary[2]; break; + case 0: dim[0] = wx; break; + default: dim[0] = add_boundary[0]; break; + } + switch (gDirAxes[dir][1]) + { + case -1: dim[1] = add_boundary[3]; break; + case 0: dim[1] = wy; break; + default: dim[1] = add_boundary[1]; break; + } + + // Resize and reshape the water objects + const S32 water_center_x = center_x + llround((wx + dim[0]) * 0.5f * gDirAxes[dir][0]); + const S32 water_center_y = center_y + llround((wy + dim[1]) * 0.5f * gDirAxes[dir][1]); + + LLVOWater* waterp = mEdgeWaterObjects[dir]; + if (!waterp || waterp->isDead()) + { + // The edge water objects can be dead because they're attached to the region that the + // agent was in when they were originally created. + mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER, + gAgent.getRegion()); + waterp = mEdgeWaterObjects[dir]; + waterp->setUseTexture(FALSE); + waterp->setIsEdgePatch(TRUE); + gPipeline.createObject(waterp); + } + + waterp->setRegion(gAgent.getRegion()); + LLVector3d water_pos(water_center_x, water_center_y, + DEFAULT_WATER_HEIGHT+256.f); + LLVector3 water_scale((F32) dim[0], (F32) dim[1], 512.f); + + //stretch out to horizon + water_scale.mV[0] += fabsf(2048.f * gDirAxes[dir][0]); + water_scale.mV[1] += fabsf(2048.f * gDirAxes[dir][1]); + + water_pos.mdV[0] += 1024.f * gDirAxes[dir][0]; + water_pos.mdV[1] += 1024.f * gDirAxes[dir][1]; + + waterp->setPositionGlobal(water_pos); + waterp->setScale(water_scale); + + gObjectList.updateActive(waterp); + } +} - // Let the Edge and Hole water boxes be 1024 meter high so that they - // are never too small to be drawn (A LL_VO_*_WATER box has water - // rendered on it's bottom surface only), and put their bottom at - // the current regions water height. - F32 const box_height = 1024; - F32 const water_center_z = water_height + box_height / 2; - - // Create new Hole water objects within 'range' where there is no region. - for (S32 x = min_x; x <= max_x; x += rwidth) - { - for (S32 y = min_y; y <= max_y; y += rwidth) - { - U64 region_handle = to_region_handle(x, y); - if (!getRegionFromHandle(region_handle)) - { - LLVOWater* waterp = (LLVOWater*)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER, gAgent.getRegion()); - waterp->setUseTexture(FALSE); - waterp->setPositionGlobal(LLVector3d(x + rwidth / 2, y + rwidth / 2, water_center_z)); - waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, box_height)); - gPipeline.createObject(waterp); - mHoleWaterObjects.push_back(waterp); - } - } - } - - // Center of the region. - S32 const center_x = region_x + rwidth / 2; - S32 const center_y = region_y + rwidth / 2; - // Width of the area with Hole water objects. - S32 const width = rwidth + 2 * range; - S32 const horizon_extend = 2048 + 512 - range; // Legacy value. - // The overlap is needed to get rid of sky pixels being visible between the - // Edge and Hole water object at greater distances (due to floating point - // round off errors). - S32 const edge_hole_overlap = 1; // Twice the actual overlap. - - for (S32 dir = 0; dir < 8; ++dir) - { - // Size of the Edge water objects. - S32 const dim_x = (gDirAxes[dir][0] == 0) ? width : (horizon_extend + edge_hole_overlap); - S32 const dim_y = (gDirAxes[dir][1] == 0) ? width : (horizon_extend + edge_hole_overlap); - // And their position. - S32 const water_center_x = center_x + (width + horizon_extend) / 2 * gDirAxes[dir][0]; - S32 const water_center_y = center_y + (width + horizon_extend) / 2 * gDirAxes[dir][1]; - - LLVOWater* waterp = mEdgeWaterObjects[dir]; - if (!waterp || waterp->isDead()) - { - // The edge water objects can be dead because they're attached to the region that the - // agent was in when they were originally created. - mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER, gAgent.getRegion()); - waterp = mEdgeWaterObjects[dir]; - waterp->setUseTexture(FALSE); - waterp->setIsEdgePatch(TRUE); // Mark that this is edge water and not hole water. - gPipeline.createObject(waterp); - } - - waterp->setRegion(gAgent.getRegion()); - LLVector3d water_pos(water_center_x, water_center_y, water_center_z); - LLVector3 water_scale((F32) dim_x, (F32) dim_y, box_height); - - waterp->setPositionGlobal(water_pos); - waterp->setScale(water_scale); - - gObjectList.updateActive(waterp); - } -} void LLWorld::shiftRegions(const LLVector3& offset) { -- cgit v1.2.3 From d74c5813600244b62d3779ccc5873b2bfe8befc2 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Wed, 9 Feb 2011 15:09:15 -0800 Subject: SH-938 [REGRESSION] Mesh costs and old style costs shown in Edit tools on mesh region with MeshEnabled set to False --- indra/newview/llfloatertools.cpp | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index a404aa0b1c..bef830a93e 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -431,13 +431,6 @@ void LLFloaterTools::refresh() getChild("RenderingCost")->setTextArg("[COUNT]", prim_cost_string); } - getChildView("linked_set_count")->setVisible(false); - getChildView("linked_set_cost")->setVisible(false); - getChildView("object_count")->setVisible(false); - getChildView("object_cost")->setVisible(false); - getChildView("obj_count")->setVisible(true); - getChildView("prim_count")->setVisible(true); - // disable the object and prim counts if nothing selected bool have_selection = ! LLSelectMgr::getInstance()->getSelection()->isEmpty(); getChildView("obj_count")->setEnabled(have_selection); @@ -495,13 +488,6 @@ void LLFloaterTools::refresh() childSetEnabled("linked_set_cost", have_selection); childSetEnabled("object_cost", have_selection); getChildView("RenderingCost")->setEnabled(have_selection && sShowObjectCost); - - getChildView("linked_set_count")->setVisible(true); - getChildView("linked_set_cost")->setVisible(true); - getChildView("object_count")->setVisible(true); - getChildView("object_cost")->setVisible(true); - getChildView("obj_count")->setVisible(false); - getChildView("prim_count")->setVisible(false); } @@ -787,20 +773,16 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) getChildView("Strength:")->setVisible( land_visible); } - if (gAgent.getRegion()->getCapability("GetMesh").empty()) - { - getChildView("obj_count")->setVisible( !land_visible); - getChildView("prim_count")->setVisible( !land_visible); - getChildView("RenderingCost")->setVisible( !land_visible && sShowObjectCost); - } - else - { - getChildView("linked_set_count")->setVisible( !land_visible); - getChildView("linked_set_cost")->setVisible( !land_visible); - getChildView("object_count")->setVisible( !land_visible); - getChildView("object_cost")->setVisible( !land_visible); - getChildView("RenderingCost")->setVisible( !land_visible && sShowObjectCost); - } + bool show_mesh_cost = !gAgent.getRegion()->getCapability("GetMesh").empty() && gSavedSettings.getBOOL("MeshEnabled"); + + getChildView("obj_count")->setVisible( !land_visible && !show_mesh_cost); + getChildView("prim_count")->setVisible( !land_visible && !show_mesh_cost); + getChildView("linked_set_count")->setVisible( !land_visible && show_mesh_cost); + getChildView("linked_set_cost")->setVisible( !land_visible && show_mesh_cost); + getChildView("object_count")->setVisible( !land_visible && show_mesh_cost); + getChildView("object_cost")->setVisible( !land_visible && show_mesh_cost); + getChildView("RenderingCost")->setVisible( !land_visible && sShowObjectCost); + mTab->setVisible(!land_visible); mPanelLandInfo->setVisible(land_visible); } -- cgit v1.2.3 From 54bf80bf450fa6b8b50c573ca5ef902b4462d410 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 9 Feb 2011 18:23:30 -0500 Subject: SH-915 WIP - cleanup --- indra/newview/llagentpilot.cpp | 41 ++--------------------------------------- 1 file changed, 2 insertions(+), 39 deletions(-) diff --git a/indra/newview/llagentpilot.cpp b/indra/newview/llagentpilot.cpp index 1a443e62a4..25318c940a 100755 --- a/indra/newview/llagentpilot.cpp +++ b/indra/newview/llagentpilot.cpp @@ -60,8 +60,6 @@ LLAgentPilot::~LLAgentPilot() { } -#define CAM_FIELDS 0 - void LLAgentPilot::load() { std::string txt_filename = gSavedSettings.getString("StatsPilotFile"); @@ -101,6 +99,7 @@ void LLAgentPilot::loadTxt(const std::string& filename) llinfos << "Opening pilot file " << filename << llendl; } + mActions.reset(); S32 num_actions; file >> num_actions; @@ -111,24 +110,6 @@ void LLAgentPilot::loadTxt(const std::string& filename) Action new_action; file >> new_action.mTime >> action_type; file >> new_action.mTarget.mdV[VX] >> new_action.mTarget.mdV[VY] >> new_action.mTarget.mdV[VZ]; -#if CAM_FIELDS - file >> new_action.mCameraView; - file >> new_action.mCameraOrigin.mV[VX] - >> new_action.mCameraOrigin.mV[VY] - >> new_action.mCameraOrigin.mV[VZ]; - - file >> new_action.mCameraXAxis.mV[VX] - >> new_action.mCameraXAxis.mV[VY] - >> new_action.mCameraXAxis.mV[VZ]; - - file >> new_action.mCameraYAxis.mV[VX] - >> new_action.mCameraYAxis.mV[VY] - >> new_action.mCameraYAxis.mV[VZ]; - - file >> new_action.mCameraZAxis.mV[VX] - >> new_action.mCameraZAxis.mV[VY] - >> new_action.mCameraZAxis.mV[VZ]; -#endif new_action.mType = (EActionType)action_type; mActions.put(new_action); } @@ -158,6 +139,7 @@ void LLAgentPilot::loadXML(const std::string& filename) llinfos << "Opening pilot file " << filename << llendl; } + mActions.reset(); LLSD record; while (!file.eof() && LLSDSerialize::fromXML(record, file)) { @@ -201,25 +183,6 @@ void LLAgentPilot::saveTxt(const std::string& filename) { file << mActions[i].mTime << "\t" << mActions[i].mType << "\t"; file << std::setprecision(32) << mActions[i].mTarget.mdV[VX] << "\t" << mActions[i].mTarget.mdV[VY] << "\t" << mActions[i].mTarget.mdV[VZ]; -#if CAM_FIELDS - file << "\t" << mActions[i].mCameraView; - - file << "\t" << mActions[i].mCameraOrigin[VX] - << "\t" << mActions[i].mCameraOrigin[VY] - << "\t" << mActions[i].mCameraOrigin[VZ]; - - file << "\t" << mActions[i].mCameraXAxis[VX] - << "\t" << mActions[i].mCameraXAxis[VY] - << "\t" << mActions[i].mCameraXAxis[VZ]; - - file << "\t" << mActions[i].mCameraYAxis[VX] - << "\t" << mActions[i].mCameraYAxis[VY] - << "\t" << mActions[i].mCameraYAxis[VZ]; - - file << "\t" << mActions[i].mCameraZAxis[VX] - << "\t" << mActions[i].mCameraZAxis[VY] - << "\t" << mActions[i].mCameraZAxis[VZ]; -#endif file << '\n'; } -- cgit v1.2.3 From d94117b80b67b6d27d2b2e14fb420682474e439e Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 9 Feb 2011 20:06:46 -0600 Subject: SH-920 Wait for threads to shut down before deleting them -- also, fix some assertions that were encouraging people to comment out the destruction of LLSignal. --- indra/llcommon/llthread.cpp | 5 ++++ indra/newview/llmeshrepository.cpp | 49 ++++++++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index b4617c5453..d9400fb5b3 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -425,6 +425,11 @@ void LLCondition::wait() if (!isLocked()) { //mAPRMutexp MUST be locked before calling apr_thread_cond_wait apr_thread_mutex_lock(mAPRMutexp); +#if MUTEX_DEBUG + // avoid asserts on destruction in non-release builds + U32 id = LLThread::currentID(); + mIsLocked[id] = TRUE; +#endif } apr_thread_cond_wait(mAPRCondp, mAPRMutexp); } diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index edcf249a21..a2b0ac09af 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -470,7 +470,12 @@ LLMeshRepoThread::LLMeshRepoThread() LLMeshRepoThread::~LLMeshRepoThread() { - + delete mMutex; + mMutex = NULL; + delete mHeaderMutex; + mHeaderMutex = NULL; + delete mSignal; + mSignal = NULL; } void LLMeshRepoThread::run() @@ -573,6 +578,11 @@ void LLMeshRepoThread::run() } } + if (mSignal->isLocked()) + { //make sure to let go of the mutex associated with the given signal before shutting down + mSignal->unlock(); + } + res = LLConvexDecomposition::quitThread(); if (res != LLCD_OK) { @@ -580,7 +590,7 @@ void LLMeshRepoThread::run() } delete mCurlRequest; - delete mMutex; + mCurlRequest = NULL; } void LLMeshRepoThread::loadMeshSkinInfo(const LLUUID& mesh_id) @@ -2115,13 +2125,24 @@ void LLMeshRepository::init() void LLMeshRepository::shutdown() { - mThread->mSignal->signal(); + llinfos << "Shutting down mesh repository." << llendl; + mThread->mSignal->signal(); + + while (!mThread->isStopped()) + { + apr_sleep(10); + } delete mThread; mThread = NULL; for (U32 i = 0; i < mUploads.size(); ++i) { + llinfos << "Waiting for pending mesh upload " << i << "/" << mUploads.size() << llendl; + while (!mUploads[i]->isStopped()) + { + apr_sleep(10); + } delete mUploads[i]; } @@ -2130,9 +2151,11 @@ void LLMeshRepository::shutdown() delete mMeshMutex; mMeshMutex = NULL; + llinfos << "Shutting down decomposition system." << llendl; + if (mDecompThread) { - mDecompThread->shutdown(); + mDecompThread->shutdown(); delete mDecompThread; mDecompThread = NULL; } @@ -3130,6 +3153,11 @@ LLPhysicsDecomp::LLPhysicsDecomp() LLPhysicsDecomp::~LLPhysicsDecomp() { shutdown(); + + delete mSignal; + mSignal = NULL; + delete mMutex; + mMutex = NULL; } void LLPhysicsDecomp::shutdown() @@ -3139,9 +3167,9 @@ void LLPhysicsDecomp::shutdown() mQuitting = true; mSignal->signal(); - while (!mDone) + while (!isStopped()) { - apr_sleep(100); + apr_sleep(10); } } } @@ -3519,10 +3547,11 @@ void LLPhysicsDecomp::run() decomp->quitThread(); - //delete mSignal; - delete mMutex; - mSignal = NULL; - mMutex = NULL; + if (mSignal->isLocked()) + { //let go of mSignal's associated mutex + mSignal->unlock(); + } + mDone = true; } -- cgit v1.2.3 From 85d91c7ad936db73b13d9780ed107672eb67dd39 Mon Sep 17 00:00:00 2001 From: Tofu Buzzard Date: Thu, 10 Feb 2011 10:42:41 -0800 Subject: crap fix --- indra/llvfs/lldir_win32.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h index 4c932c932c..9a07150f0f 100644 --- a/indra/llvfs/lldir_win32.h +++ b/indra/llvfs/lldir_win32.h @@ -47,7 +47,7 @@ public: /*virtual*/ std::string getLLPluginFilename(std::string base_name); private: - BOOL LLDir_Win32::getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname); + BOOL getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname); void* mDirSearch_h; llutf16string mCurrentDir; -- cgit v1.2.3 From 49b8f8af026a627db47c9592fc92eccda790401e Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 10 Feb 2011 15:57:08 -0500 Subject: SH-915 WIP - LLAgentPilot class cleanup, added interpolation for camera motion --- indra/newview/llagentpilot.cpp | 81 +++++++++++++++++++++++------------------- indra/newview/llagentpilot.h | 29 +++++++++------ indra/newview/llappviewer.cpp | 8 ++--- indra/newview/llstartup.cpp | 2 +- indra/newview/llviewermenu.cpp | 13 +++---- 5 files changed, 75 insertions(+), 58 deletions(-) mode change 100644 => 100755 indra/newview/llviewermenu.cpp diff --git a/indra/newview/llagentpilot.cpp b/indra/newview/llagentpilot.cpp index 25318c940a..f96db0a5df 100755 --- a/indra/newview/llagentpilot.cpp +++ b/indra/newview/llagentpilot.cpp @@ -41,9 +41,6 @@ LLAgentPilot gAgentPilot; -BOOL LLAgentPilot::sLoop = TRUE; -BOOL LLAgentPilot::sReplaySession = FALSE; - LLAgentPilot::LLAgentPilot() : mNumRuns(-1), mQuitAfterRuns(FALSE), @@ -52,7 +49,9 @@ LLAgentPilot::LLAgentPilot() : mStarted(FALSE), mPlaying(FALSE), mCurrentAction(0), - mOverrideCamera(FALSE) + mOverrideCamera(FALSE), + mLoop(TRUE), + mReplaySession(FALSE) { } @@ -266,7 +265,7 @@ void LLAgentPilot::startPlayback() LLViewerJoystick::getInstance()->toggleFlycam(); } gAgent.startAutoPilotGlobal(mActions[0].mTarget); - moveCamera(mActions[0]); + moveCamera(); mStarted = FALSE; } else @@ -287,22 +286,51 @@ void LLAgentPilot::stopPlayback() gAgent.stopAutoPilot(); } - if (sReplaySession) + if (mReplaySession) { LLAppViewer::instance()->forceQuit(); } } -void LLAgentPilot::moveCamera(Action& action) +void LLAgentPilot::moveCamera() { if (!getOverrideCamera()) return; + + if (mCurrentAction 0.0) + { + t = tickelapsed/timedelta; + } + + if ((t<0.0)||(t>1.0)) + { + llwarns << "mCurrentAction is invalid, t = " << t << llendl; + return; + } + + Action& start = mActions[start_index]; + Action& end = mActions[end_index]; + + F32 view = lerp(start.mCameraView, end.mCameraView, t); + LLVector3 origin = lerp(start.mCameraOrigin, end.mCameraOrigin, t); + LLQuaternion start_quat(start.mCameraXAxis, start.mCameraYAxis, start.mCameraZAxis); + LLQuaternion end_quat(end.mCameraXAxis, end.mCameraYAxis, end.mCameraZAxis); + LLQuaternion quat = nlerp(t, start_quat, end_quat); + LLMatrix3 mat(quat); - LLViewerCamera::getInstance()->setView(action.mCameraView); - LLViewerCamera::getInstance()->setOrigin(action.mCameraOrigin); - LLViewerCamera::getInstance()->mXAxis = LLVector3(action.mCameraXAxis); - LLViewerCamera::getInstance()->mYAxis = LLVector3(action.mCameraYAxis); - LLViewerCamera::getInstance()->mZAxis = LLVector3(action.mCameraZAxis); + LLViewerCamera::getInstance()->setView(view); + LLViewerCamera::getInstance()->setOrigin(origin); + LLViewerCamera::getInstance()->mXAxis = LLVector3(mat.mMatrix[0]); + LLViewerCamera::getInstance()->mYAxis = LLVector3(mat.mMatrix[1]); + LLViewerCamera::getInstance()->mZAxis = LLVector3(mat.mMatrix[2]); + } } void LLAgentPilot::updateTarget() @@ -336,13 +364,13 @@ void LLAgentPilot::updateTarget() if (mCurrentAction < mActions.count()) { gAgent.startAutoPilotGlobal(mActions[mCurrentAction].mTarget); - moveCamera(mActions[mCurrentAction]); + moveCamera(); } else { stopPlayback(); mNumRuns--; - if (sLoop) + if (mLoop) { if ((mNumRuns < 0) || (mNumRuns > 0)) { @@ -377,29 +405,8 @@ void LLAgentPilot::updateTarget() } } -// static -void LLAgentPilot::startRecord(void *) -{ - gAgentPilot.startRecord(); -} - -void LLAgentPilot::saveRecord(void *) -{ - gAgentPilot.stopRecord(); -} - -void LLAgentPilot::addWaypoint(void *) +void LLAgentPilot::addWaypoint() { - gAgentPilot.addAction(STRAIGHT); -} - -void LLAgentPilot::startPlayback(void *) -{ - gAgentPilot.mNumRuns = -1; - gAgentPilot.startPlayback(); + addAction(STRAIGHT); } -void LLAgentPilot::stopPlayback(void *) -{ - gAgentPilot.stopPlayback(); -} diff --git a/indra/newview/llagentpilot.h b/indra/newview/llagentpilot.h index 5e045fa695..dd1709ec0c 100755 --- a/indra/newview/llagentpilot.h +++ b/indra/newview/llagentpilot.h @@ -60,24 +60,34 @@ public: void startPlayback(); void stopPlayback(); - bool isRecording() { return mRecording; } bool isPlaying() { return mPlaying; } bool getOverrideCamera() { return mOverrideCamera; } void updateTarget(); - static void startRecord(void *); - static void addWaypoint(void *); - static void saveRecord(void *); - static void startPlayback(void *); - static void stopPlayback(void *); - static BOOL sLoop; - static BOOL sReplaySession; + void addWaypoint(); + void moveCamera(); + + void setReplaySession(BOOL new_val) { mReplaySession = new_val; } + BOOL getReplaySession() { return mReplaySession; } + + void setLoop(BOOL new_val) { mLoop = new_val; } + BOOL getLoop() { return mLoop; } + + void setQuitAfterRuns(BOOL quit_val) { mQuitAfterRuns = quit_val; } + void setNumRuns(S32 num_runs) { mNumRuns = num_runs; } + +private: + + + + BOOL mLoop; + BOOL mReplaySession; S32 mNumRuns; BOOL mQuitAfterRuns; -private: + void setAutopilotTarget(const S32 id); BOOL mRecording; @@ -106,7 +116,6 @@ private: LLDynamicArray mActions; LLTimer mTimer; - void moveCamera(Action& action); }; extern LLAgentPilot gAgentPilot; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ec3d775dc7..0118d2dfc1 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -468,8 +468,8 @@ static void settings_to_globals() LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections"); LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius"); - gAgentPilot.mNumRuns = gSavedSettings.getS32("StatsNumRuns"); - gAgentPilot.mQuitAfterRuns = gSavedSettings.getBOOL("StatsQuitAfterRuns"); + gAgentPilot.setNumRuns(gSavedSettings.getS32("StatsNumRuns")); + gAgentPilot.setQuitAfterRuns(gSavedSettings.getBOOL("StatsQuitAfterRuns")); gAgent.setHideGroupTitle(gSavedSettings.getBOOL("RenderHideGroupTitle")); gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc"); @@ -2289,7 +2289,7 @@ bool LLAppViewer::initConfiguration() if (clp.hasOption("replaysession")) { - LLAgentPilot::sReplaySession = TRUE; + gAgentPilot.setReplaySession(TRUE); } if (clp.hasOption("nonotifications")) @@ -4224,7 +4224,7 @@ void LLAppViewer::idle() { if (gAgentPilot.isPlaying() && gAgentPilot.getOverrideCamera()) { - // camera positioning handled inside gAgentPilot. + gAgentPilot.moveCamera(); } else { diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index db7e0149cc..b98cbd5b78 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1989,7 +1989,7 @@ bool idle_startup() } // Start automatic replay if the flag is set. - if (gSavedSettings.getBOOL("StatsAutoRun") || LLAgentPilot::sReplaySession) + if (gSavedSettings.getBOOL("StatsAutoRun") || gAgentPilot.getReplaySession()) { LLUUID id; LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp old mode 100644 new mode 100755 index e9e0268587..eb022851e7 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1901,19 +1901,20 @@ class LLAdvancedAgentPilot : public view_listener_t std::string command = userdata.asString(); if ("start playback" == command) { - LLAgentPilot::startPlayback(NULL); + gAgentPilot.setNumRuns(-1); + gAgentPilot.startPlayback(); } else if ("stop playback" == command) { - LLAgentPilot::stopPlayback(NULL); + gAgentPilot.stopPlayback(); } else if ("start record" == command) { - LLAgentPilot::startRecord(NULL); + gAgentPilot.startRecord(); } else if ("stop record" == command) { - LLAgentPilot::saveRecord(NULL); + gAgentPilot.stopRecord(); } return true; @@ -1931,7 +1932,7 @@ class LLAdvancedToggleAgentPilotLoop : public view_listener_t { bool handleEvent(const LLSD& userdata) { - LLAgentPilot::sLoop = !(LLAgentPilot::sLoop); + gAgentPilot.setLoop(!gAgentPilot.getLoop()); return true; } }; @@ -1940,7 +1941,7 @@ class LLAdvancedCheckAgentPilotLoop : public view_listener_t { bool handleEvent(const LLSD& userdata) { - bool new_value = LLAgentPilot::sLoop; + bool new_value = gAgentPilot.getLoop(); return new_value; } }; -- cgit v1.2.3 From 7a43bd5d9de75215a2015c0d232113747c3ad604 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 10 Feb 2011 17:33:55 -0500 Subject: Fix for linux build breakage --- indra/llvfs/lldir_win32.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 indra/llvfs/lldir_win32.h diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h old mode 100644 new mode 100755 index 4c932c932c..9a07150f0f --- a/indra/llvfs/lldir_win32.h +++ b/indra/llvfs/lldir_win32.h @@ -47,7 +47,7 @@ public: /*virtual*/ std::string getLLPluginFilename(std::string base_name); private: - BOOL LLDir_Win32::getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname); + BOOL getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname); void* mDirSearch_h; llutf16string mCurrentDir; -- cgit v1.2.3 From 27286e48713fe3c00c37d7295e8f70be103a7c63 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Thu, 10 Feb 2011 16:24:52 -0800 Subject: SH-942 Deferred rendering options in preferences should be visible even if MeshEnabled is false. --- indra/newview/llfloaterpreference.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 3673a28163..9562f2d9d2 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -656,13 +656,6 @@ void LLFloaterPreference::onOpen(const LLSD& key) getChildView("maturity_desired_combobox")->setVisible( false); } - bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled"); - - getChildView("UseLightShaders")->setVisible(enable_mesh); - getChildView("UseSSAO")->setVisible(enable_mesh); - getChildView("shadows_label")->setVisible(enable_mesh); - getChildView("ShadowDetail")->setVisible(enable_mesh); - if (LLStartUp::getStartupState() == STATE_STARTED) { mFavoritesRecordMayExist = gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"); -- cgit v1.2.3 From 5addce7331a4b64b2994ccf20ecfa1d427ce1b38 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Thu, 10 Feb 2011 16:26:23 -0800 Subject: backing out sh-512 changes --- indra/newview/llpanelobject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 8fa6beb474..b60eb893c7 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1934,7 +1934,7 @@ void LLPanelObject::refresh() getChildView("Physics Density")->setVisible(enable_mesh); getChildView("Physics Restitution")->setVisible(enable_mesh); - F32 max_scale = DEFAULT_MAX_PRIM_SCALE_NO_MESH; + F32 max_scale = get_default_max_prim_scale(); getChild("Scale X")->setMaxValue(max_scale); getChild("Scale Y")->setMaxValue(max_scale); getChild("Scale Z")->setMaxValue(max_scale); -- cgit v1.2.3 From 2111bb8eff0469647028a5a8102ee5201321ac10 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 10 Feb 2011 18:39:02 -0600 Subject: SH-958 Fix for entire scene being in shadow when shadows + SSAO disabled but "Lighting and Shadows" enabled. --- .../app_settings/shaders/class1/deferred/softenLightF.glsl | 10 +++------- indra/newview/llviewershadermgr.cpp | 7 +++++++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl index 0fb26bd9a1..29340c7e9f 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl @@ -270,14 +270,10 @@ void main() vec4 diffuse = texture2DRect(diffuseRect, tc); vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); - vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg; - float scol = max(scol_ambocc.r, diffuse.a); - float ambocc = scol_ambocc.g; - - calcAtmospherics(pos.xyz, ambocc); + calcAtmospherics(pos.xyz, 1.0); vec3 col = atmosAmbient(vec3(0)); - col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a)); + col += atmosAffectDirectionalLight(max(min(da, 1.0), diffuse.a)); col *= diffuse.rgb; @@ -287,7 +283,7 @@ void main() // vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); float sa = dot(refnormpersp, vary_light.xyz); - vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).a; + vec3 dumbshiny = vary_SunlitColor*texture2D(lightFunc, vec2(sa, spec.a)).a; /* // screen-space cheap fakey reflection map diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 7c84357de8..a9462c9d50 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -1149,7 +1149,14 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSoftenProgram.mShaderFiles.clear(); gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSoftenProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + + if (gSavedSettings.getBOOL("RenderDeferredSSAO")) + { //if using SSAO, take screen space light map into account as if shadows are enabled + gDeferredSoftenProgram.mShaderLevel = llmax(gDeferredSoftenProgram.mShaderLevel, 2); + } + success = gDeferredSoftenProgram.createShader(NULL, NULL); } -- cgit v1.2.3 From e3ce59b27d28aac4ba7325612817a71c205b498f Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Thu, 10 Feb 2011 17:29:29 -0800 Subject: Backed out changeset 4fd25c7614e0 --- indra/newview/llpanelobject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index b60eb893c7..8fa6beb474 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1934,7 +1934,7 @@ void LLPanelObject::refresh() getChildView("Physics Density")->setVisible(enable_mesh); getChildView("Physics Restitution")->setVisible(enable_mesh); - F32 max_scale = get_default_max_prim_scale(); + F32 max_scale = DEFAULT_MAX_PRIM_SCALE_NO_MESH; getChild("Scale X")->setMaxValue(max_scale); getChild("Scale Y")->setMaxValue(max_scale); getChild("Scale Z")->setMaxValue(max_scale); -- cgit v1.2.3 From d381ec420972722cc176910b4d9e2f7ecf45288a Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 11 Feb 2011 13:19:49 -0500 Subject: SH-915 WIP - removed coupling between autopilot flycam and joystick flycam --- indra/newview/llagentpilot.cpp | 6 ------ indra/newview/llappviewer.cpp | 15 ++++++--------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/indra/newview/llagentpilot.cpp b/indra/newview/llagentpilot.cpp index f96db0a5df..734c502fcf 100755 --- a/indra/newview/llagentpilot.cpp +++ b/indra/newview/llagentpilot.cpp @@ -35,7 +35,6 @@ #include "llappviewer.h" #include "llviewercontrol.h" #include "llviewercamera.h" -#include "llviewerjoystick.h" #include "llsdserialize.h" #include "llsdutil_math.h" @@ -259,11 +258,6 @@ void LLAgentPilot::startPlayback() if (mActions.count()) { llinfos << "Starting playback, moving to waypoint 0" << llendl; - if (getOverrideCamera() && - !LLViewerJoystick::getInstance()->getOverrideCamera()) - { - LLViewerJoystick::getInstance()->toggleFlycam(); - } gAgent.startAutoPilotGlobal(mActions[0].mTarget); moveCamera(); mStarted = FALSE; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 0118d2dfc1..add0e72ce2 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4220,16 +4220,13 @@ void LLAppViewer::idle() LLWorld::getInstance()->updateParticles(); } - if (LLViewerJoystick::getInstance()->getOverrideCamera()) + if (gAgentPilot.isPlaying() && gAgentPilot.getOverrideCamera()) + { + gAgentPilot.moveCamera(); + } + else if (LLViewerJoystick::getInstance()->getOverrideCamera()) { - if (gAgentPilot.isPlaying() && gAgentPilot.getOverrideCamera()) - { - gAgentPilot.moveCamera(); - } - else - { - LLViewerJoystick::getInstance()->moveFlycam(); - } + LLViewerJoystick::getInstance()->moveFlycam(); } else { -- cgit v1.2.3 From 479b5ac8ac54ea0442a237ce55f439e465316ad0 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 11 Feb 2011 13:30:37 -0600 Subject: SH-510 Fix for some mesh selection outlines appearing one region away. --- indra/newview/llselectmgr.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 746ba274ed..93c9131424 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -5492,7 +5492,12 @@ void LLSelectNode::renderOneWireframe(const LLColor4& color) BOOL is_hud_object = objectp->isHUDAttachment(); - if (!is_hud_object) + if (drawable->isActive()) + { + glLoadMatrixd(gGLModelView); + glMultMatrixf((F32*) objectp->getRenderMatrix().mMatrix); + } + else if (!is_hud_object) { glLoadIdentity(); glMultMatrixd(gGLModelView); @@ -5500,11 +5505,6 @@ void LLSelectNode::renderOneWireframe(const LLColor4& color) glTranslatef(trans.mV[0], trans.mV[1], trans.mV[2]); } - if (drawable->isActive()) - { - glMultMatrixf((F32*) objectp->getRenderMatrix().mMatrix); - } - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); if (LLSelectMgr::sRenderHiddenSelections) // && gFloaterTools && gFloaterTools->getVisible()) -- cgit v1.2.3 From 246b2100e18e6e9e596aacc92a65bd7b6442b0ec Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 11 Feb 2011 16:45:59 -0600 Subject: SH-912 Fix for avatar impostors glitching out at weird angles. --- indra/newview/llvoavatar.cpp | 10 +++++++++- indra/newview/pipeline.cpp | 28 +++++++++++++++++----------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index a257703b24..0771e72bdc 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -3335,13 +3335,21 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) if (visible && !isSelf() && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter) { + const LLVector4a* ext = mDrawable->getSpatialExtents(); + LLVector4a size; + size.setSub(ext[1],ext[0]); + F32 mag = size.getLength3().getF32()*0.5f; + F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f); if (LLMuteList::getInstance()->isMuted(getID())) { // muted avatars update at 16 hz mUpdatePeriod = 16; } - else if (mVisibilityRank <= LLVOAvatar::sMaxVisible) + else if (mVisibilityRank <= LLVOAvatar::sMaxVisible || + mDrawable->mDistanceWRTCamera < 1.f + mag) { //first 25% of max visible avatars are not impostored + //also, don't impostor avatars whose bounding box may be penetrating the + //impostor camera near clip plane mUpdatePeriod = 1; } else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 4) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 69173d26f4..b0aa50bc57 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -9352,10 +9352,10 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) glMatrixMode(GL_PROJECTION); glPushMatrix(); - //glh::matrix4f ortho = gl_ortho(-tdim.mV[0], tdim.mV[0], -tdim.mV[1], tdim.mV[1], 1.0, 256.0); + F32 distance = (pos-camera.getOrigin()).length(); F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG; - F32 aspect = tdim.mV[0]/tdim.mV[1]; //128.f/256.f; + F32 aspect = tdim.mV[0]/tdim.mV[1]; glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f); glh_set_current_projection(persp); glLoadMatrixf(persp.m); @@ -9374,7 +9374,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) gGL.setColorMask(true, true); glStencilMask(0xFFFFFFFF); glClearStencil(0); - + // get the number of pixels per angle F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView()); @@ -9424,9 +9424,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) glStencilFunc(GL_EQUAL, 1, 0xFFFFFF); { //create alpha mask based on stencil buffer (grey out if muted) - LLVector3 left = camera.getLeftAxis()*tdim.mV[0]*2.f; - LLVector3 up = camera.getUpAxis()*tdim.mV[1]*2.f; - if (LLPipeline::sRenderDeferred) { GLuint buff = GL_COLOR_ATTACHMENT0_EXT; @@ -9449,16 +9446,25 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) LLGLDepthTest depth(GL_FALSE, GL_FALSE); - gGL.color4f(1,1,1,1); + gGL.flush(); + + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gGL.color4ub(64,64,64,255); gGL.begin(LLRender::QUADS); - gGL.vertex3fv((pos+left-up).mV); - gGL.vertex3fv((pos-left-up).mV); - gGL.vertex3fv((pos-left+up).mV); - gGL.vertex3fv((pos+left+up).mV); + gGL.vertex2f(-1, -1); + gGL.vertex2f(1, -1); + gGL.vertex2f(1, 1); + gGL.vertex2f(-1, 1); gGL.end(); gGL.flush(); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); gGL.setSceneBlendType(LLRender::BT_ALPHA); } -- cgit v1.2.3 From a761351396d81c4de7598340c61bf9cd4115071f Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 11 Feb 2011 19:07:11 -0600 Subject: SH-813 Switch llerrs in llcurl.cpp to an assert. --- indra/llmessage/llcurl.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 2b9bfff536..b0f68df2e8 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -1199,10 +1199,7 @@ void LLCurl::cleanupClass() Easy::sFreeHandles.clear(); - if (!Easy::sActiveHandles.empty()) - { - llerrs << "CURL easy handles not cleaned up on shutdown!" << llendl; - } + llassert(Easy::sActiveHandles.empty()); } const unsigned int LLCurl::MAX_REDIRECTS = 5; -- cgit v1.2.3 From b862e3adfa006fbc62015ddd160a545c1bb44654 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 14 Feb 2011 18:26:12 -0600 Subject: SH-547 Fix for rigged attachments being invisible in impostors and fix for impostors not working with lighting and shadows enabled. --- .../shaders/class1/deferred/impostorF.glsl | 2 +- indra/newview/lldrawpoolalpha.cpp | 18 +++++++-- indra/newview/lldrawpoolavatar.cpp | 2 +- indra/newview/pipeline.cpp | 46 ++++++++-------------- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl index 7125d845d9..e3c15a2ab2 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl @@ -14,7 +14,7 @@ uniform sampler2D specularMap; void main() { vec4 col = texture2D(diffuseMap, gl_TexCoord[0].xy); - gl_FragData[0] = vec4(col.rgb, col.a <= 0.5 ? 0.0 : 0.005); + gl_FragData[0] = vec4(col.rgb, col.a * 0.005); gl_FragData[1] = texture2D(specularMap, gl_TexCoord[0].xy); gl_FragData[2] = vec4(texture2D(normalMap, gl_TexCoord[0].xy).xyz, 0.0); } diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 2519d0297c..7f1740e29f 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -103,7 +103,14 @@ void LLDrawPoolAlpha::renderDeferred(S32 pass) S32 LLDrawPoolAlpha::getNumPostDeferredPasses() { - return 2; + if (LLPipeline::sImpostorRender) + { //skip depth buffer filling pass when rendering impostors + return 1; + } + else + { + return 2; + } } void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) @@ -137,8 +144,13 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) void LLDrawPoolAlpha::endPostDeferredPass(S32 pass) { - gPipeline.mDeferredDepth.flush(); - gPipeline.mScreen.bindTarget(); + + if (pass == 1) + { + gPipeline.mDeferredDepth.flush(); + gPipeline.mScreen.bindTarget(); + } + deferred_render = FALSE; endRenderPass(pass); } diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index df5b341fdf..ae3421a019 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -494,7 +494,7 @@ void LLDrawPoolAvatar::render(S32 pass) LLFastTimer t(FTM_RENDER_CHARACTERS); if (LLPipeline::sImpostorRender) { - renderAvatars(NULL, 2); + renderAvatars(NULL, pass+2); return; } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index b0aa50bc57..813aab0680 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -9372,8 +9372,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) glClearColor(0.0f,0.0f,0.0f,0.0f); gGL.setColorMask(true, true); - glStencilMask(0xFFFFFFFF); - glClearStencil(0); // get the number of pixels per angle F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView()); @@ -9385,7 +9383,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() || resY != avatar->mImpostor.getHeight()) { - avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,TRUE); + avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE); if (LLPipeline::sRenderDeferred) { @@ -9397,40 +9395,30 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } - LLGLEnable stencil(GL_STENCIL_TEST); - glStencilMask(0xFFFFFFFF); - glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + avatar->mImpostor.bindTarget(); - { - LLGLEnable scissor(GL_SCISSOR_TEST); - glScissor(0, 0, resX, resY); - avatar->mImpostor.bindTarget(); - avatar->mImpostor.clear(); - } - if (LLPipeline::sRenderDeferred) { - stop_glerror(); + avatar->mImpostor.clear(); renderGeomDeferred(camera); renderGeomPostDeferred(camera); } else { + LLGLEnable scissor(GL_SCISSOR_TEST); + glScissor(0, 0, resX, resY); + avatar->mImpostor.clear(); renderGeom(camera); } - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilFunc(GL_EQUAL, 1, 0xFFFFFF); - - { //create alpha mask based on stencil buffer (grey out if muted) + { //create alpha mask based on depth buffer (grey out if muted) if (LLPipeline::sRenderDeferred) { - GLuint buff = GL_COLOR_ATTACHMENT0_EXT; + GLuint buff = GL_COLOR_ATTACHMENT0; glDrawBuffersARB(1, &buff); } - LLGLEnable blend(muted ? 0 : GL_BLEND); + LLGLDisable blend(GL_BLEND); if (muted) { @@ -9441,34 +9429,34 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) gGL.setColorMask(false, true); } - gGL.setSceneBlendType(LLRender::BT_ADD); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLDepthTest depth(GL_FALSE, GL_FALSE); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); gGL.flush(); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); + glPushMatrix(); glLoadIdentity(); + static const F32 clip_plane = 0.99999f; + gGL.color4ub(64,64,64,255); gGL.begin(LLRender::QUADS); - gGL.vertex2f(-1, -1); - gGL.vertex2f(1, -1); - gGL.vertex2f(1, 1); - gGL.vertex2f(-1, 1); + gGL.vertex3f(-1, -1, clip_plane); + gGL.vertex3f(1, -1, clip_plane); + gGL.vertex3f(1, 1, clip_plane); + gGL.vertex3f(-1, 1, clip_plane); gGL.end(); gGL.flush(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); - gGL.setSceneBlendType(LLRender::BT_ALPHA); } - avatar->mImpostor.flush(); avatar->setImpostorDim(tdim); -- cgit v1.2.3 From a44b1ff511cb8f3399aa318ac15019ad97938c45 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Mon, 14 Feb 2011 16:31:40 -0800 Subject: SH-956 Turning off Basic Shaders in Preferences > Graphics does not grey out expected Shadows options in Mesh Viewer SH-957 Turning off Atmospheric Shaders greys out Lighting and Shadows options in preferences but does not turn off shadows inworld --- indra/newview/llfloaterpreference.cpp | 27 +++++++++++++-------------- indra/newview/llviewermenu.cpp | 3 ++- indra/newview/llviewershadermgr.cpp | 19 +++++++++++++------ 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 9562f2d9d2..a90bacf41d 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1037,26 +1037,25 @@ void LLFloaterPreference::refreshEnabledState() //Deferred/SSAO/Shadows LLCheckBoxCtrl* ctrl_deferred = getChild("UseLightShaders"); - if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && - shaders && - gGLManager.mHasFramebufferObject) - { - BOOL enabled = (ctrl_wind_light->get()) ? TRUE : FALSE; + BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && + shaders && + gGLManager.mHasFramebufferObject && + gSavedSettings.getBOOL("RenderAvatarVP") && + (ctrl_wind_light->get()) ? TRUE : FALSE; - ctrl_deferred->setEnabled(enabled); + ctrl_deferred->setEnabled(enabled); - LLCheckBoxCtrl* ctrl_ssao = getChild("UseSSAO"); - LLComboBox* ctrl_shadow = getChild("ShadowDetail"); + LLCheckBoxCtrl* ctrl_ssao = getChild("UseSSAO"); + LLComboBox* ctrl_shadow = getChild("ShadowDetail"); - enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO") && (ctrl_deferred->get() ? TRUE : FALSE); + enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO") && (ctrl_deferred->get() ? TRUE : FALSE); - ctrl_ssao->setEnabled(enabled); + ctrl_ssao->setEnabled(enabled); - enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail"); - - ctrl_shadow->setEnabled(enabled); - } + enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail"); + ctrl_shadow->setEnabled(enabled); + // now turn off any features that are unavailable disableUnavailableSettings(); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index eb022851e7..cfcce3e7bb 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -2082,7 +2082,8 @@ class LLAdvancedEnableRenderDeferredOptions: public view_listener_t { bool handleEvent(const LLSD& userdata) { - bool new_value = gSavedSettings.getBOOL("RenderDeferred"); + bool new_value = gGLManager.mHasFramebufferObject && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT > 0) && + LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0 && gSavedSettings.getBOOL("RenderDeferred"); return new_value; } }; diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index a9462c9d50..25cf63a367 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -397,7 +397,9 @@ void LLViewerShaderMgr::setShaders() S32 deferred_class = 0; if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && - gSavedSettings.getBOOL("RenderDeferred")) + gSavedSettings.getBOOL("RenderDeferred") && + gSavedSettings.getBOOL("RenderAvatarVP") && + gSavedSettings.getBOOL("WindLightUseAtmosShaders")) { if (gSavedSettings.getS32("RenderShadowDetail") > 0) { @@ -416,10 +418,10 @@ void LLViewerShaderMgr::setShaders() } //make sure hardware skinning is enabled - gSavedSettings.setBOOL("RenderAvatarVP", TRUE); + //gSavedSettings.setBOOL("RenderAvatarVP", TRUE); //make sure atmospheric shaders are enabled - gSavedSettings.setBOOL("WindLightUseAtmosShaders", TRUE); + //gSavedSettings.setBOOL("WindLightUseAtmosShaders", TRUE); } @@ -505,9 +507,14 @@ void LLViewerShaderMgr::setShaders() { //hardware skinning not possible, neither is deferred rendering mVertexShaderLevel[SHADER_AVATAR] = 0; mVertexShaderLevel[SHADER_DEFERRED] = 0; - gSavedSettings.setBOOL("RenderDeferred", FALSE); - gSavedSettings.setBOOL("RenderAvatarCloth", FALSE); - gSavedSettings.setBOOL("RenderAvatarVP", FALSE); + + if (gSavedSettings.getBOOL("RenderAvatarVP")) + { + gSavedSettings.setBOOL("RenderDeferred", FALSE); + gSavedSettings.setBOOL("RenderAvatarCloth", FALSE); + gSavedSettings.setBOOL("RenderAvatarVP", FALSE); + } + loadShadersAvatar(); // unloads loadShadersObject(); } -- cgit v1.2.3 From 6e8115cd223056e91816008f11e624939058ddf4 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 14 Feb 2011 19:36:53 -0600 Subject: Fix for crash when enabling Debug GL (stack underflow) --- indra/newview/pipeline.cpp | 59 +++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 813aab0680..9d7af4aace 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -104,6 +104,26 @@ #include "llcurl.h" +void check_stack_depth(S32 stack_depth) +{ + if (gDebugGL || gDebugSession) + { + GLint depth; + glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth); + if (depth != stack_depth) + { + if (gDebugSession) + { + ll_fail("GL matrix stack corrupted."); + } + else + { + llerrs << "GL matrix stack corrupted!" << llendl; + } + } + } +} + #ifdef _DEBUG // Debug indices is disabled for now for debug performance - djs 4/24/02 //#define DEBUG_INDICES @@ -3354,6 +3374,13 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) } } + S32 stack_depth = 0; + + if (gDebugGL) + { + glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &stack_depth); + } + /////////////////////////////////////////// // // Sync and verify GL state @@ -3478,18 +3505,9 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) } poolp->endRenderPass(i); LLVertexBuffer::unbind(); - if (gDebugGL || gDebugPipeline) + if (gDebugGL) { - GLint depth; - glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth); - if (depth > 3) - { - if (gDebugSession) - { - ll_fail("GL matrix stack corrupted."); - } - llerrs << "GL matrix stack corrupted!" << llendl; - } + check_stack_depth(stack_depth); std::string msg = llformat("%s pass %d", gPoolNames[cur_type].c_str(), i); LLGLState::checkStates(msg); LLGLState::checkTextureChannels(msg); @@ -3512,11 +3530,11 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) iter1 = iter2; stop_glerror(); } - - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd"); - - LLVertexBuffer::unbind(); + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd"); + + LLVertexBuffer::unbind(); + gGLLastMatrix = NULL; glLoadMatrixd(gGLModelView); @@ -3563,9 +3581,9 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) { if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { - // Render debugging beacons. - gObjectList.renderObjectBeacons(); - gObjectList.resetObjectBeacons(); + // Render debugging beacons. + gObjectList.renderObjectBeacons(); + gObjectList.resetObjectBeacons(); } else { @@ -4269,9 +4287,10 @@ void LLPipeline::renderDebug() gGL.popMatrix(); } } + + gGL.popMatrix(); } - gGL.popMatrix(); gGL.flush(); gPipeline.renderPhysicsDisplay(); @@ -7779,7 +7798,9 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) LLPipeline::RENDER_TYPE_WL_SKY, LLPipeline::END_RENDER_TYPES); + //bad pop here renderGeom(camera, TRUE); + gPipeline.popRenderTypeMask(); } -- cgit v1.2.3 From a0b9fe00f68fd0673cd4e9b673523ecb480c0ca9 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 15 Feb 2011 16:43:47 -0500 Subject: SH-845 FIX - installer checks for SSE2 support and offers option to quit if not found (note the needed API is not present on win2k, so the check will not run there) --- .../installers/windows/installer_template.nsi | 20 ++++++++++++++++++++ indra/newview/installers/windows/lang_en-us.nsi | Bin 7162 -> 7564 bytes 2 files changed, 20 insertions(+) mode change 100644 => 100755 indra/newview/installers/windows/installer_template.nsi mode change 100644 => 100755 indra/newview/installers/windows/lang_en-us.nsi diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi old mode 100644 new mode 100755 index 4e8ed807ee..b5d43021ec --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -210,6 +210,25 @@ continue_install: Return FunctionEnd +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Checks for CPU valid (must have SSE2 support) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +Function CheckCPUFlags + Call GetWindowsVersion + Pop $R0 + StrCmp $R0 "2000" OK_SSE ; sse check not available on win2k. + + Push $1 + System::Call 'kernel32::IsProcessorFeaturePresent(i) i(10) .r1' + IntCmp $1 1 OK_SSE + MessageBox MB_OKCANCEL $(MissingSSE2) /SD IDOK IDOK OK_SSE + Quit + + OK_SSE: + Pop $1 + Return +FunctionEnd + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Close the program, if running. Modifies no variables. ; Allows user to bail out of install process. @@ -744,6 +763,7 @@ StrCpy $INSTEXE "${INSTEXE}" StrCpy $INSTSHORTCUT "${SHORTCUT}" Call CheckWindowsVersion ; warn if on Windows 98/ME +Call CheckCPUFlags ; Make sure we have SSE2 support Call CheckIfAdministrator ; Make sure the user can install/uninstall Call CheckIfAlreadyCurrent ; Make sure that we haven't already installed this version Call CloseSecondLife ; Make sure we're not running diff --git a/indra/newview/installers/windows/lang_en-us.nsi b/indra/newview/installers/windows/lang_en-us.nsi old mode 100644 new mode 100755 index a01541377d..4721a26612 Binary files a/indra/newview/installers/windows/lang_en-us.nsi and b/indra/newview/installers/windows/lang_en-us.nsi differ -- cgit v1.2.3 From 344200bcd490b3f004468ea10899ddd0a8b2f0fc Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 15 Feb 2011 16:45:00 -0500 Subject: SH-845 FIX - wording change --- indra/newview/installers/windows/lang_en-us.nsi | Bin 7564 -> 7542 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/indra/newview/installers/windows/lang_en-us.nsi b/indra/newview/installers/windows/lang_en-us.nsi index 4721a26612..da0d7f54d2 100755 Binary files a/indra/newview/installers/windows/lang_en-us.nsi and b/indra/newview/installers/windows/lang_en-us.nsi differ -- cgit v1.2.3 From 8bbbcd9c22010a259d42d23c517e04fe7afd41fd Mon Sep 17 00:00:00 2001 From: prep Date: Wed, 16 Feb 2011 10:32:12 -0500 Subject: Fix for SH-816 --- indra/llcharacter/lljoint.cpp | 4 + indra/llcharacter/lljoint.h | 11 +- indra/newview/llvoavatar.cpp | 16884 ++++++++++++++++++++-------------------- 3 files changed, 8458 insertions(+), 8441 deletions(-) diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index d68abcef5a..19907933cb 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -50,6 +50,7 @@ LLJoint::LLJoint() mUpdateXform = TRUE; mJointNum = -1; touch(); + mResetAfterRestoreOldXform = false; } @@ -250,6 +251,7 @@ void LLJoint::setDefaultFromCurrentXform( void ) void LLJoint::storeCurrentXform( const LLVector3& pos ) { mOldXform = mXform; + mResetAfterRestoreOldXform = true; setPosition( pos ); } //-------------------------------------------------------------------- @@ -257,6 +259,7 @@ void LLJoint::storeCurrentXform( const LLVector3& pos ) //-------------------------------------------------------------------- void LLJoint::restoreOldXform( void ) { + mResetAfterRestoreOldXform = false; mXform = mOldXform; } //-------------------------------------------------------------------- @@ -556,3 +559,4 @@ void LLJoint::clampRotation(LLQuaternion old_rot, LLQuaternion new_rot) } // End + diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index cbfca588b0..dc3c58cf64 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -88,6 +88,8 @@ public: U32 mDirtyFlags; BOOL mUpdateXform; + BOOL mResetAfterRestoreOldXform; + // describes the skin binding pose LLVector3 mSkinOffset; @@ -181,10 +183,17 @@ public: void restoreOldXform( void ); void restoreToDefaultXform( void ); void setDefaultFromCurrentXform( void ); - void storeCurrentXform( const LLVector3& pos ); + + //Accessor for the joint id LLUUID getId( void ) { return mId; } + //Setter for the joints id void setId( const LLUUID& id ) { mId = id;} + + //If the old transform flag has been set, then the reset logic in avatar needs to be aware(test) of it + const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; } + //Setter for joint reset flag + void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; } }; #endif // LL_LLJOINT_H diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 0771e72bdc..b1a5ea0fd6 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1,8440 +1,8444 @@ -/** - * @File llvoavatar.cpp - * @brief Implementation of LLVOAvatar class which is a derivation of LLViewerObject - * - * $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$ - */ - -#if LL_MSVC -// disable warning about boost::lexical_cast returning uninitialized data -// when it fails to parse the string -#pragma warning (disable:4701) -#endif - -#include "llviewerprecompiledheaders.h" - -#include "llvoavatar.h" - -#include -#include - -#include "llaudioengine.h" -#include "llcachename.h" -#include "noise.h" -#include "sound_ids.h" - -#include "llagent.h" // Get state values from here -#include "llagentcamera.h" -#include "llagentwearables.h" -#include "llanimationstates.h" -#include "llavatarnamecache.h" -#include "llavatarpropertiesprocessor.h" -#include "llviewercontrol.h" -#include "llcallingcard.h" // IDEVO for LLAvatarTracker -#include "lldrawpoolavatar.h" -#include "lldriverparam.h" -#include "lleditingmotion.h" -#include "llemote.h" -//#include "llfirstuse.h" -#include "llheadrotmotion.h" -#include "llhudeffecttrail.h" -#include "llhudmanager.h" -#include "llhudnametag.h" -#include "llhudtext.h" // for mText/mDebugText -#include "llkeyframefallmotion.h" -#include "llkeyframestandmotion.h" -#include "llkeyframewalkmotion.h" -#include "llmanipscale.h" // for get_default_max_prim_scale() -#include "llmeshrepository.h" -#include "llmutelist.h" -#include "llmoveview.h" -#include "llnotificationsutil.h" -#include "llquantize.h" -#include "llrand.h" -#include "llregionhandle.h" -#include "llresmgr.h" -#include "llselectmgr.h" -#include "llsprite.h" -#include "lltargetingmotion.h" -#include "lltexlayer.h" -#include "lltoolmorph.h" -#include "llviewercamera.h" -#include "llviewertexturelist.h" -#include "llviewermenu.h" -#include "llviewerobjectlist.h" -#include "llviewerparcelmgr.h" -#include "llviewershadermgr.h" -#include "llviewerstats.h" -#include "llvoavatarself.h" -#include "llvovolume.h" -#include "llworld.h" -#include "pipeline.h" -#include "llviewershadermgr.h" -#include "llsky.h" -#include "llanimstatelabels.h" -#include "lltrans.h" -#include "llappearancemgr.h" - -#include "llgesturemgr.h" //needed to trigger the voice gesticulations -#include "llvoiceclient.h" -#include "llvoicevisualizer.h" // Ventrella - -#include "lldebugmessagebox.h" -extern F32 SPEED_ADJUST_MAX; -extern F32 SPEED_ADJUST_MAX_SEC; -extern F32 ANIM_SPEED_MAX; -extern F32 ANIM_SPEED_MIN; - -#if LL_MSVC -// disable boost::lexical_cast warning -#pragma warning (disable:4702) -#endif - -#include - -using namespace LLVOAvatarDefines; - -//----------------------------------------------------------------------------- -// Global constants -//----------------------------------------------------------------------------- -const LLUUID ANIM_AGENT_BODY_NOISE = LLUUID("9aa8b0a6-0c6f-9518-c7c3-4f41f2c001ad"); //"body_noise" -const LLUUID ANIM_AGENT_BREATHE_ROT = LLUUID("4c5a103e-b830-2f1c-16bc-224aa0ad5bc8"); //"breathe_rot" -const LLUUID ANIM_AGENT_EDITING = LLUUID("2a8eba1d-a7f8-5596-d44a-b4977bf8c8bb"); //"editing" -const LLUUID ANIM_AGENT_EYE = LLUUID("5c780ea8-1cd1-c463-a128-48c023f6fbea"); //"eye" -const LLUUID ANIM_AGENT_FLY_ADJUST = LLUUID("db95561f-f1b0-9f9a-7224-b12f71af126e"); //"fly_adjust" -const LLUUID ANIM_AGENT_HAND_MOTION = LLUUID("ce986325-0ba7-6e6e-cc24-b17c4b795578"); //"hand_motion" -const LLUUID ANIM_AGENT_HEAD_ROT = LLUUID("e6e8d1dd-e643-fff7-b238-c6b4b056a68d"); //"head_rot" -const LLUUID ANIM_AGENT_PELVIS_FIX = LLUUID("0c5dd2a2-514d-8893-d44d-05beffad208b"); //"pelvis_fix" -const LLUUID ANIM_AGENT_TARGET = LLUUID("0e4896cb-fba4-926c-f355-8720189d5b55"); //"target" -const LLUUID ANIM_AGENT_WALK_ADJUST = LLUUID("829bc85b-02fc-ec41-be2e-74cc6dd7215d"); //"walk_adjust" - - -//----------------------------------------------------------------------------- -// Constants -//----------------------------------------------------------------------------- -const std::string AVATAR_DEFAULT_CHAR = "avatar"; - -const S32 MIN_PIXEL_AREA_FOR_COMPOSITE = 1024; -const F32 SHADOW_OFFSET_AMT = 0.03f; - -const F32 DELTA_TIME_MIN = 0.01f; // we clamp measured deltaTime to this -const F32 DELTA_TIME_MAX = 0.2f; // range to insure stability of computations. - -const F32 PELVIS_LAG_FLYING = 0.22f;// pelvis follow half life while flying -const F32 PELVIS_LAG_WALKING = 0.4f; // ...while walking -const F32 PELVIS_LAG_MOUSELOOK = 0.15f; -const F32 MOUSELOOK_PELVIS_FOLLOW_FACTOR = 0.5f; -const F32 PELVIS_LAG_WHEN_FOLLOW_CAM_IS_ON = 0.0001f; // not zero! - something gets divided by this! - -const F32 PELVIS_ROT_THRESHOLD_SLOW = 60.0f; // amount of deviation allowed between -const F32 PELVIS_ROT_THRESHOLD_FAST = 2.0f; // the pelvis and the view direction - // when moving fast & slow -const F32 TORSO_NOISE_AMOUNT = 1.0f; // Amount of deviation from up-axis, in degrees -const F32 TORSO_NOISE_SPEED = 0.2f; // Time scale factor on torso noise. - -const F32 BREATHE_ROT_MOTION_STRENGTH = 0.05f; -const F32 BREATHE_SCALE_MOTION_STRENGTH = 0.005f; - -const F32 MIN_SHADOW_HEIGHT = 0.f; -const F32 MAX_SHADOW_HEIGHT = 0.3f; - -const S32 MIN_REQUIRED_PIXEL_AREA_BODY_NOISE = 10000; -const S32 MIN_REQUIRED_PIXEL_AREA_BREATHE = 10000; -const S32 MIN_REQUIRED_PIXEL_AREA_PELVIS_FIX = 40; - -const S32 TEX_IMAGE_SIZE_SELF = 512; -const S32 TEX_IMAGE_AREA_SELF = TEX_IMAGE_SIZE_SELF * TEX_IMAGE_SIZE_SELF; -const S32 TEX_IMAGE_SIZE_OTHER = 512 / 4; // The size of local textures for other (!isSelf()) avatars - -const F32 HEAD_MOVEMENT_AVG_TIME = 0.9f; - -const S32 MORPH_MASK_REQUESTED_DISCARD = 0; - -// Discard level at which to switch to baked textures -// Should probably be 4 or 3, but didn't want to change it while change other logic - SJB -const S32 SWITCH_TO_BAKED_DISCARD = 5; - -const F32 FOOT_COLLIDE_FUDGE = 0.04f; - -const F32 HOVER_EFFECT_MAX_SPEED = 3.f; -const F32 HOVER_EFFECT_STRENGTH = 0.f; -const F32 UNDERWATER_EFFECT_STRENGTH = 0.1f; -const F32 UNDERWATER_FREQUENCY_DAMP = 0.33f; -const F32 APPEARANCE_MORPH_TIME = 0.65f; -const F32 TIME_BEFORE_MESH_CLEANUP = 5.f; // seconds -const S32 AVATAR_RELEASE_THRESHOLD = 10; // number of avatar instances before releasing memory -const F32 FOOT_GROUND_COLLISION_TOLERANCE = 0.25f; -const F32 AVATAR_LOD_TWEAK_RANGE = 0.7f; -const S32 MAX_BUBBLE_CHAT_LENGTH = DB_CHAT_MSG_STR_LEN; -const S32 MAX_BUBBLE_CHAT_UTTERANCES = 12; -const F32 CHAT_FADE_TIME = 8.0; -const F32 BUBBLE_CHAT_TIME = CHAT_FADE_TIME * 3.f; - -const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0); - -enum ERenderName -{ - RENDER_NAME_NEVER, - RENDER_NAME_ALWAYS, - RENDER_NAME_FADE -}; - -//----------------------------------------------------------------------------- -// Callback data -//----------------------------------------------------------------------------- - -struct LLTextureMaskData -{ - LLTextureMaskData( const LLUUID& id ) : - mAvatarID(id), - mLastDiscardLevel(S32_MAX) - {} - LLUUID mAvatarID; - S32 mLastDiscardLevel; -}; - -/********************************************************************************* - ** ** - ** Begin private LLVOAvatar Support classes - ** - **/ - -//------------------------------------------------------------------------ -// LLVOBoneInfo -// Trans/Scale/Rot etc. info about each avatar bone. Used by LLVOAvatarSkeleton. -//------------------------------------------------------------------------ -class LLVOAvatarBoneInfo -{ - friend class LLVOAvatar; - friend class LLVOAvatarSkeletonInfo; -public: - LLVOAvatarBoneInfo() : mIsJoint(FALSE) {} - ~LLVOAvatarBoneInfo() - { - std::for_each(mChildList.begin(), mChildList.end(), DeletePointer()); - } - BOOL parseXml(LLXmlTreeNode* node); - -private: - std::string mName; - BOOL mIsJoint; - LLVector3 mPos; - LLVector3 mRot; - LLVector3 mScale; - LLVector3 mPivot; - typedef std::vector child_list_t; - child_list_t mChildList; -}; - -//------------------------------------------------------------------------ -// LLVOAvatarSkeletonInfo -// Overall avatar skeleton -//------------------------------------------------------------------------ -class LLVOAvatarSkeletonInfo -{ - friend class LLVOAvatar; -public: - LLVOAvatarSkeletonInfo() : - mNumBones(0), mNumCollisionVolumes(0) {} - ~LLVOAvatarSkeletonInfo() - { - std::for_each(mBoneInfoList.begin(), mBoneInfoList.end(), DeletePointer()); - } - BOOL parseXml(LLXmlTreeNode* node); - S32 getNumBones() const { return mNumBones; } - S32 getNumCollisionVolumes() const { return mNumCollisionVolumes; } - -private: - S32 mNumBones; - S32 mNumCollisionVolumes; - typedef std::vector bone_info_list_t; - bone_info_list_t mBoneInfoList; -}; - -//----------------------------------------------------------------------------- -// class LLBodyNoiseMotion -//----------------------------------------------------------------------------- -class LLBodyNoiseMotion : - public LLMotion -{ -public: - // Constructor - LLBodyNoiseMotion(const LLUUID &id) - : LLMotion(id) - { - mName = "body_noise"; - mTorsoState = new LLJointState; - } - - // Destructor - virtual ~LLBodyNoiseMotion() { } - -public: - //------------------------------------------------------------------------- - // functions to support MotionController and MotionRegistry - //------------------------------------------------------------------------- - // static constructor - // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLBodyNoiseMotion(id); } - -public: - //------------------------------------------------------------------------- - // animation callbacks to be implemented by subclasses - //------------------------------------------------------------------------- - - // motions must specify whether or not they loop - virtual BOOL getLoop() { return TRUE; } - - // motions must report their total duration - virtual F32 getDuration() { return 0.0; } - - // motions must report their "ease in" duration - virtual F32 getEaseInDuration() { return 0.0; } - - // motions must report their "ease out" duration. - virtual F32 getEaseOutDuration() { return 0.0; } - - // motions must report their priority - virtual LLJoint::JointPriority getPriority() { return LLJoint::HIGH_PRIORITY; } - - virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; } - - // called to determine when a motion should be activated/deactivated based on avatar pixel coverage - virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_BODY_NOISE; } - - // run-time (post constructor) initialization, - // called after parameters have been set - // must return true to indicate success and be available for activation - virtual LLMotionInitStatus onInitialize(LLCharacter *character) - { - if( !mTorsoState->setJoint( character->getJoint("mTorso") )) - { - return STATUS_FAILURE; - } - - mTorsoState->setUsage(LLJointState::ROT); - - addJointState( mTorsoState ); - return STATUS_SUCCESS; - } - - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate() { return TRUE; } - - // called per time step - // must return TRUE while it is active, and - // must return FALSE when the motion is completed. - virtual BOOL onUpdate(F32 time, U8* joint_mask) - { - F32 nx[2]; - nx[0]=time*TORSO_NOISE_SPEED; - nx[1]=0.0f; - F32 ny[2]; - ny[0]=0.0f; - ny[1]=time*TORSO_NOISE_SPEED; - F32 noiseX = noise2(nx); - F32 noiseY = noise2(ny); - - F32 rx = TORSO_NOISE_AMOUNT * DEG_TO_RAD * noiseX / 0.42f; - F32 ry = TORSO_NOISE_AMOUNT * DEG_TO_RAD * noiseY / 0.42f; - LLQuaternion tQn; - tQn.setQuat( rx, ry, 0.0f ); - mTorsoState->setRotation( tQn ); - - return TRUE; - } - - // called when a motion is deactivated - virtual void onDeactivate() {} - -private: - //------------------------------------------------------------------------- - // joint states to be animated - //------------------------------------------------------------------------- - LLPointer mTorsoState; -}; - -//----------------------------------------------------------------------------- -// class LLBreatheMotionRot -//----------------------------------------------------------------------------- -class LLBreatheMotionRot : - public LLMotion -{ -public: - // Constructor - LLBreatheMotionRot(const LLUUID &id) : - LLMotion(id), - mBreatheRate(1.f), - mCharacter(NULL) - { - mName = "breathe_rot"; - mChestState = new LLJointState; - } - - // Destructor - virtual ~LLBreatheMotionRot() {} - -public: - //------------------------------------------------------------------------- - // functions to support MotionController and MotionRegistry - //------------------------------------------------------------------------- - // static constructor - // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLBreatheMotionRot(id); } - -public: - //------------------------------------------------------------------------- - // animation callbacks to be implemented by subclasses - //------------------------------------------------------------------------- - - // motions must specify whether or not they loop - virtual BOOL getLoop() { return TRUE; } - - // motions must report their total duration - virtual F32 getDuration() { return 0.0; } - - // motions must report their "ease in" duration - virtual F32 getEaseInDuration() { return 0.0; } - - // motions must report their "ease out" duration. - virtual F32 getEaseOutDuration() { return 0.0; } - - // motions must report their priority - virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; } - - virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } - - // called to determine when a motion should be activated/deactivated based on avatar pixel coverage - virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_BREATHE; } - - // run-time (post constructor) initialization, - // called after parameters have been set - // must return true to indicate success and be available for activation - virtual LLMotionInitStatus onInitialize(LLCharacter *character) - { - mCharacter = character; - BOOL success = true; - - if ( !mChestState->setJoint( character->getJoint( "mChest" ) ) ) { success = false; } - - if ( success ) - { - mChestState->setUsage(LLJointState::ROT); - addJointState( mChestState ); - } - - if ( success ) - { - return STATUS_SUCCESS; - } - else - { - return STATUS_FAILURE; - } - } - - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate() { return TRUE; } - - // called per time step - // must return TRUE while it is active, and - // must return FALSE when the motion is completed. - virtual BOOL onUpdate(F32 time, U8* joint_mask) - { - mBreatheRate = 1.f; - - F32 breathe_amt = (sinf(mBreatheRate * time) * BREATHE_ROT_MOTION_STRENGTH); - - mChestState->setRotation(LLQuaternion(breathe_amt, LLVector3(0.f, 1.f, 0.f))); - - return TRUE; - } - - // called when a motion is deactivated - virtual void onDeactivate() {} - -private: - //------------------------------------------------------------------------- - // joint states to be animated - //------------------------------------------------------------------------- - LLPointer mChestState; - F32 mBreatheRate; - LLCharacter* mCharacter; -}; - -//----------------------------------------------------------------------------- -// class LLPelvisFixMotion -//----------------------------------------------------------------------------- -class LLPelvisFixMotion : - public LLMotion -{ -public: - // Constructor - LLPelvisFixMotion(const LLUUID &id) - : LLMotion(id), mCharacter(NULL) - { - mName = "pelvis_fix"; - - mPelvisState = new LLJointState; - } - - // Destructor - virtual ~LLPelvisFixMotion() { } - -public: - //------------------------------------------------------------------------- - // functions to support MotionController and MotionRegistry - //------------------------------------------------------------------------- - // static constructor - // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID& id) { return new LLPelvisFixMotion(id); } - -public: - //------------------------------------------------------------------------- - // animation callbacks to be implemented by subclasses - //------------------------------------------------------------------------- - - // motions must specify whether or not they loop - virtual BOOL getLoop() { return TRUE; } - - // motions must report their total duration - virtual F32 getDuration() { return 0.0; } - - // motions must report their "ease in" duration - virtual F32 getEaseInDuration() { return 0.5f; } - - // motions must report their "ease out" duration. - virtual F32 getEaseOutDuration() { return 0.5f; } - - // motions must report their priority - virtual LLJoint::JointPriority getPriority() { return LLJoint::LOW_PRIORITY; } - - virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } - - // called to determine when a motion should be activated/deactivated based on avatar pixel coverage - virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_PELVIS_FIX; } - - // run-time (post constructor) initialization, - // called after parameters have been set - // must return true to indicate success and be available for activation - virtual LLMotionInitStatus onInitialize(LLCharacter *character) - { - mCharacter = character; - - if (!mPelvisState->setJoint( character->getJoint("mPelvis"))) - { - return STATUS_FAILURE; - } - - mPelvisState->setUsage(LLJointState::POS); - - addJointState( mPelvisState ); - return STATUS_SUCCESS; - } - - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate() { return TRUE; } - - // called per time step - // must return TRUE while it is active, and - // must return FALSE when the motion is completed. - virtual BOOL onUpdate(F32 time, U8* joint_mask) - { - mPelvisState->setPosition(LLVector3::zero); - - return TRUE; - } - - // called when a motion is deactivated - virtual void onDeactivate() {} - -private: - //------------------------------------------------------------------------- - // joint states to be animated - //------------------------------------------------------------------------- - LLPointer mPelvisState; - LLCharacter* mCharacter; -}; - -/** - ** - ** End LLVOAvatar Support classes - ** ** - *********************************************************************************/ - - -//----------------------------------------------------------------------------- -// Static Data -//----------------------------------------------------------------------------- -LLXmlTree LLVOAvatar::sXMLTree; -LLXmlTree LLVOAvatar::sSkeletonXMLTree; -LLVOAvatarSkeletonInfo* LLVOAvatar::sAvatarSkeletonInfo = NULL; -LLVOAvatar::LLVOAvatarXmlInfo* LLVOAvatar::sAvatarXmlInfo = NULL; -LLVOAvatarDictionary *LLVOAvatar::sAvatarDictionary = NULL; -S32 LLVOAvatar::sFreezeCounter = 0; -U32 LLVOAvatar::sMaxVisible = 12; -F32 LLVOAvatar::sRenderDistance = 256.f; -S32 LLVOAvatar::sNumVisibleAvatars = 0; -S32 LLVOAvatar::sNumLODChangesThisFrame = 0; - -const LLUUID LLVOAvatar::sStepSoundOnLand("e8af4a28-aa83-4310-a7c4-c047e15ea0df"); -const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] = -{ - SND_STONE_RUBBER, - SND_METAL_RUBBER, - SND_GLASS_RUBBER, - SND_WOOD_RUBBER, - SND_FLESH_RUBBER, - SND_RUBBER_PLASTIC, - SND_RUBBER_RUBBER -}; - -S32 LLVOAvatar::sRenderName = RENDER_NAME_ALWAYS; -BOOL LLVOAvatar::sRenderGroupTitles = TRUE; -S32 LLVOAvatar::sNumVisibleChatBubbles = 0; -BOOL LLVOAvatar::sDebugInvisible = FALSE; -BOOL LLVOAvatar::sShowAttachmentPoints = FALSE; -BOOL LLVOAvatar::sShowAnimationDebug = FALSE; -BOOL LLVOAvatar::sShowFootPlane = FALSE; -BOOL LLVOAvatar::sVisibleInFirstPerson = FALSE; -F32 LLVOAvatar::sLODFactor = 1.f; -BOOL LLVOAvatar::sUseImpostors = FALSE; -BOOL LLVOAvatar::sJointDebug = FALSE; - -F32 LLVOAvatar::sUnbakedTime = 0.f; -F32 LLVOAvatar::sUnbakedUpdateTime = 0.f; -F32 LLVOAvatar::sGreyTime = 0.f; -F32 LLVOAvatar::sGreyUpdateTime = 0.f; - -//----------------------------------------------------------------------------- -// Helper functions -//----------------------------------------------------------------------------- -static F32 calc_bouncy_animation(F32 x); - -//----------------------------------------------------------------------------- -// LLVOAvatar() -//----------------------------------------------------------------------------- -LLVOAvatar::LLVOAvatar(const LLUUID& id, - const LLPCode pcode, - LLViewerRegion* regionp) : - LLViewerObject(id, pcode, regionp), - mIsDummy(FALSE), - mSpecialRenderMode(0), - mTurning(FALSE), - mPelvisToFoot(0.f), - mLastSkeletonSerialNum( 0 ), - mHeadOffset(), - mIsSitting(FALSE), - mTimeVisible(), - mTyping(FALSE), - mMeshValid(FALSE), - mVisible(FALSE), - mWindFreq(0.f), - mRipplePhase( 0.f ), - mBelowWater(FALSE), - mLastAppearanceBlendTime(0.f), - mAppearanceAnimating(FALSE), - mNameString(), - mTitle(), - mNameAway(false), - mNameBusy(false), - mNameMute(false), - mNameAppearance(false), - mNameFriend(false), - mNameAlpha(0.f), - mRenderGroupTitles(sRenderGroupTitles), - mNameCloud(false), - mFirstTEMessageReceived( FALSE ), - mFirstAppearanceMessageReceived( FALSE ), - mCulled( FALSE ), - mVisibilityRank(0), - mTexSkinColor( NULL ), - mTexHairColor( NULL ), - mTexEyeColor( NULL ), - mNeedsSkin(FALSE), - mLastSkinTime(0.f), - mUpdatePeriod(1), - mFullyLoaded(FALSE), - mPreviousFullyLoaded(FALSE), - mFullyLoadedInitialized(FALSE), - mSupportsAlphaLayers(FALSE), - mLoadedCallbacksPaused(FALSE), - mHasPelvisOffset( FALSE ) -{ - LLMemType mt(LLMemType::MTYPE_AVATAR); - //VTResume(); // VTune - - // mVoiceVisualizer is created by the hud effects manager and uses the HUD Effects pipeline - const BOOL needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job - mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim ); - - lldebugs << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << llendl; - - mPelvisp = NULL; - - mBakedTextureDatas.resize(BAKED_NUM_INDICES); - for (U32 i = 0; i < mBakedTextureDatas.size(); i++ ) - { - mBakedTextureDatas[i].mLastTextureIndex = IMG_DEFAULT_AVATAR; - mBakedTextureDatas[i].mTexLayerSet = NULL; - mBakedTextureDatas[i].mIsLoaded = false; - mBakedTextureDatas[i].mIsUsed = false; - mBakedTextureDatas[i].mMaskTexName = 0; - mBakedTextureDatas[i].mTextureIndex = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)i); - } - - mDirtyMesh = 2; // Dirty geometry, need to regenerate. - mMeshTexturesDirty = FALSE; - mHeadp = NULL; - - mIsBuilt = FALSE; - - mNumJoints = 0; - mSkeleton = NULL; - - mNumCollisionVolumes = 0; - mCollisionVolumes = NULL; - - // set up animation variables - mSpeed = 0.f; - setAnimationData("Speed", &mSpeed); - - mNeedsImpostorUpdate = TRUE; - mNeedsAnimUpdate = TRUE; - - mImpostorDistance = 0; - mImpostorPixelArea = 0; - - setNumTEs(TEX_NUM_INDICES); - - mbCanSelect = TRUE; - - mSignaledAnimations.clear(); - mPlayingAnimations.clear(); - - mWasOnGroundLeft = FALSE; - mWasOnGroundRight = FALSE; - - mTimeLast = 0.0f; - mSpeedAccum = 0.0f; - - mRippleTimeLast = 0.f; - - mInAir = FALSE; - - mStepOnLand = TRUE; - mStepMaterial = 0; - - mLipSyncActive = false; - mOohMorph = NULL; - mAahMorph = NULL; - - mCurrentGesticulationLevel = 0; - - mRuthTimer.reset(); - mRuthDebugTimer.reset(); - mDebugExistenceTimer.reset(); - mPelvisOffset = LLVector3(0.0f,0.0f,0.0f); -} - -//------------------------------------------------------------------------ -// LLVOAvatar::~LLVOAvatar() -//------------------------------------------------------------------------ -LLVOAvatar::~LLVOAvatar() -{ - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) - { - if (!mFullyLoaded) - { - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left after " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds as cloud." << llendl; - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezLeftCloudNotification",args); - } - else - { - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left." << llendl; - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezLeftNotification",args); - } - - } - lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl; - - mRoot.removeAllChildren(); - - deleteAndClearArray(mSkeleton); - deleteAndClearArray(mCollisionVolumes); - - mNumJoints = 0; - - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - deleteAndClear(mBakedTextureDatas[i].mTexLayerSet); - mBakedTextureDatas[i].mMeshes.clear(); - - for (morph_list_t::iterator iter2 = mBakedTextureDatas[i].mMaskedMorphs.begin(); - iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); iter2++) - { - LLMaskedMorph* masked_morph = (*iter2); - delete masked_morph; - } - } - - std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer()); - mAttachmentPoints.clear(); - - deleteAndClear(mTexSkinColor); - deleteAndClear(mTexHairColor); - deleteAndClear(mTexEyeColor); - - std::for_each(mMeshes.begin(), mMeshes.end(), DeletePairedPointer()); - mMeshes.clear(); - - for (std::vector::iterator jointIter = mMeshLOD.begin(); - jointIter != mMeshLOD.end(); - ++jointIter) - { - LLViewerJoint* joint = (LLViewerJoint *) *jointIter; - std::for_each(joint->mMeshParts.begin(), joint->mMeshParts.end(), DeletePointer()); - joint->mMeshParts.clear(); - } - std::for_each(mMeshLOD.begin(), mMeshLOD.end(), DeletePointer()); - mMeshLOD.clear(); - - mDead = TRUE; - - mAnimationSources.clear(); - LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ; - - lldebugs << "LLVOAvatar Destructor end" << llendl; -} - -void LLVOAvatar::markDead() -{ - if (mNameText) - { - mNameText->markDead(); - mNameText = NULL; - sNumVisibleChatBubbles--; - } - mVoiceVisualizer->markDead(); - LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ; - LLViewerObject::markDead(); -} - - -BOOL LLVOAvatar::isFullyBaked() -{ - if (mIsDummy) return TRUE; - if (getNumTEs() == 0) return FALSE; - - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - if (!isTextureDefined(mBakedTextureDatas[i].mTextureIndex) - && ( (i != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) ) ) - { - return FALSE; - } - } - return TRUE; -} - -void LLVOAvatar::deleteLayerSetCaches(bool clearAll) -{ - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - if (mBakedTextureDatas[i].mTexLayerSet) - { - // ! BACKWARDS COMPATIBILITY ! - // Can be removed after hair baking is mandatory on the grid - if ((i != BAKED_HAIR || isSelf()) && !clearAll) - { - mBakedTextureDatas[i].mTexLayerSet->deleteCaches(); - } - } - if (mBakedTextureDatas[i].mMaskTexName) - { - glDeleteTextures(1, (GLuint*)&(mBakedTextureDatas[i].mMaskTexName)); - mBakedTextureDatas[i].mMaskTexName = 0 ; - } - } -} - -// static -BOOL LLVOAvatar::areAllNearbyInstancesBaked(S32& grey_avatars) -{ - BOOL res = TRUE; - grey_avatars = 0; - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { - LLVOAvatar* inst = (LLVOAvatar*) *iter; - if( inst->isDead() ) - { - continue; - } - else if( !inst->isFullyBaked() ) - { - res = FALSE; - if (inst->mHasGrey) - { - ++grey_avatars; - } - } - } - return res; -} - -// static -void LLVOAvatar::dumpBakedStatus() -{ - LLVector3d camera_pos_global = gAgentCamera.getCameraPositionGlobal(); - - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { - LLVOAvatar* inst = (LLVOAvatar*) *iter; - llinfos << "Avatar "; - - LLNameValue* firstname = inst->getNVPair("FirstName"); - LLNameValue* lastname = inst->getNVPair("LastName"); - - if( firstname ) - { - llcont << firstname->getString(); - } - if( lastname ) - { - llcont << " " << lastname->getString(); - } - - llcont << " " << inst->mID; - - if( inst->isDead() ) - { - llcont << " DEAD ("<< inst->getNumRefs() << " refs)"; - } - - if( inst->isSelf() ) - { - llcont << " (self)"; - } - - - F64 dist_to_camera = (inst->getPositionGlobal() - camera_pos_global).length(); - llcont << " " << dist_to_camera << "m "; - - llcont << " " << inst->mPixelArea << " pixels"; - - if( inst->isVisible() ) - { - llcont << " (visible)"; - } - else - { - llcont << " (not visible)"; - } - - if( inst->isFullyBaked() ) - { - llcont << " Baked"; - } - else - { - llcont << " Unbaked ("; - - for (LLVOAvatarDictionary::BakedTextures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); - iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); - ++iter) - { - const LLVOAvatarDictionary::BakedEntry *baked_dict = iter->second; - const ETextureIndex index = baked_dict->mTextureIndex; - if (!inst->isTextureDefined(index)) - { - llcont << " " << LLVOAvatarDictionary::getInstance()->getTexture(index)->mName; - } - } - llcont << " ) " << inst->getUnbakedPixelAreaRank(); - if( inst->isCulled() ) - { - llcont << " culled"; - } - } - llcont << llendl; - } -} - -//static -void LLVOAvatar::restoreGL() -{ - if (!isAgentAvatarValid()) return; - - gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); - for (U32 i = 0; i < gAgentAvatarp->mBakedTextureDatas.size(); i++) - { - gAgentAvatarp->invalidateComposite(gAgentAvatarp->mBakedTextureDatas[i].mTexLayerSet, FALSE); - } - gAgentAvatarp->updateMeshTextures(); -} - -//static -void LLVOAvatar::destroyGL() -{ - deleteCachedImages(); - - resetImpostors(); -} - -//static -void LLVOAvatar::resetImpostors() -{ - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { - LLVOAvatar* avatar = (LLVOAvatar*) *iter; - avatar->mImpostor.release(); - } -} - -// static -void LLVOAvatar::deleteCachedImages(bool clearAll) -{ - if (LLTexLayerSet::sHasCaches) - { - lldebugs << "Deleting layer set caches" << llendl; - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { - LLVOAvatar* inst = (LLVOAvatar*) *iter; - inst->deleteLayerSetCaches(clearAll); - } - LLTexLayerSet::sHasCaches = FALSE; - } - LLVOAvatarSelf::deleteScratchTextures(); - LLTexLayerStaticImageList::getInstance()->deleteCachedImages(); -} - - -//------------------------------------------------------------------------ -// static -// LLVOAvatar::initClass() -//------------------------------------------------------------------------ -void LLVOAvatar::initClass() -{ - std::string xmlFile; - - xmlFile = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR) + "_lad.xml"; - BOOL success = sXMLTree.parseFile( xmlFile, FALSE ); - if (!success) - { - llerrs << "Problem reading avatar configuration file:" << xmlFile << llendl; - } - - // now sanity check xml file - LLXmlTreeNode* root = sXMLTree.getRoot(); - if (!root) - { - llerrs << "No root node found in avatar configuration file: " << xmlFile << llendl; - return; - } - - //------------------------------------------------------------------------- - // (root) - //------------------------------------------------------------------------- - if( !root->hasName( "linden_avatar" ) ) - { - llerrs << "Invalid avatar file header: " << xmlFile << llendl; - } - - std::string version; - static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); - if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") ) - { - llerrs << "Invalid avatar file version: " << version << " in file: " << xmlFile << llendl; - } - - S32 wearable_def_version = 1; - static LLStdStringHandle wearable_definition_version_string = LLXmlTree::addAttributeString("wearable_definition_version"); - root->getFastAttributeS32( wearable_definition_version_string, wearable_def_version ); - LLWearable::setCurrentDefinitionVersion( wearable_def_version ); - - std::string mesh_file_name; - - LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" ); - if (!skeleton_node) - { - llerrs << "No skeleton in avatar configuration file: " << xmlFile << llendl; - return; - } - - std::string skeleton_file_name; - static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name"); - if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name)) - { - llerrs << "No file name in skeleton node in avatar config file: " << xmlFile << llendl; - } - - std::string skeleton_path; - skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name); - if (!parseSkeletonFile(skeleton_path)) - { - llerrs << "Error parsing skeleton file: " << skeleton_path << llendl; - } - - // Process XML data - - // avatar_skeleton.xml - llassert(!sAvatarSkeletonInfo); - sAvatarSkeletonInfo = new LLVOAvatarSkeletonInfo; - if (!sAvatarSkeletonInfo->parseXml(sSkeletonXMLTree.getRoot())) - { - llerrs << "Error parsing skeleton XML file: " << skeleton_path << llendl; - } - // parse avatar_lad.xml - llassert(!sAvatarXmlInfo); - sAvatarXmlInfo = new LLVOAvatarXmlInfo; - if (!sAvatarXmlInfo->parseXmlSkeletonNode(root)) - { - llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; - } - if (!sAvatarXmlInfo->parseXmlMeshNodes(root)) - { - llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; - } - if (!sAvatarXmlInfo->parseXmlColorNodes(root)) - { - llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; - } - if (!sAvatarXmlInfo->parseXmlLayerNodes(root)) - { - llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; - } - if (!sAvatarXmlInfo->parseXmlDriverNodes(root)) - { - llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; - } - if (!sAvatarXmlInfo->parseXmlMorphNodes(root)) - { - llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; - } - - gAnimLibrary.animStateSetString(ANIM_AGENT_BODY_NOISE,"body_noise"); - gAnimLibrary.animStateSetString(ANIM_AGENT_BREATHE_ROT,"breathe_rot"); - gAnimLibrary.animStateSetString(ANIM_AGENT_EDITING,"editing"); - gAnimLibrary.animStateSetString(ANIM_AGENT_EYE,"eye"); - gAnimLibrary.animStateSetString(ANIM_AGENT_FLY_ADJUST,"fly_adjust"); - gAnimLibrary.animStateSetString(ANIM_AGENT_HAND_MOTION,"hand_motion"); - gAnimLibrary.animStateSetString(ANIM_AGENT_HEAD_ROT,"head_rot"); - gAnimLibrary.animStateSetString(ANIM_AGENT_PELVIS_FIX,"pelvis_fix"); - gAnimLibrary.animStateSetString(ANIM_AGENT_TARGET,"target"); - gAnimLibrary.animStateSetString(ANIM_AGENT_WALK_ADJUST,"walk_adjust"); -} - - -void LLVOAvatar::cleanupClass() -{ - deleteAndClear(sAvatarXmlInfo); - sSkeletonXMLTree.cleanup(); - sXMLTree.cleanup(); -} - -void LLVOAvatar::initInstance(void) -{ - //------------------------------------------------------------------------- - // initialize joint, mesh and shape members - //------------------------------------------------------------------------- - mRoot.setName( "mRoot" ); - - for (LLVOAvatarDictionary::Meshes::const_iterator iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin(); - iter != LLVOAvatarDictionary::getInstance()->getMeshes().end(); - ++iter) - { - const EMeshIndex mesh_index = iter->first; - const LLVOAvatarDictionary::MeshEntry *mesh_dict = iter->second; - LLViewerJoint* joint = new LLViewerJoint(); - joint->setName(mesh_dict->mName); - joint->setMeshID(mesh_index); - mMeshLOD.push_back(joint); - - /* mHairLOD.setName("mHairLOD"); - mHairMesh0.setName("mHairMesh0"); - mHairMesh0.setMeshID(MESH_ID_HAIR); - mHairMesh1.setName("mHairMesh1"); */ - for (U32 lod = 0; lod < mesh_dict->mLOD; lod++) - { - LLViewerJointMesh* mesh = new LLViewerJointMesh(); - std::string mesh_name = "m" + mesh_dict->mName + boost::lexical_cast(lod); - // We pre-pended an m - need to capitalize first character for camelCase - mesh_name[1] = toupper(mesh_name[1]); - mesh->setName(mesh_name); - mesh->setMeshID(mesh_index); - mesh->setPickName(mesh_dict->mPickName); - mesh->setIsTransparent(FALSE); - switch((int)mesh_index) - { - case MESH_ID_HAIR: - mesh->setIsTransparent(TRUE); - break; - case MESH_ID_SKIRT: - mesh->setIsTransparent(TRUE); - break; - case MESH_ID_EYEBALL_LEFT: - case MESH_ID_EYEBALL_RIGHT: - mesh->setSpecular( LLColor4( 1.0f, 1.0f, 1.0f, 1.0f ), 1.f ); - break; - } - - joint->mMeshParts.push_back(mesh); - } - } - - //------------------------------------------------------------------------- - // associate baked textures with meshes - //------------------------------------------------------------------------- - for (LLVOAvatarDictionary::Meshes::const_iterator iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin(); - iter != LLVOAvatarDictionary::getInstance()->getMeshes().end(); - ++iter) - { - const EMeshIndex mesh_index = iter->first; - const LLVOAvatarDictionary::MeshEntry *mesh_dict = iter->second; - const EBakedTextureIndex baked_texture_index = mesh_dict->mBakedID; - // Skip it if there's no associated baked texture. - if (baked_texture_index == BAKED_NUM_INDICES) continue; - - for (std::vector::iterator iter = mMeshLOD[mesh_index]->mMeshParts.begin(); - iter != mMeshLOD[mesh_index]->mMeshParts.end(); - ++iter) - { - LLViewerJointMesh* mesh = (LLViewerJointMesh*) *iter; - mBakedTextureDatas[(int)baked_texture_index].mMeshes.push_back(mesh); - } - } - - - //------------------------------------------------------------------------- - // register motions - //------------------------------------------------------------------------- - if (LLCharacter::sInstances.size() == 1) - { - LLKeyframeMotion::setVFS(gStaticVFS); - registerMotion( ANIM_AGENT_BUSY, LLNullMotion::create ); - registerMotion( ANIM_AGENT_CROUCH, LLKeyframeStandMotion::create ); - registerMotion( ANIM_AGENT_CROUCHWALK, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_EXPRESS_AFRAID, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_ANGER, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_BORED, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_CRY, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_DISDAIN, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_EMBARRASSED, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_FROWN, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_KISS, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_LAUGH, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_OPEN_MOUTH, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_REPULSED, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_SAD, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_SHRUG, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_SMILE, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_SURPRISE, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_TONGUE_OUT, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_TOOTHSMILE, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_WINK, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_WORRY, LLEmote::create ); - registerMotion( ANIM_AGENT_FEMALE_RUN_NEW, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_FEMALE_WALK_NEW, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_RUN, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_RUN_NEW, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_STAND, LLKeyframeStandMotion::create ); - registerMotion( ANIM_AGENT_STAND_1, LLKeyframeStandMotion::create ); - registerMotion( ANIM_AGENT_STAND_2, LLKeyframeStandMotion::create ); - registerMotion( ANIM_AGENT_STAND_3, LLKeyframeStandMotion::create ); - registerMotion( ANIM_AGENT_STAND_4, LLKeyframeStandMotion::create ); - registerMotion( ANIM_AGENT_STANDUP, LLKeyframeFallMotion::create ); - registerMotion( ANIM_AGENT_TURNLEFT, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_TURNRIGHT, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_WALK, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_WALK_NEW, LLKeyframeWalkMotion::create ); - - // motions without a start/stop bit - registerMotion( ANIM_AGENT_BODY_NOISE, LLBodyNoiseMotion::create ); - registerMotion( ANIM_AGENT_BREATHE_ROT, LLBreatheMotionRot::create ); - registerMotion( ANIM_AGENT_EDITING, LLEditingMotion::create ); - registerMotion( ANIM_AGENT_EYE, LLEyeMotion::create ); - registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_FLY_ADJUST, LLFlyAdjustMotion::create ); - registerMotion( ANIM_AGENT_HAND_MOTION, LLHandMotion::create ); - registerMotion( ANIM_AGENT_HEAD_ROT, LLHeadRotMotion::create ); - registerMotion( ANIM_AGENT_PELVIS_FIX, LLPelvisFixMotion::create ); - registerMotion( ANIM_AGENT_SIT_FEMALE, LLKeyframeMotion::create ); - registerMotion( ANIM_AGENT_TARGET, LLTargetingMotion::create ); - registerMotion( ANIM_AGENT_WALK_ADJUST, LLWalkAdjustMotion::create ); - - } - - if (gNoRender) - { - return; - } - - buildCharacter(); - - if (gNoRender) - { - return; - } - - // preload specific motions here - createMotion( ANIM_AGENT_CUSTOMIZE); - createMotion( ANIM_AGENT_CUSTOMIZE_DONE); - - //VTPause(); // VTune - - mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) ); - -} - -const LLVector3 LLVOAvatar::getRenderPosition() const -{ - if (mDrawable.isNull() || mDrawable->getGeneration() < 0) - { - return getPositionAgent(); - } - else if (isRoot()) - { - return mDrawable->getPositionAgent(); - } - else - { - return getPosition() * mDrawable->getParent()->getRenderMatrix(); - } -} - -void LLVOAvatar::updateDrawable(BOOL force_damped) -{ - clearChanged(SHIFTED); -} - -void LLVOAvatar::onShift(const LLVector4a& shift_vector) -{ - const LLVector3& shift = reinterpret_cast(shift_vector); - mLastAnimExtents[0] += shift; - mLastAnimExtents[1] += shift; - mNeedsImpostorUpdate = TRUE; - mNeedsAnimUpdate = TRUE; -} - -void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) -{ - if (isImpostor() && !needsImpostorUpdate()) - { - LLVector3 delta = getRenderPosition() - - ((LLVector3(mDrawable->getPositionGroup().getF32ptr())-mImpostorOffset)); - - newMin.load3( (mLastAnimExtents[0] + delta).mV); - newMax.load3( (mLastAnimExtents[1] + delta).mV); - } - else - { - getSpatialExtents(newMin,newMax); - mLastAnimExtents[0].set(newMin.getF32ptr()); - mLastAnimExtents[1].set(newMax.getF32ptr()); - LLVector4a pos_group; - pos_group.setAdd(newMin,newMax); - pos_group.mul(0.5f); - mImpostorOffset = LLVector3(pos_group.getF32ptr())-getRenderPosition(); - mDrawable->setPositionGroup(pos_group); - } -} - -void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) -{ - LLVector4a buffer(0.25f); - LLVector4a pos; - pos.load3(getRenderPosition().mV); - newMin.setSub(pos, buffer); - newMax.setAdd(pos, buffer); - - float max_attachment_span = get_default_max_prim_scale() * 5.0f; - - //stretch bounding box by joint positions - for (polymesh_map_t::iterator i = mMeshes.begin(); i != mMeshes.end(); ++i) - { - LLPolyMesh* mesh = i->second; - for (S32 joint_num = 0; joint_num < mesh->mJointRenderData.count(); joint_num++) - { - LLVector4a trans; - trans.load3( mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation().mV); - update_min_max(newMin, newMax, trans); - } - } - - LLVector4a center, size; - center.setAdd(newMin, newMax); - center.mul(0.5f); - - size.setSub(newMax,newMin); - size.mul(0.5f); - - mPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance()); - - //stretch bounding box by attachments - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - - if (!attachment->getValid()) - { - continue ; - } - - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - const LLViewerObject* attached_object = (*attachment_iter); - if (attached_object && !attached_object->isHUDAttachment()) - { - LLDrawable* drawable = attached_object->mDrawable; - if (drawable) - { - LLSpatialBridge* bridge = drawable->getSpatialBridge(); - if (bridge) - { - const LLVector4a* ext = bridge->getSpatialExtents(); - LLVector4a distance; - distance.setSub(ext[1], ext[0]); - LLVector4a max_span(max_attachment_span); - - S32 lt = distance.lessThan(max_span).getGatheredBits() & 0x7; - - // Only add the prim to spatial extents calculations if it isn't a megaprim. - // max_attachment_span calculated at the start of the function - // (currently 5 times our max prim size) - if (lt == 0x7) - { - update_min_max(newMin,newMax,ext[0]); - update_min_max(newMin,newMax,ext[1]); - } - } - } - } - } - } - - //pad bounding box - - newMin.sub(buffer); - newMax.add(buffer); -} - -//----------------------------------------------------------------------------- -// renderCollisionVolumes() -//----------------------------------------------------------------------------- -void LLVOAvatar::renderCollisionVolumes() -{ - for (S32 i = 0; i < mNumCollisionVolumes; i++) - { - mCollisionVolumes[i].renderCollision(); - } - - if (mNameText.notNull()) - { - LLVector3 unused; - mNameText->lineSegmentIntersect(LLVector3(0,0,0), LLVector3(0,0,1), unused, TRUE); - } -} - -BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, - S32 face, - BOOL pick_transparent, - S32* face_hit, - LLVector3* intersection, - LLVector2* tex_coord, - LLVector3* normal, - LLVector3* bi_normal) -{ - if ((isSelf() && !gAgent.needsRenderAvatar()) || !LLPipeline::sPickAvatar) - { - return FALSE; - } - - if (lineSegmentBoundingBox(start, end)) - { - for (S32 i = 0; i < mNumCollisionVolumes; ++i) - { - mCollisionVolumes[i].updateWorldMatrix(); - - glh::matrix4f mat((F32*) mCollisionVolumes[i].getXform()->getWorldMatrix().mMatrix); - glh::matrix4f inverse = mat.inverse(); - glh::matrix4f norm_mat = inverse.transpose(); - - glh::vec3f p1(start.mV); - glh::vec3f p2(end.mV); - - inverse.mult_matrix_vec(p1); - inverse.mult_matrix_vec(p2); - - LLVector3 position; - LLVector3 norm; - - if (linesegment_sphere(LLVector3(p1.v), LLVector3(p2.v), LLVector3(0,0,0), 1.f, position, norm)) - { - glh::vec3f res_pos(position.mV); - mat.mult_matrix_vec(res_pos); - - norm.normalize(); - glh::vec3f res_norm(norm.mV); - norm_mat.mult_matrix_dir(res_norm); - - if (intersection) - { - *intersection = LLVector3(res_pos.v); - } - - if (normal) - { - *normal = LLVector3(res_norm.v); - } - - return TRUE; - } - } - } - - LLVector3 position; - if (mNameText.notNull() && mNameText->lineSegmentIntersect(start, end, position)) - { - if (intersection) - { - *intersection = position; - } - - return TRUE; - } - - return FALSE; -} - -//----------------------------------------------------------------------------- -// parseSkeletonFile() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::parseSkeletonFile(const std::string& filename) -{ - LLMemType mt(LLMemType::MTYPE_AVATAR); - - //------------------------------------------------------------------------- - // parse the file - //------------------------------------------------------------------------- - BOOL parsesuccess = sSkeletonXMLTree.parseFile( filename, FALSE ); - - if (!parsesuccess) - { - llerrs << "Can't parse skeleton file: " << filename << llendl; - return FALSE; - } - - // now sanity check xml file - LLXmlTreeNode* root = sSkeletonXMLTree.getRoot(); - if (!root) - { - llerrs << "No root node found in avatar skeleton file: " << filename << llendl; - return FALSE; - } - - if( !root->hasName( "linden_skeleton" ) ) - { - llerrs << "Invalid avatar skeleton file header: " << filename << llendl; - return FALSE; - } - - std::string version; - static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); - if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") ) - { - llerrs << "Invalid avatar skeleton file version: " << version << " in file: " << filename << llendl; - return FALSE; - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// setupBone() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::setupBone(const LLVOAvatarBoneInfo* info, LLViewerJoint* parent, S32 &volume_num, S32 &joint_num) -{ - LLMemType mt(LLMemType::MTYPE_AVATAR); - - LLViewerJoint* joint = NULL; - - if (info->mIsJoint) - { - joint = (LLViewerJoint*)getCharacterJoint(joint_num); - if (!joint) - { - llwarns << "Too many bones" << llendl; - return FALSE; - } - joint->setName( info->mName ); - } - else // collision volume - { - if (volume_num >= (S32)mNumCollisionVolumes) - { - llwarns << "Too many bones" << llendl; - return FALSE; - } - joint = (LLViewerJoint*)(&mCollisionVolumes[volume_num]); - joint->setName( info->mName ); - } - - // add to parent - if (parent) - { - parent->addChild( joint ); - } - - joint->setPosition(info->mPos); - joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY], - info->mRot.mV[VZ], LLQuaternion::XYZ)); - joint->setScale(info->mScale); - - joint->setDefaultFromCurrentXform(); - - if (info->mIsJoint) - { - joint->setSkinOffset( info->mPivot ); - joint_num++; - } - else // collision volume - { - volume_num++; - } - - // setup children - LLVOAvatarBoneInfo::child_list_t::const_iterator iter; - for (iter = info->mChildList.begin(); iter != info->mChildList.end(); ++iter) - { - LLVOAvatarBoneInfo *child_info = *iter; - if (!setupBone(child_info, joint, volume_num, joint_num)) - { - return FALSE; - } - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// buildSkeleton() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::buildSkeleton(const LLVOAvatarSkeletonInfo *info) -{ - LLMemType mt(LLMemType::MTYPE_AVATAR); - - //------------------------------------------------------------------------- - // allocate joints - //------------------------------------------------------------------------- - if (!allocateCharacterJoints(info->mNumBones)) - { - llerrs << "Can't allocate " << info->mNumBones << " joints" << llendl; - return FALSE; - } - - //------------------------------------------------------------------------- - // allocate volumes - //------------------------------------------------------------------------- - if (info->mNumCollisionVolumes) - { - if (!allocateCollisionVolumes(info->mNumCollisionVolumes)) - { - llerrs << "Can't allocate " << info->mNumCollisionVolumes << " collision volumes" << llendl; - return FALSE; - } - } - - S32 current_joint_num = 0; - S32 current_volume_num = 0; - LLVOAvatarSkeletonInfo::bone_info_list_t::const_iterator iter; - for (iter = info->mBoneInfoList.begin(); iter != info->mBoneInfoList.end(); ++iter) - { - LLVOAvatarBoneInfo *info = *iter; - if (!setupBone(info, NULL, current_volume_num, current_joint_num)) - { - llerrs << "Error parsing bone in skeleton file" << llendl; - return FALSE; - } - } - - return TRUE; -} - -LLVOAvatar* LLVOAvatar::asAvatar() -{ - return this; -} - -//----------------------------------------------------------------------------- -// LLVOAvatar::startDefaultMotions() -//----------------------------------------------------------------------------- -void LLVOAvatar::startDefaultMotions() -{ - //------------------------------------------------------------------------- - // start default motions - //------------------------------------------------------------------------- - startMotion( ANIM_AGENT_HEAD_ROT ); - startMotion( ANIM_AGENT_EYE ); - startMotion( ANIM_AGENT_BODY_NOISE ); - startMotion( ANIM_AGENT_BREATHE_ROT ); - startMotion( ANIM_AGENT_HAND_MOTION ); - startMotion( ANIM_AGENT_PELVIS_FIX ); - - //------------------------------------------------------------------------- - // restart any currently active motions - //------------------------------------------------------------------------- - processAnimationStateChanges(); -} - -//----------------------------------------------------------------------------- -// LLVOAvatar::buildCharacter() -// Deferred initialization and rebuild of the avatar. -//----------------------------------------------------------------------------- -void LLVOAvatar::buildCharacter() -{ - LLMemType mt(LLMemType::MTYPE_AVATAR); - - //------------------------------------------------------------------------- - // remove all references to our existing skeleton - // so we can rebuild it - //------------------------------------------------------------------------- - flushAllMotions(); - - //------------------------------------------------------------------------- - // remove all of mRoot's children - //------------------------------------------------------------------------- - mRoot.removeAllChildren(); - mIsBuilt = FALSE; - - //------------------------------------------------------------------------- - // clear mesh data - //------------------------------------------------------------------------- - for (std::vector::iterator jointIter = mMeshLOD.begin(); - jointIter != mMeshLOD.end(); ++jointIter) - { - LLViewerJoint* joint = (LLViewerJoint*) *jointIter; - for (std::vector::iterator meshIter = joint->mMeshParts.begin(); - meshIter != joint->mMeshParts.end(); ++meshIter) - { - LLViewerJointMesh * mesh = (LLViewerJointMesh *) *meshIter; - mesh->setMesh(NULL); - } - } - - //------------------------------------------------------------------------- - // (re)load our skeleton and meshes - //------------------------------------------------------------------------- - LLTimer timer; - - BOOL status = loadAvatar(); - stop_glerror(); - - if (gNoRender) - { - // Still want to load the avatar skeleton so visual parameters work. - return; - } - -// gPrintMessagesThisFrame = TRUE; - lldebugs << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << llendl; - - if (!status) - { - if (isSelf()) - { - llerrs << "Unable to load user's avatar" << llendl; - } - else - { - llwarns << "Unable to load other's avatar" << llendl; - } - return; - } - - //------------------------------------------------------------------------- - // initialize "well known" joint pointers - //------------------------------------------------------------------------- - mPelvisp = (LLViewerJoint*)mRoot.findJoint("mPelvis"); - mTorsop = (LLViewerJoint*)mRoot.findJoint("mTorso"); - mChestp = (LLViewerJoint*)mRoot.findJoint("mChest"); - mNeckp = (LLViewerJoint*)mRoot.findJoint("mNeck"); - mHeadp = (LLViewerJoint*)mRoot.findJoint("mHead"); - mSkullp = (LLViewerJoint*)mRoot.findJoint("mSkull"); - mHipLeftp = (LLViewerJoint*)mRoot.findJoint("mHipLeft"); - mHipRightp = (LLViewerJoint*)mRoot.findJoint("mHipRight"); - mKneeLeftp = (LLViewerJoint*)mRoot.findJoint("mKneeLeft"); - mKneeRightp = (LLViewerJoint*)mRoot.findJoint("mKneeRight"); - mAnkleLeftp = (LLViewerJoint*)mRoot.findJoint("mAnkleLeft"); - mAnkleRightp = (LLViewerJoint*)mRoot.findJoint("mAnkleRight"); - mFootLeftp = (LLViewerJoint*)mRoot.findJoint("mFootLeft"); - mFootRightp = (LLViewerJoint*)mRoot.findJoint("mFootRight"); - mWristLeftp = (LLViewerJoint*)mRoot.findJoint("mWristLeft"); - mWristRightp = (LLViewerJoint*)mRoot.findJoint("mWristRight"); - mEyeLeftp = (LLViewerJoint*)mRoot.findJoint("mEyeLeft"); - mEyeRightp = (LLViewerJoint*)mRoot.findJoint("mEyeRight"); - - //------------------------------------------------------------------------- - // Make sure "well known" pointers exist - //------------------------------------------------------------------------- - if (!(mPelvisp && - mTorsop && - mChestp && - mNeckp && - mHeadp && - mSkullp && - mHipLeftp && - mHipRightp && - mKneeLeftp && - mKneeRightp && - mAnkleLeftp && - mAnkleRightp && - mFootLeftp && - mFootRightp && - mWristLeftp && - mWristRightp && - mEyeLeftp && - mEyeRightp)) - { - llerrs << "Failed to create avatar." << llendl; - return; - } - - //------------------------------------------------------------------------- - // initialize the pelvis - //------------------------------------------------------------------------- - mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) ); - - //------------------------------------------------------------------------- - // set head offset from pelvis - //------------------------------------------------------------------------- - updateHeadOffset(); - - //------------------------------------------------------------------------- - // initialize lip sync morph pointers - //------------------------------------------------------------------------- - mOohMorph = getVisualParam( "Lipsync_Ooh" ); - mAahMorph = getVisualParam( "Lipsync_Aah" ); - - // If we don't have the Ooh morph, use the Kiss morph - if (!mOohMorph) - { - llwarns << "Missing 'Ooh' morph for lipsync, using fallback." << llendl; - mOohMorph = getVisualParam( "Express_Kiss" ); - } - - // If we don't have the Aah morph, use the Open Mouth morph - if (!mAahMorph) - { - llwarns << "Missing 'Aah' morph for lipsync, using fallback." << llendl; - mAahMorph = getVisualParam( "Express_Open_Mouth" ); - } - - startDefaultMotions(); - - //------------------------------------------------------------------------- - // restart any currently active motions - //------------------------------------------------------------------------- - processAnimationStateChanges(); - - mIsBuilt = TRUE; - stop_glerror(); - - mMeshValid = TRUE; -} - - -//----------------------------------------------------------------------------- -// releaseMeshData() -//----------------------------------------------------------------------------- -void LLVOAvatar::releaseMeshData() -{ - LLMemType mt(LLMemType::MTYPE_AVATAR); - - if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || mIsDummy) - { - return; - } - - //llinfos << "Releasing" << llendl; - - // cleanup mesh data - for (std::vector::iterator iter = mMeshLOD.begin(); - iter != mMeshLOD.end(); - ++iter) - { - LLViewerJoint* joint = (LLViewerJoint*) *iter; - joint->setValid(FALSE, TRUE); - } - - //cleanup data - if (mDrawable.notNull()) - { - LLFace* facep = mDrawable->getFace(0); - facep->setSize(0, 0); - for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++) - { - facep = mDrawable->getFace(i); - facep->setSize(0, 0); - } - } - - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - if (!attachment->getIsHUDAttachment()) - { - attachment->setAttachmentVisibility(FALSE); - } - } - mMeshValid = FALSE; -} - -//----------------------------------------------------------------------------- -// restoreMeshData() -//----------------------------------------------------------------------------- -// virtual -void LLVOAvatar::restoreMeshData() -{ - llassert(!isSelf()); - LLMemType mt(LLMemType::MTYPE_AVATAR); - - //llinfos << "Restoring" << llendl; - mMeshValid = TRUE; - updateJointLODs(); - - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - if (!attachment->getIsHUDAttachment()) - { - attachment->setAttachmentVisibility(TRUE); - } - } - - // force mesh update as LOD might not have changed to trigger this - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); -} - -//----------------------------------------------------------------------------- -// updateMeshData() -//----------------------------------------------------------------------------- -void LLVOAvatar::updateMeshData() -{ - if (mDrawable.notNull()) - { - stop_glerror(); - - S32 f_num = 0 ; - const U32 VERTEX_NUMBER_THRESHOLD = 128 ;//small number of this means each part of an avatar has its own vertex buffer. - const S32 num_parts = mMeshLOD.size(); - - // this order is determined by number of LODS - // if a mesh earlier in this list changed LODs while a later mesh doesn't, - // the later mesh's index offset will be inaccurate - for(S32 part_index = 0 ; part_index < num_parts ;) - { - S32 j = part_index ; - U32 last_v_num = 0, num_vertices = 0 ; - U32 last_i_num = 0, num_indices = 0 ; - - while(part_index < num_parts && num_vertices < VERTEX_NUMBER_THRESHOLD) - { - last_v_num = num_vertices ; - last_i_num = num_indices ; - - mMeshLOD[part_index++]->updateFaceSizes(num_vertices, num_indices, mAdjustedPixelArea); - } - if(num_vertices < 1)//skip empty meshes - { - continue ; - } - if(last_v_num > 0)//put the last inserted part into next vertex buffer. - { - num_vertices = last_v_num ; - num_indices = last_i_num ; - part_index-- ; - } - - LLFace* facep ; - if(f_num < mDrawable->getNumFaces()) - { - facep = mDrawable->getFace(f_num); - } - else - { - facep = mDrawable->addFace(mDrawable->getFace(0)->getPool(), mDrawable->getFace(0)->getTexture()) ; - } - - // resize immediately - facep->setSize(num_vertices, num_indices); - - bool terse_update = false; - - if(facep->mVertexBuffer.isNull()) - { - facep->mVertexBuffer = new LLVertexBufferAvatar(); - facep->mVertexBuffer->allocateBuffer(num_vertices, num_indices, TRUE); - } - else - { - if (facep->mVertexBuffer->getRequestedIndices() == num_indices && - facep->mVertexBuffer->getRequestedVerts() == num_vertices) - { - terse_update = true; - } - else - { - facep->mVertexBuffer->resizeBuffer(num_vertices, num_indices) ; - } - } - - facep->setGeomIndex(0); - facep->setIndicesIndex(0); - - // This is a hack! Avatars have their own pool, so we are detecting - // the case of more than one avatar in the pool (thus > 0 instead of >= 0) - if (facep->getGeomIndex() > 0) - { - llerrs << "non-zero geom index: " << facep->getGeomIndex() << " in LLVOAvatar::restoreMeshData" << llendl; - } - - for(S32 k = j ; k < part_index ; k++) - { - mMeshLOD[k]->updateFaceData(facep, mAdjustedPixelArea, k == MESH_ID_HAIR, terse_update); - } - - stop_glerror(); - facep->mVertexBuffer->setBuffer(0); - - if(!f_num) - { - f_num += mNumInitFaces ; - } - else - { - f_num++ ; - } - } - } -} - -//------------------------------------------------------------------------ - -//------------------------------------------------------------------------ -// The viewer can only suggest a good size for the agent, -// the simulator will keep it inside a reasonable range. -void LLVOAvatar::computeBodySize() -{ - LLVector3 pelvis_scale = mPelvisp->getScale(); - - // some of the joints have not been cached - LLVector3 skull = mSkullp->getPosition(); - LLVector3 skull_scale = mSkullp->getScale(); - - LLVector3 neck = mNeckp->getPosition(); - LLVector3 neck_scale = mNeckp->getScale(); - - LLVector3 chest = mChestp->getPosition(); - LLVector3 chest_scale = mChestp->getScale(); - - // the rest of the joints have been cached - LLVector3 head = mHeadp->getPosition(); - LLVector3 head_scale = mHeadp->getScale(); - - LLVector3 torso = mTorsop->getPosition(); - LLVector3 torso_scale = mTorsop->getScale(); - - LLVector3 hip = mHipLeftp->getPosition(); - LLVector3 hip_scale = mHipLeftp->getScale(); - - LLVector3 knee = mKneeLeftp->getPosition(); - LLVector3 knee_scale = mKneeLeftp->getScale(); - - LLVector3 ankle = mAnkleLeftp->getPosition(); - LLVector3 ankle_scale = mAnkleLeftp->getScale(); - - LLVector3 foot = mFootLeftp->getPosition(); - - mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] - - knee.mV[VZ] * hip_scale.mV[VZ] - - ankle.mV[VZ] * knee_scale.mV[VZ] - - foot.mV[VZ] * ankle_scale.mV[VZ]; - - LLVector3 new_body_size; - new_body_size.mV[VZ] = mPelvisToFoot + - // the sqrt(2) correction below is an approximate - // correction to get to the top of the head - F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) + - head.mV[VZ] * neck_scale.mV[VZ] + - neck.mV[VZ] * chest_scale.mV[VZ] + - chest.mV[VZ] * torso_scale.mV[VZ] + - torso.mV[VZ] * pelvis_scale.mV[VZ]; - - // TODO -- measure the real depth and width - new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH; - new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH; - - if (new_body_size != mBodySize) - { - mBodySize = new_body_size; - - if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF()) - { // notify simulator of change in size - // but not if we are in the middle of updating appearance - gAgent.sendAgentSetAppearance(); - } - } -} - -//------------------------------------------------------------------------ -// LLVOAvatar::processUpdateMessage() -//------------------------------------------------------------------------ -U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys, - void **user_data, - U32 block_num, const EObjectUpdateType update_type, - LLDataPacker *dp) -{ - LLMemType mt(LLMemType::MTYPE_AVATAR); - - LLVector3 old_vel = getVelocity(); - const BOOL has_name = !getNVPair("FirstName"); - - // Do base class updates... - U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); - - // Print out arrival information once we have name of avatar. - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) - { - if (has_name && getNVPair("FirstName")) - { - mDebugExistenceTimer.reset(); - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezArrivedNotification",args); - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' arrived." << llendl; - } - } - if(retval & LLViewerObject::INVALID_UPDATE) - { - if (isSelf()) - { - //tell sim to cancel this update - gAgent.teleportViaLocation(gAgent.getPositionGlobal()); - } - } - - //llinfos << getRotation() << llendl; - //llinfos << getPosition() << llendl; - - return retval; -} - -// virtual -S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid) -{ - // The core setTETexture() method requests images, so we need - // to redirect certain avatar texture requests to different sims. - if (isIndexBakedTexture((ETextureIndex)te)) - { - LLHost target_host = getObjectHost(); - return setTETextureCore(te, uuid, target_host); - } - else - { - return setTETextureCore(te, uuid, LLHost::invalid); - } -} - -static LLFastTimer::DeclareTimer FTM_AVATAR_UPDATE("Update Avatar"); -static LLFastTimer::DeclareTimer FTM_JOINT_UPDATE("Update Joints"); - -//------------------------------------------------------------------------ -// LLVOAvatar::dumpAnimationState() -//------------------------------------------------------------------------ -void LLVOAvatar::dumpAnimationState() -{ - llinfos << "==============================================" << llendl; - for (LLVOAvatar::AnimIterator it = mSignaledAnimations.begin(); it != mSignaledAnimations.end(); ++it) - { - LLUUID id = it->first; - std::string playtag = ""; - if (mPlayingAnimations.find(id) != mPlayingAnimations.end()) - { - playtag = "*"; - } - llinfos << gAnimLibrary.animationName(id) << playtag << llendl; - } - for (LLVOAvatar::AnimIterator it = mPlayingAnimations.begin(); it != mPlayingAnimations.end(); ++it) - { - LLUUID id = it->first; - bool is_signaled = mSignaledAnimations.find(id) != mSignaledAnimations.end(); - if (!is_signaled) - { - llinfos << gAnimLibrary.animationName(id) << "!S" << llendl; - } - } -} - -//------------------------------------------------------------------------ -// idleUpdate() -//------------------------------------------------------------------------ -BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) -{ - LLMemType mt(LLMemType::MTYPE_AVATAR); - LLFastTimer t(FTM_AVATAR_UPDATE); - - if (isDead()) - { - llinfos << "Warning! Idle on dead avatar" << llendl; - return TRUE; - } - - if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR))) - { - return TRUE; - } - - checkTextureLoading() ; - - // force immediate pixel area update on avatars using last frames data (before drawable or camera updates) - setPixelAreaAndAngle(gAgent); - - // force asynchronous drawable update - if(mDrawable.notNull() && !gNoRender) - { - LLFastTimer t(FTM_JOINT_UPDATE); - - if (mIsSitting && getParent()) - { - LLViewerObject *root_object = (LLViewerObject*)getRoot(); - LLDrawable* drawablep = root_object->mDrawable; - // if this object hasn't already been updated by another avatar... - if (drawablep) // && !drawablep->isState(LLDrawable::EARLY_MOVE)) - { - if (root_object->isSelected()) - { - gPipeline.updateMoveNormalAsync(drawablep); - } - else - { - gPipeline.updateMoveDampedAsync(drawablep); - } - } - } - else - { - gPipeline.updateMoveDampedAsync(mDrawable); - } - } - - //-------------------------------------------------------------------- - // set alpha flag depending on state - //-------------------------------------------------------------------- - - if (isSelf()) - { - LLViewerObject::idleUpdate(agent, world, time); - - // trigger fidget anims - if (isAnyAnimationSignaled(AGENT_STAND_ANIMS, NUM_AGENT_STAND_ANIMS)) - { - agent.fidget(); - } - } - else - { - // Should override the idleUpdate stuff and leave out the angular update part. - LLQuaternion rotation = getRotation(); - LLViewerObject::idleUpdate(agent, world, time); - setRotation(rotation); - } - - // attach objects that were waiting for a drawable - lazyAttach(); - - // animate the character - // store off last frame's root position to be consistent with camera position - LLVector3 root_pos_last = mRoot.getWorldPosition(); - BOOL detailed_update = updateCharacter(agent); - - if (gNoRender) - { - return TRUE; - } - - static LLUICachedControl visualizers_in_calls("ShowVoiceVisualizersInCalls", false); - bool voice_enabled = (visualizers_in_calls || LLVoiceClient::getInstance()->inProximalChannel()) && - LLVoiceClient::getInstance()->getVoiceEnabled(mID); - - idleUpdateVoiceVisualizer( voice_enabled ); - idleUpdateMisc( detailed_update ); - idleUpdateAppearanceAnimation(); - if (detailed_update) - { - idleUpdateLipSync( voice_enabled ); - idleUpdateLoadingEffect(); - idleUpdateBelowWater(); // wind effect uses this - idleUpdateWindEffect(); - } - - idleUpdateNameTag( root_pos_last ); - idleUpdateRenderCost(); - - return TRUE; -} - -void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) -{ - bool render_visualizer = voice_enabled; - - // Don't render the user's own voice visualizer when in mouselook, or when opening the mic is disabled. - if(isSelf()) - { - if(gAgentCamera.cameraMouselook() || gSavedSettings.getBOOL("VoiceDisableMic")) - { - render_visualizer = false; - } - } - - mVoiceVisualizer->setVoiceEnabled(render_visualizer); - - if ( voice_enabled ) - { - //---------------------------------------------------------------- - // Only do gesture triggering for your own avatar, and only when you're in a proximal channel. - //---------------------------------------------------------------- - if( isSelf() ) - { - //---------------------------------------------------------------------------------------- - // The following takes the voice signal and uses that to trigger gesticulations. - //---------------------------------------------------------------------------------------- - int lastGesticulationLevel = mCurrentGesticulationLevel; - mCurrentGesticulationLevel = mVoiceVisualizer->getCurrentGesticulationLevel(); - - //--------------------------------------------------------------------------------------------------- - // If "current gesticulation level" changes, we catch this, and trigger the new gesture - //--------------------------------------------------------------------------------------------------- - if ( lastGesticulationLevel != mCurrentGesticulationLevel ) - { - if ( mCurrentGesticulationLevel != VOICE_GESTICULATION_LEVEL_OFF ) - { - std::string gestureString = "unInitialized"; - if ( mCurrentGesticulationLevel == 0 ) { gestureString = "/voicelevel1"; } - else if ( mCurrentGesticulationLevel == 1 ) { gestureString = "/voicelevel2"; } - else if ( mCurrentGesticulationLevel == 2 ) { gestureString = "/voicelevel3"; } - else { llinfos << "oops - CurrentGesticulationLevel can be only 0, 1, or 2" << llendl; } - - // this is the call that Karl S. created for triggering gestures from within the code. - LLGestureMgr::instance().triggerAndReviseString( gestureString ); - } - } - - } //if( isSelf() ) - - //----------------------------------------------------------------------------------------------------------------- - // If the avatar is speaking, then the voice amplitude signal is passed to the voice visualizer. - // Also, here we trigger voice visualizer start and stop speaking, so it can animate the voice symbol. - // - // Notice the calls to "gAwayTimer.reset()". This resets the timer that determines how long the avatar has been - // "away", so that the avatar doesn't lapse into away-mode (and slump over) while the user is still talking. - //----------------------------------------------------------------------------------------------------------------- - if (LLVoiceClient::getInstance()->getIsSpeaking( mID )) - { - if (!mVoiceVisualizer->getCurrentlySpeaking()) - { - mVoiceVisualizer->setStartSpeaking(); - - //printf( "gAwayTimer.reset();\n" ); - } - - mVoiceVisualizer->setSpeakingAmplitude( LLVoiceClient::getInstance()->getCurrentPower( mID ) ); - - if( isSelf() ) - { - gAgent.clearAFK(); - } - } - else - { - if ( mVoiceVisualizer->getCurrentlySpeaking() ) - { - mVoiceVisualizer->setStopSpeaking(); - - if ( mLipSyncActive ) - { - if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight(), FALSE); - if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight(), FALSE); - - mLipSyncActive = false; - LLCharacter::updateVisualParams(); - dirtyMesh(); - } - } - } - - //-------------------------------------------------------------------------------------------- - // here we get the approximate head position and set as sound source for the voice symbol - // (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing) - //-------------------------------------------------------------------------------------------- - - if ( mIsSitting ) - { - LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] ); - mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset ); - } - else - { - LLVector3 tagPos = mRoot.getWorldPosition(); - tagPos[VZ] -= mPelvisToFoot; - tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); - mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos ); - } - }//if ( voiceEnabled ) -} - -static LLFastTimer::DeclareTimer FTM_ATTACHMENT_UPDATE("Update Attachments"); - -void LLVOAvatar::idleUpdateMisc(bool detailed_update) -{ - if (LLVOAvatar::sJointDebug) - { - llinfos << getFullname() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << llendl; - } - - LLJoint::sNumUpdates = 0; - LLJoint::sNumTouches = 0; - - BOOL visible = isVisible() || mNeedsAnimUpdate; - - // update attachments positions - if (detailed_update || !sUseImpostors) - { - LLFastTimer t(FTM_ATTACHMENT_UPDATE); - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - LLViewerObject* attached_object = (*attachment_iter); - BOOL visibleAttachment = visible || (attached_object && - !(attached_object->mDrawable->getSpatialBridge() && - attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0)); - - if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid()) - { - // if selecting any attachments, update all of them as non-damped - if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment()) - { - gPipeline.updateMoveNormalAsync(attached_object->mDrawable); - } - else - { - gPipeline.updateMoveDampedAsync(attached_object->mDrawable); - } - - LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge(); - if (bridge) - { - gPipeline.updateMoveNormalAsync(bridge); - } - attached_object->updateText(); - } - } - } - } - - mNeedsAnimUpdate = FALSE; - - if (isImpostor() && !mNeedsImpostorUpdate) - { - LLVector4a ext[2]; - F32 distance; - LLVector3 angle; - - getImpostorValues(ext, angle, distance); - - for (U32 i = 0; i < 3 && !mNeedsImpostorUpdate; i++) - { - F32 cur_angle = angle.mV[i]; - F32 old_angle = mImpostorAngle.mV[i]; - F32 angle_diff = fabsf(cur_angle-old_angle); - - if (angle_diff > F_PI/512.f*distance*mUpdatePeriod) - { - mNeedsImpostorUpdate = TRUE; - } - } - - if (detailed_update && !mNeedsImpostorUpdate) - { //update impostor if view angle, distance, or bounding box change - //significantly - - F32 dist_diff = fabsf(distance-mImpostorDistance); - if (dist_diff/mImpostorDistance > 0.1f) - { - mNeedsImpostorUpdate = TRUE; - } - else - { - //VECTORIZE THIS - getSpatialExtents(ext[0], ext[1]); - LLVector4a diff; - diff.setSub(ext[1], mImpostorExtents[1]); - if (diff.getLength3().getF32() > 0.05f) - { - mNeedsImpostorUpdate = TRUE; - } - else - { - diff.setSub(ext[0], mImpostorExtents[0]); - if (diff.getLength3().getF32() > 0.05f) - { - mNeedsImpostorUpdate = TRUE; - } - } - } - } - } - - mDrawable->movePartition(); - - //force a move if sitting on an active object - if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive()) - { - gPipeline.markMoved(mDrawable, TRUE); - } -} - -void LLVOAvatar::idleUpdateAppearanceAnimation() -{ - // update morphing params - if (mAppearanceAnimating) - { - ESex avatar_sex = getSex(); - F32 appearance_anim_time = mAppearanceMorphTimer.getElapsedTimeF32(); - if (appearance_anim_time >= APPEARANCE_MORPH_TIME) - { - mAppearanceAnimating = FALSE; - for (LLVisualParam *param = getFirstVisualParam(); - param; - param = getNextVisualParam()) - { - if (param->isTweakable()) - { - param->stopAnimating(FALSE); - } - } - updateVisualParams(); - if (isSelf()) - { - gAgent.sendAgentSetAppearance(); - } - } - else - { - F32 morph_amt = calcMorphAmount(); - LLVisualParam *param; - - if (!isSelf()) - { - // animate only top level params for non-self avatars - for (param = getFirstVisualParam(); - param; - param = getNextVisualParam()) - { - if (param->isTweakable()) - { - param->animate(morph_amt, FALSE); - } - } - } - - // apply all params - for (param = getFirstVisualParam(); - param; - param = getNextVisualParam()) - { - param->apply(avatar_sex); - } - - mLastAppearanceBlendTime = appearance_anim_time; - } - dirtyMesh(); - } -} - -F32 LLVOAvatar::calcMorphAmount() -{ - F32 appearance_anim_time = mAppearanceMorphTimer.getElapsedTimeF32(); - F32 blend_frac = calc_bouncy_animation(appearance_anim_time / APPEARANCE_MORPH_TIME); - F32 last_blend_frac = calc_bouncy_animation(mLastAppearanceBlendTime / APPEARANCE_MORPH_TIME); - - F32 morph_amt; - if (last_blend_frac == 1.f) - { - morph_amt = 1.f; - } - else - { - morph_amt = (blend_frac - last_blend_frac) / (1.f - last_blend_frac); - } - - return morph_amt; -} - -void LLVOAvatar::idleUpdateLipSync(bool voice_enabled) -{ - // Use the Lipsync_Ooh and Lipsync_Aah morphs for lip sync - if ( voice_enabled && (LLVoiceClient::getInstance()->lipSyncEnabled()) && LLVoiceClient::getInstance()->getIsSpeaking( mID ) ) - { - F32 ooh_morph_amount = 0.0f; - F32 aah_morph_amount = 0.0f; - - mVoiceVisualizer->lipSyncOohAah( ooh_morph_amount, aah_morph_amount ); - - if( mOohMorph ) - { - F32 ooh_weight = mOohMorph->getMinWeight() - + ooh_morph_amount * (mOohMorph->getMaxWeight() - mOohMorph->getMinWeight()); - - mOohMorph->setWeight( ooh_weight, FALSE ); - } - - if( mAahMorph ) - { - F32 aah_weight = mAahMorph->getMinWeight() - + aah_morph_amount * (mAahMorph->getMaxWeight() - mAahMorph->getMinWeight()); - - mAahMorph->setWeight( aah_weight, FALSE ); - } - - mLipSyncActive = true; - LLCharacter::updateVisualParams(); - dirtyMesh(); - } -} - -void LLVOAvatar::idleUpdateLoadingEffect() -{ - // update visibility when avatar is partially loaded - if (updateIsFullyLoaded()) // changed? - { - if (isFullyLoaded() && isSelf()) - { - static bool first_fully_visible = true; - if (first_fully_visible) - { - llinfos << "self isFullyLoaded, first_fully_visible" << llendl; - - first_fully_visible = false; - LLAppearanceMgr::instance().onFirstFullyVisible(); - } - } - if (isFullyLoaded()) - { - deleteParticleSource(); - updateLOD(); - } - else - { - LLPartSysData particle_parameters; - - // fancy particle cloud designed by Brent - particle_parameters.mPartData.mMaxAge = 4.f; - particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f; - particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f; - particle_parameters.mPartData.mStartScale.mV[VY] = 1.0f; - particle_parameters.mPartData.mEndScale.mV[VX] = 0.02f; - particle_parameters.mPartData.mEndScale.mV[VY] = 0.02f; - particle_parameters.mPartData.mStartColor = LLColor4(1, 1, 1, 0.5f); - particle_parameters.mPartData.mEndColor = LLColor4(1, 1, 1, 0.0f); - particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f; - LLViewerTexture* cloud = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c"); - particle_parameters.mPartImageID = cloud->getID(); - particle_parameters.mMaxAge = 0.f; - particle_parameters.mPattern = LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE; - particle_parameters.mInnerAngle = F_PI; - particle_parameters.mOuterAngle = 0.f; - particle_parameters.mBurstRate = 0.02f; - particle_parameters.mBurstRadius = 0.0f; - particle_parameters.mBurstPartCount = 1; - particle_parameters.mBurstSpeedMin = 0.1f; - particle_parameters.mBurstSpeedMax = 1.f; - particle_parameters.mPartData.mFlags = ( LLPartData::LL_PART_INTERP_COLOR_MASK | LLPartData::LL_PART_INTERP_SCALE_MASK | - LLPartData::LL_PART_EMISSIVE_MASK | // LLPartData::LL_PART_FOLLOW_SRC_MASK | - LLPartData::LL_PART_TARGET_POS_MASK ); - - setParticleSource(particle_parameters, getID()); - } - } -} - -void LLVOAvatar::idleUpdateWindEffect() -{ - // update wind effect - if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH)) - { - F32 hover_strength = 0.f; - F32 time_delta = mRippleTimer.getElapsedTimeF32() - mRippleTimeLast; - mRippleTimeLast = mRippleTimer.getElapsedTimeF32(); - LLVector3 velocity = getVelocity(); - F32 speed = velocity.length(); - //RN: velocity varies too much frame to frame for this to work - mRippleAccel.clearVec();//lerp(mRippleAccel, (velocity - mLastVel) * time_delta, LLCriticalDamp::getInterpolant(0.02f)); - mLastVel = velocity; - LLVector4 wind; - wind.setVec(getRegion()->mWind.getVelocityNoisy(getPositionAgent(), 4.f) - velocity); - - if (mInAir) - { - hover_strength = HOVER_EFFECT_STRENGTH * llmax(0.f, HOVER_EFFECT_MAX_SPEED - speed); - } - - if (mBelowWater) - { - // TODO: make cloth flow more gracefully when underwater - hover_strength += UNDERWATER_EFFECT_STRENGTH; - } - - wind.mV[VZ] += hover_strength; - wind.normalize(); - - wind.mV[VW] = llmin(0.025f + (speed * 0.015f) + hover_strength, 0.5f); - F32 interp; - if (wind.mV[VW] > mWindVec.mV[VW]) - { - interp = LLCriticalDamp::getInterpolant(0.2f); - } - else - { - interp = LLCriticalDamp::getInterpolant(0.4f); - } - mWindVec = lerp(mWindVec, wind, interp); - - F32 wind_freq = hover_strength + llclamp(8.f + (speed * 0.7f) + (noise1(mRipplePhase) * 4.f), 8.f, 25.f); - mWindFreq = lerp(mWindFreq, wind_freq, interp); - - if (mBelowWater) - { - mWindFreq *= UNDERWATER_FREQUENCY_DAMP; - } - - mRipplePhase += (time_delta * mWindFreq); - if (mRipplePhase > F_TWO_PI) - { - mRipplePhase = fmodf(mRipplePhase, F_TWO_PI); - } - } -} - -void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) -{ - // update chat bubble - //-------------------------------------------------------------------- - // draw text label over character's head - //-------------------------------------------------------------------- - if (mChatTimer.getElapsedTimeF32() > BUBBLE_CHAT_TIME) - { - mChats.clear(); - } - - const F32 time_visible = mTimeVisible.getElapsedTimeF32(); - const F32 NAME_SHOW_TIME = gSavedSettings.getF32("RenderNameShowTime"); // seconds - const F32 FADE_DURATION = gSavedSettings.getF32("RenderNameFadeDuration"); // seconds - BOOL visible_avatar = isVisible() || mNeedsAnimUpdate; - BOOL visible_chat = gSavedSettings.getBOOL("UseChatBubbles") && (mChats.size() || mTyping); - BOOL render_name = visible_chat || - (visible_avatar && - ((sRenderName == RENDER_NAME_ALWAYS) || - (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME))); - // If it's your own avatar, don't draw in mouselook, and don't - // draw if we're specifically hiding our own name. - if (isSelf()) - { - render_name = render_name - && !gAgentCamera.cameraMouselook() - && (visible_chat || (gSavedSettings.getBOOL("RenderNameShowSelf") - && gSavedSettings.getS32("AvatarNameTagMode") )); - } - - if ( !render_name ) - { - if (mNameText) - { - // ...clean up old name tag - mNameText->markDead(); - mNameText = NULL; - sNumVisibleChatBubbles--; - } - return; - } - - BOOL new_name = FALSE; - if (visible_chat != mVisibleChat) - { - mVisibleChat = visible_chat; - new_name = TRUE; - } - - if (sRenderGroupTitles != mRenderGroupTitles) - { - mRenderGroupTitles = sRenderGroupTitles; - new_name = TRUE; - } - - // First Calculate Alpha - // If alpha > 0, create mNameText if necessary, otherwise delete it - F32 alpha = 0.f; - if (mAppAngle > 5.f) - { - const F32 START_FADE_TIME = NAME_SHOW_TIME - FADE_DURATION; - if (!visible_chat && sRenderName == RENDER_NAME_FADE && time_visible > START_FADE_TIME) - { - alpha = 1.f - (time_visible - START_FADE_TIME) / FADE_DURATION; - } - else - { - // ...not fading, full alpha - alpha = 1.f; - } - } - else if (mAppAngle > 2.f) - { - // far away is faded out also - alpha = (mAppAngle-2.f)/3.f; - } - - if (alpha <= 0.f) - { - if (mNameText) - { - mNameText->markDead(); - mNameText = NULL; - sNumVisibleChatBubbles--; - } - return; - } - - if (!mNameText) - { - mNameText = static_cast( LLHUDObject::addHUDObject( - LLHUDObject::LL_HUD_NAME_TAG) ); - //mNameText->setMass(10.f); - mNameText->setSourceObject(this); - mNameText->setVertAlignment(LLHUDNameTag::ALIGN_VERT_TOP); - mNameText->setVisibleOffScreen(TRUE); - mNameText->setMaxLines(11); - mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f); - sNumVisibleChatBubbles++; - new_name = TRUE; - } - - LLVector3 name_position = idleUpdateNameTagPosition(root_pos_last); - mNameText->setPositionAgent(name_position); - idleUpdateNameTagText(new_name); - idleUpdateNameTagAlpha(new_name, alpha); -} - -void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) - { - LLNameValue *title = getNVPair("Title"); - LLNameValue* firstname = getNVPair("FirstName"); - LLNameValue* lastname = getNVPair("LastName"); - - // Avatars must have a first and last name - if (!firstname || !lastname) return; - - bool is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY) != mSignaledAnimations.end(); - bool is_busy = mSignaledAnimations.find(ANIM_AGENT_BUSY) != mSignaledAnimations.end(); - bool is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end(); - bool is_muted; - if (isSelf()) - { - is_muted = false; - } - else - { - is_muted = LLMuteList::getInstance()->isMuted(getID()); - } - bool is_friend = LLAvatarTracker::instance().isBuddy(getID()); - bool is_cloud = getIsCloud(); - - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) - { - if (is_appearance != mNameAppearance) - { - if (is_appearance) - { - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezEnteredAppearanceNotification",args); - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' entered appearance mode." << llendl; - } - else - { - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezLeftAppearanceNotification",args); - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left appearance mode." << llendl; - } - } - } - - // Rebuild name tag if state change detected - if (mNameString.empty() - || new_name - || (!title && !mTitle.empty()) - || (title && mTitle != title->getString()) - || is_away != mNameAway - || is_busy != mNameBusy - || is_muted != mNameMute - || is_appearance != mNameAppearance - || is_friend != mNameFriend - || is_cloud != mNameCloud) - { - LLColor4 name_tag_color = getNameTagColor(is_friend); - - clearNameTag(); - - if (is_away || is_muted || is_busy || is_appearance) - { - std::string line; - if (is_away) - { - line += LLTrans::getString("AvatarAway"); - line += ", "; - } - if (is_busy) - { - line += LLTrans::getString("AvatarBusy"); - line += ", "; - } - if (is_muted) - { - line += LLTrans::getString("AvatarMuted"); - line += ", "; - } - if (is_appearance) - { - line += LLTrans::getString("AvatarEditingAppearance"); - line += ", "; - } - if (is_cloud) - { - line += LLTrans::getString("LoadingData"); - line += ", "; - } - // trim last ", " - line.resize( line.length() - 2 ); - addNameTagLine(line, name_tag_color, LLFontGL::NORMAL, - LLFontGL::getFontSansSerifSmall()); - } - - if (sRenderGroupTitles - && title && title->getString() && title->getString()[0] != '\0') - { - std::string title_str = title->getString(); - LLStringFn::replace_ascii_controlchars(title_str,LL_UNKNOWN_CHAR); - addNameTagLine(title_str, name_tag_color, LLFontGL::NORMAL, - LLFontGL::getFontSansSerifSmall()); - } - - static LLUICachedControl show_display_names("NameTagShowDisplayNames"); - static LLUICachedControl show_usernames("NameTagShowUsernames"); - - if (LLAvatarNameCache::useDisplayNames()) - { - LLAvatarName av_name; - if (!LLAvatarNameCache::get(getID(), &av_name)) - { - // ...call this function back when the name arrives - // and force a rebuild - LLAvatarNameCache::get(getID(), - boost::bind(&LLVOAvatar::clearNameTag, this)); - } - - // Might be blank if name not available yet, that's OK - if (show_display_names) - { - addNameTagLine(av_name.mDisplayName, name_tag_color, LLFontGL::NORMAL, - LLFontGL::getFontSansSerif()); - } - // Suppress SLID display if display name matches exactly (ugh) - if (show_usernames && !av_name.mIsDisplayNameDefault) - { - // *HACK: Desaturate the color - LLColor4 username_color = name_tag_color * 0.83f; - addNameTagLine(av_name.mUsername, username_color, LLFontGL::NORMAL, - LLFontGL::getFontSansSerifSmall()); - } - } - else - { - const LLFontGL* font = LLFontGL::getFontSansSerif(); - std::string full_name = - LLCacheName::buildFullName( firstname->getString(), lastname->getString() ); - addNameTagLine(full_name, name_tag_color, LLFontGL::NORMAL, font); - } - - mNameAway = is_away; - mNameBusy = is_busy; - mNameMute = is_muted; - mNameAppearance = is_appearance; - mNameFriend = is_friend; - mNameCloud = is_cloud; - mTitle = title ? title->getString() : ""; - LLStringFn::replace_ascii_controlchars(mTitle,LL_UNKNOWN_CHAR); - new_name = TRUE; - } - - if (mVisibleChat) - { - mNameText->setFont(LLFontGL::getFontSansSerif()); - mNameText->setTextAlignment(LLHUDNameTag::ALIGN_TEXT_LEFT); - mNameText->setFadeDistance(CHAT_NORMAL_RADIUS * 2.f, 5.f); - - char line[MAX_STRING]; /* Flawfinder: ignore */ - line[0] = '\0'; - std::deque::iterator chat_iter = mChats.begin(); - mNameText->clearString(); - - LLColor4 new_chat = LLUIColorTable::instance().getColor( isSelf() ? "UserChatColor" : "AgentChatColor" ); - LLColor4 normal_chat = lerp(new_chat, LLColor4(0.8f, 0.8f, 0.8f, 1.f), 0.7f); - LLColor4 old_chat = lerp(normal_chat, LLColor4(0.6f, 0.6f, 0.6f, 1.f), 0.7f); - if (mTyping && mChats.size() >= MAX_BUBBLE_CHAT_UTTERANCES) - { - ++chat_iter; - } - - for(; chat_iter != mChats.end(); ++chat_iter) - { - F32 chat_fade_amt = llclamp((F32)((LLFrameTimer::getElapsedSeconds() - chat_iter->mTime) / CHAT_FADE_TIME), 0.f, 4.f); - LLFontGL::StyleFlags style; - switch(chat_iter->mChatType) - { - case CHAT_TYPE_WHISPER: - style = LLFontGL::ITALIC; - break; - case CHAT_TYPE_SHOUT: - style = LLFontGL::BOLD; - break; - default: - style = LLFontGL::NORMAL; - break; - } - if (chat_fade_amt < 1.f) - { - F32 u = clamp_rescale(chat_fade_amt, 0.9f, 1.f, 0.f, 1.f); - mNameText->addLine(chat_iter->mText, lerp(new_chat, normal_chat, u), style); - } - else if (chat_fade_amt < 2.f) - { - F32 u = clamp_rescale(chat_fade_amt, 1.9f, 2.f, 0.f, 1.f); - mNameText->addLine(chat_iter->mText, lerp(normal_chat, old_chat, u), style); - } - else if (chat_fade_amt < 3.f) - { - // *NOTE: only remove lines down to minimum number - mNameText->addLine(chat_iter->mText, old_chat, style); - } - } - mNameText->setVisibleOffScreen(TRUE); - - if (mTyping) - { - S32 dot_count = (llfloor(mTypingTimer.getElapsedTimeF32() * 3.f) + 2) % 3 + 1; - switch(dot_count) - { - case 1: - mNameText->addLine(".", new_chat); - break; - case 2: - mNameText->addLine("..", new_chat); - break; - case 3: - mNameText->addLine("...", new_chat); - break; - } - - } - } - else - { - // ...not using chat bubbles, just names - mNameText->setTextAlignment(LLHUDNameTag::ALIGN_TEXT_CENTER); - mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f); - mNameText->setVisibleOffScreen(FALSE); - } -} - -void LLVOAvatar::addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font) -{ - llassert(mNameText); - if (mVisibleChat) - { - mNameText->addLabel(line); - } - else - { - mNameText->addLine(line, color, (LLFontGL::StyleFlags)style, font); - } - mNameString += line; - mNameString += '\n'; -} - -void LLVOAvatar::clearNameTag() -{ - mNameString.clear(); - if (mNameText) - { - mNameText->setLabel(""); - mNameText->setString( "" ); - } -} - -//static -void LLVOAvatar::invalidateNameTag(const LLUUID& agent_id) -{ - LLViewerObject* obj = gObjectList.findObject(agent_id); - if (!obj) return; - - LLVOAvatar* avatar = dynamic_cast(obj); - if (!avatar) return; - - avatar->clearNameTag(); -} - -//static -void LLVOAvatar::invalidateNameTags() -{ - std::vector::iterator it = LLCharacter::sInstances.begin(); - for ( ; it != LLCharacter::sInstances.end(); ++it) - { - LLVOAvatar* avatar = dynamic_cast(*it); - if (!avatar) continue; - if (avatar->isDead()) continue; - - avatar->clearNameTag(); - - } -} - -// Compute name tag position during idle update -LLVector3 LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last) -{ - LLQuaternion root_rot = mRoot.getWorldRotation(); - LLVector3 pixel_right_vec; - LLVector3 pixel_up_vec; - LLViewerCamera::getInstance()->getPixelVectors(root_pos_last, pixel_up_vec, pixel_right_vec); - LLVector3 camera_to_av = root_pos_last - LLViewerCamera::getInstance()->getOrigin(); - camera_to_av.normalize(); - LLVector3 local_camera_at = camera_to_av * ~root_rot; - LLVector3 local_camera_up = camera_to_av % LLViewerCamera::getInstance()->getLeftAxis(); - local_camera_up.normalize(); - local_camera_up = local_camera_up * ~root_rot; - - local_camera_up.scaleVec(mBodySize * 0.5f); - local_camera_at.scaleVec(mBodySize * 0.5f); - - LLVector3 name_position = mRoot.getWorldPosition(); - name_position[VZ] -= mPelvisToFoot; - name_position[VZ] += (mBodySize[VZ]* 0.55f); - name_position += (local_camera_up * root_rot) - (projected_vec(local_camera_at * root_rot, camera_to_av)); - name_position += pixel_up_vec * 15.f; - - return name_position; -} - -void LLVOAvatar::idleUpdateNameTagAlpha(BOOL new_name, F32 alpha) -{ - llassert(mNameText); - - if (new_name - || alpha != mNameAlpha) - { - mNameText->setAlpha(alpha); - mNameAlpha = alpha; - } -} - -LLColor4 LLVOAvatar::getNameTagColor(bool is_friend) -{ - static LLUICachedControl show_friends("NameTagShowFriends"); - const char* color_name; - if (show_friends && is_friend) - { - color_name = "NameTagFriend"; - } - else if (LLAvatarNameCache::useDisplayNames()) - { - // ...color based on whether username "matches" a computed display - // name - LLAvatarName av_name; - if (LLAvatarNameCache::get(getID(), &av_name) - && av_name.mIsDisplayNameDefault) - { - color_name = "NameTagMatch"; - } - else - { - color_name = "NameTagMismatch"; - } - } - else - { - // ...not using display names - color_name = "NameTagLegacy"; - } - return LLUIColorTable::getInstance()->getColor( color_name ); -} - -void LLVOAvatar::idleUpdateBelowWater() -{ - F32 avatar_height = (F32)(getPositionGlobal().mdV[VZ]); - - F32 water_height; - water_height = getRegion()->getWaterHeight(); - - mBelowWater = avatar_height < water_height; -} - -void LLVOAvatar::slamPosition() -{ - gAgent.setPositionAgent(getPositionAgent()); - mRoot.setWorldPosition(getPositionAgent()); // teleport - setChanged(TRANSLATED); - if (mDrawable.notNull()) - { - gPipeline.updateMoveNormalAsync(mDrawable); - } - mRoot.updateWorldMatrixChildren(); -} - -//------------------------------------------------------------------------ -// updateCharacter() -// called on both your avatar and other avatars -//------------------------------------------------------------------------ -BOOL LLVOAvatar::updateCharacter(LLAgent &agent) -{ - LLMemType mt(LLMemType::MTYPE_AVATAR); - - // clear debug text - mDebugText.clear(); - if (LLVOAvatar::sShowAnimationDebug) - { - for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin(); - iter != mMotionController.getActiveMotions().end(); ++iter) - { - LLMotion* motionp = *iter; - if (motionp->getMinPixelArea() < getPixelArea()) - { - std::string output; - if (motionp->getName().empty()) - { - output = llformat("%s - %d", - gAgent.isGodlikeWithoutAdminMenuFakery() ? - motionp->getID().asString().c_str() : - LLUUID::null.asString().c_str(), - (U32)motionp->getPriority()); - } - else - { - output = llformat("%s - %d", - motionp->getName().c_str(), - (U32)motionp->getPriority()); - } - addDebugText(output); - } - } - } - - if (gNoRender) - { - // Hack if we're running drones... - if (isSelf()) - { - gAgent.setPositionAgent(getPositionAgent()); - } - return FALSE; - } - - - LLVector3d root_pos_global; - - if (!mIsBuilt) - { - return FALSE; - } - - BOOL visible = isVisible(); - - // For fading out the names above heads, only let the timer - // run if we're visible. - if (mDrawable.notNull() && !visible) - { - mTimeVisible.reset(); - } - - - //-------------------------------------------------------------------- - // the rest should only be done occasionally for far away avatars - //-------------------------------------------------------------------- - - if (visible && !isSelf() && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter) - { - const LLVector4a* ext = mDrawable->getSpatialExtents(); - LLVector4a size; - size.setSub(ext[1],ext[0]); - F32 mag = size.getLength3().getF32()*0.5f; - - F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f); - if (LLMuteList::getInstance()->isMuted(getID())) - { // muted avatars update at 16 hz - mUpdatePeriod = 16; - } - else if (mVisibilityRank <= LLVOAvatar::sMaxVisible || - mDrawable->mDistanceWRTCamera < 1.f + mag) - { //first 25% of max visible avatars are not impostored - //also, don't impostor avatars whose bounding box may be penetrating the - //impostor camera near clip plane - mUpdatePeriod = 1; - } - else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 4) - { //background avatars are REALLY slow updating impostors - mUpdatePeriod = 16; - } - else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 3) - { //back 25% of max visible avatars are slow updating impostors - mUpdatePeriod = 8; - } - else if (mImpostorPixelArea <= impostor_area) - { // stuff in between gets an update period based on pixel area - mUpdatePeriod = llclamp((S32) sqrtf(impostor_area*4.f/mImpostorPixelArea), 2, 8); - } - else - { - //nearby avatars, update the impostors more frequently. - mUpdatePeriod = 4; - } - - visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE; - } - - // don't early out for your own avatar, as we rely on your animations playing reliably - // for example, the "turn around" animation when entering customize avatar needs to trigger - // even when your avatar is offscreen - if (!visible && !isSelf()) - { - updateMotions(LLCharacter::HIDDEN_UPDATE); - return FALSE; - } - - // change animation time quanta based on avatar render load - if (!isSelf() && !mIsDummy) - { - F32 time_quantum = clamp_rescale((F32)sInstances.size(), 10.f, 35.f, 0.f, 0.25f); - F32 pixel_area_scale = clamp_rescale(mPixelArea, 100, 5000, 1.f, 0.f); - F32 time_step = time_quantum * pixel_area_scale; - if (time_step != 0.f) - { - // disable walk motion servo controller as it doesn't work with motion timesteps - stopMotion(ANIM_AGENT_WALK_ADJUST); - removeAnimationData("Walk Speed"); - } - mMotionController.setTimeStep(time_step); -// llinfos << "Setting timestep to " << time_quantum * pixel_area_scale << llendl; - } - - if (getParent() && !mIsSitting) - { - sitOnObject((LLViewerObject*)getParent()); - } - else if (!getParent() && mIsSitting && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED)) - { - getOffObject(); - } - - //-------------------------------------------------------------------- - // create local variables in world coords for region position values - //-------------------------------------------------------------------- - F32 speed; - LLVector3 normal; - - LLVector3 xyVel = getVelocity(); - xyVel.mV[VZ] = 0.0f; - speed = xyVel.length(); - - BOOL throttle = TRUE; - - if (!(mIsSitting && getParent())) - { - //-------------------------------------------------------------------- - // get timing info - // handle initial condition case - //-------------------------------------------------------------------- - F32 animation_time = mAnimTimer.getElapsedTimeF32(); - if (mTimeLast == 0.0f) - { - mTimeLast = animation_time; - throttle = FALSE; - - // put the pelvis at slaved position/mRotation - mRoot.setWorldPosition( getPositionAgent() ); // first frame - mRoot.setWorldRotation( getRotation() ); - } - - //-------------------------------------------------------------------- - // dont' let dT get larger than 1/5th of a second - //-------------------------------------------------------------------- - F32 deltaTime = animation_time - mTimeLast; - - deltaTime = llclamp( deltaTime, DELTA_TIME_MIN, DELTA_TIME_MAX ); - mTimeLast = animation_time; - - mSpeedAccum = (mSpeedAccum * 0.95f) + (speed * 0.05f); - - //-------------------------------------------------------------------- - // compute the position of the avatar's root - //-------------------------------------------------------------------- - LLVector3d root_pos; - LLVector3d ground_under_pelvis; - - if (isSelf()) - { - if ( !mHasPelvisOffset ) - { - gAgent.setPositionAgent(getRenderPosition()); - } - else - { - gAgent.setPositionAgent( getRenderPosition() + mPelvisOffset ); - } - } - - root_pos = gAgent.getPosGlobalFromAgent(getRenderPosition()); - - resolveHeightGlobal(root_pos, ground_under_pelvis, normal); - F32 foot_to_ground = (F32) (root_pos.mdV[VZ] - mPelvisToFoot - ground_under_pelvis.mdV[VZ]); - BOOL in_air = ((!LLWorld::getInstance()->getRegionFromPosGlobal(ground_under_pelvis)) || - foot_to_ground > FOOT_GROUND_COLLISION_TOLERANCE); - - if (in_air && !mInAir) - { - mTimeInAir.reset(); - } - mInAir = in_air; - - // correct for the fact that the pelvis is not necessarily the center - // of the agent's physical representation - root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot; - - LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos); - - if (newPosition != mRoot.getXform()->getWorldPosition()) - { - if ( !mHasPelvisOffset ) - { - mRoot.touch(); - mRoot.setWorldPosition( newPosition ); // regular update - } - else - { - mRoot.touch(); - mRoot.setWorldPosition( newPosition + mPelvisOffset ); - } - } - - - //-------------------------------------------------------------------- - // Propagate viewer object rotation to root of avatar - //-------------------------------------------------------------------- - if (!isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS)) - { - LLQuaternion iQ; - LLVector3 upDir( 0.0f, 0.0f, 1.0f ); - - // Compute a forward direction vector derived from the primitive rotation - // and the velocity vector. When walking or jumping, don't let body deviate - // more than 90 from the view, if necessary, flip the velocity vector. - - LLVector3 primDir; - if (isSelf()) - { - primDir = agent.getAtAxis() - projected_vec(agent.getAtAxis(), agent.getReferenceUpVector()); - primDir.normalize(); - } - else - { - primDir = getRotation().getMatrix3().getFwdRow(); - } - LLVector3 velDir = getVelocity(); - velDir.normalize(); - if ( mSignaledAnimations.find(ANIM_AGENT_WALK) != mSignaledAnimations.end()) - { - F32 vpD = velDir * primDir; - if (vpD < -0.5f) - { - velDir *= -1.0f; - } - } - LLVector3 fwdDir = lerp(primDir, velDir, clamp_rescale(speed, 0.5f, 2.0f, 0.0f, 1.0f)); - if (isSelf() && gAgentCamera.cameraMouselook()) - { - // make sure fwdDir stays in same general direction as primdir - if (gAgent.getFlying()) - { - fwdDir = LLViewerCamera::getInstance()->getAtAxis(); - } - else - { - LLVector3 at_axis = LLViewerCamera::getInstance()->getAtAxis(); - LLVector3 up_vector = gAgent.getReferenceUpVector(); - at_axis -= up_vector * (at_axis * up_vector); - at_axis.normalize(); - - F32 dot = fwdDir * at_axis; - if (dot < 0.f) - { - fwdDir -= 2.f * at_axis * dot; - fwdDir.normalize(); - } - } - - } - - LLQuaternion root_rotation = mRoot.getWorldMatrix().quaternion(); - F32 root_roll, root_pitch, root_yaw; - root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw); - - // When moving very slow, the pelvis is allowed to deviate from the - // forward direction to allow it to hold it's position while the torso - // and head turn. Once in motion, it must conform however. - BOOL self_in_mouselook = isSelf() && gAgentCamera.cameraMouselook(); - - LLVector3 pelvisDir( mRoot.getWorldMatrix().getFwdRow4().mV ); - F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, PELVIS_ROT_THRESHOLD_SLOW, PELVIS_ROT_THRESHOLD_FAST); - - if (self_in_mouselook) - { - pelvis_rot_threshold *= MOUSELOOK_PELVIS_FOLLOW_FACTOR; - } - pelvis_rot_threshold *= DEG_TO_RAD; - - F32 angle = angle_between( pelvisDir, fwdDir ); - - // The avatar's root is allowed to have a yaw that deviates widely - // from the forward direction, but if roll or pitch are off even - // a little bit we need to correct the rotation. - if(root_roll < 1.f * DEG_TO_RAD - && root_pitch < 5.f * DEG_TO_RAD) - { - // smaller correction vector means pelvis follows prim direction more closely - if (!mTurning && angle > pelvis_rot_threshold*0.75f) - { - mTurning = TRUE; - } - - // use tighter threshold when turning - if (mTurning) - { - pelvis_rot_threshold *= 0.4f; - } - - // am I done turning? - if (angle < pelvis_rot_threshold) - { - mTurning = FALSE; - } - - LLVector3 correction_vector = (pelvisDir - fwdDir) * clamp_rescale(angle, pelvis_rot_threshold*0.75f, pelvis_rot_threshold, 1.0f, 0.0f); - fwdDir += correction_vector; - } - else - { - mTurning = FALSE; - } - - // Now compute the full world space rotation for the whole body (wQv) - LLVector3 leftDir = upDir % fwdDir; - leftDir.normalize(); - fwdDir = leftDir % upDir; - LLQuaternion wQv( fwdDir, leftDir, upDir ); - - if (isSelf() && mTurning) - { - if ((fwdDir % pelvisDir) * upDir > 0.f) - { - gAgent.setControlFlags(AGENT_CONTROL_TURN_RIGHT); - } - else - { - gAgent.setControlFlags(AGENT_CONTROL_TURN_LEFT); - } - } - - // Set the root rotation, but do so incrementally so that it - // lags in time by some fixed amount. - //F32 u = LLCriticalDamp::getInterpolant(PELVIS_LAG); - F32 pelvis_lag_time = 0.f; - if (self_in_mouselook) - { - pelvis_lag_time = PELVIS_LAG_MOUSELOOK; - } - else if (mInAir) - { - pelvis_lag_time = PELVIS_LAG_FLYING; - // increase pelvis lag time when moving slowly - pelvis_lag_time *= clamp_rescale(mSpeedAccum, 0.f, 15.f, 3.f, 1.f); - } - else - { - pelvis_lag_time = PELVIS_LAG_WALKING; - } - - F32 u = llclamp((deltaTime / pelvis_lag_time), 0.0f, 1.0f); - - mRoot.setWorldRotation( slerp(u, mRoot.getWorldRotation(), wQv) ); - - } - } - else if (mDrawable.notNull()) - { - mRoot.setPosition(mDrawable->getPosition()); - mRoot.setRotation(mDrawable->getRotation()); - } - - //------------------------------------------------------------------------- - // Update character motions - //------------------------------------------------------------------------- - // store data relevant to motions - mSpeed = speed; - - // update animations - if (mSpecialRenderMode == 1) // Animation Preview - updateMotions(LLCharacter::FORCE_UPDATE); - else - updateMotions(LLCharacter::NORMAL_UPDATE); - - // update head position - updateHeadOffset(); - - //------------------------------------------------------------------------- - // Find the ground under each foot, these are used for a variety - // of things that follow - //------------------------------------------------------------------------- - LLVector3 ankle_left_pos_agent = mFootLeftp->getWorldPosition(); - LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition(); - - LLVector3 ankle_left_ground_agent = ankle_left_pos_agent; - LLVector3 ankle_right_ground_agent = ankle_right_pos_agent; - resolveHeightAgent(ankle_left_pos_agent, ankle_left_ground_agent, normal); - resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal); - - F32 leftElev = llmax(-0.2f, ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]); - F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]); - - if (!mIsSitting) - { - //------------------------------------------------------------------------- - // Figure out which foot is on ground - //------------------------------------------------------------------------- - if (!mInAir) - { - if ((leftElev < 0.0f) || (rightElev < 0.0f)) - { - ankle_left_pos_agent = mFootLeftp->getWorldPosition(); - ankle_right_pos_agent = mFootRightp->getWorldPosition(); - leftElev = ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]; - rightElev = ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]; - } - } - } - - //------------------------------------------------------------------------- - // Generate footstep sounds when feet hit the ground - //------------------------------------------------------------------------- - const LLUUID AGENT_FOOTSTEP_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_LAND}; - const S32 NUM_AGENT_FOOTSTEP_ANIMS = LL_ARRAY_SIZE(AGENT_FOOTSTEP_ANIMS); - - if ( gAudiop && isAnyAnimationSignaled(AGENT_FOOTSTEP_ANIMS, NUM_AGENT_FOOTSTEP_ANIMS) ) - { - BOOL playSound = FALSE; - LLVector3 foot_pos_agent; - - BOOL onGroundLeft = (leftElev <= 0.05f); - BOOL onGroundRight = (rightElev <= 0.05f); - - // did left foot hit the ground? - if ( onGroundLeft && !mWasOnGroundLeft ) - { - foot_pos_agent = ankle_left_pos_agent; - playSound = TRUE; - } - - // did right foot hit the ground? - if ( onGroundRight && !mWasOnGroundRight ) - { - foot_pos_agent = ankle_right_pos_agent; - playSound = TRUE; - } - - mWasOnGroundLeft = onGroundLeft; - mWasOnGroundRight = onGroundRight; - - if ( playSound ) - { -// F32 gain = clamp_rescale( mSpeedAccum, -// AUDIO_STEP_LO_SPEED, AUDIO_STEP_HI_SPEED, -// AUDIO_STEP_LO_GAIN, AUDIO_STEP_HI_GAIN ); - - const F32 STEP_VOLUME = 0.1f; - const LLUUID& step_sound_id = getStepSound(); - - LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent); - - if (LLViewerParcelMgr::getInstance()->canHearSound(foot_pos_global) - && !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds)) - { - gAudiop->triggerSound(step_sound_id, getID(), STEP_VOLUME, LLAudioEngine::AUDIO_TYPE_AMBIENT, foot_pos_global); - } - } - } - - mRoot.updateWorldMatrixChildren(); - - if (!mDebugText.size() && mText.notNull()) - { - mText->markDead(); - mText = NULL; - } - else if (mDebugText.size()) - { - setDebugText(mDebugText); - } - - //mesh vertices need to be reskinned - mNeedsSkin = TRUE; - - return TRUE; -} - -//----------------------------------------------------------------------------- -// updateHeadOffset() -//----------------------------------------------------------------------------- -void LLVOAvatar::updateHeadOffset() -{ - // since we only care about Z, just grab one of the eyes - LLVector3 midEyePt = mEyeLeftp->getWorldPosition(); - midEyePt -= mDrawable.notNull() ? mDrawable->getWorldPosition() : mRoot.getWorldPosition(); - midEyePt.mV[VZ] = llmax(-mPelvisToFoot + LLViewerCamera::getInstance()->getNear(), midEyePt.mV[VZ]); - - if (mDrawable.notNull()) - { - midEyePt = midEyePt * ~mDrawable->getWorldRotation(); - } - if (mIsSitting) - { - mHeadOffset = midEyePt; - } - else - { - F32 u = llmax(0.f, HEAD_MOVEMENT_AVG_TIME - (1.f / gFPSClamped)); - mHeadOffset = lerp(midEyePt, mHeadOffset, u); - } -} -//------------------------------------------------------------------------ -// setPelvisOffset -//------------------------------------------------------------------------ -void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount ) -{ - mHasPelvisOffset = hasOffset; - if ( mHasPelvisOffset ) - { - mPelvisOffset = offsetAmount; - } -} -//------------------------------------------------------------------------ -// postPelvisSetRecalc -//------------------------------------------------------------------------ -void LLVOAvatar::postPelvisSetRecalc( void ) -{ - computeBodySize(); - mRoot.updateWorldMatrixChildren(); - dirtyMesh(); - updateHeadOffset(); -} -//------------------------------------------------------------------------ -// updateVisibility() -//------------------------------------------------------------------------ -void LLVOAvatar::updateVisibility() -{ - BOOL visible = FALSE; - - if (mIsDummy) - { - visible = TRUE; - } - else if (mDrawable.isNull()) - { - visible = FALSE; - } - else - { - if (!mDrawable->getSpatialGroup() || mDrawable->getSpatialGroup()->isVisible()) - { - visible = TRUE; - } - else - { - visible = FALSE; - } - - if(isSelf()) - { - if (!gAgentWearables.areWearablesLoaded()) - { - visible = FALSE; - } - } - else if( !mFirstAppearanceMessageReceived ) - { - visible = FALSE; - } - - if (sDebugInvisible) - { - LLNameValue* firstname = getNVPair("FirstName"); - if (firstname) - { - llinfos << "Avatar " << firstname->getString() << " updating visiblity" << llendl; - } - else - { - llinfos << "Avatar " << this << " updating visiblity" << llendl; - } - - if (visible) - { - llinfos << "Visible" << llendl; - } - else - { - llinfos << "Not visible" << llendl; - } - - /*if (avatar_in_frustum) - { - llinfos << "Avatar in frustum" << llendl; - } - else - { - llinfos << "Avatar not in frustum" << llendl; - }*/ - - /*if (LLViewerCamera::getInstance()->sphereInFrustum(sel_pos_agent, 2.0f)) - { - llinfos << "Sel pos visible" << llendl; - } - if (LLViewerCamera::getInstance()->sphereInFrustum(wrist_right_pos_agent, 0.2f)) - { - llinfos << "Wrist pos visible" << llendl; - } - if (LLViewerCamera::getInstance()->sphereInFrustum(getPositionAgent(), getMaxScale()*2.f)) - { - llinfos << "Agent visible" << llendl; - }*/ - llinfos << "PA: " << getPositionAgent() << llendl; - /*llinfos << "SPA: " << sel_pos_agent << llendl; - llinfos << "WPA: " << wrist_right_pos_agent << llendl;*/ - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - if (LLViewerObject *attached_object = (*attachment_iter)) - { - if(attached_object->mDrawable->isVisible()) - { - llinfos << attachment->getName() << " visible" << llendl; - } - else - { - llinfos << attachment->getName() << " not visible at " << mDrawable->getWorldPosition() << " and radius " << mDrawable->getRadius() << llendl; - } - } - } - } - } - } - - if (!visible && mVisible) - { - mMeshInvisibleTime.reset(); - } - - if (visible) - { - if (!mMeshValid) - { - restoreMeshData(); - } - } - else - { - if (mMeshValid && mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP) - { - releaseMeshData(); - } - // this breaks off-screen chat bubbles - //if (mNameText) - //{ - // mNameText->markDead(); - // mNameText = NULL; - // sNumVisibleChatBubbles--; - //} - } - - mVisible = visible; -} - -// private -bool LLVOAvatar::shouldAlphaMask() -{ - const bool should_alpha_mask = mSupportsAlphaLayers && !LLDrawPoolAlpha::sShowDebugAlpha // Don't alpha mask if "Highlight Transparent" checked - && !LLDrawPoolAvatar::sSkipTransparent; - - return should_alpha_mask; - -} - -U32 LLVOAvatar::renderSkinnedAttachments() -{ - /*U32 num_indices = 0; - - const U32 data_mask = LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_NORMAL | - LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_COLOR | - LLVertexBuffer::MAP_WEIGHT4; - - for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - const LLViewerObject* attached_object = (*attachment_iter); - if (attached_object && !attached_object->isHUDAttachment()) - { - const LLDrawable* drawable = attached_object->mDrawable; - if (drawable) - { - for (S32 i = 0; i < drawable->getNumFaces(); ++i) - { - LLFace* face = drawable->getFace(i); - if (face->isState(LLFace::RIGGED)) - { - - } - } - } - } - - return num_indices;*/ - return 0; -} - -//----------------------------------------------------------------------------- -// renderSkinned() -//----------------------------------------------------------------------------- -U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) -{ - U32 num_indices = 0; - - if (!mIsBuilt) - { - return num_indices; - } - - LLFace* face = mDrawable->getFace(0); - - bool needs_rebuild = !face || face->mVertexBuffer.isNull() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY); - - if (needs_rebuild || mDirtyMesh) - { //LOD changed or new mesh created, allocate new vertex buffer if needed - if (needs_rebuild || mDirtyMesh >= 2 || mVisibilityRank <= 4) - { - updateMeshData(); - mDirtyMesh = 0; - mNeedsSkin = TRUE; - mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY); - } - } - - if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) <= 0) - { - if (mNeedsSkin) - { - //generate animated mesh - mMeshLOD[MESH_ID_LOWER_BODY]->updateJointGeometry(); - mMeshLOD[MESH_ID_UPPER_BODY]->updateJointGeometry(); - - if( isWearingWearableType( LLWearableType::WT_SKIRT ) ) - { - mMeshLOD[MESH_ID_SKIRT]->updateJointGeometry(); - } - - if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) - { - mMeshLOD[MESH_ID_EYELASH]->updateJointGeometry(); - mMeshLOD[MESH_ID_HEAD]->updateJointGeometry(); - mMeshLOD[MESH_ID_HAIR]->updateJointGeometry(); - } - mNeedsSkin = FALSE; - mLastSkinTime = gFrameTimeSeconds; - - LLVertexBuffer* vb = mDrawable->getFace(0)->mVertexBuffer; - if (vb) - { - vb->setBuffer(0); - } - } - } - else - { - mNeedsSkin = FALSE; - } - - if (sDebugInvisible) - { - LLNameValue* firstname = getNVPair("FirstName"); - if (firstname) - { - llinfos << "Avatar " << firstname->getString() << " in render" << llendl; - } - else - { - llinfos << "Avatar " << this << " in render" << llendl; - } - if (!mIsBuilt) - { - llinfos << "Not built!" << llendl; - } - else if (!gAgent.needsRenderAvatar()) - { - llinfos << "Doesn't need avatar render!" << llendl; - } - else - { - llinfos << "Rendering!" << llendl; - } - } - - if (!mIsBuilt) - { - return num_indices; - } - - if (isSelf() && !gAgent.needsRenderAvatar()) - { - return num_indices; - } - - // render collision normal - // *NOTE: this is disabled (there is no UI for enabling sShowFootPlane) due - // to DEV-14477. the code is left here to aid in tracking down the cause - // of the crash in the future. -brad - if (sShowFootPlane && mDrawable.notNull()) - { - LLVector3 slaved_pos = mDrawable->getPositionAgent(); - LLVector3 foot_plane_normal(mFootPlane.mV[VX], mFootPlane.mV[VY], mFootPlane.mV[VZ]); - F32 dist_from_plane = (slaved_pos * foot_plane_normal) - mFootPlane.mV[VW]; - LLVector3 collide_point = slaved_pos; - collide_point.mV[VZ] -= foot_plane_normal.mV[VZ] * (dist_from_plane + COLLISION_TOLERANCE - FOOT_COLLIDE_FUDGE); - - gGL.begin(LLRender::LINES); - { - F32 SQUARE_SIZE = 0.2f; - gGL.color4f(1.f, 0.f, 0.f, 1.f); - - gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]); - gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]); - - gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]); - gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]); - - gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]); - gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]); - - gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]); - gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]); - - gGL.vertex3f(collide_point.mV[VX], collide_point.mV[VY], collide_point.mV[VZ]); - gGL.vertex3f(collide_point.mV[VX] + mFootPlane.mV[VX], collide_point.mV[VY] + mFootPlane.mV[VY], collide_point.mV[VZ] + mFootPlane.mV[VZ]); - - } - gGL.end(); - gGL.flush(); - } - //-------------------------------------------------------------------- - // render all geometry attached to the skeleton - //-------------------------------------------------------------------- - static LLStat render_stat; - - LLViewerJointMesh::sRenderPass = pass; - - if (pass == AVATAR_RENDER_PASS_SINGLE) - { - - bool should_alpha_mask = shouldAlphaMask(); - LLGLState test(GL_ALPHA_TEST, should_alpha_mask); - - if (should_alpha_mask) - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); - } - - BOOL first_pass = TRUE; - if (!LLDrawPoolAvatar::sSkipOpaque) - { - if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) - { - if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy) - { - num_indices += mMeshLOD[MESH_ID_HEAD]->render(mAdjustedPixelArea, TRUE, mIsDummy); - first_pass = FALSE; - } - } - if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy) - { - num_indices += mMeshLOD[MESH_ID_UPPER_BODY]->render(mAdjustedPixelArea, first_pass, mIsDummy); - first_pass = FALSE; - } - - if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy) - { - num_indices += mMeshLOD[MESH_ID_LOWER_BODY]->render(mAdjustedPixelArea, first_pass, mIsDummy); - first_pass = FALSE; - } - } - - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); - - if (!LLDrawPoolAvatar::sSkipTransparent || LLPipeline::sImpostorRender) - { - LLGLState blend(GL_BLEND, !mIsDummy); - LLGLState test(GL_ALPHA_TEST, !mIsDummy); - num_indices += renderTransparent(first_pass); - } - } - - LLViewerJointMesh::sRenderPass = AVATAR_RENDER_PASS_SINGLE; - - //llinfos << "Avatar render: " << render_timer.getElapsedTimeF32() << llendl; - - //render_stat.addValue(render_timer.getElapsedTimeF32()*1000.f); - - return num_indices; -} - -U32 LLVOAvatar::renderTransparent(BOOL first_pass) -{ - U32 num_indices = 0; - if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (mIsDummy || isTextureVisible(TEX_SKIRT_BAKED)) ) - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f); - num_indices += mMeshLOD[MESH_ID_SKIRT]->render(mAdjustedPixelArea, FALSE); - first_pass = FALSE; - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); - } - - if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) - { - if (LLPipeline::sImpostorRender) - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); - } - - if (isTextureVisible(TEX_HEAD_BAKED)) - { - num_indices += mMeshLOD[MESH_ID_EYELASH]->render(mAdjustedPixelArea, first_pass, mIsDummy); - first_pass = FALSE; - } - // Can't test for baked hair being defined, since that won't always be the case (not all viewers send baked hair) - // TODO: 1.25 will be able to switch this logic back to calling isTextureVisible(); - if (getImage(TEX_HAIR_BAKED, 0)->getID() != IMG_INVISIBLE || LLDrawPoolAlpha::sShowDebugAlpha) - { - num_indices += mMeshLOD[MESH_ID_HAIR]->render(mAdjustedPixelArea, first_pass, mIsDummy); - first_pass = FALSE; - } - if (LLPipeline::sImpostorRender) - { - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); - } - } - - return num_indices; -} - -//----------------------------------------------------------------------------- -// renderRigid() -//----------------------------------------------------------------------------- -U32 LLVOAvatar::renderRigid() -{ - U32 num_indices = 0; - - if (!mIsBuilt) - { - return 0; - } - - if (isSelf() && (!gAgent.needsRenderAvatar() || !gAgent.needsRenderHead())) - { - return 0; - } - - if (!mIsBuilt) - { - return 0; - } - - bool should_alpha_mask = shouldAlphaMask(); - LLGLState test(GL_ALPHA_TEST, should_alpha_mask); - - if (should_alpha_mask) - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); - } - - if (isTextureVisible(TEX_EYES_BAKED) || mIsDummy) - { - num_indices += mMeshLOD[MESH_ID_EYEBALL_LEFT]->render(mAdjustedPixelArea, TRUE, mIsDummy); - num_indices += mMeshLOD[MESH_ID_EYEBALL_RIGHT]->render(mAdjustedPixelArea, TRUE, mIsDummy); - } - - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); - - return num_indices; -} - -U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel) -{ - if (!mImpostor.isComplete()) - { - return 0; - } - - LLVector3 pos(getRenderPosition()+mImpostorOffset); - LLVector3 at = (pos - LLViewerCamera::getInstance()->getOrigin()); - at.normalize(); - LLVector3 left = LLViewerCamera::getInstance()->getUpAxis() % at; - LLVector3 up = at%left; - - left *= mImpostorDim.mV[0]; - up *= mImpostorDim.mV[1]; - - LLGLEnable test(GL_ALPHA_TEST); - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f); - - gGL.color4ubv(color.mV); - gGL.getTexUnit(diffuse_channel)->bind(&mImpostor); - gGL.begin(LLRender::QUADS); - gGL.texCoord2f(0,0); - gGL.vertex3fv((pos+left-up).mV); - gGL.texCoord2f(1,0); - gGL.vertex3fv((pos-left-up).mV); - gGL.texCoord2f(1,1); - gGL.vertex3fv((pos-left+up).mV); - gGL.texCoord2f(0,1); - gGL.vertex3fv((pos+left+up).mV); - gGL.end(); - gGL.flush(); - - return 6; -} - -//------------------------------------------------------------------------ -// LLVOAvatar::updateTextures() -//------------------------------------------------------------------------ -void LLVOAvatar::updateTextures() -{ - BOOL render_avatar = TRUE; - - if (mIsDummy || gNoRender) - { - return; - } - - if( isSelf() ) - { - render_avatar = TRUE; - } - else - { - if(!isVisible()) - { - return ;//do not update for invisible avatar. - } - - render_avatar = !mCulled; //visible and not culled. - } - - std::vector layer_baked; - // GL NOT ACTIVE HERE - *TODO - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - layer_baked.push_back(isTextureDefined(mBakedTextureDatas[i].mTextureIndex)); - // bind the texture so that they'll be decoded slightly - // inefficient, we can short-circuit this if we have to - if (render_avatar && !gGLManager.mIsDisabled) - { - if (layer_baked[i] && !mBakedTextureDatas[i].mIsLoaded) - { - gGL.getTexUnit(0)->bind(getImage( mBakedTextureDatas[i].mTextureIndex, 0 )); - } - } - } - - mMaxPixelArea = 0.f; - mMinPixelArea = 99999999.f; - mHasGrey = FALSE; // debug - for (U32 texture_index = 0; texture_index < getNumTEs(); texture_index++) - { - LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType((ETextureIndex)texture_index); - U32 num_wearables = gAgentWearables.getWearableCount(wearable_type); - const LLTextureEntry *te = getTE(texture_index); - const F32 texel_area_ratio = fabs(te->mScaleS * te->mScaleT); - LLViewerFetchedTexture *imagep = NULL; - for (U32 wearable_index = 0; wearable_index < num_wearables; wearable_index++) - { - imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index, wearable_index), TRUE); - if (imagep) - { - const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture((ETextureIndex)texture_index); - const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; - if (texture_dict->mIsLocalTexture) - { - addLocalTextureStats((ETextureIndex)texture_index, imagep, texel_area_ratio, render_avatar, layer_baked[baked_index]); - } - } - } - if (isIndexBakedTexture((ETextureIndex) texture_index) && render_avatar) - { - const S32 boost_level = getAvatarBakedBoostLevel(); - imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE); - // Spam if this is a baked texture, not set to default image, without valid host info - if (isIndexBakedTexture((ETextureIndex)texture_index) - && imagep->getID() != IMG_DEFAULT_AVATAR - && imagep->getID() != IMG_INVISIBLE - && !imagep->getTargetHost().isOk()) - { - LL_WARNS_ONCE("Texture") << "LLVOAvatar::updateTextures No host for texture " - << imagep->getID() << " for avatar " - << (isSelf() ? "" : getID().asString()) - << " on host " << getRegion()->getHost() << llendl; - } - - addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); - } - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) - { - setDebugText(llformat("%4.0f:%4.0f", (F32) sqrt(mMinPixelArea),(F32) sqrt(mMaxPixelArea))); - } -} - - -void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture* imagep, - F32 texel_area_ratio, BOOL render_avatar, BOOL covered_by_baked, U32 index ) -{ - // No local texture stats for non-self avatars - return; -} - -const S32 MAX_TEXTURE_UPDATE_INTERVAL = 64 ; //need to call updateTextures() at least every 32 frames. -const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = S32_MAX ; //frames -void LLVOAvatar::checkTextureLoading() -{ - static const F32 MAX_INVISIBLE_WAITING_TIME = 15.f ; //seconds - - BOOL pause = !isVisible() ; - if(!pause) - { - mInvisibleTimer.reset() ; - } - if(mLoadedCallbacksPaused == pause) - { - return ; - } - - if(mCallbackTextureList.empty()) //when is self or no callbacks. Note: this list for self is always empty. - { - mLoadedCallbacksPaused = pause ; - return ; //nothing to check. - } - - if(pause && mInvisibleTimer.getElapsedTimeF32() < MAX_INVISIBLE_WAITING_TIME) - { - return ; //have not been invisible for enough time. - } - - for(LLLoadedCallbackEntry::source_callback_list_t::iterator iter = mCallbackTextureList.begin(); - iter != mCallbackTextureList.end(); ++iter) - { - LLViewerFetchedTexture* tex = gTextureList.findImage(*iter) ; - if(tex) - { - if(pause)//pause texture fetching. - { - tex->pauseLoadedCallbacks(&mCallbackTextureList) ; - - //set to terminate texture fetching after MAX_TEXTURE_UPDATE_INTERVAL frames. - tex->setMaxVirtualSizeResetInterval(MAX_TEXTURE_UPDATE_INTERVAL); - tex->resetMaxVirtualSizeResetCounter() ; - } - else//unpause - { - static const F32 START_AREA = 100.f ; - - tex->unpauseLoadedCallbacks(&mCallbackTextureList) ; - tex->addTextureStats(START_AREA); //jump start the fetching again - } - } - } - - if(!pause) - { - updateTextures() ; //refresh texture stats. - } - mLoadedCallbacksPaused = pause ; - return ; -} - -const F32 SELF_ADDITIONAL_PRI = 0.75f ; -const F32 ADDITIONAL_PRI = 0.5f; -void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level) -{ - //Note: - //if this function is not called for the last MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL frames, - //the texture pipeline will stop fetching this texture. - - imagep->resetTextureStats(); - imagep->setCanUseHTTP(false) ; //turn off http fetching for baked textures. - imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); - imagep->resetMaxVirtualSizeResetCounter() ; - - mMaxPixelArea = llmax(pixel_area, mMaxPixelArea); - mMinPixelArea = llmin(pixel_area, mMinPixelArea); - imagep->addTextureStats(pixel_area / texel_area_ratio); - imagep->setBoostLevel(boost_level); - - if(boost_level != LLViewerTexture::BOOST_AVATAR_BAKED_SELF) - { - imagep->setAdditionalDecodePriority(ADDITIONAL_PRI) ; - } - else - { - imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ; - } -} - -//virtual -void LLVOAvatar::setImage(const U8 te, LLViewerTexture *imagep, const U32 index) -{ - setTEImage(te, imagep); -} - -//virtual -LLViewerTexture* LLVOAvatar::getImage(const U8 te, const U32 index) const -{ - return getTEImage(te); -} -//virtual -const LLTextureEntry* LLVOAvatar::getTexEntry(const U8 te_num) const -{ - return getTE(te_num); -} - -//virtual -void LLVOAvatar::setTexEntry(const U8 index, const LLTextureEntry &te) -{ - setTE(index, te); -} - -//----------------------------------------------------------------------------- -// resolveHeight() -//----------------------------------------------------------------------------- - -void LLVOAvatar::resolveHeightAgent(const LLVector3 &in_pos_agent, LLVector3 &out_pos_agent, LLVector3 &out_norm) -{ - LLVector3d in_pos_global, out_pos_global; - - in_pos_global = gAgent.getPosGlobalFromAgent(in_pos_agent); - resolveHeightGlobal(in_pos_global, out_pos_global, out_norm); - out_pos_agent = gAgent.getPosAgentFromGlobal(out_pos_global); -} - - -void LLVOAvatar::resolveRayCollisionAgent(const LLVector3d start_pt, const LLVector3d end_pt, LLVector3d &out_pos, LLVector3 &out_norm) -{ - LLViewerObject *obj; - LLWorld::getInstance()->resolveStepHeightGlobal(this, start_pt, end_pt, out_pos, out_norm, &obj); -} - - -void LLVOAvatar::resolveHeightGlobal(const LLVector3d &inPos, LLVector3d &outPos, LLVector3 &outNorm) -{ - LLVector3d zVec(0.0f, 0.0f, 0.5f); - LLVector3d p0 = inPos + zVec; - LLVector3d p1 = inPos - zVec; - LLViewerObject *obj; - LLWorld::getInstance()->resolveStepHeightGlobal(this, p0, p1, outPos, outNorm, &obj); - if (!obj) - { - mStepOnLand = TRUE; - mStepMaterial = 0; - mStepObjectVelocity.setVec(0.0f, 0.0f, 0.0f); - } - else - { - mStepOnLand = FALSE; - mStepMaterial = obj->getMaterial(); - - // We want the primitive velocity, not our velocity... (which actually subtracts the - // step object velocity) - LLVector3 angularVelocity = obj->getAngularVelocity(); - LLVector3 relativePos = gAgent.getPosAgentFromGlobal(outPos) - obj->getPositionAgent(); - - LLVector3 linearComponent = angularVelocity % relativePos; -// llinfos << "Linear Component of Rotation Velocity " << linearComponent << llendl; - mStepObjectVelocity = obj->getVelocity() + linearComponent; - } -} - - -//----------------------------------------------------------------------------- -// getStepSound() -//----------------------------------------------------------------------------- -const LLUUID& LLVOAvatar::getStepSound() const -{ - if ( mStepOnLand ) - { - return sStepSoundOnLand; - } - - return sStepSounds[mStepMaterial]; -} - - -//----------------------------------------------------------------------------- -// processAnimationStateChanges() -//----------------------------------------------------------------------------- -void LLVOAvatar::processAnimationStateChanges() -{ - LLMemType mt(LLMemType::MTYPE_AVATAR); - - if (gNoRender) - { - return; - } - - if ( isAnyAnimationSignaled(AGENT_WALK_ANIMS, NUM_AGENT_WALK_ANIMS) ) - { - startMotion(ANIM_AGENT_WALK_ADJUST); - stopMotion(ANIM_AGENT_FLY_ADJUST); - } - else if (mInAir && !mIsSitting) - { - stopMotion(ANIM_AGENT_WALK_ADJUST); - startMotion(ANIM_AGENT_FLY_ADJUST); - } - else - { - stopMotion(ANIM_AGENT_WALK_ADJUST); - stopMotion(ANIM_AGENT_FLY_ADJUST); - } - - if ( isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) ) - { - startMotion(ANIM_AGENT_TARGET); - stopMotion(ANIM_AGENT_BODY_NOISE); - } - else - { - stopMotion(ANIM_AGENT_TARGET); - startMotion(ANIM_AGENT_BODY_NOISE); - } - - // clear all current animations - AnimIterator anim_it; - for (anim_it = mPlayingAnimations.begin(); anim_it != mPlayingAnimations.end();) - { - AnimIterator found_anim = mSignaledAnimations.find(anim_it->first); - - // playing, but not signaled, so stop - if (found_anim == mSignaledAnimations.end()) - { - processSingleAnimationStateChange(anim_it->first, FALSE); - mPlayingAnimations.erase(anim_it++); - continue; - } - - ++anim_it; - } - - // start up all new anims - for (anim_it = mSignaledAnimations.begin(); anim_it != mSignaledAnimations.end();) - { - AnimIterator found_anim = mPlayingAnimations.find(anim_it->first); - - // signaled but not playing, or different sequence id, start motion - if (found_anim == mPlayingAnimations.end() || found_anim->second != anim_it->second) - { - if (processSingleAnimationStateChange(anim_it->first, TRUE)) - { - mPlayingAnimations[anim_it->first] = anim_it->second; - ++anim_it; - continue; - } - } - - ++anim_it; - } - - // clear source information for animations which have been stopped - if (isSelf()) - { - AnimSourceIterator source_it = mAnimationSources.begin(); - - for (source_it = mAnimationSources.begin(); source_it != mAnimationSources.end();) - { - if (mSignaledAnimations.find(source_it->second) == mSignaledAnimations.end()) - { - mAnimationSources.erase(source_it++); - } - else - { - ++source_it; - } - } - } - - stop_glerror(); -} - - -//----------------------------------------------------------------------------- -// processSingleAnimationStateChange(); -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL start ) -{ - LLMemType mt(LLMemType::MTYPE_AVATAR); - - BOOL result = FALSE; - - if ( start ) // start animation - { - if (anim_id == ANIM_AGENT_TYPE) - { - if (gAudiop) - { - LLVector3d char_pos_global = gAgent.getPosGlobalFromAgent(getCharacterPosition()); - if (LLViewerParcelMgr::getInstance()->canHearSound(char_pos_global) - && !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds)) - { - // RN: uncomment this to play on typing sound at fixed volume once sound engine is fixed - // to support both spatialized and non-spatialized instances of the same sound - //if (isSelf()) - //{ - // gAudiop->triggerSound(LLUUID(gSavedSettings.getString("UISndTyping")), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); - //} - //else - { - LLUUID sound_id = LLUUID(gSavedSettings.getString("UISndTyping")); - gAudiop->triggerSound(sound_id, getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_SFX, char_pos_global); - } - } - } - } - else if (anim_id == ANIM_AGENT_SIT_GROUND_CONSTRAINED) - { - sitDown(TRUE); - } - - - if (startMotion(anim_id)) - { - result = TRUE; - } - else - { - llwarns << "Failed to start motion!" << llendl; - } - } - else //stop animation - { - if (anim_id == ANIM_AGENT_SIT_GROUND_CONSTRAINED) - { - sitDown(FALSE); - } - stopMotion(anim_id); - result = TRUE; - } - - return result; -} - -//----------------------------------------------------------------------------- -// isAnyAnimationSignaled() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::isAnyAnimationSignaled(const LLUUID *anim_array, const S32 num_anims) const -{ - for (S32 i = 0; i < num_anims; i++) - { - if(mSignaledAnimations.find(anim_array[i]) != mSignaledAnimations.end()) - { - return TRUE; - } - } - return FALSE; -} - -//----------------------------------------------------------------------------- -// resetAnimations() -//----------------------------------------------------------------------------- -void LLVOAvatar::resetAnimations() -{ - LLKeyframeMotion::flushKeyframeCache(); - flushAllMotions(); -} - -// Override selectively based on avatar sex and whether we're using new -// animations. -LLUUID LLVOAvatar::remapMotionID(const LLUUID& id) -{ - BOOL use_new_walk_run = gSavedSettings.getBOOL("UseNewWalkRun"); - LLUUID result = id; - - // start special case female walk for female avatars - if (getSex() == SEX_FEMALE) - { - if (id == ANIM_AGENT_WALK) - { - if (use_new_walk_run) - result = ANIM_AGENT_FEMALE_WALK_NEW; - else - result = ANIM_AGENT_FEMALE_WALK; - } - else if (id == ANIM_AGENT_RUN) - { - // There is no old female run animation, so only override - // in one case. - if (use_new_walk_run) - result = ANIM_AGENT_FEMALE_RUN_NEW; - } - else if (id == ANIM_AGENT_SIT) - { - result = ANIM_AGENT_SIT_FEMALE; - } - } - else - { - // Male avatar. - if (id == ANIM_AGENT_WALK) - { - if (use_new_walk_run) - result = ANIM_AGENT_WALK_NEW; - } - else if (id == ANIM_AGENT_RUN) - { - if (use_new_walk_run) - result = ANIM_AGENT_RUN_NEW; - } - - } - - return result; - -} - -//----------------------------------------------------------------------------- -// startMotion() -// id is the asset if of the animation to start -// time_offset is the offset into the animation at which to start playing -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset) -{ - LLMemType mt(LLMemType::MTYPE_AVATAR); - - lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl; - - LLUUID remap_id = remapMotionID(id); - - if (remap_id != id) - { - lldebugs << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << llendl; - } - - if (isSelf() && remap_id == ANIM_AGENT_AWAY) - { - gAgent.setAFK(); - } - - return LLCharacter::startMotion(remap_id, time_offset); -} - -//----------------------------------------------------------------------------- -// stopMotion() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::stopMotion(const LLUUID& id, BOOL stop_immediate) -{ - lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl; - - LLUUID remap_id = remapMotionID(id); - - if (remap_id != id) - { - lldebugs << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << llendl; - } - - if (isSelf()) - { - gAgent.onAnimStop(remap_id); - } - - return LLCharacter::stopMotion(remap_id, stop_immediate); -} - -//----------------------------------------------------------------------------- -// stopMotionFromSource() -//----------------------------------------------------------------------------- -// virtual -void LLVOAvatar::stopMotionFromSource(const LLUUID& source_id) -{ -} - -//----------------------------------------------------------------------------- -// getVolumePos() -//----------------------------------------------------------------------------- -LLVector3 LLVOAvatar::getVolumePos(S32 joint_index, LLVector3& volume_offset) -{ - if (joint_index > mNumCollisionVolumes) - { - return LLVector3::zero; - } - - return mCollisionVolumes[joint_index].getVolumePos(volume_offset); -} - -//----------------------------------------------------------------------------- -// findCollisionVolume() -//----------------------------------------------------------------------------- -LLJoint* LLVOAvatar::findCollisionVolume(U32 volume_id) -{ - if ((S32)volume_id > mNumCollisionVolumes) - { - return NULL; - } - - return &mCollisionVolumes[volume_id]; -} - -//----------------------------------------------------------------------------- -// findCollisionVolume() -//----------------------------------------------------------------------------- -S32 LLVOAvatar::getCollisionVolumeID(std::string &name) -{ - for (S32 i = 0; i < mNumCollisionVolumes; i++) - { - if (mCollisionVolumes[i].getName() == name) - { - return i; - } - } - - return -1; -} - -//----------------------------------------------------------------------------- -// addDebugText() -//----------------------------------------------------------------------------- -void LLVOAvatar::addDebugText(const std::string& text) -{ - mDebugText.append(1, '\n'); - mDebugText.append(text); -} - -//----------------------------------------------------------------------------- -// getID() -//----------------------------------------------------------------------------- -const LLUUID& LLVOAvatar::getID() -{ - return mID; -} - -//----------------------------------------------------------------------------- -// getJoint() -//----------------------------------------------------------------------------- -// RN: avatar joints are multi-rooted to include screen-based attachments -LLJoint *LLVOAvatar::getJoint( const std::string &name ) -{ - LLJoint* jointp = mRoot.findJoint(name); - return jointp; -} - -//----------------------------------------------------------------------------- -// resetJointPositions -//----------------------------------------------------------------------------- -void LLVOAvatar::resetJointPositions( void ) -{ - for(S32 i = 0; i < (S32)mNumJoints; ++i) - { - mSkeleton[i].restoreOldXform(); - mSkeleton[i].setId( LLUUID::null ); - } - mHasPelvisOffset = false; -} -//----------------------------------------------------------------------------- -// resetSpecificJointPosition -//----------------------------------------------------------------------------- -void LLVOAvatar::resetSpecificJointPosition( const std::string& name ) -{ - LLJoint* pJoint = mRoot.findJoint( name ); - - if ( pJoint ) - { - pJoint->restoreOldXform(); - pJoint->setId( LLUUID::null ); - //If we're reseting the pelvis position make sure not to apply offset - if ( name == "mPelvis" ) - { - mHasPelvisOffset = false; - } - } - else - { - llinfos<<"Did not find "<< name.c_str()<setPosition( avPos + pPelvis->getPosition() ); - } - else - { - llwarns<<"Can't get pelvis joint."<setId( LLUUID::null ); - //restore joints to default positions, however skip over the pelvis - if ( pJoint && pPelvis != pJoint ) - { - pJoint->restoreOldXform(); - } - } - //make sure we don't apply the joint offset - mHasPelvisOffset = false; - postPelvisSetRecalc(); -} -//----------------------------------------------------------------------------- -// getCharacterPosition() -//----------------------------------------------------------------------------- -LLVector3 LLVOAvatar::getCharacterPosition() -{ - if (mDrawable.notNull()) - { - return mDrawable->getPositionAgent(); - } - else - { - return getPositionAgent(); - } -} - - -//----------------------------------------------------------------------------- -// LLVOAvatar::getCharacterRotation() -//----------------------------------------------------------------------------- -LLQuaternion LLVOAvatar::getCharacterRotation() -{ - return getRotation(); -} - - -//----------------------------------------------------------------------------- -// LLVOAvatar::getCharacterVelocity() -//----------------------------------------------------------------------------- -LLVector3 LLVOAvatar::getCharacterVelocity() -{ - return getVelocity() - mStepObjectVelocity; -} - - -//----------------------------------------------------------------------------- -// LLVOAvatar::getCharacterAngularVelocity() -//----------------------------------------------------------------------------- -LLVector3 LLVOAvatar::getCharacterAngularVelocity() -{ - return getAngularVelocity(); -} - -//----------------------------------------------------------------------------- -// LLVOAvatar::getGround() -//----------------------------------------------------------------------------- -void LLVOAvatar::getGround(const LLVector3 &in_pos_agent, LLVector3 &out_pos_agent, LLVector3 &outNorm) -{ - LLVector3d z_vec(0.0f, 0.0f, 1.0f); - LLVector3d p0_global, p1_global; - - if (gNoRender || mIsDummy) - { - outNorm.setVec(z_vec); - out_pos_agent = in_pos_agent; - return; - } - - p0_global = gAgent.getPosGlobalFromAgent(in_pos_agent) + z_vec; - p1_global = gAgent.getPosGlobalFromAgent(in_pos_agent) - z_vec; - LLViewerObject *obj; - LLVector3d out_pos_global; - LLWorld::getInstance()->resolveStepHeightGlobal(this, p0_global, p1_global, out_pos_global, outNorm, &obj); - out_pos_agent = gAgent.getPosAgentFromGlobal(out_pos_global); -} - -//----------------------------------------------------------------------------- -// LLVOAvatar::getTimeDilation() -//----------------------------------------------------------------------------- -F32 LLVOAvatar::getTimeDilation() -{ - return mTimeDilation; -} - - -//----------------------------------------------------------------------------- -// LLVOAvatar::getPixelArea() -//----------------------------------------------------------------------------- -F32 LLVOAvatar::getPixelArea() const -{ - if (mIsDummy) - { - return 100000.f; - } - return mPixelArea; -} - - -//----------------------------------------------------------------------------- -// LLVOAvatar::getHeadMesh() -//----------------------------------------------------------------------------- -LLPolyMesh* LLVOAvatar::getHeadMesh() -{ - return mMeshLOD[MESH_ID_HEAD]->mMeshParts[0]->getMesh(); -} - - -//----------------------------------------------------------------------------- -// LLVOAvatar::getUpperBodyMesh() -//----------------------------------------------------------------------------- -LLPolyMesh* LLVOAvatar::getUpperBodyMesh() -{ - return mMeshLOD[MESH_ID_UPPER_BODY]->mMeshParts[0]->getMesh(); -} - - -//----------------------------------------------------------------------------- -// LLVOAvatar::getPosGlobalFromAgent() -//----------------------------------------------------------------------------- -LLVector3d LLVOAvatar::getPosGlobalFromAgent(const LLVector3 &position) -{ - return gAgent.getPosGlobalFromAgent(position); -} - -//----------------------------------------------------------------------------- -// getPosAgentFromGlobal() -//----------------------------------------------------------------------------- -LLVector3 LLVOAvatar::getPosAgentFromGlobal(const LLVector3d &position) -{ - return gAgent.getPosAgentFromGlobal(position); -} - -//----------------------------------------------------------------------------- -// allocateCharacterJoints() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::allocateCharacterJoints( U32 num ) -{ - deleteAndClearArray(mSkeleton); - mNumJoints = 0; - - mSkeleton = new LLViewerJoint[num]; - - for(S32 joint_num = 0; joint_num < (S32)num; joint_num++) - { - mSkeleton[joint_num].setJointNum(joint_num); - } - - if (!mSkeleton) - { - return FALSE; - } - - mNumJoints = num; - return TRUE; -} - -//----------------------------------------------------------------------------- -// allocateCollisionVolumes() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::allocateCollisionVolumes( U32 num ) -{ - deleteAndClearArray(mCollisionVolumes); - mNumCollisionVolumes = 0; - - mCollisionVolumes = new LLViewerJointCollisionVolume[num]; - if (!mCollisionVolumes) - { - return FALSE; - } - - mNumCollisionVolumes = num; - return TRUE; -} - - -//----------------------------------------------------------------------------- -// getCharacterJoint() -//----------------------------------------------------------------------------- -LLJoint *LLVOAvatar::getCharacterJoint( U32 num ) -{ - if ((S32)num >= mNumJoints - || (S32)num < 0) - { - return NULL; - } - return (LLJoint*)&mSkeleton[num]; -} - -//----------------------------------------------------------------------------- -// requestStopMotion() -//----------------------------------------------------------------------------- -// virtual -void LLVOAvatar::requestStopMotion( LLMotion* motion ) -{ - // Only agent avatars should handle the stop motion notifications. -} - -//----------------------------------------------------------------------------- -// loadAvatar() -//----------------------------------------------------------------------------- -static LLFastTimer::DeclareTimer FTM_LOAD_AVATAR("Load Avatar"); - -BOOL LLVOAvatar::loadAvatar() -{ -// LLFastTimer t(FTM_LOAD_AVATAR); - - // avatar_skeleton.xml - if( !buildSkeleton(sAvatarSkeletonInfo) ) - { - llwarns << "avatar file: buildSkeleton() failed" << llendl; - return FALSE; - } - - // avatar_lad.xml : - if( !loadSkeletonNode() ) - { - llwarns << "avatar file: loadNodeSkeleton() failed" << llendl; - return FALSE; - } - - // avatar_lad.xml : - if( !loadMeshNodes() ) - { - llwarns << "avatar file: loadNodeMesh() failed" << llendl; - return FALSE; - } - - // avatar_lad.xml : - if( sAvatarXmlInfo->mTexSkinColorInfo ) - { - mTexSkinColor = new LLTexGlobalColor( this ); - if( !mTexSkinColor->setInfo( sAvatarXmlInfo->mTexSkinColorInfo ) ) - { - llwarns << "avatar file: mTexSkinColor->setInfo() failed" << llendl; - return FALSE; - } - } - else - { - llwarns << " name=\"skin_color\" not found" << llendl; - return FALSE; - } - if( sAvatarXmlInfo->mTexHairColorInfo ) - { - mTexHairColor = new LLTexGlobalColor( this ); - if( !mTexHairColor->setInfo( sAvatarXmlInfo->mTexHairColorInfo ) ) - { - llwarns << "avatar file: mTexHairColor->setInfo() failed" << llendl; - return FALSE; - } - } - else - { - llwarns << " name=\"hair_color\" not found" << llendl; - return FALSE; - } - if( sAvatarXmlInfo->mTexEyeColorInfo ) - { - mTexEyeColor = new LLTexGlobalColor( this ); - if( !mTexEyeColor->setInfo( sAvatarXmlInfo->mTexEyeColorInfo ) ) - { - llwarns << "avatar file: mTexEyeColor->setInfo() failed" << llendl; - return FALSE; - } - } - else - { - llwarns << " name=\"eye_color\" not found" << llendl; - return FALSE; - } - - // avatar_lad.xml : - if (sAvatarXmlInfo->mLayerInfoList.empty()) - { - llwarns << "avatar file: missing node" << llendl; - return FALSE; - } - - if (sAvatarXmlInfo->mMorphMaskInfoList.empty()) - { - llwarns << "avatar file: missing node" << llendl; - return FALSE; - } - - // avatar_lad.xml : - for (LLVOAvatarXmlInfo::morph_info_list_t::iterator iter = sAvatarXmlInfo->mMorphMaskInfoList.begin(); - iter != sAvatarXmlInfo->mMorphMaskInfoList.end(); - ++iter) - { - LLVOAvatarXmlInfo::LLVOAvatarMorphInfo *info = *iter; - - EBakedTextureIndex baked = LLVOAvatarDictionary::findBakedByRegionName(info->mRegion); - if (baked != BAKED_NUM_INDICES) - { - LLPolyMorphTarget *morph_param; - const std::string *name = &info->mName; - morph_param = (LLPolyMorphTarget *)(getVisualParam(name->c_str())); - if (morph_param) - { - BOOL invert = info->mInvert; - addMaskedMorph(baked, morph_param, invert, info->mLayer); - } - } - - } - - loadLayersets(); - - // avatar_lad.xml : - for (LLVOAvatarXmlInfo::driver_info_list_t::iterator iter = sAvatarXmlInfo->mDriverInfoList.begin(); - iter != sAvatarXmlInfo->mDriverInfoList.end(); - ++iter) - { - LLDriverParamInfo *info = *iter; - LLDriverParam* driver_param = new LLDriverParam( this ); - if (driver_param->setInfo(info)) - { - addVisualParam( driver_param ); - LLVisualParam*(LLVOAvatar::*avatar_function)(S32)const = &LLVOAvatar::getVisualParam; - if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLVOAvatar*)this,_1 ), false)) - { - llwarns << "could not link driven params for avatar " << this->getFullname() << " id: " << driver_param->getID() << llendl; - continue; - } - } - else - { - delete driver_param; - llwarns << "avatar file: driver_param->parseData() failed" << llendl; - return FALSE; - } - } - - // Uncomment to enable avatar_lad.xml debugging. - std::ofstream file; - file.open("avatar_lad.log"); - for( LLViewerVisualParam* param = (LLViewerVisualParam*) getFirstVisualParam(); - param; - param = (LLViewerVisualParam*) getNextVisualParam() ) - { - param->getInfo()->toStream(file); - file << std::endl; - } - - file.close(); - - return TRUE; -} - -//----------------------------------------------------------------------------- -// loadSkeletonNode(): loads node from XML tree -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::loadSkeletonNode () -{ - mRoot.addChild( &mSkeleton[0] ); - - for (std::vector::iterator iter = mMeshLOD.begin(); - iter != mMeshLOD.end(); - ++iter) - { - LLViewerJoint *joint = (LLViewerJoint *) *iter; - joint->mUpdateXform = FALSE; - joint->setMeshesToChildren(); - } - - mRoot.addChild(mMeshLOD[MESH_ID_HEAD]); - mRoot.addChild(mMeshLOD[MESH_ID_EYELASH]); - mRoot.addChild(mMeshLOD[MESH_ID_UPPER_BODY]); - mRoot.addChild(mMeshLOD[MESH_ID_LOWER_BODY]); - mRoot.addChild(mMeshLOD[MESH_ID_SKIRT]); - mRoot.addChild(mMeshLOD[MESH_ID_HEAD]); - - LLViewerJoint *skull = (LLViewerJoint*)mRoot.findJoint("mSkull"); - if (skull) - { - skull->addChild(mMeshLOD[MESH_ID_HAIR] ); - } - - LLViewerJoint *eyeL = (LLViewerJoint*)mRoot.findJoint("mEyeLeft"); - if (eyeL) - { - eyeL->addChild( mMeshLOD[MESH_ID_EYEBALL_LEFT] ); - } - - LLViewerJoint *eyeR = (LLViewerJoint*)mRoot.findJoint("mEyeRight"); - if (eyeR) - { - eyeR->addChild( mMeshLOD[MESH_ID_EYEBALL_RIGHT] ); - } - - // SKELETAL DISTORTIONS - { - LLVOAvatarXmlInfo::skeletal_distortion_info_list_t::iterator iter; - for (iter = sAvatarXmlInfo->mSkeletalDistortionInfoList.begin(); - iter != sAvatarXmlInfo->mSkeletalDistortionInfoList.end(); - ++iter) - { - LLPolySkeletalDistortionInfo *info = *iter; - LLPolySkeletalDistortion *param = new LLPolySkeletalDistortion(this); - if (!param->setInfo(info)) - { - delete param; - return FALSE; - } - else - { - addVisualParam(param); - } - } - } - - // ATTACHMENTS - { - LLVOAvatarXmlInfo::attachment_info_list_t::iterator iter; - for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin(); - iter != sAvatarXmlInfo->mAttachmentInfoList.end(); - ++iter) - { - LLVOAvatarXmlInfo::LLVOAvatarAttachmentInfo *info = *iter; - if (!isSelf() && info->mJointName == "mScreen") - { //don't process screen joint for other avatars - continue; - } - - LLViewerJointAttachment* attachment = new LLViewerJointAttachment(); - - attachment->setName(info->mName); - LLJoint *parentJoint = getJoint(info->mJointName); - if (!parentJoint) - { - llwarns << "No parent joint by name " << info->mJointName << " found for attachment point " << info->mName << llendl; - delete attachment; - continue; - } - - if (info->mHasPosition) - { - attachment->setOriginalPosition(info->mPosition); - } - - if (info->mHasRotation) - { - LLQuaternion rotation; - rotation.setQuat(info->mRotationEuler.mV[VX] * DEG_TO_RAD, - info->mRotationEuler.mV[VY] * DEG_TO_RAD, - info->mRotationEuler.mV[VZ] * DEG_TO_RAD); - attachment->setRotation(rotation); - } - - int group = info->mGroup; - if (group >= 0) - { - if (group < 0 || group >= 9) - { - llwarns << "Invalid group number (" << group << ") for attachment point " << info->mName << llendl; - } - else - { - attachment->setGroup(group); - } - } - - S32 attachmentID = info->mAttachmentID; - if (attachmentID < 1 || attachmentID > 255) - { - llwarns << "Attachment point out of range [1-255]: " << attachmentID << " on attachment point " << info->mName << llendl; - delete attachment; - continue; - } - if (mAttachmentPoints.find(attachmentID) != mAttachmentPoints.end()) - { - llwarns << "Attachment point redefined with id " << attachmentID << " on attachment point " << info->mName << llendl; - delete attachment; - continue; - } - - attachment->setPieSlice(info->mPieMenuSlice); - attachment->setVisibleInFirstPerson(info->mVisibleFirstPerson); - attachment->setIsHUDAttachment(info->mIsHUDAttachment); - - mAttachmentPoints[attachmentID] = attachment; - - // now add attachment joint - parentJoint->addChild(attachment); - } - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// loadMeshNodes(): loads nodes from XML tree -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::loadMeshNodes() -{ - for (LLVOAvatarXmlInfo::mesh_info_list_t::const_iterator meshinfo_iter = sAvatarXmlInfo->mMeshInfoList.begin(); - meshinfo_iter != sAvatarXmlInfo->mMeshInfoList.end(); - ++meshinfo_iter) - { - const LLVOAvatarXmlInfo::LLVOAvatarMeshInfo *info = *meshinfo_iter; - const std::string &type = info->mType; - S32 lod = info->mLOD; - - LLViewerJointMesh* mesh = NULL; - U8 mesh_id = 0; - BOOL found_mesh_id = FALSE; - - /* if (type == "hairMesh") - switch(lod) - case 0: - mesh = &mHairMesh0; */ - for (LLVOAvatarDictionary::Meshes::const_iterator mesh_iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin(); - mesh_iter != LLVOAvatarDictionary::getInstance()->getMeshes().end(); - ++mesh_iter) - { - const EMeshIndex mesh_index = mesh_iter->first; - const LLVOAvatarDictionary::MeshEntry *mesh_dict = mesh_iter->second; - if (type.compare(mesh_dict->mName) == 0) - { - mesh_id = mesh_index; - found_mesh_id = TRUE; - break; - } - } - - if (found_mesh_id) - { - if (lod < (S32)mMeshLOD[mesh_id]->mMeshParts.size()) - { - mesh = mMeshLOD[mesh_id]->mMeshParts[lod]; - } - else - { - llwarns << "Avatar file: has invalid lod setting " << lod << llendl; - return FALSE; - } - } - else - { - llwarns << "Ignoring unrecognized mesh type: " << type << llendl; - return FALSE; - } - - // llinfos << "Parsing mesh data for " << type << "..." << llendl; - - // If this isn't set to white (1.0), avatars will *ALWAYS* be darker than their surroundings. - // Do not touch!!! - mesh->setColor( 1.0f, 1.0f, 1.0f, 1.0f ); - - LLPolyMesh *poly_mesh = NULL; - - if (!info->mReferenceMeshName.empty()) - { - polymesh_map_t::const_iterator polymesh_iter = mMeshes.find(info->mReferenceMeshName); - if (polymesh_iter != mMeshes.end()) - { - poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName, polymesh_iter->second); - poly_mesh->setAvatar(this); - } - else - { - // This should never happen - LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL; - } - } - else - { - poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName); - poly_mesh->setAvatar(this); - } - - if( !poly_mesh ) - { - llwarns << "Failed to load mesh of type " << type << llendl; - return FALSE; - } - - // Multimap insert - mMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh)); - - mesh->setMesh( poly_mesh ); - mesh->setLOD( info->mMinPixelArea ); - - for (LLVOAvatarXmlInfo::LLVOAvatarMeshInfo::morph_info_list_t::const_iterator xmlinfo_iter = info->mPolyMorphTargetInfoList.begin(); - xmlinfo_iter != info->mPolyMorphTargetInfoList.end(); - ++xmlinfo_iter) - { - const LLVOAvatarXmlInfo::LLVOAvatarMeshInfo::morph_info_pair_t *info_pair = &(*xmlinfo_iter); - LLPolyMorphTarget *param = new LLPolyMorphTarget(mesh->getMesh()); - if (!param->setInfo(info_pair->first)) - { - delete param; - return FALSE; - } - else - { - if (info_pair->second) - { - addSharedVisualParam(param); - } - else - { - addVisualParam(param); - } - } - } - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// loadLayerSets() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::loadLayersets() -{ - BOOL success = TRUE; - for (LLVOAvatarXmlInfo::layer_info_list_t::const_iterator layerset_iter = sAvatarXmlInfo->mLayerInfoList.begin(); - layerset_iter != sAvatarXmlInfo->mLayerInfoList.end(); - ++layerset_iter) - { - // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such. - LLTexLayerSetInfo *layerset_info = *layerset_iter; - layerset_info->createVisualParams(this); - } - return success; -} - -//----------------------------------------------------------------------------- -// updateVisualParams() -//----------------------------------------------------------------------------- -void LLVOAvatar::updateVisualParams() -{ - if (gNoRender) - { - return; - } - - setSex( (getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE ); - - LLCharacter::updateVisualParams(); - - if (mLastSkeletonSerialNum != mSkeletonSerialNum) - { - computeBodySize(); - mLastSkeletonSerialNum = mSkeletonSerialNum; - mRoot.updateWorldMatrixChildren(); - } - - dirtyMesh(); - updateHeadOffset(); -} - -//----------------------------------------------------------------------------- -// isActive() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::isActive() const -{ - return TRUE; -} - -//----------------------------------------------------------------------------- -// setPixelAreaAndAngle() -//----------------------------------------------------------------------------- -void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent) -{ - LLMemType mt(LLMemType::MTYPE_AVATAR); - - if (mDrawable.isNull()) - { - return; - } - - const LLVector4a* ext = mDrawable->getSpatialExtents(); - LLVector4a center; - center.setAdd(ext[1], ext[0]); - center.mul(0.5f); - LLVector4a size; - size.setSub(ext[1], ext[0]); - size.mul(0.5f); - - mImpostorPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance()); - - F32 range = mDrawable->mDistanceWRTCamera; - - if (range < 0.001f) // range == zero - { - mAppAngle = 180.f; - } - else - { - F32 radius = size.getLength3().getF32(); - mAppAngle = (F32) atan2( radius, range) * RAD_TO_DEG; - } - - // We always want to look good to ourselves - if( isSelf() ) - { - mPixelArea = llmax( mPixelArea, F32(getTexImageSize() / 16) ); - } -} - -//----------------------------------------------------------------------------- -// updateJointLODs() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::updateJointLODs() -{ - const F32 MAX_PIXEL_AREA = 100000000.f; - F32 lod_factor = (sLODFactor * AVATAR_LOD_TWEAK_RANGE + (1.f - AVATAR_LOD_TWEAK_RANGE)); - F32 avatar_num_min_factor = clamp_rescale(sLODFactor, 0.f, 1.f, 0.25f, 0.6f); - F32 avatar_num_factor = clamp_rescale((F32)sNumVisibleAvatars, 8, 25, 1.f, avatar_num_min_factor); - F32 area_scale = 0.16f; - - { - if (isSelf()) - { - if(gAgentCamera.cameraCustomizeAvatar() || gAgentCamera.cameraMouselook()) - { - mAdjustedPixelArea = MAX_PIXEL_AREA; - } - else - { - mAdjustedPixelArea = mPixelArea*area_scale; - } - } - else if (mIsDummy) - { - mAdjustedPixelArea = MAX_PIXEL_AREA; - } - else - { - // reported avatar pixel area is dependent on avatar render load, based on number of visible avatars - mAdjustedPixelArea = (F32)mPixelArea * area_scale * lod_factor * lod_factor * avatar_num_factor * avatar_num_factor; - } - - // now select meshes to render based on adjusted pixel area - BOOL res = mRoot.updateLOD(mAdjustedPixelArea, TRUE); - if (res) - { - sNumLODChangesThisFrame++; - dirtyMesh(2); - return TRUE; - } - } - - return FALSE; -} - -//----------------------------------------------------------------------------- -// createDrawable() -//----------------------------------------------------------------------------- -LLDrawable *LLVOAvatar::createDrawable(LLPipeline *pipeline) -{ - pipeline->allocDrawable(this); - mDrawable->setLit(FALSE); - - LLDrawPoolAvatar *poolp = (LLDrawPoolAvatar*) gPipeline.getPool(LLDrawPool::POOL_AVATAR); - - // Only a single face (one per avatar) - //this face will be splitted into several if its vertex buffer is too long. - mDrawable->setState(LLDrawable::ACTIVE); - mDrawable->addFace(poolp, NULL); - mDrawable->setRenderType(LLPipeline::RENDER_TYPE_AVATAR); - - mNumInitFaces = mDrawable->getNumFaces() ; - - dirtyMesh(2); - return mDrawable; -} - - -void LLVOAvatar::updateGL() -{ - if (mMeshTexturesDirty) - { - updateMeshTextures(); - mMeshTexturesDirty = FALSE; - } -} - -//----------------------------------------------------------------------------- -// updateGeometry() -//----------------------------------------------------------------------------- -static LLFastTimer::DeclareTimer FTM_UPDATE_AVATAR("Update Avatar"); -BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable) -{ - LLFastTimer ftm(FTM_UPDATE_AVATAR); - if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR))) - { - return TRUE; - } - - if (!mMeshValid) - { - return TRUE; - } - - if (!drawable) - { - llerrs << "LLVOAvatar::updateGeometry() called with NULL drawable" << llendl; - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// updateSexDependentLayerSets() -//----------------------------------------------------------------------------- -void LLVOAvatar::updateSexDependentLayerSets( BOOL upload_bake ) -{ - invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); - invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake ); - invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake ); -} - -//----------------------------------------------------------------------------- -// dirtyMesh() -//----------------------------------------------------------------------------- -void LLVOAvatar::dirtyMesh() -{ - dirtyMesh(1); -} -void LLVOAvatar::dirtyMesh(S32 priority) -{ - mDirtyMesh = llmax(mDirtyMesh, priority); -} -//----------------------------------------------------------------------------- -// hideSkirt() -//----------------------------------------------------------------------------- -void LLVOAvatar::hideSkirt() -{ - mMeshLOD[MESH_ID_SKIRT]->setVisible(FALSE, TRUE); -} - -BOOL LLVOAvatar::setParent(LLViewerObject* parent) -{ - BOOL ret ; - if (parent == NULL) - { - getOffObject(); - ret = LLViewerObject::setParent(parent); - if (isSelf()) - { - gAgentCamera.resetCamera(); - } - } - else - { - ret = LLViewerObject::setParent(parent); - if(ret) - { - sitOnObject(parent); - } - } - return ret ; -} - -void LLVOAvatar::addChild(LLViewerObject *childp) -{ - childp->extractAttachmentItemID(); // find the inventory item this object is associated with. - LLViewerObject::addChild(childp); - if (childp->mDrawable) - { - attachObject(childp); - } - else - { - mPendingAttachment.push_back(childp); - } -} - -void LLVOAvatar::removeChild(LLViewerObject *childp) -{ - LLViewerObject::removeChild(childp); - if (!detachObject(childp)) - { - llwarns << "Calling detach on non-attached object " << llendl; - } -} - -LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object) -{ - S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState()); - - // This should never happen unless the server didn't process the attachment point - // correctly, but putting this check in here to be safe. - if (attachmentID & ATTACHMENT_ADD) - { - llwarns << "Got an attachment with ATTACHMENT_ADD mask, removing ( attach pt:" << attachmentID << " )" << llendl; attachmentID &= ~ATTACHMENT_ADD; - } - - LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); - - if (!attachment) - { - llwarns << "Object attachment point invalid: " << attachmentID << llendl; - attachment = get_if_there(mAttachmentPoints, 1, (LLViewerJointAttachment*)NULL); // Arbitrary using 1 (chest) - } - - return attachment; -} - -//----------------------------------------------------------------------------- -// attachObject() -//----------------------------------------------------------------------------- -const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_object) -{ - LLViewerJointAttachment* attachment = getTargetAttachmentPoint(viewer_object); - - if (!attachment || !attachment->addObject(viewer_object)) - { - return 0; - } - - if (viewer_object->isSelected()) - { - LLSelectMgr::getInstance()->updateSelectionCenter(); - LLSelectMgr::getInstance()->updatePointAt(); - } - - return attachment; -} - -//----------------------------------------------------------------------------- -// attachObject() -//----------------------------------------------------------------------------- -U32 LLVOAvatar::getNumAttachments() const -{ - U32 num_attachments = 0; - for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - const LLViewerJointAttachment *attachment_pt = (*iter).second; - num_attachments += attachment_pt->getNumObjects(); - } - return num_attachments; -} - -//----------------------------------------------------------------------------- -// canAttachMoreObjects() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::canAttachMoreObjects() const -{ - return (getNumAttachments() < MAX_AGENT_ATTACHMENTS); -} - -//----------------------------------------------------------------------------- -// canAttachMoreObjects() -// Returns true if we can attach more objects. -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const -{ - return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS; -} - -//----------------------------------------------------------------------------- -// lazyAttach() -//----------------------------------------------------------------------------- -void LLVOAvatar::lazyAttach() -{ - std::vector > still_pending; - - for (U32 i = 0; i < mPendingAttachment.size(); i++) - { - if (mPendingAttachment[i]->mDrawable) - { - attachObject(mPendingAttachment[i]); - } - else - { - still_pending.push_back(mPendingAttachment[i]); - } - } - - mPendingAttachment = still_pending; -} - -void LLVOAvatar::resetHUDAttachments() -{ - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - if (attachment->getIsHUDAttachment()) - { - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - const LLViewerObject* attached_object = (*attachment_iter); - if (attached_object && attached_object->mDrawable.notNull()) - { - gPipeline.markMoved(attached_object->mDrawable); - } - } - } - } -} - -void LLVOAvatar::rebuildRiggedAttachments( void ) -{ - for ( attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter ) - { - LLViewerJointAttachment* pAttachment = iter->second; - LLViewerJointAttachment::attachedobjs_vec_t::iterator attachmentIterEnd = pAttachment->mAttachedObjects.end(); - - for ( LLViewerJointAttachment::attachedobjs_vec_t::iterator attachmentIter = pAttachment->mAttachedObjects.begin(); - attachmentIter != attachmentIterEnd; ++attachmentIter) - { - const LLViewerObject* pAttachedObject = *attachmentIter; - if ( pAttachment && pAttachedObject->mDrawable.notNull() ) - { - gPipeline.markRebuild(pAttachedObject->mDrawable); - } - } - } -} -//----------------------------------------------------------------------------- -// cleanupAttachedMesh() -//----------------------------------------------------------------------------- -void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO ) -{ - //If a VO has a skin that we'll reset the joint positions to their default - if ( pVO && pVO->mDrawable ) - { - LLVOVolume* pVObj = pVO->mDrawable->getVOVolume(); - if ( pVObj ) - { - const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID() ); - if ( pSkinData ) - { - const int jointCnt = pSkinData->mJointNames.size(); - bool fullRig = ( jointCnt>=20 ) ? true : false; - if ( fullRig ) - { - const int bindCnt = pSkinData->mAlternateBindMatrix.size(); - if ( bindCnt > 0 ) - { - LLVOAvatar::resetJointPositionsToDefault(); - } - } - } - } - } -} -//----------------------------------------------------------------------------- -// detachObject() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) -{ - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - - if (attachment->isObjectAttached(viewer_object)) - { - cleanupAttachedMesh( viewer_object ); - attachment->removeObject(viewer_object); - lldebugs << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << llendl; - return TRUE; - } - } - - std::vector >::iterator iter = std::find(mPendingAttachment.begin(), mPendingAttachment.end(), viewer_object); - if (iter != mPendingAttachment.end()) - { - mPendingAttachment.erase(iter); - return TRUE; - } - - return FALSE; -} - -//----------------------------------------------------------------------------- -// sitDown() -//----------------------------------------------------------------------------- -void LLVOAvatar::sitDown(BOOL bSitting) -{ - mIsSitting = bSitting; - if (isSelf()) - { - // Update Movement Controls according to own Sitting mode - LLFloaterMove::setSittingMode(bSitting); - } -} - -//----------------------------------------------------------------------------- -// sitOnObject() -//----------------------------------------------------------------------------- -void LLVOAvatar::sitOnObject(LLViewerObject *sit_object) -{ - if (isSelf()) - { - // Might be first sit - //LLFirstUse::useSit(); - - gAgent.setFlying(FALSE); - gAgentCamera.setThirdPersonHeadOffset(LLVector3::zero); - //interpolate to new camera position - gAgentCamera.startCameraAnimation(); - // make sure we are not trying to autopilot - gAgent.stopAutoPilot(); - gAgentCamera.setupSitCamera(); - if (gAgentCamera.getForceMouselook()) - { - gAgentCamera.changeCameraToMouselook(); - } - } - - if (mDrawable.isNull()) - { - return; - } - LLQuaternion inv_obj_rot = ~sit_object->getRenderRotation(); - LLVector3 obj_pos = sit_object->getRenderPosition(); - - LLVector3 rel_pos = getRenderPosition() - obj_pos; - rel_pos.rotVec(inv_obj_rot); - - mDrawable->mXform.setPosition(rel_pos); - mDrawable->mXform.setRotation(mDrawable->getWorldRotation() * inv_obj_rot); - - gPipeline.markMoved(mDrawable, TRUE); - // Notice that removing sitDown() from here causes avatars sitting on - // objects to be not rendered for new arrivals. See EXT-6835 and EXT-1655. - sitDown(TRUE); - mRoot.getXform()->setParent(&sit_object->mDrawable->mXform); // LLVOAvatar::sitOnObject - mRoot.setPosition(getPosition()); - mRoot.updateWorldMatrixChildren(); - - stopMotion(ANIM_AGENT_BODY_NOISE); - -} - -//----------------------------------------------------------------------------- -// getOffObject() -//----------------------------------------------------------------------------- -void LLVOAvatar::getOffObject() -{ - if (mDrawable.isNull()) - { - return; - } - - LLViewerObject* sit_object = (LLViewerObject*)getParent(); - - if (sit_object) - { - stopMotionFromSource(sit_object->getID()); - LLFollowCamMgr::setCameraActive(sit_object->getID(), FALSE); - - LLViewerObject::const_child_list_t& child_list = sit_object->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); ++iter) - { - LLViewerObject* child_objectp = *iter; - - stopMotionFromSource(child_objectp->getID()); - LLFollowCamMgr::setCameraActive(child_objectp->getID(), FALSE); - } - } - - // assumes that transform will not be updated with drawable still having a parent - LLVector3 cur_position_world = mDrawable->getWorldPosition(); - LLQuaternion cur_rotation_world = mDrawable->getWorldRotation(); - - // set *local* position based on last *world* position, since we're unparenting the avatar - mDrawable->mXform.setPosition(cur_position_world); - mDrawable->mXform.setRotation(cur_rotation_world); - - gPipeline.markMoved(mDrawable, TRUE); - - sitDown(FALSE); - - mRoot.getXform()->setParent(NULL); // LLVOAvatar::getOffObject - mRoot.setPosition(cur_position_world); - mRoot.setRotation(cur_rotation_world); - mRoot.getXform()->update(); - - startMotion(ANIM_AGENT_BODY_NOISE); - - if (isSelf()) - { - LLQuaternion av_rot = gAgent.getFrameAgent().getQuaternion(); - LLQuaternion obj_rot = sit_object ? sit_object->getRenderRotation() : LLQuaternion::DEFAULT; - av_rot = av_rot * obj_rot; - LLVector3 at_axis = LLVector3::x_axis; - at_axis = at_axis * av_rot; - at_axis.mV[VZ] = 0.f; - at_axis.normalize(); - gAgent.resetAxes(at_axis); - - //reset orientation -// mRoot.setRotation(avWorldRot); - gAgentCamera.setThirdPersonHeadOffset(LLVector3(0.f, 0.f, 1.f)); - - gAgentCamera.setSitCamera(LLUUID::null); - } -} - -//----------------------------------------------------------------------------- -// findAvatarFromAttachment() -//----------------------------------------------------------------------------- -// static -LLVOAvatar* LLVOAvatar::findAvatarFromAttachment( LLViewerObject* obj ) -{ - if( obj->isAttachment() ) - { - do - { - obj = (LLViewerObject*) obj->getParent(); - } - while( obj && !obj->isAvatar() ); - - if( obj && !obj->isDead() ) - { - return (LLVOAvatar*)obj; - } - } - return NULL; -} - -// warning: order(N) not order(1) -S32 LLVOAvatar::getAttachmentCount() -{ - S32 count = mAttachmentPoints.size(); - return count; -} - -LLColor4 LLVOAvatar::getGlobalColor( const std::string& color_name ) const -{ - if (color_name=="skin_color" && mTexSkinColor) - { - return mTexSkinColor->getColor(); - } - else if(color_name=="hair_color" && mTexHairColor) - { - return mTexHairColor->getColor(); - } - if(color_name=="eye_color" && mTexEyeColor) - { - return mTexEyeColor->getColor(); - } - else - { -// return LLColor4( .5f, .5f, .5f, .5f ); - return LLColor4( 0.f, 1.f, 1.f, 1.f ); // good debugging color - } -} - -// virtual -void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result ) -{ -} - -void LLVOAvatar::invalidateAll() -{ -} - -void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake ) -{ - if (global_color == mTexSkinColor) - { - invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); - invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake ); - invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake ); - } - else if (global_color == mTexHairColor) - { - invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); - invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet, upload_bake ); - - // ! BACKWARDS COMPATIBILITY ! - // Fix for dealing with avatars from viewers that don't bake hair. - if (!isTextureDefined(mBakedTextureDatas[BAKED_HAIR].mTextureIndex)) - { - LLColor4 color = mTexHairColor->getColor(); - for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++) - { - mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( color.mV[VX], color.mV[VY], color.mV[VZ], color.mV[VW] ); - } - } - } - else if (global_color == mTexEyeColor) - { -// llinfos << "invalidateComposite cause: onGlobalColorChanged( eyecolor )" << llendl; - invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet, upload_bake ); - } - updateMeshTextures(); -} - -BOOL LLVOAvatar::isVisible() const -{ - return mDrawable.notNull() - && (mDrawable->isVisible() || mIsDummy); -} - -// Determine if we have enough avatar data to render -BOOL LLVOAvatar::getIsCloud() -{ - // Do we have a shape? - if (visualParamWeightsAreDefault()) - { - return TRUE; - } - - if (!isTextureDefined(TEX_LOWER_BAKED) || - !isTextureDefined(TEX_UPPER_BAKED) || - !isTextureDefined(TEX_HEAD_BAKED)) - { - return TRUE; - } - return FALSE; -} - -// call periodically to keep isFullyLoaded up to date. -// returns true if the value has changed. -BOOL LLVOAvatar::updateIsFullyLoaded() -{ - const BOOL loading = getIsCloud(); - updateRuthTimer(loading); - return processFullyLoadedChange(loading); -} - -void LLVOAvatar::updateRuthTimer(bool loading) -{ - if (isSelf() || !loading) - { - return; - } - - if (mPreviousFullyLoaded) - { - mRuthTimer.reset(); - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) - { - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' became cloud." << llendl; - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezCloudNotification",args); - } - mRuthDebugTimer.reset(); - } - - const F32 LOADING_TIMEOUT__SECONDS = 120.f; - if (mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT__SECONDS) - { - llinfos << "Ruth Timer timeout: Missing texture data for '" << getFullname() << "' " - << "( Params loaded : " << !visualParamWeightsAreDefault() << " ) " - << "( Lower : " << isTextureDefined(TEX_LOWER_BAKED) << " ) " - << "( Upper : " << isTextureDefined(TEX_UPPER_BAKED) << " ) " - << "( Head : " << isTextureDefined(TEX_HEAD_BAKED) << " )." - << llendl; - - LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); - mRuthTimer.reset(); - } -} - -BOOL LLVOAvatar::processFullyLoadedChange(bool loading) -{ - // we wait a little bit before giving the all clear, - // to let textures settle down - const F32 PAUSE = 1.f; - if (loading) - mFullyLoadedTimer.reset(); - - mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > PAUSE); - - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) - { - if (!mPreviousFullyLoaded && !loading && mFullyLoaded) - { - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' resolved in " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl; - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezNotification",args); - } - } - - // did our loading state "change" from last call? - const S32 UPDATE_RATE = 30; - BOOL changed = - ((mFullyLoaded != mPreviousFullyLoaded) || // if the value is different from the previous call - (!mFullyLoadedInitialized) || // if we've never been called before - (mFullyLoadedFrameCounter % UPDATE_RATE == 0)); // every now and then issue a change - - mPreviousFullyLoaded = mFullyLoaded; - mFullyLoadedInitialized = TRUE; - mFullyLoadedFrameCounter++; - - return changed; -} - -BOOL LLVOAvatar::isFullyLoaded() const -{ - if (gSavedSettings.getBOOL("RenderUnloadedAvatar")) - return TRUE; - else - return mFullyLoaded; -} - - -//----------------------------------------------------------------------------- -// findMotion() -//----------------------------------------------------------------------------- -LLMotion* LLVOAvatar::findMotion(const LLUUID& id) const -{ - return mMotionController.findMotion(id); -} - -//----------------------------------------------------------------------------- -// updateMeshTextures() -// Uses the current TE values to set the meshes' and layersets' textures. -//----------------------------------------------------------------------------- -void LLVOAvatar::updateMeshTextures() -{ - // llinfos << "updateMeshTextures" << llendl; - if (gNoRender) return; - - // if user has never specified a texture, assign the default - for (U32 i=0; i < getNumTEs(); i++) - { - const LLViewerTexture* te_image = getImage(i, 0); - if(!te_image || te_image->getID().isNull() || (te_image->getID() == IMG_DEFAULT)) - { - setImage(i, LLViewerTextureManager::getFetchedTexture(i == TEX_HAIR ? IMG_DEFAULT : IMG_DEFAULT_AVATAR), 0); // IMG_DEFAULT_AVATAR = a special texture that's never rendered. - } - } - - const BOOL self_customizing = isSelf() && gAgentCamera.cameraCustomizeAvatar(); // During face edit mode, we don't use baked textures - const BOOL other_culled = !isSelf() && mCulled; - LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ; - BOOL paused = FALSE; - if(!isSelf()) - { - src_callback_list = &mCallbackTextureList ; - paused = mLoadedCallbacksPaused ; - } - - std::vector is_layer_baked; - is_layer_baked.resize(mBakedTextureDatas.size(), false); - - std::vector use_lkg_baked_layer; // lkg = "last known good" - use_lkg_baked_layer.resize(mBakedTextureDatas.size(), false); - - for (U32 i=0; i < mBakedTextureDatas.size(); i++) - { - is_layer_baked[i] = isTextureDefined(mBakedTextureDatas[i].mTextureIndex); - - if (!other_culled) - { - // When an avatar is changing clothes and not in Appearance mode, - // use the last-known good baked texture until it finish the first - // render of the new layerset. - - const BOOL layerset_invalid = mBakedTextureDatas[i].mTexLayerSet - && ( !mBakedTextureDatas[i].mTexLayerSet->getComposite()->isInitialized() - || !mBakedTextureDatas[i].mTexLayerSet->isLocalTextureDataAvailable() ); - - use_lkg_baked_layer[i] = (!is_layer_baked[i] - && (mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR) - && layerset_invalid); - if (use_lkg_baked_layer[i]) - { - mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled(TRUE); - } - } - else - { - use_lkg_baked_layer[i] = (!is_layer_baked[i] - && mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR); - if (mBakedTextureDatas[i].mTexLayerSet) - { - mBakedTextureDatas[i].mTexLayerSet->destroyComposite(); - } - } - - } - - // Turn on alpha masking correctly for yourself and other avatars on 1.23+ - mSupportsAlphaLayers = isSelf() || is_layer_baked[BAKED_HAIR]; - - // Baked textures should be requested from the sim this avatar is on. JC - const LLHost target_host = getObjectHost(); - if (!target_host.isOk()) - { - llwarns << "updateMeshTextures: invalid host for object: " << getID() << llendl; - } - - for (U32 i=0; i < mBakedTextureDatas.size(); i++) - { - if (use_lkg_baked_layer[i] && !self_customizing ) - { - LLViewerFetchedTexture* baked_img = LLViewerTextureManager::getFetchedTextureFromHost( mBakedTextureDatas[i].mLastTextureIndex, target_host ); - mBakedTextureDatas[i].mIsUsed = TRUE; - for (U32 k=0; k < mBakedTextureDatas[i].mMeshes.size(); k++) - { - mBakedTextureDatas[i].mMeshes[k]->setTexture( baked_img ); - } - } - else if (!self_customizing && is_layer_baked[i]) - { - LLViewerFetchedTexture* baked_img = LLViewerTextureManager::staticCastToFetchedTexture(getImage( mBakedTextureDatas[i].mTextureIndex, 0 ), TRUE) ; - if( baked_img->getID() == mBakedTextureDatas[i].mLastTextureIndex ) - { - // Even though the file may not be finished loading, we'll consider it loaded and use it (rather than doing compositing). - useBakedTexture( baked_img->getID() ); - } - else - { - mBakedTextureDatas[i].mIsLoaded = FALSE; - if ( (baked_img->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) ) - { - baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), - src_callback_list, paused); - } - baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ), - src_callback_list, paused ); - } - } - else if (mBakedTextureDatas[i].mTexLayerSet - && !other_culled) - { - mBakedTextureDatas[i].mTexLayerSet->createComposite(); - mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled( TRUE ); - mBakedTextureDatas[i].mIsUsed = FALSE; - for (U32 k=0; k < mBakedTextureDatas[i].mMeshes.size(); k++) - { - mBakedTextureDatas[i].mMeshes[k]->setLayerSet( mBakedTextureDatas[i].mTexLayerSet ); - } - } - } - - // set texture and color of hair manually if we are not using a baked image. - // This can happen while loading hair for yourself, or for clients that did not - // bake a hair texture. Still needed for yourself after 1.22 is depricated. - if (!is_layer_baked[BAKED_HAIR] || self_customizing) - { - const LLColor4 color = mTexHairColor ? mTexHairColor->getColor() : LLColor4(1,1,1,1); - LLViewerTexture* hair_img = getImage( TEX_HAIR, 0 ); - for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++) - { - mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( color.mV[VX], color.mV[VY], color.mV[VZ], color.mV[VW] ); - mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setTexture( hair_img ); - } - } - - - for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); - ++baked_iter) - { - const EBakedTextureIndex baked_index = baked_iter->first; - const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second; - - for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); - local_tex_iter != baked_dict->mLocalTextures.end(); - ++local_tex_iter) - { - const ETextureIndex texture_index = *local_tex_iter; - const BOOL is_baked_ready = (is_layer_baked[baked_index] && mBakedTextureDatas[baked_index].mIsLoaded) || other_culled; - if (isSelf()) - { - setBakedReady(texture_index, is_baked_ready); - } - } - } - removeMissingBakedTextures(); -} - -// virtual -//----------------------------------------------------------------------------- -// setLocalTexture() -//----------------------------------------------------------------------------- -void LLVOAvatar::setLocalTexture( ETextureIndex type, LLViewerTexture* in_tex, BOOL baked_version_ready, U32 index ) -{ - // invalid for anyone but self - llassert(0); -} - -//virtual -void LLVOAvatar::setBakedReady(LLVOAvatarDefines::ETextureIndex type, BOOL baked_version_exists, U32 index) -{ - // invalid for anyone but self - llassert(0); -} - -void LLVOAvatar::addChat(const LLChat& chat) -{ - std::deque::iterator chat_iter; - - mChats.push_back(chat); - - S32 chat_length = 0; - for( chat_iter = mChats.begin(); chat_iter != mChats.end(); ++chat_iter) - { - chat_length += chat_iter->mText.size(); - } - - // remove any excess chat - chat_iter = mChats.begin(); - while ((chat_length > MAX_BUBBLE_CHAT_LENGTH || mChats.size() > MAX_BUBBLE_CHAT_UTTERANCES) && chat_iter != mChats.end()) - { - chat_length -= chat_iter->mText.size(); - mChats.pop_front(); - chat_iter = mChats.begin(); - } - - mChatTimer.reset(); -} - -void LLVOAvatar::clearChat() -{ - mChats.clear(); -} - -// adds a morph mask to the appropriate baked texture structure -void LLVOAvatar::addMaskedMorph(EBakedTextureIndex index, LLPolyMorphTarget* morph_target, BOOL invert, std::string layer) -{ - if (index < BAKED_NUM_INDICES) - { - LLMaskedMorph *morph = new LLMaskedMorph(morph_target, invert, layer); - mBakedTextureDatas[index].mMaskedMorphs.push_front(morph); - } -} - -// returns TRUE if morph masks are present and not valid for a given baked texture, FALSE otherwise -BOOL LLVOAvatar::morphMaskNeedsUpdate(LLVOAvatarDefines::EBakedTextureIndex index) -{ - if (index >= BAKED_NUM_INDICES) - { - return FALSE; - } - - if (!mBakedTextureDatas[index].mMaskedMorphs.empty()) - { - if (isSelf()) - { - LLTexLayerSet *layer_set = mBakedTextureDatas[index].mTexLayerSet; - if (layer_set) - { - return !layer_set->isMorphValid(); - } - } - else - { - return FALSE; - } - } - - return FALSE; -} - -void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLVOAvatarDefines::EBakedTextureIndex index) -{ - if (index >= BAKED_NUM_INDICES) - { - llwarns << "invalid baked texture index passed to applyMorphMask" << llendl; - return; - } - - for (morph_list_t::const_iterator iter = mBakedTextureDatas[index].mMaskedMorphs.begin(); - iter != mBakedTextureDatas[index].mMaskedMorphs.end(); ++iter) - { - const LLMaskedMorph* maskedMorph = (*iter); - maskedMorph->mMorphTarget->applyMask(tex_data, width, height, num_components, maskedMorph->mInvert); - } -} - - -//----------------------------------------------------------------------------- -// releaseComponentTextures() -// release any component texture UUIDs for which we have a baked texture -// ! BACKWARDS COMPATIBILITY ! -// This is only called for non-self avatars, it can be taken out once component -// textures aren't communicated by non-self avatars. -//----------------------------------------------------------------------------- -void LLVOAvatar::releaseComponentTextures() -{ - // ! BACKWARDS COMPATIBILITY ! - // Detect if the baked hair texture actually wasn't sent, and if so set to default - if (isTextureDefined(TEX_HAIR_BAKED) && getImage(TEX_HAIR_BAKED,0)->getID() == getImage(TEX_SKIRT_BAKED,0)->getID()) - { - if (getImage(TEX_HAIR_BAKED,0)->getID() != IMG_INVISIBLE) - { - // Regression case of messaging system. Expected 21 textures, received 20. last texture is not valid so set to default - setTETexture(TEX_HAIR_BAKED, IMG_DEFAULT_AVATAR); - } - } - - for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) - { - const LLVOAvatarDictionary::BakedEntry * bakedDicEntry = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); - // skip if this is a skirt and av is not wearing one, or if we don't have a baked texture UUID - if (!isTextureDefined(bakedDicEntry->mTextureIndex) - && ( (baked_index != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) )) - { - continue; - } - - for (U8 texture = 0; texture < bakedDicEntry->mLocalTextures.size(); texture++) - { - const U8 te = (ETextureIndex)bakedDicEntry->mLocalTextures[texture]; - setTETexture(te, IMG_DEFAULT_AVATAR); - } - } -} - -//static -BOOL LLVOAvatar::teToColorParams( ETextureIndex te, U32 *param_name ) -{ - switch( te ) - { - case TEX_UPPER_SHIRT: - param_name[0] = 803; //"shirt_red"; - param_name[1] = 804; //"shirt_green"; - param_name[2] = 805; //"shirt_blue"; - break; - - case TEX_LOWER_PANTS: - param_name[0] = 806; //"pants_red"; - param_name[1] = 807; //"pants_green"; - param_name[2] = 808; //"pants_blue"; - break; - - case TEX_LOWER_SHOES: - param_name[0] = 812; //"shoes_red"; - param_name[1] = 813; //"shoes_green"; - param_name[2] = 817; //"shoes_blue"; - break; - - case TEX_LOWER_SOCKS: - param_name[0] = 818; //"socks_red"; - param_name[1] = 819; //"socks_green"; - param_name[2] = 820; //"socks_blue"; - break; - - case TEX_UPPER_JACKET: - case TEX_LOWER_JACKET: - param_name[0] = 834; //"jacket_red"; - param_name[1] = 835; //"jacket_green"; - param_name[2] = 836; //"jacket_blue"; - break; - - case TEX_UPPER_GLOVES: - param_name[0] = 827; //"gloves_red"; - param_name[1] = 829; //"gloves_green"; - param_name[2] = 830; //"gloves_blue"; - break; - - case TEX_UPPER_UNDERSHIRT: - param_name[0] = 821; //"undershirt_red"; - param_name[1] = 822; //"undershirt_green"; - param_name[2] = 823; //"undershirt_blue"; - break; - - case TEX_LOWER_UNDERPANTS: - param_name[0] = 824; //"underpants_red"; - param_name[1] = 825; //"underpants_green"; - param_name[2] = 826; //"underpants_blue"; - break; - - case TEX_SKIRT: - param_name[0] = 921; //"skirt_red"; - param_name[1] = 922; //"skirt_green"; - param_name[2] = 923; //"skirt_blue"; - break; - - case TEX_HEAD_TATTOO: - case TEX_LOWER_TATTOO: - case TEX_UPPER_TATTOO: - param_name[0] = 1071; //"tattoo_red"; - param_name[1] = 1072; //"tattoo_green"; - param_name[2] = 1073; //"tattoo_blue"; - break; - - default: - llassert(0); - return FALSE; - } - - return TRUE; -} - -void LLVOAvatar::setClothesColor( ETextureIndex te, const LLColor4& new_color, BOOL upload_bake ) -{ - U32 param_name[3]; - if( teToColorParams( te, param_name ) ) - { - setVisualParamWeight( param_name[0], new_color.mV[VX], upload_bake ); - setVisualParamWeight( param_name[1], new_color.mV[VY], upload_bake ); - setVisualParamWeight( param_name[2], new_color.mV[VZ], upload_bake ); - } -} - -LLColor4 LLVOAvatar::getClothesColor( ETextureIndex te ) -{ - LLColor4 color; - U32 param_name[3]; - if( teToColorParams( te, param_name ) ) - { - color.mV[VX] = getVisualParamWeight( param_name[0] ); - color.mV[VY] = getVisualParamWeight( param_name[1] ); - color.mV[VZ] = getVisualParamWeight( param_name[2] ); - } - return color; -} - -// static -LLColor4 LLVOAvatar::getDummyColor() -{ - return DUMMY_COLOR; -} - -void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const -{ - llinfos << (isSelf() ? "Self: " : "Other: ") << context << llendl; - for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); - iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); - ++iter) - { - const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; - // TODO: MULTI-WEARABLE: handle multiple textures for self - const LLViewerTexture* te_image = getImage(iter->first,0); - if( !te_image ) - { - llinfos << " " << texture_dict->mName << ": null ptr" << llendl; - } - else if( te_image->getID().isNull() ) - { - llinfos << " " << texture_dict->mName << ": null UUID" << llendl; - } - else if( te_image->getID() == IMG_DEFAULT ) - { - llinfos << " " << texture_dict->mName << ": IMG_DEFAULT" << llendl; - } - else if( te_image->getID() == IMG_DEFAULT_AVATAR ) - { - llinfos << " " << texture_dict->mName << ": IMG_DEFAULT_AVATAR" << llendl; - } - else - { - llinfos << " " << texture_dict->mName << ": " << te_image->getID() << llendl; - } - } -} - -// Unlike most wearable functions, this works for both self and other. -BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const -{ - if (mIsDummy) return TRUE; - - switch(type) - { - case LLWearableType::WT_SHAPE: - case LLWearableType::WT_SKIN: - case LLWearableType::WT_HAIR: - case LLWearableType::WT_EYES: - return TRUE; // everyone has all bodyparts - default: - break; // Do nothing - } - - /* switch(type) - case LLWearableType::WT_SHIRT: - indicator_te = TEX_UPPER_SHIRT; */ - for (LLVOAvatarDictionary::Textures::const_iterator tex_iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); - tex_iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); - ++tex_iter) - { - const LLVOAvatarDictionary::TextureEntry *texture_dict = tex_iter->second; - if (texture_dict->mWearableType == type) - { - // If you're checking another avatar's clothing, you don't have component textures. - // Thus, you must check to see if the corresponding baked texture is defined. - // NOTE: this is a poor substitute if you actually want to know about individual pieces of clothing - // this works for detecting a skirt (most important), but is ineffective at any piece of clothing that - // gets baked into a texture that always exists (upper or lower). - if (texture_dict->mIsUsedByBakedTexture) - { - const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; - return isTextureDefined(LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex); - } - return FALSE; - } - } - return FALSE; -} - -//----------------------------------------------------------------------------- -// clampAttachmentPositions() -//----------------------------------------------------------------------------- -void LLVOAvatar::clampAttachmentPositions() -{ - if (isDead()) - { - return; - } - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - if (attachment) - { - attachment->clampObjectPosition(); - } - } -} - -BOOL LLVOAvatar::hasHUDAttachment() const -{ - for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - if (attachment->getIsHUDAttachment() && attachment->getNumObjects() > 0) - { - return TRUE; - } - } - return FALSE; -} - -LLBBox LLVOAvatar::getHUDBBox() const -{ - LLBBox bbox; - for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - if (attachment->getIsHUDAttachment()) - { - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - const LLViewerObject* attached_object = (*attachment_iter); - if (attached_object == NULL) - { - llwarns << "HUD attached object is NULL!" << llendl; - continue; - } - // initialize bounding box to contain identity orientation and center point for attached object - bbox.addPointLocal(attached_object->getPosition()); - // add rotated bounding box for attached object - bbox.addBBoxAgent(attached_object->getBoundingBoxAgent()); - LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); - ++iter) - { - const LLViewerObject* child_objectp = *iter; - bbox.addBBoxAgent(child_objectp->getBoundingBoxAgent()); - } - } - } - } - - return bbox; -} - -void LLVOAvatar::rebuildHUD() -{ -} - -//----------------------------------------------------------------------------- -// onFirstTEMessageReceived() -//----------------------------------------------------------------------------- -void LLVOAvatar::onFirstTEMessageReceived() -{ - if( !mFirstTEMessageReceived ) - { - mFirstTEMessageReceived = TRUE; - - LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ; - BOOL paused = FALSE ; - if(!isSelf()) - { - src_callback_list = &mCallbackTextureList ; - paused = mLoadedCallbacksPaused ; - } - - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - const BOOL layer_baked = isTextureDefined(mBakedTextureDatas[i].mTextureIndex); - - // Use any baked textures that we have even if they haven't downloaded yet. - // (That is, don't do a transition from unbaked to baked.) - if (layer_baked) - { - LLViewerFetchedTexture* image = LLViewerTextureManager::staticCastToFetchedTexture(getImage( mBakedTextureDatas[i].mTextureIndex, 0 ), TRUE) ; - mBakedTextureDatas[i].mLastTextureIndex = image->getID(); - // If we have more than one texture for the other baked layers, we'll want to call this for them too. - if ( (image->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) ) - { - image->setLoadedCallback( onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), - src_callback_list, paused); - } - image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ), - src_callback_list, paused ); - } - } - - mMeshTexturesDirty = TRUE; - gPipeline.markGLRebuild(this); - } -} - -//----------------------------------------------------------------------------- -// bool visualParamWeightsAreDefault() -//----------------------------------------------------------------------------- -bool LLVOAvatar::visualParamWeightsAreDefault() -{ - bool rtn = true; - - bool is_wearing_skirt = isWearingWearableType(LLWearableType::WT_SKIRT); - for (LLVisualParam *param = getFirstVisualParam(); - param; - param = getNextVisualParam()) - { - if (param->isTweakable()) - { - LLViewerVisualParam* vparam = dynamic_cast(param); - llassert(vparam); - bool is_skirt_param = vparam && - LLWearableType::WT_SKIRT == vparam->getWearableType(); - if (param->getWeight() != param->getDefaultWeight() && - // we have to not care whether skirt weights are default, if we're not actually wearing a skirt - (is_wearing_skirt || !is_skirt_param)) - { - //llinfos << "param '" << param->getName() << "'=" << param->getWeight() << " which differs from default=" << param->getDefaultWeight() << llendl; - rtn = false; - break; - } - } - } - - //llinfos << "params are default ? " << int(rtn) << llendl; - - return rtn; -} - - -//----------------------------------------------------------------------------- -// processAvatarAppearance() -//----------------------------------------------------------------------------- -void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) -{ - if (gSavedSettings.getBOOL("BlockAvatarAppearanceMessages")) - { - llwarns << "Blocking AvatarAppearance message" << llendl; - return; - } - - LLMemType mt(LLMemType::MTYPE_AVATAR); - -// llinfos << "processAvatarAppearance start " << mID << llendl; - BOOL is_first_appearance_message = !mFirstAppearanceMessageReceived; - - mFirstAppearanceMessageReceived = TRUE; - - if( isSelf() ) - { - llwarns << "Received AvatarAppearance for self" << llendl; - if( mFirstTEMessageReceived ) - { -// llinfos << "processAvatarAppearance end " << mID << llendl; - return; - } - } - - if (gNoRender) - { - return; - } - - ESex old_sex = getSex(); - -// llinfos << "LLVOAvatar::processAvatarAppearance()" << llendl; -// dumpAvatarTEs( "PRE processAvatarAppearance()" ); - unpackTEMessage(mesgsys, _PREHASH_ObjectData); -// dumpAvatarTEs( "POST processAvatarAppearance()" ); - - // prevent the overwriting of valid baked textures with invalid baked textures - for (U8 baked_index = 0; baked_index < mBakedTextureDatas.size(); baked_index++) - { - if (!isTextureDefined(mBakedTextureDatas[baked_index].mTextureIndex) - && mBakedTextureDatas[baked_index].mLastTextureIndex != IMG_DEFAULT - && baked_index != BAKED_SKIRT) - { - setTEImage(mBakedTextureDatas[baked_index].mTextureIndex, - LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureIndex, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); - } - } - - - if( !is_first_appearance_message ) - { - onFirstTEMessageReceived(); - } - - setCompositeUpdatesEnabled( FALSE ); - mMeshTexturesDirty = TRUE; - gPipeline.markGLRebuild(this); - - // ! BACKWARDS COMPATIBILITY ! - // Non-self avatars will no longer have component textures - if (!isSelf()) - { - releaseComponentTextures(); - } - - // parse visual params - S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam); - bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing - if( num_blocks > 1 && !drop_visual_params_debug) - { - BOOL params_changed = FALSE; - BOOL interp_params = FALSE; - - LLVisualParam* param = getFirstVisualParam(); - llassert(param); // if this ever fires, we should do the same as when num_blocks<=1 - if (!param) - { - llwarns << "No visual params!" << llendl; - } - else - { - for( S32 i = 0; i < num_blocks; i++ ) - { - while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT - { - param = getNextVisualParam(); - } - - if( !param ) - { - // more visual params supplied than expected - just process what we know about - break; - } - - U8 value; - mesgsys->getU8Fast(_PREHASH_VisualParam, _PREHASH_ParamValue, value, i); - F32 newWeight = U8_to_F32(value, param->getMinWeight(), param->getMaxWeight()); - - if (is_first_appearance_message || (param->getWeight() != newWeight)) - { - //llinfos << "Received update for param " << param->getDisplayName() << " at value " << newWeight << llendl; - params_changed = TRUE; - if(is_first_appearance_message) - { - param->setWeight(newWeight, FALSE); - } - else - { - interp_params = TRUE; - param->setAnimationTarget(newWeight, FALSE); - } - } - param = getNextVisualParam(); - } - } - - const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT - if (num_blocks != expected_tweakable_count) - { - llinfos << "Number of params in AvatarAppearance msg (" << num_blocks << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << llendl; - } - - if (params_changed) - { - if (interp_params) - { - startAppearanceAnimation(); - } - updateVisualParams(); - - ESex new_sex = getSex(); - if( old_sex != new_sex ) - { - updateSexDependentLayerSets( FALSE ); - } - } - - llassert( getSex() == ((getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE) ); - } - else - { - // AvatarAppearance message arrived without visual params - if (drop_visual_params_debug) - { - llinfos << "Debug-faked lack of parameters on AvatarAppearance for object: " << getID() << llendl; - } - else - { - llinfos << "AvatarAppearance msg received without any parameters, object: " << getID() << llendl; - } - - const F32 LOADING_TIMEOUT_SECONDS = 60.f; - // this isn't really a problem if we already have a non-default shape - if (visualParamWeightsAreDefault() && mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT_SECONDS) - { - // re-request appearance, hoping that it comes back with a shape next time - llinfos << "Re-requesting AvatarAppearance for object: " << getID() << llendl; - LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); - mRuthTimer.reset(); - } - else - { - llinfos << "That's okay, we already have a non-default shape for object: " << getID() << llendl; - // we don't really care. - } - } - - setCompositeUpdatesEnabled( TRUE ); - - // If all of the avatars are completely baked, release the global image caches to conserve memory. - LLVOAvatar::cullAvatarsByPixelArea(); - -// llinfos << "processAvatarAppearance end " << mID << llendl; -} - -// static -void LLVOAvatar::getAnimLabels( LLDynamicArray* labels ) -{ - S32 i; - for( i = 0; i < gUserAnimStatesCount; i++ ) - { - labels->put( LLAnimStateLabels::getStateLabel( gUserAnimStates[i].mName ) ); - } - - // Special case to trigger away (AFK) state - labels->put( "Away From Keyboard" ); -} - -// static -void LLVOAvatar::getAnimNames( LLDynamicArray* names ) -{ - S32 i; - - for( i = 0; i < gUserAnimStatesCount; i++ ) - { - names->put( std::string(gUserAnimStates[i].mName) ); - } - - // Special case to trigger away (AFK) state - names->put( "enter_away_from_keyboard_state" ); -} - -void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) -{ - if (!userdata) return; - - //llinfos << "onBakedTextureMasksLoaded: " << src_vi->getID() << llendl; - const LLMemType mt(LLMemType::MTYPE_AVATAR); - const LLUUID id = src_vi->getID(); - - LLTextureMaskData* maskData = (LLTextureMaskData*) userdata; - LLVOAvatar* self = (LLVOAvatar*) gObjectList.findObject( maskData->mAvatarID ); - - // if discard level is 2 less than last discard level we processed, or we hit 0, - // then generate morph masks - if(self && success && (discard_level < maskData->mLastDiscardLevel - 2 || discard_level == 0)) - { - if(aux_src && aux_src->getComponents() == 1) - { - if (!aux_src->getData()) - { - llerrs << "No auxiliary source data for onBakedTextureMasksLoaded" << llendl; - return; - } - - U32 gl_name; - LLImageGL::generateTextures(1, &gl_name ); - stop_glerror(); - - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name); - stop_glerror(); - - LLImageGL::setManualImage( - GL_TEXTURE_2D, 0, GL_ALPHA8, - aux_src->getWidth(), aux_src->getHeight(), - GL_ALPHA, GL_UNSIGNED_BYTE, aux_src->getData()); - stop_glerror(); - - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - - /* if( id == head_baked->getID() ) - if (self->mBakedTextureDatas[BAKED_HEAD].mTexLayerSet) - //llinfos << "onBakedTextureMasksLoaded for head " << id << " discard = " << discard_level << llendl; - self->mBakedTextureDatas[BAKED_HEAD].mTexLayerSet->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1); - maskData->mLastDiscardLevel = discard_level; */ - BOOL found_texture_id = false; - for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); - iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); - ++iter) - { - - const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; - if (texture_dict->mIsUsedByBakedTexture) - { - const ETextureIndex texture_index = iter->first; - const LLViewerTexture *baked_img = self->getImage(texture_index, 0); - if (baked_img && id == baked_img->getID()) - { - const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; - self->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1, baked_index); - maskData->mLastDiscardLevel = discard_level; - if (self->mBakedTextureDatas[baked_index].mMaskTexName) - { - LLImageGL::deleteTextures(1, &(self->mBakedTextureDatas[baked_index].mMaskTexName)); - } - self->mBakedTextureDatas[baked_index].mMaskTexName = gl_name; - found_texture_id = true; - break; - } - } - } - if (!found_texture_id) - { - llinfos << "onBakedTextureMasksLoaded(): unexpected image id: " << id << llendl; - } - self->dirtyMesh(); - } - else - { - // this can happen when someone uses an old baked texture possibly provided by - // viewer-side baked texture caching - llwarns << "Masks loaded callback but NO aux source!" << llendl; - } - } - - if (final || !success) - { - delete maskData; - } -} - -// static -void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) -{ - LLUUID *avatar_idp = (LLUUID *)userdata; - LLVOAvatar *selfp = (LLVOAvatar *)gObjectList.findObject(*avatar_idp); - - if (!success && selfp) - { - selfp->removeMissingBakedTextures(); - } - if (final || !success ) - { - delete avatar_idp; - } -} - -void LLVOAvatar::onBakedTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) -{ - //llinfos << "onBakedTextureLoaded: " << src_vi->getID() << llendl; - - LLUUID id = src_vi->getID(); - LLUUID *avatar_idp = (LLUUID *)userdata; - LLVOAvatar *selfp = (LLVOAvatar *)gObjectList.findObject(*avatar_idp); - - if (selfp && !success) - { - selfp->removeMissingBakedTextures(); - } - - if( final || !success ) - { - delete avatar_idp; - } - - if( selfp && success && final ) - { - selfp->useBakedTexture( id ); - } -} - - -// Called when baked texture is loaded and also when we start up with a baked texture -void LLVOAvatar::useBakedTexture( const LLUUID& id ) -{ - /* if(id == head_baked->getID()) - mHeadBakedLoaded = TRUE; - mLastHeadBakedID = id; - mHeadMesh0.setTexture( head_baked ); - mHeadMesh1.setTexture( head_baked ); */ - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - LLViewerTexture* image_baked = getImage( mBakedTextureDatas[i].mTextureIndex, 0 ); - if (id == image_baked->getID()) - { - mBakedTextureDatas[i].mIsLoaded = true; - mBakedTextureDatas[i].mLastTextureIndex = id; - mBakedTextureDatas[i].mIsUsed = true; - for (U32 k = 0; k < mBakedTextureDatas[i].mMeshes.size(); k++) - { - mBakedTextureDatas[i].mMeshes[k]->setTexture( image_baked ); - } - if (mBakedTextureDatas[i].mTexLayerSet) - { - //mBakedTextureDatas[i].mTexLayerSet->destroyComposite(); - } - const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); - for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); - local_tex_iter != baked_dict->mLocalTextures.end(); - ++local_tex_iter) - { - if (isSelf()) setBakedReady(*local_tex_iter, TRUE); - } - - // ! BACKWARDS COMPATIBILITY ! - // Workaround for viewing avatars from old viewers that haven't baked hair textures. - // This is paired with similar code in updateMeshTextures that sets hair mesh color. - if (i == BAKED_HAIR) - { - for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++) - { - mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( 1.f, 1.f, 1.f, 1.f ); - } - } - } - } - - dirtyMesh(); -} - -// static -void LLVOAvatar::dumpArchetypeXML( void* ) -{ - LLAPRFile outfile; - outfile.open(gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,"new archetype.xml"), LL_APR_WB ); - apr_file_t* file = outfile.getFileHandle() ; - if (!file) - { - return; - } - - apr_file_printf( file, "\n" ); - apr_file_printf( file, "\n" ); - apr_file_printf( file, "\n\t\n" ); - - // only body parts, not clothing. - for (S32 type = LLWearableType::WT_SHAPE; type <= LLWearableType::WT_EYES; type++) - { - const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type); - apr_file_printf( file, "\n\t\t\n", wearable_name.c_str() ); - - for (LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->getNextVisualParam()) - { - LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param; - if( (viewer_param->getWearableType() == type) && - (viewer_param->isTweakable() ) ) - { - apr_file_printf(file, "\t\t\n", - viewer_param->getID(), viewer_param->getName().c_str(), viewer_param->getWeight()); - } - } - - for (U8 te = 0; te < TEX_NUM_INDICES; te++) - { - if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex)te) == type) - { - // MULTIPLE_WEARABLES: extend to multiple wearables? - LLViewerTexture* te_image = ((LLVOAvatar *)(gAgentAvatarp))->getImage((ETextureIndex)te, 0); - if( te_image ) - { - std::string uuid_str; - te_image->getID().toString( uuid_str ); - apr_file_printf( file, "\t\t\n", te, uuid_str.c_str()); - } - } - } - } - apr_file_printf( file, "\t\n" ); - apr_file_printf( file, "\n\n" ); -} - - -void LLVOAvatar::setVisibilityRank(U32 rank) -{ - if (mDrawable.isNull() || mDrawable->isDead()) - { - // do nothing - return; - } - mVisibilityRank = rank; -} - -// Assumes LLVOAvatar::sInstances has already been sorted. -S32 LLVOAvatar::getUnbakedPixelAreaRank() -{ - S32 rank = 1; - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { - LLVOAvatar* inst = (LLVOAvatar*) *iter; - if (inst == this) - { - return rank; - } - else if (!inst->isDead() && !inst->isFullyBaked()) - { - rank++; - } - } - - llassert(0); - return 0; -} - -struct CompareScreenAreaGreater -{ - BOOL operator()(const LLCharacter* const& lhs, const LLCharacter* const& rhs) - { - return lhs->getPixelArea() > rhs->getPixelArea(); - } -}; - -// static -void LLVOAvatar::cullAvatarsByPixelArea() -{ - std::sort(LLCharacter::sInstances.begin(), LLCharacter::sInstances.end(), CompareScreenAreaGreater()); - - // Update the avatars that have changed status - U32 rank = 2; //1 is reserved for self. - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { - LLVOAvatar* inst = (LLVOAvatar*) *iter; - BOOL culled; - if (inst->isSelf() || inst->isFullyBaked()) - { - culled = FALSE; - } - else - { - culled = TRUE; - } - - if (inst->mCulled != culled) - { - inst->mCulled = culled; - lldebugs << "avatar " << inst->getID() << (culled ? " start culled" : " start not culled" ) << llendl; - inst->updateMeshTextures(); - } - - if (inst->isSelf()) - { - inst->setVisibilityRank(1); - } - else if (inst->mDrawable.notNull() && inst->mDrawable->isVisible()) - { - inst->setVisibilityRank(rank++); - } - } - - S32 grey_avatars = 0; - if (LLVOAvatar::areAllNearbyInstancesBaked(grey_avatars)) - { - LLVOAvatar::deleteCachedImages(false); - } - else - { - if (gFrameTimeSeconds != sUnbakedUpdateTime) // only update once per frame - { - sUnbakedUpdateTime = gFrameTimeSeconds; - sUnbakedTime += gFrameIntervalSeconds; - } - if (grey_avatars > 0) - { - if (gFrameTimeSeconds != sGreyUpdateTime) // only update once per frame - { - sGreyUpdateTime = gFrameTimeSeconds; - sGreyTime += gFrameIntervalSeconds; - } - } - } -} - -void LLVOAvatar::startAppearanceAnimation() -{ - if(!mAppearanceAnimating) - { - mAppearanceAnimating = TRUE; - mAppearanceMorphTimer.reset(); - mLastAppearanceBlendTime = 0.f; - } -} - -// virtual -void LLVOAvatar::removeMissingBakedTextures() -{ -} - -//----------------------------------------------------------------------------- -// LLVOAvatarXmlInfo -//----------------------------------------------------------------------------- - -LLVOAvatar::LLVOAvatarXmlInfo::LLVOAvatarXmlInfo() - : mTexSkinColorInfo(0), mTexHairColorInfo(0), mTexEyeColorInfo(0) -{ -} - -LLVOAvatar::LLVOAvatarXmlInfo::~LLVOAvatarXmlInfo() -{ - std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer()); - std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer()); - std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer()); - deleteAndClear(mTexSkinColorInfo); - deleteAndClear(mTexHairColorInfo); - deleteAndClear(mTexEyeColorInfo); - std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer()); - std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer()); - std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer()); -} - -//----------------------------------------------------------------------------- -// LLVOAvatarBoneInfo::parseXml() -//----------------------------------------------------------------------------- -BOOL LLVOAvatarBoneInfo::parseXml(LLXmlTreeNode* node) -{ - if (node->hasName("bone")) - { - mIsJoint = TRUE; - static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); - if (!node->getFastAttributeString(name_string, mName)) - { - llwarns << "Bone without name" << llendl; - return FALSE; - } - } - else if (node->hasName("collision_volume")) - { - mIsJoint = FALSE; - static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); - if (!node->getFastAttributeString(name_string, mName)) - { - mName = "Collision Volume"; - } - } - else - { - llwarns << "Invalid node " << node->getName() << llendl; - return FALSE; - } - - static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos"); - if (!node->getFastAttributeVector3(pos_string, mPos)) - { - llwarns << "Bone without position" << llendl; - return FALSE; - } - - static LLStdStringHandle rot_string = LLXmlTree::addAttributeString("rot"); - if (!node->getFastAttributeVector3(rot_string, mRot)) - { - llwarns << "Bone without rotation" << llendl; - return FALSE; - } - - static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale"); - if (!node->getFastAttributeVector3(scale_string, mScale)) - { - llwarns << "Bone without scale" << llendl; - return FALSE; - } - - if (mIsJoint) - { - static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot"); - if (!node->getFastAttributeVector3(pivot_string, mPivot)) - { - llwarns << "Bone without pivot" << llendl; - return FALSE; - } - } - - // parse children - LLXmlTreeNode* child; - for( child = node->getFirstChild(); child; child = node->getNextChild() ) - { - LLVOAvatarBoneInfo *child_info = new LLVOAvatarBoneInfo; - if (!child_info->parseXml(child)) - { - delete child_info; - return FALSE; - } - mChildList.push_back(child_info); - } - return TRUE; -} - -//----------------------------------------------------------------------------- -// LLVOAvatarSkeletonInfo::parseXml() -//----------------------------------------------------------------------------- -BOOL LLVOAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node) -{ - static LLStdStringHandle num_bones_string = LLXmlTree::addAttributeString("num_bones"); - if (!node->getFastAttributeS32(num_bones_string, mNumBones)) - { - llwarns << "Couldn't find number of bones." << llendl; - return FALSE; - } - - static LLStdStringHandle num_collision_volumes_string = LLXmlTree::addAttributeString("num_collision_volumes"); - node->getFastAttributeS32(num_collision_volumes_string, mNumCollisionVolumes); - - LLXmlTreeNode* child; - for( child = node->getFirstChild(); child; child = node->getNextChild() ) - { - LLVOAvatarBoneInfo *info = new LLVOAvatarBoneInfo; - if (!info->parseXml(child)) - { - delete info; - llwarns << "Error parsing bone in skeleton file" << llendl; - return FALSE; - } - mBoneInfoList.push_back(info); - } - return TRUE; -} - -//----------------------------------------------------------------------------- -// parseXmlSkeletonNode(): parses nodes from XML tree -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* root) -{ - LLXmlTreeNode* node = root->getChildByName( "skeleton" ); - if( !node ) - { - llwarns << "avatar file: missing " << llendl; - return FALSE; - } - - LLXmlTreeNode* child; - - // SKELETON DISTORTIONS - for (child = node->getChildByName( "param" ); - child; - child = node->getNextNamedChild()) - { - if (!child->getChildByName("param_skeleton")) - { - if (child->getChildByName("param_morph")) - { - llwarns << "Can't specify morph param in skeleton definition." << llendl; - } - else - { - llwarns << "Unknown param type." << llendl; - } - continue; - } - - LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo; - if (!info->parseXml(child)) - { - delete info; - return FALSE; - } - - mSkeletalDistortionInfoList.push_back(info); - } - - // ATTACHMENT POINTS - for (child = node->getChildByName( "attachment_point" ); - child; - child = node->getNextNamedChild()) - { - LLVOAvatarAttachmentInfo* info = new LLVOAvatarAttachmentInfo(); - - static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); - if (!child->getFastAttributeString(name_string, info->mName)) - { - llwarns << "No name supplied for attachment point." << llendl; - delete info; - continue; - } - - static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint"); - if (!child->getFastAttributeString(joint_string, info->mJointName)) - { - llwarns << "No bone declared in attachment point " << info->mName << llendl; - delete info; - continue; - } - - static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position"); - if (child->getFastAttributeVector3(position_string, info->mPosition)) - { - info->mHasPosition = TRUE; - } - - static LLStdStringHandle rotation_string = LLXmlTree::addAttributeString("rotation"); - if (child->getFastAttributeVector3(rotation_string, info->mRotationEuler)) - { - info->mHasRotation = TRUE; - } - static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group"); - if (child->getFastAttributeS32(group_string, info->mGroup)) - { - if (info->mGroup == -1) - info->mGroup = -1111; // -1 = none parsed, < -1 = bad value - } - - static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id"); - if (!child->getFastAttributeS32(id_string, info->mAttachmentID)) - { - llwarns << "No id supplied for attachment point " << info->mName << llendl; - delete info; - continue; - } - - static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice"); - child->getFastAttributeS32(slot_string, info->mPieMenuSlice); - - static LLStdStringHandle visible_in_first_person_string = LLXmlTree::addAttributeString("visible_in_first_person"); - child->getFastAttributeBOOL(visible_in_first_person_string, info->mVisibleFirstPerson); - - static LLStdStringHandle hud_attachment_string = LLXmlTree::addAttributeString("hud"); - child->getFastAttributeBOOL(hud_attachment_string, info->mIsHUDAttachment); - - mAttachmentInfoList.push_back(info); - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// parseXmlMeshNodes(): parses nodes from XML tree -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root) -{ - for (LLXmlTreeNode* node = root->getChildByName( "mesh" ); - node; - node = root->getNextNamedChild()) - { - LLVOAvatarMeshInfo *info = new LLVOAvatarMeshInfo; - - // attribute: type - static LLStdStringHandle type_string = LLXmlTree::addAttributeString("type"); - if( !node->getFastAttributeString( type_string, info->mType ) ) - { - llwarns << "Avatar file: is missing type attribute. Ignoring element. " << llendl; - delete info; - return FALSE; // Ignore this element - } - - static LLStdStringHandle lod_string = LLXmlTree::addAttributeString("lod"); - if (!node->getFastAttributeS32( lod_string, info->mLOD )) - { - llwarns << "Avatar file: is missing lod attribute. Ignoring element. " << llendl; - delete info; - return FALSE; // Ignore this element - } - - static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name"); - if( !node->getFastAttributeString( file_name_string, info->mMeshFileName ) ) - { - llwarns << "Avatar file: is missing file_name attribute. Ignoring: " << info->mType << llendl; - delete info; - return FALSE; // Ignore this element - } - - static LLStdStringHandle reference_string = LLXmlTree::addAttributeString("reference"); - node->getFastAttributeString( reference_string, info->mReferenceMeshName ); - - // attribute: min_pixel_area - static LLStdStringHandle min_pixel_area_string = LLXmlTree::addAttributeString("min_pixel_area"); - static LLStdStringHandle min_pixel_width_string = LLXmlTree::addAttributeString("min_pixel_width"); - if (!node->getFastAttributeF32( min_pixel_area_string, info->mMinPixelArea )) - { - F32 min_pixel_area = 0.1f; - if (node->getFastAttributeF32( min_pixel_width_string, min_pixel_area )) - { - // this is square root of pixel area (sensible to use linear space in defining lods) - min_pixel_area = min_pixel_area * min_pixel_area; - } - info->mMinPixelArea = min_pixel_area; - } - - // Parse visual params for this node only if we haven't already - for (LLXmlTreeNode* child = node->getChildByName( "param" ); - child; - child = node->getNextNamedChild()) - { - if (!child->getChildByName("param_morph")) - { - if (child->getChildByName("param_skeleton")) - { - llwarns << "Can't specify skeleton param in a mesh definition." << llendl; - } - else - { - llwarns << "Unknown param type." << llendl; - } - continue; - } - - LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo(); - if (!morphinfo->parseXml(child)) - { - delete morphinfo; - delete info; - return -1; - } - BOOL shared = FALSE; - static LLStdStringHandle shared_string = LLXmlTree::addAttributeString("shared"); - child->getFastAttributeBOOL(shared_string, shared); - - info->mPolyMorphTargetInfoList.push_back(LLVOAvatarMeshInfo::morph_info_pair_t(morphinfo, shared)); - } - - mMeshInfoList.push_back(info); - } - return TRUE; -} - -//----------------------------------------------------------------------------- -// parseXmlColorNodes(): parses nodes from XML tree -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root) -{ - for (LLXmlTreeNode* color_node = root->getChildByName( "global_color" ); - color_node; - color_node = root->getNextNamedChild()) - { - std::string global_color_name; - static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); - if (color_node->getFastAttributeString( name_string, global_color_name ) ) - { - if( global_color_name == "skin_color" ) - { - if (mTexSkinColorInfo) - { - llwarns << "avatar file: multiple instances of skin_color" << llendl; - return FALSE; - } - mTexSkinColorInfo = new LLTexGlobalColorInfo; - if( !mTexSkinColorInfo->parseXml( color_node ) ) - { - deleteAndClear(mTexSkinColorInfo); - llwarns << "avatar file: mTexSkinColor->parseXml() failed" << llendl; - return FALSE; - } - } - else if( global_color_name == "hair_color" ) - { - if (mTexHairColorInfo) - { - llwarns << "avatar file: multiple instances of hair_color" << llendl; - return FALSE; - } - mTexHairColorInfo = new LLTexGlobalColorInfo; - if( !mTexHairColorInfo->parseXml( color_node ) ) - { - deleteAndClear(mTexHairColorInfo); - llwarns << "avatar file: mTexHairColor->parseXml() failed" << llendl; - return FALSE; - } - } - else if( global_color_name == "eye_color" ) - { - if (mTexEyeColorInfo) - { - llwarns << "avatar file: multiple instances of eye_color" << llendl; - return FALSE; - } - mTexEyeColorInfo = new LLTexGlobalColorInfo; - if( !mTexEyeColorInfo->parseXml( color_node ) ) - { - llwarns << "avatar file: mTexEyeColor->parseXml() failed" << llendl; - return FALSE; - } - } - } - } - return TRUE; -} - -//----------------------------------------------------------------------------- -// parseXmlLayerNodes(): parses nodes from XML tree -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root) -{ - for (LLXmlTreeNode* layer_node = root->getChildByName( "layer_set" ); - layer_node; - layer_node = root->getNextNamedChild()) - { - LLTexLayerSetInfo* layer_info = new LLTexLayerSetInfo(); - if( layer_info->parseXml( layer_node ) ) - { - mLayerInfoList.push_back(layer_info); - } - else - { - delete layer_info; - llwarns << "avatar file: layer_set->parseXml() failed" << llendl; - return FALSE; - } - } - return TRUE; -} - -//----------------------------------------------------------------------------- -// parseXmlDriverNodes(): parses nodes from XML tree -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root) -{ - LLXmlTreeNode* driver = root->getChildByName( "driver_parameters" ); - if( driver ) - { - for (LLXmlTreeNode* grand_child = driver->getChildByName( "param" ); - grand_child; - grand_child = driver->getNextNamedChild()) - { - if( grand_child->getChildByName( "param_driver" ) ) - { - LLDriverParamInfo* driver_info = new LLDriverParamInfo(); - if( driver_info->parseXml( grand_child ) ) - { - mDriverInfoList.push_back(driver_info); - } - else - { - delete driver_info; - llwarns << "avatar file: driver_param->parseXml() failed" << llendl; - return FALSE; - } - } - } - } - return TRUE; -} - -//----------------------------------------------------------------------------- -// parseXmlDriverNodes(): parses nodes from XML tree -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root) -{ - LLXmlTreeNode* masks = root->getChildByName( "morph_masks" ); - if( !masks ) - { - return FALSE; - } - - for (LLXmlTreeNode* grand_child = masks->getChildByName( "mask" ); - grand_child; - grand_child = masks->getNextNamedChild()) - { - LLVOAvatarMorphInfo* info = new LLVOAvatarMorphInfo(); - - static LLStdStringHandle name_string = LLXmlTree::addAttributeString("morph_name"); - if (!grand_child->getFastAttributeString(name_string, info->mName)) - { - llwarns << "No name supplied for morph mask." << llendl; - delete info; - continue; - } - - static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region"); - if (!grand_child->getFastAttributeString(region_string, info->mRegion)) - { - llwarns << "No region supplied for morph mask." << llendl; - delete info; - continue; - } - - static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer"); - if (!grand_child->getFastAttributeString(layer_string, info->mLayer)) - { - llwarns << "No layer supplied for morph mask." << llendl; - delete info; - continue; - } - - // optional parameter. don't throw a warning if not present. - static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert"); - grand_child->getFastAttributeBOOL(invert_string, info->mInvert); - - mMorphMaskInfoList.push_back(info); - } - - return TRUE; -} - -//virtual -void LLVOAvatar::updateRegion(LLViewerRegion *regionp) -{ - LLViewerObject::updateRegion(regionp); -} - -std::string LLVOAvatar::getFullname() const -{ - std::string name; - - LLNameValue* first = getNVPair("FirstName"); - LLNameValue* last = getNVPair("LastName"); - if (first && last) - { - name = LLCacheName::buildFullName( first->getString(), last->getString() ); - } - - return name; -} - -LLHost LLVOAvatar::getObjectHost() const -{ - LLViewerRegion* region = getRegion(); - if (region && !isDead()) - { - return region->getHost(); - } - else - { - return LLHost::invalid; - } -} - -//static -void LLVOAvatar::updateFreezeCounter(S32 counter) -{ - if(counter) - { - sFreezeCounter = counter; - } - else if(sFreezeCounter > 0) - { - sFreezeCounter--; - } - else - { - sFreezeCounter = 0; - } -} - -BOOL LLVOAvatar::updateLOD() -{ - if (isImpostor()) - { - return TRUE; - } - - BOOL res = updateJointLODs(); - - LLFace* facep = mDrawable->getFace(0); - if (facep->mVertexBuffer.isNull()) - { - dirtyMesh(2); - } - - if (mDirtyMesh >= 2 || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY)) - { //LOD changed or new mesh created, allocate new vertex buffer if needed - updateMeshData(); - mDirtyMesh = 0; - mNeedsSkin = TRUE; - mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY); - } - updateVisibility(); - - return res; -} - -void LLVOAvatar::updateLODRiggedAttachments( void ) -{ - updateLOD(); - rebuildRiggedAttachments(); -} -U32 LLVOAvatar::getPartitionType() const -{ - // Avatars merely exist as drawables in the bridge partition - return LLViewerRegion::PARTITION_BRIDGE; -} - -//static -void LLVOAvatar::updateImpostors() -{ - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { - LLVOAvatar* avatar = (LLVOAvatar*) *iter; - if (!avatar->isDead() && avatar->needsImpostorUpdate() && avatar->isVisible() && avatar->isImpostor()) - { - gPipeline.generateImpostor(avatar); - } - } -} - -BOOL LLVOAvatar::isImpostor() const -{ - return (sUseImpostors && mUpdatePeriod >= IMPOSTOR_PERIOD) ? TRUE : FALSE; -} - - -BOOL LLVOAvatar::needsImpostorUpdate() const -{ - return mNeedsImpostorUpdate; -} - -const LLVector3& LLVOAvatar::getImpostorOffset() const -{ - return mImpostorOffset; -} - -const LLVector2& LLVOAvatar::getImpostorDim() const -{ - return mImpostorDim; -} - -void LLVOAvatar::setImpostorDim(const LLVector2& dim) -{ - mImpostorDim = dim; -} - -void LLVOAvatar::cacheImpostorValues() -{ - getImpostorValues(mImpostorExtents, mImpostorAngle, mImpostorDistance); -} - -void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& distance) const -{ - const LLVector4a* ext = mDrawable->getSpatialExtents(); - extents[0] = ext[0]; - extents[1] = ext[1]; - - LLVector3 at = LLViewerCamera::getInstance()->getOrigin()-(getRenderPosition()+mImpostorOffset); - distance = at.normalize(); - F32 da = 1.f - (at*LLViewerCamera::getInstance()->getAtAxis()); - angle.mV[0] = LLViewerCamera::getInstance()->getYaw()*da; - angle.mV[1] = LLViewerCamera::getInstance()->getPitch()*da; - angle.mV[2] = da; -} - -void LLVOAvatar::idleUpdateRenderCost() -{ - static const U32 ARC_BODY_PART_COST = 20; - static const U32 ARC_LIMIT = 2048; - - static std::set all_textures; - - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME)) - { - return; - } - - U32 cost = 0; - std::set textures; - - for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) - { - const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); - ETextureIndex tex_index = baked_dict->mTextureIndex; - if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT))) - { - if (isTextureVisible(tex_index)) - { - cost +=ARC_BODY_PART_COST; - } - } - } - - for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - const LLViewerObject* attached_object = (*attachment_iter); - if (attached_object && !attached_object->isHUDAttachment()) - { - const LLDrawable* drawable = attached_object->mDrawable; - if (drawable) - { - const LLVOVolume* volume = drawable->getVOVolume(); - if (volume) - { - cost += volume->getRenderCost(textures); - } - } - } - } - - } - - // Diagnostic output to identify all avatar-related textures. - // Does not affect rendering cost calculation. - // Could be wrapped in a debug option if output becomes problematic. - if (isSelf()) - { - // print any attachment textures we didn't already know about. - for (std::set::iterator it = textures.begin(); it != textures.end(); ++it) - { - LLUUID image_id = *it; - if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) - continue; - if (all_textures.find(image_id) == all_textures.end()) - { - // attachment texture not previously seen. - llinfos << "attachment_texture: " << image_id.asString() << llendl; - all_textures.insert(image_id); - } - } - - // print any avatar textures we didn't already know about - for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); - iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); - ++iter) - { - const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; - // TODO: MULTI-WEARABLE: handle multiple textures for self - const LLViewerTexture* te_image = getImage(iter->first,0); - if (!te_image) - continue; - LLUUID image_id = te_image->getID(); - if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) - continue; - if (all_textures.find(image_id) == all_textures.end()) - { - llinfos << "local_texture: " << texture_dict->mName << ": " << image_id << llendl; - all_textures.insert(image_id); - } - } - } - - cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST; - - setDebugText(llformat("%d", cost)); - F32 green = 1.f-llclamp(((F32) cost-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f); - F32 red = llmin((F32) cost/(F32)ARC_LIMIT, 1.f); - mText->setColor(LLColor4(red,green,0,1)); -} - -// static -BOOL LLVOAvatar::isIndexLocalTexture(ETextureIndex index) -{ - if (index < 0 || index >= TEX_NUM_INDICES) return false; - return LLVOAvatarDictionary::getInstance()->getTexture(index)->mIsLocalTexture; -} - -// static -BOOL LLVOAvatar::isIndexBakedTexture(ETextureIndex index) -{ - if (index < 0 || index >= TEX_NUM_INDICES) return false; - return LLVOAvatarDictionary::getInstance()->getTexture(index)->mIsBakedTexture; -} - -const std::string LLVOAvatar::getBakedStatusForPrintout() const -{ - std::string line; - - for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); - iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); - ++iter) - { - const ETextureIndex index = iter->first; - const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; - if (texture_dict->mIsBakedTexture) - { - line += texture_dict->mName; - if (isTextureDefined(index)) - { - line += "_baked"; - } - line += " "; - } - } - return line; -} - - - -//virtual -S32 LLVOAvatar::getTexImageSize() const -{ - return TEX_IMAGE_SIZE_OTHER; -} - -//----------------------------------------------------------------------------- -// Utility functions -//----------------------------------------------------------------------------- - -F32 calc_bouncy_animation(F32 x) -{ - return -(cosf(x * F_PI * 2.5f - F_PI_BY_TWO))*(0.4f + x * -0.1f) + x * 1.3f; -} - -//virtual -BOOL LLVOAvatar::isTextureDefined(LLVOAvatarDefines::ETextureIndex te, U32 index ) const -{ - if (isIndexLocalTexture(te)) - { - return FALSE; - } - - return (getImage(te, index)->getID() != IMG_DEFAULT_AVATAR && - getImage(te, index)->getID() != IMG_DEFAULT); -} - -//virtual -BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index) const -{ - if (isIndexLocalTexture(type)) - { - return isTextureDefined(type, index); - } - else - { - // baked textures can use TE images directly - return ((isTextureDefined(type) || isSelf()) - && (getTEImage(type)->getID() != IMG_INVISIBLE - || LLDrawPoolAlpha::sShowDebugAlpha)); - } -} - -//virtual -BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const -{ - // non-self avatars don't have wearables - return FALSE; -} - +/** + * @File llvoavatar.cpp + * @brief Implementation of LLVOAvatar class which is a derivation of LLViewerObject + * + * $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$ + */ + +#if LL_MSVC +// disable warning about boost::lexical_cast returning uninitialized data +// when it fails to parse the string +#pragma warning (disable:4701) +#endif + +#include "llviewerprecompiledheaders.h" + +#include "llvoavatar.h" + +#include +#include + +#include "llaudioengine.h" +#include "llcachename.h" +#include "noise.h" +#include "sound_ids.h" + +#include "llagent.h" // Get state values from here +#include "llagentcamera.h" +#include "llagentwearables.h" +#include "llanimationstates.h" +#include "llavatarnamecache.h" +#include "llavatarpropertiesprocessor.h" +#include "llviewercontrol.h" +#include "llcallingcard.h" // IDEVO for LLAvatarTracker +#include "lldrawpoolavatar.h" +#include "lldriverparam.h" +#include "lleditingmotion.h" +#include "llemote.h" +//#include "llfirstuse.h" +#include "llheadrotmotion.h" +#include "llhudeffecttrail.h" +#include "llhudmanager.h" +#include "llhudnametag.h" +#include "llhudtext.h" // for mText/mDebugText +#include "llkeyframefallmotion.h" +#include "llkeyframestandmotion.h" +#include "llkeyframewalkmotion.h" +#include "llmanipscale.h" // for get_default_max_prim_scale() +#include "llmeshrepository.h" +#include "llmutelist.h" +#include "llmoveview.h" +#include "llnotificationsutil.h" +#include "llquantize.h" +#include "llrand.h" +#include "llregionhandle.h" +#include "llresmgr.h" +#include "llselectmgr.h" +#include "llsprite.h" +#include "lltargetingmotion.h" +#include "lltexlayer.h" +#include "lltoolmorph.h" +#include "llviewercamera.h" +#include "llviewertexturelist.h" +#include "llviewermenu.h" +#include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" +#include "llviewershadermgr.h" +#include "llviewerstats.h" +#include "llvoavatarself.h" +#include "llvovolume.h" +#include "llworld.h" +#include "pipeline.h" +#include "llviewershadermgr.h" +#include "llsky.h" +#include "llanimstatelabels.h" +#include "lltrans.h" +#include "llappearancemgr.h" + +#include "llgesturemgr.h" //needed to trigger the voice gesticulations +#include "llvoiceclient.h" +#include "llvoicevisualizer.h" // Ventrella + +#include "lldebugmessagebox.h" +extern F32 SPEED_ADJUST_MAX; +extern F32 SPEED_ADJUST_MAX_SEC; +extern F32 ANIM_SPEED_MAX; +extern F32 ANIM_SPEED_MIN; + +#if LL_MSVC +// disable boost::lexical_cast warning +#pragma warning (disable:4702) +#endif + +#include + +using namespace LLVOAvatarDefines; + +//----------------------------------------------------------------------------- +// Global constants +//----------------------------------------------------------------------------- +const LLUUID ANIM_AGENT_BODY_NOISE = LLUUID("9aa8b0a6-0c6f-9518-c7c3-4f41f2c001ad"); //"body_noise" +const LLUUID ANIM_AGENT_BREATHE_ROT = LLUUID("4c5a103e-b830-2f1c-16bc-224aa0ad5bc8"); //"breathe_rot" +const LLUUID ANIM_AGENT_EDITING = LLUUID("2a8eba1d-a7f8-5596-d44a-b4977bf8c8bb"); //"editing" +const LLUUID ANIM_AGENT_EYE = LLUUID("5c780ea8-1cd1-c463-a128-48c023f6fbea"); //"eye" +const LLUUID ANIM_AGENT_FLY_ADJUST = LLUUID("db95561f-f1b0-9f9a-7224-b12f71af126e"); //"fly_adjust" +const LLUUID ANIM_AGENT_HAND_MOTION = LLUUID("ce986325-0ba7-6e6e-cc24-b17c4b795578"); //"hand_motion" +const LLUUID ANIM_AGENT_HEAD_ROT = LLUUID("e6e8d1dd-e643-fff7-b238-c6b4b056a68d"); //"head_rot" +const LLUUID ANIM_AGENT_PELVIS_FIX = LLUUID("0c5dd2a2-514d-8893-d44d-05beffad208b"); //"pelvis_fix" +const LLUUID ANIM_AGENT_TARGET = LLUUID("0e4896cb-fba4-926c-f355-8720189d5b55"); //"target" +const LLUUID ANIM_AGENT_WALK_ADJUST = LLUUID("829bc85b-02fc-ec41-be2e-74cc6dd7215d"); //"walk_adjust" + + +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- +const std::string AVATAR_DEFAULT_CHAR = "avatar"; + +const S32 MIN_PIXEL_AREA_FOR_COMPOSITE = 1024; +const F32 SHADOW_OFFSET_AMT = 0.03f; + +const F32 DELTA_TIME_MIN = 0.01f; // we clamp measured deltaTime to this +const F32 DELTA_TIME_MAX = 0.2f; // range to insure stability of computations. + +const F32 PELVIS_LAG_FLYING = 0.22f;// pelvis follow half life while flying +const F32 PELVIS_LAG_WALKING = 0.4f; // ...while walking +const F32 PELVIS_LAG_MOUSELOOK = 0.15f; +const F32 MOUSELOOK_PELVIS_FOLLOW_FACTOR = 0.5f; +const F32 PELVIS_LAG_WHEN_FOLLOW_CAM_IS_ON = 0.0001f; // not zero! - something gets divided by this! + +const F32 PELVIS_ROT_THRESHOLD_SLOW = 60.0f; // amount of deviation allowed between +const F32 PELVIS_ROT_THRESHOLD_FAST = 2.0f; // the pelvis and the view direction + // when moving fast & slow +const F32 TORSO_NOISE_AMOUNT = 1.0f; // Amount of deviation from up-axis, in degrees +const F32 TORSO_NOISE_SPEED = 0.2f; // Time scale factor on torso noise. + +const F32 BREATHE_ROT_MOTION_STRENGTH = 0.05f; +const F32 BREATHE_SCALE_MOTION_STRENGTH = 0.005f; + +const F32 MIN_SHADOW_HEIGHT = 0.f; +const F32 MAX_SHADOW_HEIGHT = 0.3f; + +const S32 MIN_REQUIRED_PIXEL_AREA_BODY_NOISE = 10000; +const S32 MIN_REQUIRED_PIXEL_AREA_BREATHE = 10000; +const S32 MIN_REQUIRED_PIXEL_AREA_PELVIS_FIX = 40; + +const S32 TEX_IMAGE_SIZE_SELF = 512; +const S32 TEX_IMAGE_AREA_SELF = TEX_IMAGE_SIZE_SELF * TEX_IMAGE_SIZE_SELF; +const S32 TEX_IMAGE_SIZE_OTHER = 512 / 4; // The size of local textures for other (!isSelf()) avatars + +const F32 HEAD_MOVEMENT_AVG_TIME = 0.9f; + +const S32 MORPH_MASK_REQUESTED_DISCARD = 0; + +// Discard level at which to switch to baked textures +// Should probably be 4 or 3, but didn't want to change it while change other logic - SJB +const S32 SWITCH_TO_BAKED_DISCARD = 5; + +const F32 FOOT_COLLIDE_FUDGE = 0.04f; + +const F32 HOVER_EFFECT_MAX_SPEED = 3.f; +const F32 HOVER_EFFECT_STRENGTH = 0.f; +const F32 UNDERWATER_EFFECT_STRENGTH = 0.1f; +const F32 UNDERWATER_FREQUENCY_DAMP = 0.33f; +const F32 APPEARANCE_MORPH_TIME = 0.65f; +const F32 TIME_BEFORE_MESH_CLEANUP = 5.f; // seconds +const S32 AVATAR_RELEASE_THRESHOLD = 10; // number of avatar instances before releasing memory +const F32 FOOT_GROUND_COLLISION_TOLERANCE = 0.25f; +const F32 AVATAR_LOD_TWEAK_RANGE = 0.7f; +const S32 MAX_BUBBLE_CHAT_LENGTH = DB_CHAT_MSG_STR_LEN; +const S32 MAX_BUBBLE_CHAT_UTTERANCES = 12; +const F32 CHAT_FADE_TIME = 8.0; +const F32 BUBBLE_CHAT_TIME = CHAT_FADE_TIME * 3.f; + +const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0); + +enum ERenderName +{ + RENDER_NAME_NEVER, + RENDER_NAME_ALWAYS, + RENDER_NAME_FADE +}; + +//----------------------------------------------------------------------------- +// Callback data +//----------------------------------------------------------------------------- + +struct LLTextureMaskData +{ + LLTextureMaskData( const LLUUID& id ) : + mAvatarID(id), + mLastDiscardLevel(S32_MAX) + {} + LLUUID mAvatarID; + S32 mLastDiscardLevel; +}; + +/********************************************************************************* + ** ** + ** Begin private LLVOAvatar Support classes + ** + **/ + +//------------------------------------------------------------------------ +// LLVOBoneInfo +// Trans/Scale/Rot etc. info about each avatar bone. Used by LLVOAvatarSkeleton. +//------------------------------------------------------------------------ +class LLVOAvatarBoneInfo +{ + friend class LLVOAvatar; + friend class LLVOAvatarSkeletonInfo; +public: + LLVOAvatarBoneInfo() : mIsJoint(FALSE) {} + ~LLVOAvatarBoneInfo() + { + std::for_each(mChildList.begin(), mChildList.end(), DeletePointer()); + } + BOOL parseXml(LLXmlTreeNode* node); + +private: + std::string mName; + BOOL mIsJoint; + LLVector3 mPos; + LLVector3 mRot; + LLVector3 mScale; + LLVector3 mPivot; + typedef std::vector child_list_t; + child_list_t mChildList; +}; + +//------------------------------------------------------------------------ +// LLVOAvatarSkeletonInfo +// Overall avatar skeleton +//------------------------------------------------------------------------ +class LLVOAvatarSkeletonInfo +{ + friend class LLVOAvatar; +public: + LLVOAvatarSkeletonInfo() : + mNumBones(0), mNumCollisionVolumes(0) {} + ~LLVOAvatarSkeletonInfo() + { + std::for_each(mBoneInfoList.begin(), mBoneInfoList.end(), DeletePointer()); + } + BOOL parseXml(LLXmlTreeNode* node); + S32 getNumBones() const { return mNumBones; } + S32 getNumCollisionVolumes() const { return mNumCollisionVolumes; } + +private: + S32 mNumBones; + S32 mNumCollisionVolumes; + typedef std::vector bone_info_list_t; + bone_info_list_t mBoneInfoList; +}; + +//----------------------------------------------------------------------------- +// class LLBodyNoiseMotion +//----------------------------------------------------------------------------- +class LLBodyNoiseMotion : + public LLMotion +{ +public: + // Constructor + LLBodyNoiseMotion(const LLUUID &id) + : LLMotion(id) + { + mName = "body_noise"; + mTorsoState = new LLJointState; + } + + // Destructor + virtual ~LLBodyNoiseMotion() { } + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID &id) { return new LLBodyNoiseMotion(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + + // motions must specify whether or not they loop + virtual BOOL getLoop() { return TRUE; } + + // motions must report their total duration + virtual F32 getDuration() { return 0.0; } + + // motions must report their "ease in" duration + virtual F32 getEaseInDuration() { return 0.0; } + + // motions must report their "ease out" duration. + virtual F32 getEaseOutDuration() { return 0.0; } + + // motions must report their priority + virtual LLJoint::JointPriority getPriority() { return LLJoint::HIGH_PRIORITY; } + + virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; } + + // called to determine when a motion should be activated/deactivated based on avatar pixel coverage + virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_BODY_NOISE; } + + // run-time (post constructor) initialization, + // called after parameters have been set + // must return true to indicate success and be available for activation + virtual LLMotionInitStatus onInitialize(LLCharacter *character) + { + if( !mTorsoState->setJoint( character->getJoint("mTorso") )) + { + return STATUS_FAILURE; + } + + mTorsoState->setUsage(LLJointState::ROT); + + addJointState( mTorsoState ); + return STATUS_SUCCESS; + } + + // called when a motion is activated + // must return TRUE to indicate success, or else + // it will be deactivated + virtual BOOL onActivate() { return TRUE; } + + // called per time step + // must return TRUE while it is active, and + // must return FALSE when the motion is completed. + virtual BOOL onUpdate(F32 time, U8* joint_mask) + { + F32 nx[2]; + nx[0]=time*TORSO_NOISE_SPEED; + nx[1]=0.0f; + F32 ny[2]; + ny[0]=0.0f; + ny[1]=time*TORSO_NOISE_SPEED; + F32 noiseX = noise2(nx); + F32 noiseY = noise2(ny); + + F32 rx = TORSO_NOISE_AMOUNT * DEG_TO_RAD * noiseX / 0.42f; + F32 ry = TORSO_NOISE_AMOUNT * DEG_TO_RAD * noiseY / 0.42f; + LLQuaternion tQn; + tQn.setQuat( rx, ry, 0.0f ); + mTorsoState->setRotation( tQn ); + + return TRUE; + } + + // called when a motion is deactivated + virtual void onDeactivate() {} + +private: + //------------------------------------------------------------------------- + // joint states to be animated + //------------------------------------------------------------------------- + LLPointer mTorsoState; +}; + +//----------------------------------------------------------------------------- +// class LLBreatheMotionRot +//----------------------------------------------------------------------------- +class LLBreatheMotionRot : + public LLMotion +{ +public: + // Constructor + LLBreatheMotionRot(const LLUUID &id) : + LLMotion(id), + mBreatheRate(1.f), + mCharacter(NULL) + { + mName = "breathe_rot"; + mChestState = new LLJointState; + } + + // Destructor + virtual ~LLBreatheMotionRot() {} + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID &id) { return new LLBreatheMotionRot(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + + // motions must specify whether or not they loop + virtual BOOL getLoop() { return TRUE; } + + // motions must report their total duration + virtual F32 getDuration() { return 0.0; } + + // motions must report their "ease in" duration + virtual F32 getEaseInDuration() { return 0.0; } + + // motions must report their "ease out" duration. + virtual F32 getEaseOutDuration() { return 0.0; } + + // motions must report their priority + virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; } + + virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } + + // called to determine when a motion should be activated/deactivated based on avatar pixel coverage + virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_BREATHE; } + + // run-time (post constructor) initialization, + // called after parameters have been set + // must return true to indicate success and be available for activation + virtual LLMotionInitStatus onInitialize(LLCharacter *character) + { + mCharacter = character; + BOOL success = true; + + if ( !mChestState->setJoint( character->getJoint( "mChest" ) ) ) { success = false; } + + if ( success ) + { + mChestState->setUsage(LLJointState::ROT); + addJointState( mChestState ); + } + + if ( success ) + { + return STATUS_SUCCESS; + } + else + { + return STATUS_FAILURE; + } + } + + // called when a motion is activated + // must return TRUE to indicate success, or else + // it will be deactivated + virtual BOOL onActivate() { return TRUE; } + + // called per time step + // must return TRUE while it is active, and + // must return FALSE when the motion is completed. + virtual BOOL onUpdate(F32 time, U8* joint_mask) + { + mBreatheRate = 1.f; + + F32 breathe_amt = (sinf(mBreatheRate * time) * BREATHE_ROT_MOTION_STRENGTH); + + mChestState->setRotation(LLQuaternion(breathe_amt, LLVector3(0.f, 1.f, 0.f))); + + return TRUE; + } + + // called when a motion is deactivated + virtual void onDeactivate() {} + +private: + //------------------------------------------------------------------------- + // joint states to be animated + //------------------------------------------------------------------------- + LLPointer mChestState; + F32 mBreatheRate; + LLCharacter* mCharacter; +}; + +//----------------------------------------------------------------------------- +// class LLPelvisFixMotion +//----------------------------------------------------------------------------- +class LLPelvisFixMotion : + public LLMotion +{ +public: + // Constructor + LLPelvisFixMotion(const LLUUID &id) + : LLMotion(id), mCharacter(NULL) + { + mName = "pelvis_fix"; + + mPelvisState = new LLJointState; + } + + // Destructor + virtual ~LLPelvisFixMotion() { } + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID& id) { return new LLPelvisFixMotion(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + + // motions must specify whether or not they loop + virtual BOOL getLoop() { return TRUE; } + + // motions must report their total duration + virtual F32 getDuration() { return 0.0; } + + // motions must report their "ease in" duration + virtual F32 getEaseInDuration() { return 0.5f; } + + // motions must report their "ease out" duration. + virtual F32 getEaseOutDuration() { return 0.5f; } + + // motions must report their priority + virtual LLJoint::JointPriority getPriority() { return LLJoint::LOW_PRIORITY; } + + virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } + + // called to determine when a motion should be activated/deactivated based on avatar pixel coverage + virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_PELVIS_FIX; } + + // run-time (post constructor) initialization, + // called after parameters have been set + // must return true to indicate success and be available for activation + virtual LLMotionInitStatus onInitialize(LLCharacter *character) + { + mCharacter = character; + + if (!mPelvisState->setJoint( character->getJoint("mPelvis"))) + { + return STATUS_FAILURE; + } + + mPelvisState->setUsage(LLJointState::POS); + + addJointState( mPelvisState ); + return STATUS_SUCCESS; + } + + // called when a motion is activated + // must return TRUE to indicate success, or else + // it will be deactivated + virtual BOOL onActivate() { return TRUE; } + + // called per time step + // must return TRUE while it is active, and + // must return FALSE when the motion is completed. + virtual BOOL onUpdate(F32 time, U8* joint_mask) + { + mPelvisState->setPosition(LLVector3::zero); + + return TRUE; + } + + // called when a motion is deactivated + virtual void onDeactivate() {} + +private: + //------------------------------------------------------------------------- + // joint states to be animated + //------------------------------------------------------------------------- + LLPointer mPelvisState; + LLCharacter* mCharacter; +}; + +/** + ** + ** End LLVOAvatar Support classes + ** ** + *********************************************************************************/ + + +//----------------------------------------------------------------------------- +// Static Data +//----------------------------------------------------------------------------- +LLXmlTree LLVOAvatar::sXMLTree; +LLXmlTree LLVOAvatar::sSkeletonXMLTree; +LLVOAvatarSkeletonInfo* LLVOAvatar::sAvatarSkeletonInfo = NULL; +LLVOAvatar::LLVOAvatarXmlInfo* LLVOAvatar::sAvatarXmlInfo = NULL; +LLVOAvatarDictionary *LLVOAvatar::sAvatarDictionary = NULL; +S32 LLVOAvatar::sFreezeCounter = 0; +U32 LLVOAvatar::sMaxVisible = 12; +F32 LLVOAvatar::sRenderDistance = 256.f; +S32 LLVOAvatar::sNumVisibleAvatars = 0; +S32 LLVOAvatar::sNumLODChangesThisFrame = 0; + +const LLUUID LLVOAvatar::sStepSoundOnLand("e8af4a28-aa83-4310-a7c4-c047e15ea0df"); +const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] = +{ + SND_STONE_RUBBER, + SND_METAL_RUBBER, + SND_GLASS_RUBBER, + SND_WOOD_RUBBER, + SND_FLESH_RUBBER, + SND_RUBBER_PLASTIC, + SND_RUBBER_RUBBER +}; + +S32 LLVOAvatar::sRenderName = RENDER_NAME_ALWAYS; +BOOL LLVOAvatar::sRenderGroupTitles = TRUE; +S32 LLVOAvatar::sNumVisibleChatBubbles = 0; +BOOL LLVOAvatar::sDebugInvisible = FALSE; +BOOL LLVOAvatar::sShowAttachmentPoints = FALSE; +BOOL LLVOAvatar::sShowAnimationDebug = FALSE; +BOOL LLVOAvatar::sShowFootPlane = FALSE; +BOOL LLVOAvatar::sVisibleInFirstPerson = FALSE; +F32 LLVOAvatar::sLODFactor = 1.f; +BOOL LLVOAvatar::sUseImpostors = FALSE; +BOOL LLVOAvatar::sJointDebug = FALSE; + +F32 LLVOAvatar::sUnbakedTime = 0.f; +F32 LLVOAvatar::sUnbakedUpdateTime = 0.f; +F32 LLVOAvatar::sGreyTime = 0.f; +F32 LLVOAvatar::sGreyUpdateTime = 0.f; + +//----------------------------------------------------------------------------- +// Helper functions +//----------------------------------------------------------------------------- +static F32 calc_bouncy_animation(F32 x); + +//----------------------------------------------------------------------------- +// LLVOAvatar() +//----------------------------------------------------------------------------- +LLVOAvatar::LLVOAvatar(const LLUUID& id, + const LLPCode pcode, + LLViewerRegion* regionp) : + LLViewerObject(id, pcode, regionp), + mIsDummy(FALSE), + mSpecialRenderMode(0), + mTurning(FALSE), + mPelvisToFoot(0.f), + mLastSkeletonSerialNum( 0 ), + mHeadOffset(), + mIsSitting(FALSE), + mTimeVisible(), + mTyping(FALSE), + mMeshValid(FALSE), + mVisible(FALSE), + mWindFreq(0.f), + mRipplePhase( 0.f ), + mBelowWater(FALSE), + mLastAppearanceBlendTime(0.f), + mAppearanceAnimating(FALSE), + mNameString(), + mTitle(), + mNameAway(false), + mNameBusy(false), + mNameMute(false), + mNameAppearance(false), + mNameFriend(false), + mNameAlpha(0.f), + mRenderGroupTitles(sRenderGroupTitles), + mNameCloud(false), + mFirstTEMessageReceived( FALSE ), + mFirstAppearanceMessageReceived( FALSE ), + mCulled( FALSE ), + mVisibilityRank(0), + mTexSkinColor( NULL ), + mTexHairColor( NULL ), + mTexEyeColor( NULL ), + mNeedsSkin(FALSE), + mLastSkinTime(0.f), + mUpdatePeriod(1), + mFullyLoaded(FALSE), + mPreviousFullyLoaded(FALSE), + mFullyLoadedInitialized(FALSE), + mSupportsAlphaLayers(FALSE), + mLoadedCallbacksPaused(FALSE), + mHasPelvisOffset( FALSE ) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + //VTResume(); // VTune + + // mVoiceVisualizer is created by the hud effects manager and uses the HUD Effects pipeline + const BOOL needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job + mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim ); + + lldebugs << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << llendl; + + mPelvisp = NULL; + + mBakedTextureDatas.resize(BAKED_NUM_INDICES); + for (U32 i = 0; i < mBakedTextureDatas.size(); i++ ) + { + mBakedTextureDatas[i].mLastTextureIndex = IMG_DEFAULT_AVATAR; + mBakedTextureDatas[i].mTexLayerSet = NULL; + mBakedTextureDatas[i].mIsLoaded = false; + mBakedTextureDatas[i].mIsUsed = false; + mBakedTextureDatas[i].mMaskTexName = 0; + mBakedTextureDatas[i].mTextureIndex = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)i); + } + + mDirtyMesh = 2; // Dirty geometry, need to regenerate. + mMeshTexturesDirty = FALSE; + mHeadp = NULL; + + mIsBuilt = FALSE; + + mNumJoints = 0; + mSkeleton = NULL; + + mNumCollisionVolumes = 0; + mCollisionVolumes = NULL; + + // set up animation variables + mSpeed = 0.f; + setAnimationData("Speed", &mSpeed); + + mNeedsImpostorUpdate = TRUE; + mNeedsAnimUpdate = TRUE; + + mImpostorDistance = 0; + mImpostorPixelArea = 0; + + setNumTEs(TEX_NUM_INDICES); + + mbCanSelect = TRUE; + + mSignaledAnimations.clear(); + mPlayingAnimations.clear(); + + mWasOnGroundLeft = FALSE; + mWasOnGroundRight = FALSE; + + mTimeLast = 0.0f; + mSpeedAccum = 0.0f; + + mRippleTimeLast = 0.f; + + mInAir = FALSE; + + mStepOnLand = TRUE; + mStepMaterial = 0; + + mLipSyncActive = false; + mOohMorph = NULL; + mAahMorph = NULL; + + mCurrentGesticulationLevel = 0; + + mRuthTimer.reset(); + mRuthDebugTimer.reset(); + mDebugExistenceTimer.reset(); + mPelvisOffset = LLVector3(0.0f,0.0f,0.0f); +} + +//------------------------------------------------------------------------ +// LLVOAvatar::~LLVOAvatar() +//------------------------------------------------------------------------ +LLVOAvatar::~LLVOAvatar() +{ + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + if (!mFullyLoaded) + { + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left after " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds as cloud." << llendl; + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezLeftCloudNotification",args); + } + else + { + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left." << llendl; + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezLeftNotification",args); + } + + } + lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl; + + mRoot.removeAllChildren(); + + deleteAndClearArray(mSkeleton); + deleteAndClearArray(mCollisionVolumes); + + mNumJoints = 0; + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + deleteAndClear(mBakedTextureDatas[i].mTexLayerSet); + mBakedTextureDatas[i].mMeshes.clear(); + + for (morph_list_t::iterator iter2 = mBakedTextureDatas[i].mMaskedMorphs.begin(); + iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); iter2++) + { + LLMaskedMorph* masked_morph = (*iter2); + delete masked_morph; + } + } + + std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer()); + mAttachmentPoints.clear(); + + deleteAndClear(mTexSkinColor); + deleteAndClear(mTexHairColor); + deleteAndClear(mTexEyeColor); + + std::for_each(mMeshes.begin(), mMeshes.end(), DeletePairedPointer()); + mMeshes.clear(); + + for (std::vector::iterator jointIter = mMeshLOD.begin(); + jointIter != mMeshLOD.end(); + ++jointIter) + { + LLViewerJoint* joint = (LLViewerJoint *) *jointIter; + std::for_each(joint->mMeshParts.begin(), joint->mMeshParts.end(), DeletePointer()); + joint->mMeshParts.clear(); + } + std::for_each(mMeshLOD.begin(), mMeshLOD.end(), DeletePointer()); + mMeshLOD.clear(); + + mDead = TRUE; + + mAnimationSources.clear(); + LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ; + + lldebugs << "LLVOAvatar Destructor end" << llendl; +} + +void LLVOAvatar::markDead() +{ + if (mNameText) + { + mNameText->markDead(); + mNameText = NULL; + sNumVisibleChatBubbles--; + } + mVoiceVisualizer->markDead(); + LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ; + LLViewerObject::markDead(); +} + + +BOOL LLVOAvatar::isFullyBaked() +{ + if (mIsDummy) return TRUE; + if (getNumTEs() == 0) return FALSE; + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if (!isTextureDefined(mBakedTextureDatas[i].mTextureIndex) + && ( (i != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) ) ) + { + return FALSE; + } + } + return TRUE; +} + +void LLVOAvatar::deleteLayerSetCaches(bool clearAll) +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if (mBakedTextureDatas[i].mTexLayerSet) + { + // ! BACKWARDS COMPATIBILITY ! + // Can be removed after hair baking is mandatory on the grid + if ((i != BAKED_HAIR || isSelf()) && !clearAll) + { + mBakedTextureDatas[i].mTexLayerSet->deleteCaches(); + } + } + if (mBakedTextureDatas[i].mMaskTexName) + { + glDeleteTextures(1, (GLuint*)&(mBakedTextureDatas[i].mMaskTexName)); + mBakedTextureDatas[i].mMaskTexName = 0 ; + } + } +} + +// static +BOOL LLVOAvatar::areAllNearbyInstancesBaked(S32& grey_avatars) +{ + BOOL res = TRUE; + grey_avatars = 0; + for (std::vector::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { + LLVOAvatar* inst = (LLVOAvatar*) *iter; + if( inst->isDead() ) + { + continue; + } + else if( !inst->isFullyBaked() ) + { + res = FALSE; + if (inst->mHasGrey) + { + ++grey_avatars; + } + } + } + return res; +} + +// static +void LLVOAvatar::dumpBakedStatus() +{ + LLVector3d camera_pos_global = gAgentCamera.getCameraPositionGlobal(); + + for (std::vector::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { + LLVOAvatar* inst = (LLVOAvatar*) *iter; + llinfos << "Avatar "; + + LLNameValue* firstname = inst->getNVPair("FirstName"); + LLNameValue* lastname = inst->getNVPair("LastName"); + + if( firstname ) + { + llcont << firstname->getString(); + } + if( lastname ) + { + llcont << " " << lastname->getString(); + } + + llcont << " " << inst->mID; + + if( inst->isDead() ) + { + llcont << " DEAD ("<< inst->getNumRefs() << " refs)"; + } + + if( inst->isSelf() ) + { + llcont << " (self)"; + } + + + F64 dist_to_camera = (inst->getPositionGlobal() - camera_pos_global).length(); + llcont << " " << dist_to_camera << "m "; + + llcont << " " << inst->mPixelArea << " pixels"; + + if( inst->isVisible() ) + { + llcont << " (visible)"; + } + else + { + llcont << " (not visible)"; + } + + if( inst->isFullyBaked() ) + { + llcont << " Baked"; + } + else + { + llcont << " Unbaked ("; + + for (LLVOAvatarDictionary::BakedTextures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); + ++iter) + { + const LLVOAvatarDictionary::BakedEntry *baked_dict = iter->second; + const ETextureIndex index = baked_dict->mTextureIndex; + if (!inst->isTextureDefined(index)) + { + llcont << " " << LLVOAvatarDictionary::getInstance()->getTexture(index)->mName; + } + } + llcont << " ) " << inst->getUnbakedPixelAreaRank(); + if( inst->isCulled() ) + { + llcont << " culled"; + } + } + llcont << llendl; + } +} + +//static +void LLVOAvatar::restoreGL() +{ + if (!isAgentAvatarValid()) return; + + gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); + for (U32 i = 0; i < gAgentAvatarp->mBakedTextureDatas.size(); i++) + { + gAgentAvatarp->invalidateComposite(gAgentAvatarp->mBakedTextureDatas[i].mTexLayerSet, FALSE); + } + gAgentAvatarp->updateMeshTextures(); +} + +//static +void LLVOAvatar::destroyGL() +{ + deleteCachedImages(); + + resetImpostors(); +} + +//static +void LLVOAvatar::resetImpostors() +{ + for (std::vector::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { + LLVOAvatar* avatar = (LLVOAvatar*) *iter; + avatar->mImpostor.release(); + } +} + +// static +void LLVOAvatar::deleteCachedImages(bool clearAll) +{ + if (LLTexLayerSet::sHasCaches) + { + lldebugs << "Deleting layer set caches" << llendl; + for (std::vector::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { + LLVOAvatar* inst = (LLVOAvatar*) *iter; + inst->deleteLayerSetCaches(clearAll); + } + LLTexLayerSet::sHasCaches = FALSE; + } + LLVOAvatarSelf::deleteScratchTextures(); + LLTexLayerStaticImageList::getInstance()->deleteCachedImages(); +} + + +//------------------------------------------------------------------------ +// static +// LLVOAvatar::initClass() +//------------------------------------------------------------------------ +void LLVOAvatar::initClass() +{ + std::string xmlFile; + + xmlFile = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR) + "_lad.xml"; + BOOL success = sXMLTree.parseFile( xmlFile, FALSE ); + if (!success) + { + llerrs << "Problem reading avatar configuration file:" << xmlFile << llendl; + } + + // now sanity check xml file + LLXmlTreeNode* root = sXMLTree.getRoot(); + if (!root) + { + llerrs << "No root node found in avatar configuration file: " << xmlFile << llendl; + return; + } + + //------------------------------------------------------------------------- + // (root) + //------------------------------------------------------------------------- + if( !root->hasName( "linden_avatar" ) ) + { + llerrs << "Invalid avatar file header: " << xmlFile << llendl; + } + + std::string version; + static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); + if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") ) + { + llerrs << "Invalid avatar file version: " << version << " in file: " << xmlFile << llendl; + } + + S32 wearable_def_version = 1; + static LLStdStringHandle wearable_definition_version_string = LLXmlTree::addAttributeString("wearable_definition_version"); + root->getFastAttributeS32( wearable_definition_version_string, wearable_def_version ); + LLWearable::setCurrentDefinitionVersion( wearable_def_version ); + + std::string mesh_file_name; + + LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" ); + if (!skeleton_node) + { + llerrs << "No skeleton in avatar configuration file: " << xmlFile << llendl; + return; + } + + std::string skeleton_file_name; + static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name"); + if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name)) + { + llerrs << "No file name in skeleton node in avatar config file: " << xmlFile << llendl; + } + + std::string skeleton_path; + skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name); + if (!parseSkeletonFile(skeleton_path)) + { + llerrs << "Error parsing skeleton file: " << skeleton_path << llendl; + } + + // Process XML data + + // avatar_skeleton.xml + llassert(!sAvatarSkeletonInfo); + sAvatarSkeletonInfo = new LLVOAvatarSkeletonInfo; + if (!sAvatarSkeletonInfo->parseXml(sSkeletonXMLTree.getRoot())) + { + llerrs << "Error parsing skeleton XML file: " << skeleton_path << llendl; + } + // parse avatar_lad.xml + llassert(!sAvatarXmlInfo); + sAvatarXmlInfo = new LLVOAvatarXmlInfo; + if (!sAvatarXmlInfo->parseXmlSkeletonNode(root)) + { + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + } + if (!sAvatarXmlInfo->parseXmlMeshNodes(root)) + { + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + } + if (!sAvatarXmlInfo->parseXmlColorNodes(root)) + { + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + } + if (!sAvatarXmlInfo->parseXmlLayerNodes(root)) + { + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + } + if (!sAvatarXmlInfo->parseXmlDriverNodes(root)) + { + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + } + if (!sAvatarXmlInfo->parseXmlMorphNodes(root)) + { + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + } + + gAnimLibrary.animStateSetString(ANIM_AGENT_BODY_NOISE,"body_noise"); + gAnimLibrary.animStateSetString(ANIM_AGENT_BREATHE_ROT,"breathe_rot"); + gAnimLibrary.animStateSetString(ANIM_AGENT_EDITING,"editing"); + gAnimLibrary.animStateSetString(ANIM_AGENT_EYE,"eye"); + gAnimLibrary.animStateSetString(ANIM_AGENT_FLY_ADJUST,"fly_adjust"); + gAnimLibrary.animStateSetString(ANIM_AGENT_HAND_MOTION,"hand_motion"); + gAnimLibrary.animStateSetString(ANIM_AGENT_HEAD_ROT,"head_rot"); + gAnimLibrary.animStateSetString(ANIM_AGENT_PELVIS_FIX,"pelvis_fix"); + gAnimLibrary.animStateSetString(ANIM_AGENT_TARGET,"target"); + gAnimLibrary.animStateSetString(ANIM_AGENT_WALK_ADJUST,"walk_adjust"); +} + + +void LLVOAvatar::cleanupClass() +{ + deleteAndClear(sAvatarXmlInfo); + sSkeletonXMLTree.cleanup(); + sXMLTree.cleanup(); +} + +void LLVOAvatar::initInstance(void) +{ + //------------------------------------------------------------------------- + // initialize joint, mesh and shape members + //------------------------------------------------------------------------- + mRoot.setName( "mRoot" ); + + for (LLVOAvatarDictionary::Meshes::const_iterator iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin(); + iter != LLVOAvatarDictionary::getInstance()->getMeshes().end(); + ++iter) + { + const EMeshIndex mesh_index = iter->first; + const LLVOAvatarDictionary::MeshEntry *mesh_dict = iter->second; + LLViewerJoint* joint = new LLViewerJoint(); + joint->setName(mesh_dict->mName); + joint->setMeshID(mesh_index); + mMeshLOD.push_back(joint); + + /* mHairLOD.setName("mHairLOD"); + mHairMesh0.setName("mHairMesh0"); + mHairMesh0.setMeshID(MESH_ID_HAIR); + mHairMesh1.setName("mHairMesh1"); */ + for (U32 lod = 0; lod < mesh_dict->mLOD; lod++) + { + LLViewerJointMesh* mesh = new LLViewerJointMesh(); + std::string mesh_name = "m" + mesh_dict->mName + boost::lexical_cast(lod); + // We pre-pended an m - need to capitalize first character for camelCase + mesh_name[1] = toupper(mesh_name[1]); + mesh->setName(mesh_name); + mesh->setMeshID(mesh_index); + mesh->setPickName(mesh_dict->mPickName); + mesh->setIsTransparent(FALSE); + switch((int)mesh_index) + { + case MESH_ID_HAIR: + mesh->setIsTransparent(TRUE); + break; + case MESH_ID_SKIRT: + mesh->setIsTransparent(TRUE); + break; + case MESH_ID_EYEBALL_LEFT: + case MESH_ID_EYEBALL_RIGHT: + mesh->setSpecular( LLColor4( 1.0f, 1.0f, 1.0f, 1.0f ), 1.f ); + break; + } + + joint->mMeshParts.push_back(mesh); + } + } + + //------------------------------------------------------------------------- + // associate baked textures with meshes + //------------------------------------------------------------------------- + for (LLVOAvatarDictionary::Meshes::const_iterator iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin(); + iter != LLVOAvatarDictionary::getInstance()->getMeshes().end(); + ++iter) + { + const EMeshIndex mesh_index = iter->first; + const LLVOAvatarDictionary::MeshEntry *mesh_dict = iter->second; + const EBakedTextureIndex baked_texture_index = mesh_dict->mBakedID; + // Skip it if there's no associated baked texture. + if (baked_texture_index == BAKED_NUM_INDICES) continue; + + for (std::vector::iterator iter = mMeshLOD[mesh_index]->mMeshParts.begin(); + iter != mMeshLOD[mesh_index]->mMeshParts.end(); + ++iter) + { + LLViewerJointMesh* mesh = (LLViewerJointMesh*) *iter; + mBakedTextureDatas[(int)baked_texture_index].mMeshes.push_back(mesh); + } + } + + + //------------------------------------------------------------------------- + // register motions + //------------------------------------------------------------------------- + if (LLCharacter::sInstances.size() == 1) + { + LLKeyframeMotion::setVFS(gStaticVFS); + registerMotion( ANIM_AGENT_BUSY, LLNullMotion::create ); + registerMotion( ANIM_AGENT_CROUCH, LLKeyframeStandMotion::create ); + registerMotion( ANIM_AGENT_CROUCHWALK, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_EXPRESS_AFRAID, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_ANGER, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_BORED, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_CRY, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_DISDAIN, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_EMBARRASSED, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_FROWN, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_KISS, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_LAUGH, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_OPEN_MOUTH, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_REPULSED, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_SAD, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_SHRUG, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_SMILE, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_SURPRISE, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_TONGUE_OUT, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_TOOTHSMILE, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_WINK, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_WORRY, LLEmote::create ); + registerMotion( ANIM_AGENT_FEMALE_RUN_NEW, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_FEMALE_WALK_NEW, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_RUN, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_RUN_NEW, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_STAND, LLKeyframeStandMotion::create ); + registerMotion( ANIM_AGENT_STAND_1, LLKeyframeStandMotion::create ); + registerMotion( ANIM_AGENT_STAND_2, LLKeyframeStandMotion::create ); + registerMotion( ANIM_AGENT_STAND_3, LLKeyframeStandMotion::create ); + registerMotion( ANIM_AGENT_STAND_4, LLKeyframeStandMotion::create ); + registerMotion( ANIM_AGENT_STANDUP, LLKeyframeFallMotion::create ); + registerMotion( ANIM_AGENT_TURNLEFT, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_TURNRIGHT, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_WALK, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_WALK_NEW, LLKeyframeWalkMotion::create ); + + // motions without a start/stop bit + registerMotion( ANIM_AGENT_BODY_NOISE, LLBodyNoiseMotion::create ); + registerMotion( ANIM_AGENT_BREATHE_ROT, LLBreatheMotionRot::create ); + registerMotion( ANIM_AGENT_EDITING, LLEditingMotion::create ); + registerMotion( ANIM_AGENT_EYE, LLEyeMotion::create ); + registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_FLY_ADJUST, LLFlyAdjustMotion::create ); + registerMotion( ANIM_AGENT_HAND_MOTION, LLHandMotion::create ); + registerMotion( ANIM_AGENT_HEAD_ROT, LLHeadRotMotion::create ); + registerMotion( ANIM_AGENT_PELVIS_FIX, LLPelvisFixMotion::create ); + registerMotion( ANIM_AGENT_SIT_FEMALE, LLKeyframeMotion::create ); + registerMotion( ANIM_AGENT_TARGET, LLTargetingMotion::create ); + registerMotion( ANIM_AGENT_WALK_ADJUST, LLWalkAdjustMotion::create ); + + } + + if (gNoRender) + { + return; + } + + buildCharacter(); + + if (gNoRender) + { + return; + } + + // preload specific motions here + createMotion( ANIM_AGENT_CUSTOMIZE); + createMotion( ANIM_AGENT_CUSTOMIZE_DONE); + + //VTPause(); // VTune + + mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) ); + +} + +const LLVector3 LLVOAvatar::getRenderPosition() const +{ + if (mDrawable.isNull() || mDrawable->getGeneration() < 0) + { + return getPositionAgent(); + } + else if (isRoot()) + { + return mDrawable->getPositionAgent(); + } + else + { + return getPosition() * mDrawable->getParent()->getRenderMatrix(); + } +} + +void LLVOAvatar::updateDrawable(BOOL force_damped) +{ + clearChanged(SHIFTED); +} + +void LLVOAvatar::onShift(const LLVector4a& shift_vector) +{ + const LLVector3& shift = reinterpret_cast(shift_vector); + mLastAnimExtents[0] += shift; + mLastAnimExtents[1] += shift; + mNeedsImpostorUpdate = TRUE; + mNeedsAnimUpdate = TRUE; +} + +void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) +{ + if (isImpostor() && !needsImpostorUpdate()) + { + LLVector3 delta = getRenderPosition() - + ((LLVector3(mDrawable->getPositionGroup().getF32ptr())-mImpostorOffset)); + + newMin.load3( (mLastAnimExtents[0] + delta).mV); + newMax.load3( (mLastAnimExtents[1] + delta).mV); + } + else + { + getSpatialExtents(newMin,newMax); + mLastAnimExtents[0].set(newMin.getF32ptr()); + mLastAnimExtents[1].set(newMax.getF32ptr()); + LLVector4a pos_group; + pos_group.setAdd(newMin,newMax); + pos_group.mul(0.5f); + mImpostorOffset = LLVector3(pos_group.getF32ptr())-getRenderPosition(); + mDrawable->setPositionGroup(pos_group); + } +} + +void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) +{ + LLVector4a buffer(0.25f); + LLVector4a pos; + pos.load3(getRenderPosition().mV); + newMin.setSub(pos, buffer); + newMax.setAdd(pos, buffer); + + float max_attachment_span = get_default_max_prim_scale() * 5.0f; + + //stretch bounding box by joint positions + for (polymesh_map_t::iterator i = mMeshes.begin(); i != mMeshes.end(); ++i) + { + LLPolyMesh* mesh = i->second; + for (S32 joint_num = 0; joint_num < mesh->mJointRenderData.count(); joint_num++) + { + LLVector4a trans; + trans.load3( mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation().mV); + update_min_max(newMin, newMax, trans); + } + } + + LLVector4a center, size; + center.setAdd(newMin, newMax); + center.mul(0.5f); + + size.setSub(newMax,newMin); + size.mul(0.5f); + + mPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance()); + + //stretch bounding box by attachments + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + + if (!attachment->getValid()) + { + continue ; + } + + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object && !attached_object->isHUDAttachment()) + { + LLDrawable* drawable = attached_object->mDrawable; + if (drawable) + { + LLSpatialBridge* bridge = drawable->getSpatialBridge(); + if (bridge) + { + const LLVector4a* ext = bridge->getSpatialExtents(); + LLVector4a distance; + distance.setSub(ext[1], ext[0]); + LLVector4a max_span(max_attachment_span); + + S32 lt = distance.lessThan(max_span).getGatheredBits() & 0x7; + + // Only add the prim to spatial extents calculations if it isn't a megaprim. + // max_attachment_span calculated at the start of the function + // (currently 5 times our max prim size) + if (lt == 0x7) + { + update_min_max(newMin,newMax,ext[0]); + update_min_max(newMin,newMax,ext[1]); + } + } + } + } + } + } + + //pad bounding box + + newMin.sub(buffer); + newMax.add(buffer); +} + +//----------------------------------------------------------------------------- +// renderCollisionVolumes() +//----------------------------------------------------------------------------- +void LLVOAvatar::renderCollisionVolumes() +{ + for (S32 i = 0; i < mNumCollisionVolumes; i++) + { + mCollisionVolumes[i].renderCollision(); + } + + if (mNameText.notNull()) + { + LLVector3 unused; + mNameText->lineSegmentIntersect(LLVector3(0,0,0), LLVector3(0,0,1), unused, TRUE); + } +} + +BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + S32 face, + BOOL pick_transparent, + S32* face_hit, + LLVector3* intersection, + LLVector2* tex_coord, + LLVector3* normal, + LLVector3* bi_normal) +{ + if ((isSelf() && !gAgent.needsRenderAvatar()) || !LLPipeline::sPickAvatar) + { + return FALSE; + } + + if (lineSegmentBoundingBox(start, end)) + { + for (S32 i = 0; i < mNumCollisionVolumes; ++i) + { + mCollisionVolumes[i].updateWorldMatrix(); + + glh::matrix4f mat((F32*) mCollisionVolumes[i].getXform()->getWorldMatrix().mMatrix); + glh::matrix4f inverse = mat.inverse(); + glh::matrix4f norm_mat = inverse.transpose(); + + glh::vec3f p1(start.mV); + glh::vec3f p2(end.mV); + + inverse.mult_matrix_vec(p1); + inverse.mult_matrix_vec(p2); + + LLVector3 position; + LLVector3 norm; + + if (linesegment_sphere(LLVector3(p1.v), LLVector3(p2.v), LLVector3(0,0,0), 1.f, position, norm)) + { + glh::vec3f res_pos(position.mV); + mat.mult_matrix_vec(res_pos); + + norm.normalize(); + glh::vec3f res_norm(norm.mV); + norm_mat.mult_matrix_dir(res_norm); + + if (intersection) + { + *intersection = LLVector3(res_pos.v); + } + + if (normal) + { + *normal = LLVector3(res_norm.v); + } + + return TRUE; + } + } + } + + LLVector3 position; + if (mNameText.notNull() && mNameText->lineSegmentIntersect(start, end, position)) + { + if (intersection) + { + *intersection = position; + } + + return TRUE; + } + + return FALSE; +} + +//----------------------------------------------------------------------------- +// parseSkeletonFile() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::parseSkeletonFile(const std::string& filename) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + //------------------------------------------------------------------------- + // parse the file + //------------------------------------------------------------------------- + BOOL parsesuccess = sSkeletonXMLTree.parseFile( filename, FALSE ); + + if (!parsesuccess) + { + llerrs << "Can't parse skeleton file: " << filename << llendl; + return FALSE; + } + + // now sanity check xml file + LLXmlTreeNode* root = sSkeletonXMLTree.getRoot(); + if (!root) + { + llerrs << "No root node found in avatar skeleton file: " << filename << llendl; + return FALSE; + } + + if( !root->hasName( "linden_skeleton" ) ) + { + llerrs << "Invalid avatar skeleton file header: " << filename << llendl; + return FALSE; + } + + std::string version; + static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); + if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") ) + { + llerrs << "Invalid avatar skeleton file version: " << version << " in file: " << filename << llendl; + return FALSE; + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// setupBone() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::setupBone(const LLVOAvatarBoneInfo* info, LLViewerJoint* parent, S32 &volume_num, S32 &joint_num) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + LLViewerJoint* joint = NULL; + + if (info->mIsJoint) + { + joint = (LLViewerJoint*)getCharacterJoint(joint_num); + if (!joint) + { + llwarns << "Too many bones" << llendl; + return FALSE; + } + joint->setName( info->mName ); + } + else // collision volume + { + if (volume_num >= (S32)mNumCollisionVolumes) + { + llwarns << "Too many bones" << llendl; + return FALSE; + } + joint = (LLViewerJoint*)(&mCollisionVolumes[volume_num]); + joint->setName( info->mName ); + } + + // add to parent + if (parent) + { + parent->addChild( joint ); + } + + joint->setPosition(info->mPos); + joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY], + info->mRot.mV[VZ], LLQuaternion::XYZ)); + joint->setScale(info->mScale); + + joint->setDefaultFromCurrentXform(); + + if (info->mIsJoint) + { + joint->setSkinOffset( info->mPivot ); + joint_num++; + } + else // collision volume + { + volume_num++; + } + + // setup children + LLVOAvatarBoneInfo::child_list_t::const_iterator iter; + for (iter = info->mChildList.begin(); iter != info->mChildList.end(); ++iter) + { + LLVOAvatarBoneInfo *child_info = *iter; + if (!setupBone(child_info, joint, volume_num, joint_num)) + { + return FALSE; + } + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// buildSkeleton() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::buildSkeleton(const LLVOAvatarSkeletonInfo *info) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + //------------------------------------------------------------------------- + // allocate joints + //------------------------------------------------------------------------- + if (!allocateCharacterJoints(info->mNumBones)) + { + llerrs << "Can't allocate " << info->mNumBones << " joints" << llendl; + return FALSE; + } + + //------------------------------------------------------------------------- + // allocate volumes + //------------------------------------------------------------------------- + if (info->mNumCollisionVolumes) + { + if (!allocateCollisionVolumes(info->mNumCollisionVolumes)) + { + llerrs << "Can't allocate " << info->mNumCollisionVolumes << " collision volumes" << llendl; + return FALSE; + } + } + + S32 current_joint_num = 0; + S32 current_volume_num = 0; + LLVOAvatarSkeletonInfo::bone_info_list_t::const_iterator iter; + for (iter = info->mBoneInfoList.begin(); iter != info->mBoneInfoList.end(); ++iter) + { + LLVOAvatarBoneInfo *info = *iter; + if (!setupBone(info, NULL, current_volume_num, current_joint_num)) + { + llerrs << "Error parsing bone in skeleton file" << llendl; + return FALSE; + } + } + + return TRUE; +} + +LLVOAvatar* LLVOAvatar::asAvatar() +{ + return this; +} + +//----------------------------------------------------------------------------- +// LLVOAvatar::startDefaultMotions() +//----------------------------------------------------------------------------- +void LLVOAvatar::startDefaultMotions() +{ + //------------------------------------------------------------------------- + // start default motions + //------------------------------------------------------------------------- + startMotion( ANIM_AGENT_HEAD_ROT ); + startMotion( ANIM_AGENT_EYE ); + startMotion( ANIM_AGENT_BODY_NOISE ); + startMotion( ANIM_AGENT_BREATHE_ROT ); + startMotion( ANIM_AGENT_HAND_MOTION ); + startMotion( ANIM_AGENT_PELVIS_FIX ); + + //------------------------------------------------------------------------- + // restart any currently active motions + //------------------------------------------------------------------------- + processAnimationStateChanges(); +} + +//----------------------------------------------------------------------------- +// LLVOAvatar::buildCharacter() +// Deferred initialization and rebuild of the avatar. +//----------------------------------------------------------------------------- +void LLVOAvatar::buildCharacter() +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + //------------------------------------------------------------------------- + // remove all references to our existing skeleton + // so we can rebuild it + //------------------------------------------------------------------------- + flushAllMotions(); + + //------------------------------------------------------------------------- + // remove all of mRoot's children + //------------------------------------------------------------------------- + mRoot.removeAllChildren(); + mIsBuilt = FALSE; + + //------------------------------------------------------------------------- + // clear mesh data + //------------------------------------------------------------------------- + for (std::vector::iterator jointIter = mMeshLOD.begin(); + jointIter != mMeshLOD.end(); ++jointIter) + { + LLViewerJoint* joint = (LLViewerJoint*) *jointIter; + for (std::vector::iterator meshIter = joint->mMeshParts.begin(); + meshIter != joint->mMeshParts.end(); ++meshIter) + { + LLViewerJointMesh * mesh = (LLViewerJointMesh *) *meshIter; + mesh->setMesh(NULL); + } + } + + //------------------------------------------------------------------------- + // (re)load our skeleton and meshes + //------------------------------------------------------------------------- + LLTimer timer; + + BOOL status = loadAvatar(); + stop_glerror(); + + if (gNoRender) + { + // Still want to load the avatar skeleton so visual parameters work. + return; + } + +// gPrintMessagesThisFrame = TRUE; + lldebugs << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << llendl; + + if (!status) + { + if (isSelf()) + { + llerrs << "Unable to load user's avatar" << llendl; + } + else + { + llwarns << "Unable to load other's avatar" << llendl; + } + return; + } + + //------------------------------------------------------------------------- + // initialize "well known" joint pointers + //------------------------------------------------------------------------- + mPelvisp = (LLViewerJoint*)mRoot.findJoint("mPelvis"); + mTorsop = (LLViewerJoint*)mRoot.findJoint("mTorso"); + mChestp = (LLViewerJoint*)mRoot.findJoint("mChest"); + mNeckp = (LLViewerJoint*)mRoot.findJoint("mNeck"); + mHeadp = (LLViewerJoint*)mRoot.findJoint("mHead"); + mSkullp = (LLViewerJoint*)mRoot.findJoint("mSkull"); + mHipLeftp = (LLViewerJoint*)mRoot.findJoint("mHipLeft"); + mHipRightp = (LLViewerJoint*)mRoot.findJoint("mHipRight"); + mKneeLeftp = (LLViewerJoint*)mRoot.findJoint("mKneeLeft"); + mKneeRightp = (LLViewerJoint*)mRoot.findJoint("mKneeRight"); + mAnkleLeftp = (LLViewerJoint*)mRoot.findJoint("mAnkleLeft"); + mAnkleRightp = (LLViewerJoint*)mRoot.findJoint("mAnkleRight"); + mFootLeftp = (LLViewerJoint*)mRoot.findJoint("mFootLeft"); + mFootRightp = (LLViewerJoint*)mRoot.findJoint("mFootRight"); + mWristLeftp = (LLViewerJoint*)mRoot.findJoint("mWristLeft"); + mWristRightp = (LLViewerJoint*)mRoot.findJoint("mWristRight"); + mEyeLeftp = (LLViewerJoint*)mRoot.findJoint("mEyeLeft"); + mEyeRightp = (LLViewerJoint*)mRoot.findJoint("mEyeRight"); + + //------------------------------------------------------------------------- + // Make sure "well known" pointers exist + //------------------------------------------------------------------------- + if (!(mPelvisp && + mTorsop && + mChestp && + mNeckp && + mHeadp && + mSkullp && + mHipLeftp && + mHipRightp && + mKneeLeftp && + mKneeRightp && + mAnkleLeftp && + mAnkleRightp && + mFootLeftp && + mFootRightp && + mWristLeftp && + mWristRightp && + mEyeLeftp && + mEyeRightp)) + { + llerrs << "Failed to create avatar." << llendl; + return; + } + + //------------------------------------------------------------------------- + // initialize the pelvis + //------------------------------------------------------------------------- + mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) ); + + //------------------------------------------------------------------------- + // set head offset from pelvis + //------------------------------------------------------------------------- + updateHeadOffset(); + + //------------------------------------------------------------------------- + // initialize lip sync morph pointers + //------------------------------------------------------------------------- + mOohMorph = getVisualParam( "Lipsync_Ooh" ); + mAahMorph = getVisualParam( "Lipsync_Aah" ); + + // If we don't have the Ooh morph, use the Kiss morph + if (!mOohMorph) + { + llwarns << "Missing 'Ooh' morph for lipsync, using fallback." << llendl; + mOohMorph = getVisualParam( "Express_Kiss" ); + } + + // If we don't have the Aah morph, use the Open Mouth morph + if (!mAahMorph) + { + llwarns << "Missing 'Aah' morph for lipsync, using fallback." << llendl; + mAahMorph = getVisualParam( "Express_Open_Mouth" ); + } + + startDefaultMotions(); + + //------------------------------------------------------------------------- + // restart any currently active motions + //------------------------------------------------------------------------- + processAnimationStateChanges(); + + mIsBuilt = TRUE; + stop_glerror(); + + mMeshValid = TRUE; +} + + +//----------------------------------------------------------------------------- +// releaseMeshData() +//----------------------------------------------------------------------------- +void LLVOAvatar::releaseMeshData() +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || mIsDummy) + { + return; + } + + //llinfos << "Releasing" << llendl; + + // cleanup mesh data + for (std::vector::iterator iter = mMeshLOD.begin(); + iter != mMeshLOD.end(); + ++iter) + { + LLViewerJoint* joint = (LLViewerJoint*) *iter; + joint->setValid(FALSE, TRUE); + } + + //cleanup data + if (mDrawable.notNull()) + { + LLFace* facep = mDrawable->getFace(0); + facep->setSize(0, 0); + for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++) + { + facep = mDrawable->getFace(i); + facep->setSize(0, 0); + } + } + + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (!attachment->getIsHUDAttachment()) + { + attachment->setAttachmentVisibility(FALSE); + } + } + mMeshValid = FALSE; +} + +//----------------------------------------------------------------------------- +// restoreMeshData() +//----------------------------------------------------------------------------- +// virtual +void LLVOAvatar::restoreMeshData() +{ + llassert(!isSelf()); + LLMemType mt(LLMemType::MTYPE_AVATAR); + + //llinfos << "Restoring" << llendl; + mMeshValid = TRUE; + updateJointLODs(); + + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (!attachment->getIsHUDAttachment()) + { + attachment->setAttachmentVisibility(TRUE); + } + } + + // force mesh update as LOD might not have changed to trigger this + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); +} + +//----------------------------------------------------------------------------- +// updateMeshData() +//----------------------------------------------------------------------------- +void LLVOAvatar::updateMeshData() +{ + if (mDrawable.notNull()) + { + stop_glerror(); + + S32 f_num = 0 ; + const U32 VERTEX_NUMBER_THRESHOLD = 128 ;//small number of this means each part of an avatar has its own vertex buffer. + const S32 num_parts = mMeshLOD.size(); + + // this order is determined by number of LODS + // if a mesh earlier in this list changed LODs while a later mesh doesn't, + // the later mesh's index offset will be inaccurate + for(S32 part_index = 0 ; part_index < num_parts ;) + { + S32 j = part_index ; + U32 last_v_num = 0, num_vertices = 0 ; + U32 last_i_num = 0, num_indices = 0 ; + + while(part_index < num_parts && num_vertices < VERTEX_NUMBER_THRESHOLD) + { + last_v_num = num_vertices ; + last_i_num = num_indices ; + + mMeshLOD[part_index++]->updateFaceSizes(num_vertices, num_indices, mAdjustedPixelArea); + } + if(num_vertices < 1)//skip empty meshes + { + continue ; + } + if(last_v_num > 0)//put the last inserted part into next vertex buffer. + { + num_vertices = last_v_num ; + num_indices = last_i_num ; + part_index-- ; + } + + LLFace* facep ; + if(f_num < mDrawable->getNumFaces()) + { + facep = mDrawable->getFace(f_num); + } + else + { + facep = mDrawable->addFace(mDrawable->getFace(0)->getPool(), mDrawable->getFace(0)->getTexture()) ; + } + + // resize immediately + facep->setSize(num_vertices, num_indices); + + bool terse_update = false; + + if(facep->mVertexBuffer.isNull()) + { + facep->mVertexBuffer = new LLVertexBufferAvatar(); + facep->mVertexBuffer->allocateBuffer(num_vertices, num_indices, TRUE); + } + else + { + if (facep->mVertexBuffer->getRequestedIndices() == num_indices && + facep->mVertexBuffer->getRequestedVerts() == num_vertices) + { + terse_update = true; + } + else + { + facep->mVertexBuffer->resizeBuffer(num_vertices, num_indices) ; + } + } + + facep->setGeomIndex(0); + facep->setIndicesIndex(0); + + // This is a hack! Avatars have their own pool, so we are detecting + // the case of more than one avatar in the pool (thus > 0 instead of >= 0) + if (facep->getGeomIndex() > 0) + { + llerrs << "non-zero geom index: " << facep->getGeomIndex() << " in LLVOAvatar::restoreMeshData" << llendl; + } + + for(S32 k = j ; k < part_index ; k++) + { + mMeshLOD[k]->updateFaceData(facep, mAdjustedPixelArea, k == MESH_ID_HAIR, terse_update); + } + + stop_glerror(); + facep->mVertexBuffer->setBuffer(0); + + if(!f_num) + { + f_num += mNumInitFaces ; + } + else + { + f_num++ ; + } + } + } +} + +//------------------------------------------------------------------------ + +//------------------------------------------------------------------------ +// The viewer can only suggest a good size for the agent, +// the simulator will keep it inside a reasonable range. +void LLVOAvatar::computeBodySize() +{ + LLVector3 pelvis_scale = mPelvisp->getScale(); + + // some of the joints have not been cached + LLVector3 skull = mSkullp->getPosition(); + LLVector3 skull_scale = mSkullp->getScale(); + + LLVector3 neck = mNeckp->getPosition(); + LLVector3 neck_scale = mNeckp->getScale(); + + LLVector3 chest = mChestp->getPosition(); + LLVector3 chest_scale = mChestp->getScale(); + + // the rest of the joints have been cached + LLVector3 head = mHeadp->getPosition(); + LLVector3 head_scale = mHeadp->getScale(); + + LLVector3 torso = mTorsop->getPosition(); + LLVector3 torso_scale = mTorsop->getScale(); + + LLVector3 hip = mHipLeftp->getPosition(); + LLVector3 hip_scale = mHipLeftp->getScale(); + + LLVector3 knee = mKneeLeftp->getPosition(); + LLVector3 knee_scale = mKneeLeftp->getScale(); + + LLVector3 ankle = mAnkleLeftp->getPosition(); + LLVector3 ankle_scale = mAnkleLeftp->getScale(); + + LLVector3 foot = mFootLeftp->getPosition(); + + mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] - + knee.mV[VZ] * hip_scale.mV[VZ] - + ankle.mV[VZ] * knee_scale.mV[VZ] - + foot.mV[VZ] * ankle_scale.mV[VZ]; + + LLVector3 new_body_size; + new_body_size.mV[VZ] = mPelvisToFoot + + // the sqrt(2) correction below is an approximate + // correction to get to the top of the head + F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) + + head.mV[VZ] * neck_scale.mV[VZ] + + neck.mV[VZ] * chest_scale.mV[VZ] + + chest.mV[VZ] * torso_scale.mV[VZ] + + torso.mV[VZ] * pelvis_scale.mV[VZ]; + + // TODO -- measure the real depth and width + new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH; + new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH; + + if (new_body_size != mBodySize) + { + mBodySize = new_body_size; + + if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF()) + { // notify simulator of change in size + // but not if we are in the middle of updating appearance + gAgent.sendAgentSetAppearance(); + } + } +} + +//------------------------------------------------------------------------ +// LLVOAvatar::processUpdateMessage() +//------------------------------------------------------------------------ +U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys, + void **user_data, + U32 block_num, const EObjectUpdateType update_type, + LLDataPacker *dp) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + LLVector3 old_vel = getVelocity(); + const BOOL has_name = !getNVPair("FirstName"); + + // Do base class updates... + U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); + + // Print out arrival information once we have name of avatar. + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + if (has_name && getNVPair("FirstName")) + { + mDebugExistenceTimer.reset(); + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezArrivedNotification",args); + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' arrived." << llendl; + } + } + if(retval & LLViewerObject::INVALID_UPDATE) + { + if (isSelf()) + { + //tell sim to cancel this update + gAgent.teleportViaLocation(gAgent.getPositionGlobal()); + } + } + + //llinfos << getRotation() << llendl; + //llinfos << getPosition() << llendl; + + return retval; +} + +// virtual +S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid) +{ + // The core setTETexture() method requests images, so we need + // to redirect certain avatar texture requests to different sims. + if (isIndexBakedTexture((ETextureIndex)te)) + { + LLHost target_host = getObjectHost(); + return setTETextureCore(te, uuid, target_host); + } + else + { + return setTETextureCore(te, uuid, LLHost::invalid); + } +} + +static LLFastTimer::DeclareTimer FTM_AVATAR_UPDATE("Update Avatar"); +static LLFastTimer::DeclareTimer FTM_JOINT_UPDATE("Update Joints"); + +//------------------------------------------------------------------------ +// LLVOAvatar::dumpAnimationState() +//------------------------------------------------------------------------ +void LLVOAvatar::dumpAnimationState() +{ + llinfos << "==============================================" << llendl; + for (LLVOAvatar::AnimIterator it = mSignaledAnimations.begin(); it != mSignaledAnimations.end(); ++it) + { + LLUUID id = it->first; + std::string playtag = ""; + if (mPlayingAnimations.find(id) != mPlayingAnimations.end()) + { + playtag = "*"; + } + llinfos << gAnimLibrary.animationName(id) << playtag << llendl; + } + for (LLVOAvatar::AnimIterator it = mPlayingAnimations.begin(); it != mPlayingAnimations.end(); ++it) + { + LLUUID id = it->first; + bool is_signaled = mSignaledAnimations.find(id) != mSignaledAnimations.end(); + if (!is_signaled) + { + llinfos << gAnimLibrary.animationName(id) << "!S" << llendl; + } + } +} + +//------------------------------------------------------------------------ +// idleUpdate() +//------------------------------------------------------------------------ +BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + LLFastTimer t(FTM_AVATAR_UPDATE); + + if (isDead()) + { + llinfos << "Warning! Idle on dead avatar" << llendl; + return TRUE; + } + + if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR))) + { + return TRUE; + } + + checkTextureLoading() ; + + // force immediate pixel area update on avatars using last frames data (before drawable or camera updates) + setPixelAreaAndAngle(gAgent); + + // force asynchronous drawable update + if(mDrawable.notNull() && !gNoRender) + { + LLFastTimer t(FTM_JOINT_UPDATE); + + if (mIsSitting && getParent()) + { + LLViewerObject *root_object = (LLViewerObject*)getRoot(); + LLDrawable* drawablep = root_object->mDrawable; + // if this object hasn't already been updated by another avatar... + if (drawablep) // && !drawablep->isState(LLDrawable::EARLY_MOVE)) + { + if (root_object->isSelected()) + { + gPipeline.updateMoveNormalAsync(drawablep); + } + else + { + gPipeline.updateMoveDampedAsync(drawablep); + } + } + } + else + { + gPipeline.updateMoveDampedAsync(mDrawable); + } + } + + //-------------------------------------------------------------------- + // set alpha flag depending on state + //-------------------------------------------------------------------- + + if (isSelf()) + { + LLViewerObject::idleUpdate(agent, world, time); + + // trigger fidget anims + if (isAnyAnimationSignaled(AGENT_STAND_ANIMS, NUM_AGENT_STAND_ANIMS)) + { + agent.fidget(); + } + } + else + { + // Should override the idleUpdate stuff and leave out the angular update part. + LLQuaternion rotation = getRotation(); + LLViewerObject::idleUpdate(agent, world, time); + setRotation(rotation); + } + + // attach objects that were waiting for a drawable + lazyAttach(); + + // animate the character + // store off last frame's root position to be consistent with camera position + LLVector3 root_pos_last = mRoot.getWorldPosition(); + BOOL detailed_update = updateCharacter(agent); + + if (gNoRender) + { + return TRUE; + } + + static LLUICachedControl visualizers_in_calls("ShowVoiceVisualizersInCalls", false); + bool voice_enabled = (visualizers_in_calls || LLVoiceClient::getInstance()->inProximalChannel()) && + LLVoiceClient::getInstance()->getVoiceEnabled(mID); + + idleUpdateVoiceVisualizer( voice_enabled ); + idleUpdateMisc( detailed_update ); + idleUpdateAppearanceAnimation(); + if (detailed_update) + { + idleUpdateLipSync( voice_enabled ); + idleUpdateLoadingEffect(); + idleUpdateBelowWater(); // wind effect uses this + idleUpdateWindEffect(); + } + + idleUpdateNameTag( root_pos_last ); + idleUpdateRenderCost(); + + return TRUE; +} + +void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) +{ + bool render_visualizer = voice_enabled; + + // Don't render the user's own voice visualizer when in mouselook, or when opening the mic is disabled. + if(isSelf()) + { + if(gAgentCamera.cameraMouselook() || gSavedSettings.getBOOL("VoiceDisableMic")) + { + render_visualizer = false; + } + } + + mVoiceVisualizer->setVoiceEnabled(render_visualizer); + + if ( voice_enabled ) + { + //---------------------------------------------------------------- + // Only do gesture triggering for your own avatar, and only when you're in a proximal channel. + //---------------------------------------------------------------- + if( isSelf() ) + { + //---------------------------------------------------------------------------------------- + // The following takes the voice signal and uses that to trigger gesticulations. + //---------------------------------------------------------------------------------------- + int lastGesticulationLevel = mCurrentGesticulationLevel; + mCurrentGesticulationLevel = mVoiceVisualizer->getCurrentGesticulationLevel(); + + //--------------------------------------------------------------------------------------------------- + // If "current gesticulation level" changes, we catch this, and trigger the new gesture + //--------------------------------------------------------------------------------------------------- + if ( lastGesticulationLevel != mCurrentGesticulationLevel ) + { + if ( mCurrentGesticulationLevel != VOICE_GESTICULATION_LEVEL_OFF ) + { + std::string gestureString = "unInitialized"; + if ( mCurrentGesticulationLevel == 0 ) { gestureString = "/voicelevel1"; } + else if ( mCurrentGesticulationLevel == 1 ) { gestureString = "/voicelevel2"; } + else if ( mCurrentGesticulationLevel == 2 ) { gestureString = "/voicelevel3"; } + else { llinfos << "oops - CurrentGesticulationLevel can be only 0, 1, or 2" << llendl; } + + // this is the call that Karl S. created for triggering gestures from within the code. + LLGestureMgr::instance().triggerAndReviseString( gestureString ); + } + } + + } //if( isSelf() ) + + //----------------------------------------------------------------------------------------------------------------- + // If the avatar is speaking, then the voice amplitude signal is passed to the voice visualizer. + // Also, here we trigger voice visualizer start and stop speaking, so it can animate the voice symbol. + // + // Notice the calls to "gAwayTimer.reset()". This resets the timer that determines how long the avatar has been + // "away", so that the avatar doesn't lapse into away-mode (and slump over) while the user is still talking. + //----------------------------------------------------------------------------------------------------------------- + if (LLVoiceClient::getInstance()->getIsSpeaking( mID )) + { + if (!mVoiceVisualizer->getCurrentlySpeaking()) + { + mVoiceVisualizer->setStartSpeaking(); + + //printf( "gAwayTimer.reset();\n" ); + } + + mVoiceVisualizer->setSpeakingAmplitude( LLVoiceClient::getInstance()->getCurrentPower( mID ) ); + + if( isSelf() ) + { + gAgent.clearAFK(); + } + } + else + { + if ( mVoiceVisualizer->getCurrentlySpeaking() ) + { + mVoiceVisualizer->setStopSpeaking(); + + if ( mLipSyncActive ) + { + if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight(), FALSE); + if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight(), FALSE); + + mLipSyncActive = false; + LLCharacter::updateVisualParams(); + dirtyMesh(); + } + } + } + + //-------------------------------------------------------------------------------------------- + // here we get the approximate head position and set as sound source for the voice symbol + // (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing) + //-------------------------------------------------------------------------------------------- + + if ( mIsSitting ) + { + LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] ); + mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset ); + } + else + { + LLVector3 tagPos = mRoot.getWorldPosition(); + tagPos[VZ] -= mPelvisToFoot; + tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); + mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos ); + } + }//if ( voiceEnabled ) +} + +static LLFastTimer::DeclareTimer FTM_ATTACHMENT_UPDATE("Update Attachments"); + +void LLVOAvatar::idleUpdateMisc(bool detailed_update) +{ + if (LLVOAvatar::sJointDebug) + { + llinfos << getFullname() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << llendl; + } + + LLJoint::sNumUpdates = 0; + LLJoint::sNumTouches = 0; + + BOOL visible = isVisible() || mNeedsAnimUpdate; + + // update attachments positions + if (detailed_update || !sUseImpostors) + { + LLFastTimer t(FTM_ATTACHMENT_UPDATE); + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject* attached_object = (*attachment_iter); + BOOL visibleAttachment = visible || (attached_object && + !(attached_object->mDrawable->getSpatialBridge() && + attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0)); + + if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid()) + { + // if selecting any attachments, update all of them as non-damped + if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment()) + { + gPipeline.updateMoveNormalAsync(attached_object->mDrawable); + } + else + { + gPipeline.updateMoveDampedAsync(attached_object->mDrawable); + } + + LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge(); + if (bridge) + { + gPipeline.updateMoveNormalAsync(bridge); + } + attached_object->updateText(); + } + } + } + } + + mNeedsAnimUpdate = FALSE; + + if (isImpostor() && !mNeedsImpostorUpdate) + { + LLVector4a ext[2]; + F32 distance; + LLVector3 angle; + + getImpostorValues(ext, angle, distance); + + for (U32 i = 0; i < 3 && !mNeedsImpostorUpdate; i++) + { + F32 cur_angle = angle.mV[i]; + F32 old_angle = mImpostorAngle.mV[i]; + F32 angle_diff = fabsf(cur_angle-old_angle); + + if (angle_diff > F_PI/512.f*distance*mUpdatePeriod) + { + mNeedsImpostorUpdate = TRUE; + } + } + + if (detailed_update && !mNeedsImpostorUpdate) + { //update impostor if view angle, distance, or bounding box change + //significantly + + F32 dist_diff = fabsf(distance-mImpostorDistance); + if (dist_diff/mImpostorDistance > 0.1f) + { + mNeedsImpostorUpdate = TRUE; + } + else + { + //VECTORIZE THIS + getSpatialExtents(ext[0], ext[1]); + LLVector4a diff; + diff.setSub(ext[1], mImpostorExtents[1]); + if (diff.getLength3().getF32() > 0.05f) + { + mNeedsImpostorUpdate = TRUE; + } + else + { + diff.setSub(ext[0], mImpostorExtents[0]); + if (diff.getLength3().getF32() > 0.05f) + { + mNeedsImpostorUpdate = TRUE; + } + } + } + } + } + + mDrawable->movePartition(); + + //force a move if sitting on an active object + if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive()) + { + gPipeline.markMoved(mDrawable, TRUE); + } +} + +void LLVOAvatar::idleUpdateAppearanceAnimation() +{ + // update morphing params + if (mAppearanceAnimating) + { + ESex avatar_sex = getSex(); + F32 appearance_anim_time = mAppearanceMorphTimer.getElapsedTimeF32(); + if (appearance_anim_time >= APPEARANCE_MORPH_TIME) + { + mAppearanceAnimating = FALSE; + for (LLVisualParam *param = getFirstVisualParam(); + param; + param = getNextVisualParam()) + { + if (param->isTweakable()) + { + param->stopAnimating(FALSE); + } + } + updateVisualParams(); + if (isSelf()) + { + gAgent.sendAgentSetAppearance(); + } + } + else + { + F32 morph_amt = calcMorphAmount(); + LLVisualParam *param; + + if (!isSelf()) + { + // animate only top level params for non-self avatars + for (param = getFirstVisualParam(); + param; + param = getNextVisualParam()) + { + if (param->isTweakable()) + { + param->animate(morph_amt, FALSE); + } + } + } + + // apply all params + for (param = getFirstVisualParam(); + param; + param = getNextVisualParam()) + { + param->apply(avatar_sex); + } + + mLastAppearanceBlendTime = appearance_anim_time; + } + dirtyMesh(); + } +} + +F32 LLVOAvatar::calcMorphAmount() +{ + F32 appearance_anim_time = mAppearanceMorphTimer.getElapsedTimeF32(); + F32 blend_frac = calc_bouncy_animation(appearance_anim_time / APPEARANCE_MORPH_TIME); + F32 last_blend_frac = calc_bouncy_animation(mLastAppearanceBlendTime / APPEARANCE_MORPH_TIME); + + F32 morph_amt; + if (last_blend_frac == 1.f) + { + morph_amt = 1.f; + } + else + { + morph_amt = (blend_frac - last_blend_frac) / (1.f - last_blend_frac); + } + + return morph_amt; +} + +void LLVOAvatar::idleUpdateLipSync(bool voice_enabled) +{ + // Use the Lipsync_Ooh and Lipsync_Aah morphs for lip sync + if ( voice_enabled && (LLVoiceClient::getInstance()->lipSyncEnabled()) && LLVoiceClient::getInstance()->getIsSpeaking( mID ) ) + { + F32 ooh_morph_amount = 0.0f; + F32 aah_morph_amount = 0.0f; + + mVoiceVisualizer->lipSyncOohAah( ooh_morph_amount, aah_morph_amount ); + + if( mOohMorph ) + { + F32 ooh_weight = mOohMorph->getMinWeight() + + ooh_morph_amount * (mOohMorph->getMaxWeight() - mOohMorph->getMinWeight()); + + mOohMorph->setWeight( ooh_weight, FALSE ); + } + + if( mAahMorph ) + { + F32 aah_weight = mAahMorph->getMinWeight() + + aah_morph_amount * (mAahMorph->getMaxWeight() - mAahMorph->getMinWeight()); + + mAahMorph->setWeight( aah_weight, FALSE ); + } + + mLipSyncActive = true; + LLCharacter::updateVisualParams(); + dirtyMesh(); + } +} + +void LLVOAvatar::idleUpdateLoadingEffect() +{ + // update visibility when avatar is partially loaded + if (updateIsFullyLoaded()) // changed? + { + if (isFullyLoaded() && isSelf()) + { + static bool first_fully_visible = true; + if (first_fully_visible) + { + llinfos << "self isFullyLoaded, first_fully_visible" << llendl; + + first_fully_visible = false; + LLAppearanceMgr::instance().onFirstFullyVisible(); + } + } + if (isFullyLoaded()) + { + deleteParticleSource(); + updateLOD(); + } + else + { + LLPartSysData particle_parameters; + + // fancy particle cloud designed by Brent + particle_parameters.mPartData.mMaxAge = 4.f; + particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f; + particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f; + particle_parameters.mPartData.mStartScale.mV[VY] = 1.0f; + particle_parameters.mPartData.mEndScale.mV[VX] = 0.02f; + particle_parameters.mPartData.mEndScale.mV[VY] = 0.02f; + particle_parameters.mPartData.mStartColor = LLColor4(1, 1, 1, 0.5f); + particle_parameters.mPartData.mEndColor = LLColor4(1, 1, 1, 0.0f); + particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f; + LLViewerTexture* cloud = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c"); + particle_parameters.mPartImageID = cloud->getID(); + particle_parameters.mMaxAge = 0.f; + particle_parameters.mPattern = LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE; + particle_parameters.mInnerAngle = F_PI; + particle_parameters.mOuterAngle = 0.f; + particle_parameters.mBurstRate = 0.02f; + particle_parameters.mBurstRadius = 0.0f; + particle_parameters.mBurstPartCount = 1; + particle_parameters.mBurstSpeedMin = 0.1f; + particle_parameters.mBurstSpeedMax = 1.f; + particle_parameters.mPartData.mFlags = ( LLPartData::LL_PART_INTERP_COLOR_MASK | LLPartData::LL_PART_INTERP_SCALE_MASK | + LLPartData::LL_PART_EMISSIVE_MASK | // LLPartData::LL_PART_FOLLOW_SRC_MASK | + LLPartData::LL_PART_TARGET_POS_MASK ); + + setParticleSource(particle_parameters, getID()); + } + } +} + +void LLVOAvatar::idleUpdateWindEffect() +{ + // update wind effect + if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH)) + { + F32 hover_strength = 0.f; + F32 time_delta = mRippleTimer.getElapsedTimeF32() - mRippleTimeLast; + mRippleTimeLast = mRippleTimer.getElapsedTimeF32(); + LLVector3 velocity = getVelocity(); + F32 speed = velocity.length(); + //RN: velocity varies too much frame to frame for this to work + mRippleAccel.clearVec();//lerp(mRippleAccel, (velocity - mLastVel) * time_delta, LLCriticalDamp::getInterpolant(0.02f)); + mLastVel = velocity; + LLVector4 wind; + wind.setVec(getRegion()->mWind.getVelocityNoisy(getPositionAgent(), 4.f) - velocity); + + if (mInAir) + { + hover_strength = HOVER_EFFECT_STRENGTH * llmax(0.f, HOVER_EFFECT_MAX_SPEED - speed); + } + + if (mBelowWater) + { + // TODO: make cloth flow more gracefully when underwater + hover_strength += UNDERWATER_EFFECT_STRENGTH; + } + + wind.mV[VZ] += hover_strength; + wind.normalize(); + + wind.mV[VW] = llmin(0.025f + (speed * 0.015f) + hover_strength, 0.5f); + F32 interp; + if (wind.mV[VW] > mWindVec.mV[VW]) + { + interp = LLCriticalDamp::getInterpolant(0.2f); + } + else + { + interp = LLCriticalDamp::getInterpolant(0.4f); + } + mWindVec = lerp(mWindVec, wind, interp); + + F32 wind_freq = hover_strength + llclamp(8.f + (speed * 0.7f) + (noise1(mRipplePhase) * 4.f), 8.f, 25.f); + mWindFreq = lerp(mWindFreq, wind_freq, interp); + + if (mBelowWater) + { + mWindFreq *= UNDERWATER_FREQUENCY_DAMP; + } + + mRipplePhase += (time_delta * mWindFreq); + if (mRipplePhase > F_TWO_PI) + { + mRipplePhase = fmodf(mRipplePhase, F_TWO_PI); + } + } +} + +void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) +{ + // update chat bubble + //-------------------------------------------------------------------- + // draw text label over character's head + //-------------------------------------------------------------------- + if (mChatTimer.getElapsedTimeF32() > BUBBLE_CHAT_TIME) + { + mChats.clear(); + } + + const F32 time_visible = mTimeVisible.getElapsedTimeF32(); + const F32 NAME_SHOW_TIME = gSavedSettings.getF32("RenderNameShowTime"); // seconds + const F32 FADE_DURATION = gSavedSettings.getF32("RenderNameFadeDuration"); // seconds + BOOL visible_avatar = isVisible() || mNeedsAnimUpdate; + BOOL visible_chat = gSavedSettings.getBOOL("UseChatBubbles") && (mChats.size() || mTyping); + BOOL render_name = visible_chat || + (visible_avatar && + ((sRenderName == RENDER_NAME_ALWAYS) || + (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME))); + // If it's your own avatar, don't draw in mouselook, and don't + // draw if we're specifically hiding our own name. + if (isSelf()) + { + render_name = render_name + && !gAgentCamera.cameraMouselook() + && (visible_chat || (gSavedSettings.getBOOL("RenderNameShowSelf") + && gSavedSettings.getS32("AvatarNameTagMode") )); + } + + if ( !render_name ) + { + if (mNameText) + { + // ...clean up old name tag + mNameText->markDead(); + mNameText = NULL; + sNumVisibleChatBubbles--; + } + return; + } + + BOOL new_name = FALSE; + if (visible_chat != mVisibleChat) + { + mVisibleChat = visible_chat; + new_name = TRUE; + } + + if (sRenderGroupTitles != mRenderGroupTitles) + { + mRenderGroupTitles = sRenderGroupTitles; + new_name = TRUE; + } + + // First Calculate Alpha + // If alpha > 0, create mNameText if necessary, otherwise delete it + F32 alpha = 0.f; + if (mAppAngle > 5.f) + { + const F32 START_FADE_TIME = NAME_SHOW_TIME - FADE_DURATION; + if (!visible_chat && sRenderName == RENDER_NAME_FADE && time_visible > START_FADE_TIME) + { + alpha = 1.f - (time_visible - START_FADE_TIME) / FADE_DURATION; + } + else + { + // ...not fading, full alpha + alpha = 1.f; + } + } + else if (mAppAngle > 2.f) + { + // far away is faded out also + alpha = (mAppAngle-2.f)/3.f; + } + + if (alpha <= 0.f) + { + if (mNameText) + { + mNameText->markDead(); + mNameText = NULL; + sNumVisibleChatBubbles--; + } + return; + } + + if (!mNameText) + { + mNameText = static_cast( LLHUDObject::addHUDObject( + LLHUDObject::LL_HUD_NAME_TAG) ); + //mNameText->setMass(10.f); + mNameText->setSourceObject(this); + mNameText->setVertAlignment(LLHUDNameTag::ALIGN_VERT_TOP); + mNameText->setVisibleOffScreen(TRUE); + mNameText->setMaxLines(11); + mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f); + sNumVisibleChatBubbles++; + new_name = TRUE; + } + + LLVector3 name_position = idleUpdateNameTagPosition(root_pos_last); + mNameText->setPositionAgent(name_position); + idleUpdateNameTagText(new_name); + idleUpdateNameTagAlpha(new_name, alpha); +} + +void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) + { + LLNameValue *title = getNVPair("Title"); + LLNameValue* firstname = getNVPair("FirstName"); + LLNameValue* lastname = getNVPair("LastName"); + + // Avatars must have a first and last name + if (!firstname || !lastname) return; + + bool is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY) != mSignaledAnimations.end(); + bool is_busy = mSignaledAnimations.find(ANIM_AGENT_BUSY) != mSignaledAnimations.end(); + bool is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end(); + bool is_muted; + if (isSelf()) + { + is_muted = false; + } + else + { + is_muted = LLMuteList::getInstance()->isMuted(getID()); + } + bool is_friend = LLAvatarTracker::instance().isBuddy(getID()); + bool is_cloud = getIsCloud(); + + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + if (is_appearance != mNameAppearance) + { + if (is_appearance) + { + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezEnteredAppearanceNotification",args); + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' entered appearance mode." << llendl; + } + else + { + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezLeftAppearanceNotification",args); + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left appearance mode." << llendl; + } + } + } + + // Rebuild name tag if state change detected + if (mNameString.empty() + || new_name + || (!title && !mTitle.empty()) + || (title && mTitle != title->getString()) + || is_away != mNameAway + || is_busy != mNameBusy + || is_muted != mNameMute + || is_appearance != mNameAppearance + || is_friend != mNameFriend + || is_cloud != mNameCloud) + { + LLColor4 name_tag_color = getNameTagColor(is_friend); + + clearNameTag(); + + if (is_away || is_muted || is_busy || is_appearance) + { + std::string line; + if (is_away) + { + line += LLTrans::getString("AvatarAway"); + line += ", "; + } + if (is_busy) + { + line += LLTrans::getString("AvatarBusy"); + line += ", "; + } + if (is_muted) + { + line += LLTrans::getString("AvatarMuted"); + line += ", "; + } + if (is_appearance) + { + line += LLTrans::getString("AvatarEditingAppearance"); + line += ", "; + } + if (is_cloud) + { + line += LLTrans::getString("LoadingData"); + line += ", "; + } + // trim last ", " + line.resize( line.length() - 2 ); + addNameTagLine(line, name_tag_color, LLFontGL::NORMAL, + LLFontGL::getFontSansSerifSmall()); + } + + if (sRenderGroupTitles + && title && title->getString() && title->getString()[0] != '\0') + { + std::string title_str = title->getString(); + LLStringFn::replace_ascii_controlchars(title_str,LL_UNKNOWN_CHAR); + addNameTagLine(title_str, name_tag_color, LLFontGL::NORMAL, + LLFontGL::getFontSansSerifSmall()); + } + + static LLUICachedControl show_display_names("NameTagShowDisplayNames"); + static LLUICachedControl show_usernames("NameTagShowUsernames"); + + if (LLAvatarNameCache::useDisplayNames()) + { + LLAvatarName av_name; + if (!LLAvatarNameCache::get(getID(), &av_name)) + { + // ...call this function back when the name arrives + // and force a rebuild + LLAvatarNameCache::get(getID(), + boost::bind(&LLVOAvatar::clearNameTag, this)); + } + + // Might be blank if name not available yet, that's OK + if (show_display_names) + { + addNameTagLine(av_name.mDisplayName, name_tag_color, LLFontGL::NORMAL, + LLFontGL::getFontSansSerif()); + } + // Suppress SLID display if display name matches exactly (ugh) + if (show_usernames && !av_name.mIsDisplayNameDefault) + { + // *HACK: Desaturate the color + LLColor4 username_color = name_tag_color * 0.83f; + addNameTagLine(av_name.mUsername, username_color, LLFontGL::NORMAL, + LLFontGL::getFontSansSerifSmall()); + } + } + else + { + const LLFontGL* font = LLFontGL::getFontSansSerif(); + std::string full_name = + LLCacheName::buildFullName( firstname->getString(), lastname->getString() ); + addNameTagLine(full_name, name_tag_color, LLFontGL::NORMAL, font); + } + + mNameAway = is_away; + mNameBusy = is_busy; + mNameMute = is_muted; + mNameAppearance = is_appearance; + mNameFriend = is_friend; + mNameCloud = is_cloud; + mTitle = title ? title->getString() : ""; + LLStringFn::replace_ascii_controlchars(mTitle,LL_UNKNOWN_CHAR); + new_name = TRUE; + } + + if (mVisibleChat) + { + mNameText->setFont(LLFontGL::getFontSansSerif()); + mNameText->setTextAlignment(LLHUDNameTag::ALIGN_TEXT_LEFT); + mNameText->setFadeDistance(CHAT_NORMAL_RADIUS * 2.f, 5.f); + + char line[MAX_STRING]; /* Flawfinder: ignore */ + line[0] = '\0'; + std::deque::iterator chat_iter = mChats.begin(); + mNameText->clearString(); + + LLColor4 new_chat = LLUIColorTable::instance().getColor( isSelf() ? "UserChatColor" : "AgentChatColor" ); + LLColor4 normal_chat = lerp(new_chat, LLColor4(0.8f, 0.8f, 0.8f, 1.f), 0.7f); + LLColor4 old_chat = lerp(normal_chat, LLColor4(0.6f, 0.6f, 0.6f, 1.f), 0.7f); + if (mTyping && mChats.size() >= MAX_BUBBLE_CHAT_UTTERANCES) + { + ++chat_iter; + } + + for(; chat_iter != mChats.end(); ++chat_iter) + { + F32 chat_fade_amt = llclamp((F32)((LLFrameTimer::getElapsedSeconds() - chat_iter->mTime) / CHAT_FADE_TIME), 0.f, 4.f); + LLFontGL::StyleFlags style; + switch(chat_iter->mChatType) + { + case CHAT_TYPE_WHISPER: + style = LLFontGL::ITALIC; + break; + case CHAT_TYPE_SHOUT: + style = LLFontGL::BOLD; + break; + default: + style = LLFontGL::NORMAL; + break; + } + if (chat_fade_amt < 1.f) + { + F32 u = clamp_rescale(chat_fade_amt, 0.9f, 1.f, 0.f, 1.f); + mNameText->addLine(chat_iter->mText, lerp(new_chat, normal_chat, u), style); + } + else if (chat_fade_amt < 2.f) + { + F32 u = clamp_rescale(chat_fade_amt, 1.9f, 2.f, 0.f, 1.f); + mNameText->addLine(chat_iter->mText, lerp(normal_chat, old_chat, u), style); + } + else if (chat_fade_amt < 3.f) + { + // *NOTE: only remove lines down to minimum number + mNameText->addLine(chat_iter->mText, old_chat, style); + } + } + mNameText->setVisibleOffScreen(TRUE); + + if (mTyping) + { + S32 dot_count = (llfloor(mTypingTimer.getElapsedTimeF32() * 3.f) + 2) % 3 + 1; + switch(dot_count) + { + case 1: + mNameText->addLine(".", new_chat); + break; + case 2: + mNameText->addLine("..", new_chat); + break; + case 3: + mNameText->addLine("...", new_chat); + break; + } + + } + } + else + { + // ...not using chat bubbles, just names + mNameText->setTextAlignment(LLHUDNameTag::ALIGN_TEXT_CENTER); + mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f); + mNameText->setVisibleOffScreen(FALSE); + } +} + +void LLVOAvatar::addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font) +{ + llassert(mNameText); + if (mVisibleChat) + { + mNameText->addLabel(line); + } + else + { + mNameText->addLine(line, color, (LLFontGL::StyleFlags)style, font); + } + mNameString += line; + mNameString += '\n'; +} + +void LLVOAvatar::clearNameTag() +{ + mNameString.clear(); + if (mNameText) + { + mNameText->setLabel(""); + mNameText->setString( "" ); + } +} + +//static +void LLVOAvatar::invalidateNameTag(const LLUUID& agent_id) +{ + LLViewerObject* obj = gObjectList.findObject(agent_id); + if (!obj) return; + + LLVOAvatar* avatar = dynamic_cast(obj); + if (!avatar) return; + + avatar->clearNameTag(); +} + +//static +void LLVOAvatar::invalidateNameTags() +{ + std::vector::iterator it = LLCharacter::sInstances.begin(); + for ( ; it != LLCharacter::sInstances.end(); ++it) + { + LLVOAvatar* avatar = dynamic_cast(*it); + if (!avatar) continue; + if (avatar->isDead()) continue; + + avatar->clearNameTag(); + + } +} + +// Compute name tag position during idle update +LLVector3 LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last) +{ + LLQuaternion root_rot = mRoot.getWorldRotation(); + LLVector3 pixel_right_vec; + LLVector3 pixel_up_vec; + LLViewerCamera::getInstance()->getPixelVectors(root_pos_last, pixel_up_vec, pixel_right_vec); + LLVector3 camera_to_av = root_pos_last - LLViewerCamera::getInstance()->getOrigin(); + camera_to_av.normalize(); + LLVector3 local_camera_at = camera_to_av * ~root_rot; + LLVector3 local_camera_up = camera_to_av % LLViewerCamera::getInstance()->getLeftAxis(); + local_camera_up.normalize(); + local_camera_up = local_camera_up * ~root_rot; + + local_camera_up.scaleVec(mBodySize * 0.5f); + local_camera_at.scaleVec(mBodySize * 0.5f); + + LLVector3 name_position = mRoot.getWorldPosition(); + name_position[VZ] -= mPelvisToFoot; + name_position[VZ] += (mBodySize[VZ]* 0.55f); + name_position += (local_camera_up * root_rot) - (projected_vec(local_camera_at * root_rot, camera_to_av)); + name_position += pixel_up_vec * 15.f; + + return name_position; +} + +void LLVOAvatar::idleUpdateNameTagAlpha(BOOL new_name, F32 alpha) +{ + llassert(mNameText); + + if (new_name + || alpha != mNameAlpha) + { + mNameText->setAlpha(alpha); + mNameAlpha = alpha; + } +} + +LLColor4 LLVOAvatar::getNameTagColor(bool is_friend) +{ + static LLUICachedControl show_friends("NameTagShowFriends"); + const char* color_name; + if (show_friends && is_friend) + { + color_name = "NameTagFriend"; + } + else if (LLAvatarNameCache::useDisplayNames()) + { + // ...color based on whether username "matches" a computed display + // name + LLAvatarName av_name; + if (LLAvatarNameCache::get(getID(), &av_name) + && av_name.mIsDisplayNameDefault) + { + color_name = "NameTagMatch"; + } + else + { + color_name = "NameTagMismatch"; + } + } + else + { + // ...not using display names + color_name = "NameTagLegacy"; + } + return LLUIColorTable::getInstance()->getColor( color_name ); +} + +void LLVOAvatar::idleUpdateBelowWater() +{ + F32 avatar_height = (F32)(getPositionGlobal().mdV[VZ]); + + F32 water_height; + water_height = getRegion()->getWaterHeight(); + + mBelowWater = avatar_height < water_height; +} + +void LLVOAvatar::slamPosition() +{ + gAgent.setPositionAgent(getPositionAgent()); + mRoot.setWorldPosition(getPositionAgent()); // teleport + setChanged(TRANSLATED); + if (mDrawable.notNull()) + { + gPipeline.updateMoveNormalAsync(mDrawable); + } + mRoot.updateWorldMatrixChildren(); +} + +//------------------------------------------------------------------------ +// updateCharacter() +// called on both your avatar and other avatars +//------------------------------------------------------------------------ +BOOL LLVOAvatar::updateCharacter(LLAgent &agent) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + // clear debug text + mDebugText.clear(); + if (LLVOAvatar::sShowAnimationDebug) + { + for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin(); + iter != mMotionController.getActiveMotions().end(); ++iter) + { + LLMotion* motionp = *iter; + if (motionp->getMinPixelArea() < getPixelArea()) + { + std::string output; + if (motionp->getName().empty()) + { + output = llformat("%s - %d", + gAgent.isGodlikeWithoutAdminMenuFakery() ? + motionp->getID().asString().c_str() : + LLUUID::null.asString().c_str(), + (U32)motionp->getPriority()); + } + else + { + output = llformat("%s - %d", + motionp->getName().c_str(), + (U32)motionp->getPriority()); + } + addDebugText(output); + } + } + } + + if (gNoRender) + { + // Hack if we're running drones... + if (isSelf()) + { + gAgent.setPositionAgent(getPositionAgent()); + } + return FALSE; + } + + + LLVector3d root_pos_global; + + if (!mIsBuilt) + { + return FALSE; + } + + BOOL visible = isVisible(); + + // For fading out the names above heads, only let the timer + // run if we're visible. + if (mDrawable.notNull() && !visible) + { + mTimeVisible.reset(); + } + + + //-------------------------------------------------------------------- + // the rest should only be done occasionally for far away avatars + //-------------------------------------------------------------------- + + if (visible && !isSelf() && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter) + { + const LLVector4a* ext = mDrawable->getSpatialExtents(); + LLVector4a size; + size.setSub(ext[1],ext[0]); + F32 mag = size.getLength3().getF32()*0.5f; + + F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f); + if (LLMuteList::getInstance()->isMuted(getID())) + { // muted avatars update at 16 hz + mUpdatePeriod = 16; + } + else if (mVisibilityRank <= LLVOAvatar::sMaxVisible || + mDrawable->mDistanceWRTCamera < 1.f + mag) + { //first 25% of max visible avatars are not impostored + //also, don't impostor avatars whose bounding box may be penetrating the + //impostor camera near clip plane + mUpdatePeriod = 1; + } + else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 4) + { //background avatars are REALLY slow updating impostors + mUpdatePeriod = 16; + } + else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 3) + { //back 25% of max visible avatars are slow updating impostors + mUpdatePeriod = 8; + } + else if (mImpostorPixelArea <= impostor_area) + { // stuff in between gets an update period based on pixel area + mUpdatePeriod = llclamp((S32) sqrtf(impostor_area*4.f/mImpostorPixelArea), 2, 8); + } + else + { + //nearby avatars, update the impostors more frequently. + mUpdatePeriod = 4; + } + + visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE; + } + + // don't early out for your own avatar, as we rely on your animations playing reliably + // for example, the "turn around" animation when entering customize avatar needs to trigger + // even when your avatar is offscreen + if (!visible && !isSelf()) + { + updateMotions(LLCharacter::HIDDEN_UPDATE); + return FALSE; + } + + // change animation time quanta based on avatar render load + if (!isSelf() && !mIsDummy) + { + F32 time_quantum = clamp_rescale((F32)sInstances.size(), 10.f, 35.f, 0.f, 0.25f); + F32 pixel_area_scale = clamp_rescale(mPixelArea, 100, 5000, 1.f, 0.f); + F32 time_step = time_quantum * pixel_area_scale; + if (time_step != 0.f) + { + // disable walk motion servo controller as it doesn't work with motion timesteps + stopMotion(ANIM_AGENT_WALK_ADJUST); + removeAnimationData("Walk Speed"); + } + mMotionController.setTimeStep(time_step); +// llinfos << "Setting timestep to " << time_quantum * pixel_area_scale << llendl; + } + + if (getParent() && !mIsSitting) + { + sitOnObject((LLViewerObject*)getParent()); + } + else if (!getParent() && mIsSitting && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED)) + { + getOffObject(); + } + + //-------------------------------------------------------------------- + // create local variables in world coords for region position values + //-------------------------------------------------------------------- + F32 speed; + LLVector3 normal; + + LLVector3 xyVel = getVelocity(); + xyVel.mV[VZ] = 0.0f; + speed = xyVel.length(); + + BOOL throttle = TRUE; + + if (!(mIsSitting && getParent())) + { + //-------------------------------------------------------------------- + // get timing info + // handle initial condition case + //-------------------------------------------------------------------- + F32 animation_time = mAnimTimer.getElapsedTimeF32(); + if (mTimeLast == 0.0f) + { + mTimeLast = animation_time; + throttle = FALSE; + + // put the pelvis at slaved position/mRotation + mRoot.setWorldPosition( getPositionAgent() ); // first frame + mRoot.setWorldRotation( getRotation() ); + } + + //-------------------------------------------------------------------- + // dont' let dT get larger than 1/5th of a second + //-------------------------------------------------------------------- + F32 deltaTime = animation_time - mTimeLast; + + deltaTime = llclamp( deltaTime, DELTA_TIME_MIN, DELTA_TIME_MAX ); + mTimeLast = animation_time; + + mSpeedAccum = (mSpeedAccum * 0.95f) + (speed * 0.05f); + + //-------------------------------------------------------------------- + // compute the position of the avatar's root + //-------------------------------------------------------------------- + LLVector3d root_pos; + LLVector3d ground_under_pelvis; + + if (isSelf()) + { + if ( !mHasPelvisOffset ) + { + gAgent.setPositionAgent(getRenderPosition()); + } + else + { + gAgent.setPositionAgent( getRenderPosition() + mPelvisOffset ); + } + } + + root_pos = gAgent.getPosGlobalFromAgent(getRenderPosition()); + + resolveHeightGlobal(root_pos, ground_under_pelvis, normal); + F32 foot_to_ground = (F32) (root_pos.mdV[VZ] - mPelvisToFoot - ground_under_pelvis.mdV[VZ]); + BOOL in_air = ((!LLWorld::getInstance()->getRegionFromPosGlobal(ground_under_pelvis)) || + foot_to_ground > FOOT_GROUND_COLLISION_TOLERANCE); + + if (in_air && !mInAir) + { + mTimeInAir.reset(); + } + mInAir = in_air; + + // correct for the fact that the pelvis is not necessarily the center + // of the agent's physical representation + root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot; + + LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos); + + if (newPosition != mRoot.getXform()->getWorldPosition()) + { + if ( !mHasPelvisOffset ) + { + mRoot.touch(); + mRoot.setWorldPosition( newPosition ); // regular update + } + else + { + mRoot.touch(); + mRoot.setWorldPosition( newPosition + mPelvisOffset ); + } + } + + + //-------------------------------------------------------------------- + // Propagate viewer object rotation to root of avatar + //-------------------------------------------------------------------- + if (!isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS)) + { + LLQuaternion iQ; + LLVector3 upDir( 0.0f, 0.0f, 1.0f ); + + // Compute a forward direction vector derived from the primitive rotation + // and the velocity vector. When walking or jumping, don't let body deviate + // more than 90 from the view, if necessary, flip the velocity vector. + + LLVector3 primDir; + if (isSelf()) + { + primDir = agent.getAtAxis() - projected_vec(agent.getAtAxis(), agent.getReferenceUpVector()); + primDir.normalize(); + } + else + { + primDir = getRotation().getMatrix3().getFwdRow(); + } + LLVector3 velDir = getVelocity(); + velDir.normalize(); + if ( mSignaledAnimations.find(ANIM_AGENT_WALK) != mSignaledAnimations.end()) + { + F32 vpD = velDir * primDir; + if (vpD < -0.5f) + { + velDir *= -1.0f; + } + } + LLVector3 fwdDir = lerp(primDir, velDir, clamp_rescale(speed, 0.5f, 2.0f, 0.0f, 1.0f)); + if (isSelf() && gAgentCamera.cameraMouselook()) + { + // make sure fwdDir stays in same general direction as primdir + if (gAgent.getFlying()) + { + fwdDir = LLViewerCamera::getInstance()->getAtAxis(); + } + else + { + LLVector3 at_axis = LLViewerCamera::getInstance()->getAtAxis(); + LLVector3 up_vector = gAgent.getReferenceUpVector(); + at_axis -= up_vector * (at_axis * up_vector); + at_axis.normalize(); + + F32 dot = fwdDir * at_axis; + if (dot < 0.f) + { + fwdDir -= 2.f * at_axis * dot; + fwdDir.normalize(); + } + } + + } + + LLQuaternion root_rotation = mRoot.getWorldMatrix().quaternion(); + F32 root_roll, root_pitch, root_yaw; + root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw); + + // When moving very slow, the pelvis is allowed to deviate from the + // forward direction to allow it to hold it's position while the torso + // and head turn. Once in motion, it must conform however. + BOOL self_in_mouselook = isSelf() && gAgentCamera.cameraMouselook(); + + LLVector3 pelvisDir( mRoot.getWorldMatrix().getFwdRow4().mV ); + F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, PELVIS_ROT_THRESHOLD_SLOW, PELVIS_ROT_THRESHOLD_FAST); + + if (self_in_mouselook) + { + pelvis_rot_threshold *= MOUSELOOK_PELVIS_FOLLOW_FACTOR; + } + pelvis_rot_threshold *= DEG_TO_RAD; + + F32 angle = angle_between( pelvisDir, fwdDir ); + + // The avatar's root is allowed to have a yaw that deviates widely + // from the forward direction, but if roll or pitch are off even + // a little bit we need to correct the rotation. + if(root_roll < 1.f * DEG_TO_RAD + && root_pitch < 5.f * DEG_TO_RAD) + { + // smaller correction vector means pelvis follows prim direction more closely + if (!mTurning && angle > pelvis_rot_threshold*0.75f) + { + mTurning = TRUE; + } + + // use tighter threshold when turning + if (mTurning) + { + pelvis_rot_threshold *= 0.4f; + } + + // am I done turning? + if (angle < pelvis_rot_threshold) + { + mTurning = FALSE; + } + + LLVector3 correction_vector = (pelvisDir - fwdDir) * clamp_rescale(angle, pelvis_rot_threshold*0.75f, pelvis_rot_threshold, 1.0f, 0.0f); + fwdDir += correction_vector; + } + else + { + mTurning = FALSE; + } + + // Now compute the full world space rotation for the whole body (wQv) + LLVector3 leftDir = upDir % fwdDir; + leftDir.normalize(); + fwdDir = leftDir % upDir; + LLQuaternion wQv( fwdDir, leftDir, upDir ); + + if (isSelf() && mTurning) + { + if ((fwdDir % pelvisDir) * upDir > 0.f) + { + gAgent.setControlFlags(AGENT_CONTROL_TURN_RIGHT); + } + else + { + gAgent.setControlFlags(AGENT_CONTROL_TURN_LEFT); + } + } + + // Set the root rotation, but do so incrementally so that it + // lags in time by some fixed amount. + //F32 u = LLCriticalDamp::getInterpolant(PELVIS_LAG); + F32 pelvis_lag_time = 0.f; + if (self_in_mouselook) + { + pelvis_lag_time = PELVIS_LAG_MOUSELOOK; + } + else if (mInAir) + { + pelvis_lag_time = PELVIS_LAG_FLYING; + // increase pelvis lag time when moving slowly + pelvis_lag_time *= clamp_rescale(mSpeedAccum, 0.f, 15.f, 3.f, 1.f); + } + else + { + pelvis_lag_time = PELVIS_LAG_WALKING; + } + + F32 u = llclamp((deltaTime / pelvis_lag_time), 0.0f, 1.0f); + + mRoot.setWorldRotation( slerp(u, mRoot.getWorldRotation(), wQv) ); + + } + } + else if (mDrawable.notNull()) + { + mRoot.setPosition(mDrawable->getPosition()); + mRoot.setRotation(mDrawable->getRotation()); + } + + //------------------------------------------------------------------------- + // Update character motions + //------------------------------------------------------------------------- + // store data relevant to motions + mSpeed = speed; + + // update animations + if (mSpecialRenderMode == 1) // Animation Preview + updateMotions(LLCharacter::FORCE_UPDATE); + else + updateMotions(LLCharacter::NORMAL_UPDATE); + + // update head position + updateHeadOffset(); + + //------------------------------------------------------------------------- + // Find the ground under each foot, these are used for a variety + // of things that follow + //------------------------------------------------------------------------- + LLVector3 ankle_left_pos_agent = mFootLeftp->getWorldPosition(); + LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition(); + + LLVector3 ankle_left_ground_agent = ankle_left_pos_agent; + LLVector3 ankle_right_ground_agent = ankle_right_pos_agent; + resolveHeightAgent(ankle_left_pos_agent, ankle_left_ground_agent, normal); + resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal); + + F32 leftElev = llmax(-0.2f, ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]); + F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]); + + if (!mIsSitting) + { + //------------------------------------------------------------------------- + // Figure out which foot is on ground + //------------------------------------------------------------------------- + if (!mInAir) + { + if ((leftElev < 0.0f) || (rightElev < 0.0f)) + { + ankle_left_pos_agent = mFootLeftp->getWorldPosition(); + ankle_right_pos_agent = mFootRightp->getWorldPosition(); + leftElev = ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]; + rightElev = ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]; + } + } + } + + //------------------------------------------------------------------------- + // Generate footstep sounds when feet hit the ground + //------------------------------------------------------------------------- + const LLUUID AGENT_FOOTSTEP_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_LAND}; + const S32 NUM_AGENT_FOOTSTEP_ANIMS = LL_ARRAY_SIZE(AGENT_FOOTSTEP_ANIMS); + + if ( gAudiop && isAnyAnimationSignaled(AGENT_FOOTSTEP_ANIMS, NUM_AGENT_FOOTSTEP_ANIMS) ) + { + BOOL playSound = FALSE; + LLVector3 foot_pos_agent; + + BOOL onGroundLeft = (leftElev <= 0.05f); + BOOL onGroundRight = (rightElev <= 0.05f); + + // did left foot hit the ground? + if ( onGroundLeft && !mWasOnGroundLeft ) + { + foot_pos_agent = ankle_left_pos_agent; + playSound = TRUE; + } + + // did right foot hit the ground? + if ( onGroundRight && !mWasOnGroundRight ) + { + foot_pos_agent = ankle_right_pos_agent; + playSound = TRUE; + } + + mWasOnGroundLeft = onGroundLeft; + mWasOnGroundRight = onGroundRight; + + if ( playSound ) + { +// F32 gain = clamp_rescale( mSpeedAccum, +// AUDIO_STEP_LO_SPEED, AUDIO_STEP_HI_SPEED, +// AUDIO_STEP_LO_GAIN, AUDIO_STEP_HI_GAIN ); + + const F32 STEP_VOLUME = 0.1f; + const LLUUID& step_sound_id = getStepSound(); + + LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent); + + if (LLViewerParcelMgr::getInstance()->canHearSound(foot_pos_global) + && !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds)) + { + gAudiop->triggerSound(step_sound_id, getID(), STEP_VOLUME, LLAudioEngine::AUDIO_TYPE_AMBIENT, foot_pos_global); + } + } + } + + mRoot.updateWorldMatrixChildren(); + + if (!mDebugText.size() && mText.notNull()) + { + mText->markDead(); + mText = NULL; + } + else if (mDebugText.size()) + { + setDebugText(mDebugText); + } + + //mesh vertices need to be reskinned + mNeedsSkin = TRUE; + + return TRUE; +} + +//----------------------------------------------------------------------------- +// updateHeadOffset() +//----------------------------------------------------------------------------- +void LLVOAvatar::updateHeadOffset() +{ + // since we only care about Z, just grab one of the eyes + LLVector3 midEyePt = mEyeLeftp->getWorldPosition(); + midEyePt -= mDrawable.notNull() ? mDrawable->getWorldPosition() : mRoot.getWorldPosition(); + midEyePt.mV[VZ] = llmax(-mPelvisToFoot + LLViewerCamera::getInstance()->getNear(), midEyePt.mV[VZ]); + + if (mDrawable.notNull()) + { + midEyePt = midEyePt * ~mDrawable->getWorldRotation(); + } + if (mIsSitting) + { + mHeadOffset = midEyePt; + } + else + { + F32 u = llmax(0.f, HEAD_MOVEMENT_AVG_TIME - (1.f / gFPSClamped)); + mHeadOffset = lerp(midEyePt, mHeadOffset, u); + } +} +//------------------------------------------------------------------------ +// setPelvisOffset +//------------------------------------------------------------------------ +void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount ) +{ + mHasPelvisOffset = hasOffset; + if ( mHasPelvisOffset ) + { + mPelvisOffset = offsetAmount; + } +} +//------------------------------------------------------------------------ +// postPelvisSetRecalc +//------------------------------------------------------------------------ +void LLVOAvatar::postPelvisSetRecalc( void ) +{ + computeBodySize(); + mRoot.updateWorldMatrixChildren(); + dirtyMesh(); + updateHeadOffset(); +} +//------------------------------------------------------------------------ +// updateVisibility() +//------------------------------------------------------------------------ +void LLVOAvatar::updateVisibility() +{ + BOOL visible = FALSE; + + if (mIsDummy) + { + visible = TRUE; + } + else if (mDrawable.isNull()) + { + visible = FALSE; + } + else + { + if (!mDrawable->getSpatialGroup() || mDrawable->getSpatialGroup()->isVisible()) + { + visible = TRUE; + } + else + { + visible = FALSE; + } + + if(isSelf()) + { + if (!gAgentWearables.areWearablesLoaded()) + { + visible = FALSE; + } + } + else if( !mFirstAppearanceMessageReceived ) + { + visible = FALSE; + } + + if (sDebugInvisible) + { + LLNameValue* firstname = getNVPair("FirstName"); + if (firstname) + { + llinfos << "Avatar " << firstname->getString() << " updating visiblity" << llendl; + } + else + { + llinfos << "Avatar " << this << " updating visiblity" << llendl; + } + + if (visible) + { + llinfos << "Visible" << llendl; + } + else + { + llinfos << "Not visible" << llendl; + } + + /*if (avatar_in_frustum) + { + llinfos << "Avatar in frustum" << llendl; + } + else + { + llinfos << "Avatar not in frustum" << llendl; + }*/ + + /*if (LLViewerCamera::getInstance()->sphereInFrustum(sel_pos_agent, 2.0f)) + { + llinfos << "Sel pos visible" << llendl; + } + if (LLViewerCamera::getInstance()->sphereInFrustum(wrist_right_pos_agent, 0.2f)) + { + llinfos << "Wrist pos visible" << llendl; + } + if (LLViewerCamera::getInstance()->sphereInFrustum(getPositionAgent(), getMaxScale()*2.f)) + { + llinfos << "Agent visible" << llendl; + }*/ + llinfos << "PA: " << getPositionAgent() << llendl; + /*llinfos << "SPA: " << sel_pos_agent << llendl; + llinfos << "WPA: " << wrist_right_pos_agent << llendl;*/ + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + if (LLViewerObject *attached_object = (*attachment_iter)) + { + if(attached_object->mDrawable->isVisible()) + { + llinfos << attachment->getName() << " visible" << llendl; + } + else + { + llinfos << attachment->getName() << " not visible at " << mDrawable->getWorldPosition() << " and radius " << mDrawable->getRadius() << llendl; + } + } + } + } + } + } + + if (!visible && mVisible) + { + mMeshInvisibleTime.reset(); + } + + if (visible) + { + if (!mMeshValid) + { + restoreMeshData(); + } + } + else + { + if (mMeshValid && mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP) + { + releaseMeshData(); + } + // this breaks off-screen chat bubbles + //if (mNameText) + //{ + // mNameText->markDead(); + // mNameText = NULL; + // sNumVisibleChatBubbles--; + //} + } + + mVisible = visible; +} + +// private +bool LLVOAvatar::shouldAlphaMask() +{ + const bool should_alpha_mask = mSupportsAlphaLayers && !LLDrawPoolAlpha::sShowDebugAlpha // Don't alpha mask if "Highlight Transparent" checked + && !LLDrawPoolAvatar::sSkipTransparent; + + return should_alpha_mask; + +} + +U32 LLVOAvatar::renderSkinnedAttachments() +{ + /*U32 num_indices = 0; + + const U32 data_mask = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_WEIGHT4; + + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object && !attached_object->isHUDAttachment()) + { + const LLDrawable* drawable = attached_object->mDrawable; + if (drawable) + { + for (S32 i = 0; i < drawable->getNumFaces(); ++i) + { + LLFace* face = drawable->getFace(i); + if (face->isState(LLFace::RIGGED)) + { + + } + } + } + } + + return num_indices;*/ + return 0; +} + +//----------------------------------------------------------------------------- +// renderSkinned() +//----------------------------------------------------------------------------- +U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) +{ + U32 num_indices = 0; + + if (!mIsBuilt) + { + return num_indices; + } + + LLFace* face = mDrawable->getFace(0); + + bool needs_rebuild = !face || face->mVertexBuffer.isNull() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY); + + if (needs_rebuild || mDirtyMesh) + { //LOD changed or new mesh created, allocate new vertex buffer if needed + if (needs_rebuild || mDirtyMesh >= 2 || mVisibilityRank <= 4) + { + updateMeshData(); + mDirtyMesh = 0; + mNeedsSkin = TRUE; + mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY); + } + } + + if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) <= 0) + { + if (mNeedsSkin) + { + //generate animated mesh + mMeshLOD[MESH_ID_LOWER_BODY]->updateJointGeometry(); + mMeshLOD[MESH_ID_UPPER_BODY]->updateJointGeometry(); + + if( isWearingWearableType( LLWearableType::WT_SKIRT ) ) + { + mMeshLOD[MESH_ID_SKIRT]->updateJointGeometry(); + } + + if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) + { + mMeshLOD[MESH_ID_EYELASH]->updateJointGeometry(); + mMeshLOD[MESH_ID_HEAD]->updateJointGeometry(); + mMeshLOD[MESH_ID_HAIR]->updateJointGeometry(); + } + mNeedsSkin = FALSE; + mLastSkinTime = gFrameTimeSeconds; + + LLVertexBuffer* vb = mDrawable->getFace(0)->mVertexBuffer; + if (vb) + { + vb->setBuffer(0); + } + } + } + else + { + mNeedsSkin = FALSE; + } + + if (sDebugInvisible) + { + LLNameValue* firstname = getNVPair("FirstName"); + if (firstname) + { + llinfos << "Avatar " << firstname->getString() << " in render" << llendl; + } + else + { + llinfos << "Avatar " << this << " in render" << llendl; + } + if (!mIsBuilt) + { + llinfos << "Not built!" << llendl; + } + else if (!gAgent.needsRenderAvatar()) + { + llinfos << "Doesn't need avatar render!" << llendl; + } + else + { + llinfos << "Rendering!" << llendl; + } + } + + if (!mIsBuilt) + { + return num_indices; + } + + if (isSelf() && !gAgent.needsRenderAvatar()) + { + return num_indices; + } + + // render collision normal + // *NOTE: this is disabled (there is no UI for enabling sShowFootPlane) due + // to DEV-14477. the code is left here to aid in tracking down the cause + // of the crash in the future. -brad + if (sShowFootPlane && mDrawable.notNull()) + { + LLVector3 slaved_pos = mDrawable->getPositionAgent(); + LLVector3 foot_plane_normal(mFootPlane.mV[VX], mFootPlane.mV[VY], mFootPlane.mV[VZ]); + F32 dist_from_plane = (slaved_pos * foot_plane_normal) - mFootPlane.mV[VW]; + LLVector3 collide_point = slaved_pos; + collide_point.mV[VZ] -= foot_plane_normal.mV[VZ] * (dist_from_plane + COLLISION_TOLERANCE - FOOT_COLLIDE_FUDGE); + + gGL.begin(LLRender::LINES); + { + F32 SQUARE_SIZE = 0.2f; + gGL.color4f(1.f, 0.f, 0.f, 1.f); + + gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]); + gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]); + + gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]); + gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]); + + gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]); + gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]); + + gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]); + gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]); + + gGL.vertex3f(collide_point.mV[VX], collide_point.mV[VY], collide_point.mV[VZ]); + gGL.vertex3f(collide_point.mV[VX] + mFootPlane.mV[VX], collide_point.mV[VY] + mFootPlane.mV[VY], collide_point.mV[VZ] + mFootPlane.mV[VZ]); + + } + gGL.end(); + gGL.flush(); + } + //-------------------------------------------------------------------- + // render all geometry attached to the skeleton + //-------------------------------------------------------------------- + static LLStat render_stat; + + LLViewerJointMesh::sRenderPass = pass; + + if (pass == AVATAR_RENDER_PASS_SINGLE) + { + + bool should_alpha_mask = shouldAlphaMask(); + LLGLState test(GL_ALPHA_TEST, should_alpha_mask); + + if (should_alpha_mask) + { + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); + } + + BOOL first_pass = TRUE; + if (!LLDrawPoolAvatar::sSkipOpaque) + { + if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) + { + if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy) + { + num_indices += mMeshLOD[MESH_ID_HEAD]->render(mAdjustedPixelArea, TRUE, mIsDummy); + first_pass = FALSE; + } + } + if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy) + { + num_indices += mMeshLOD[MESH_ID_UPPER_BODY]->render(mAdjustedPixelArea, first_pass, mIsDummy); + first_pass = FALSE; + } + + if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy) + { + num_indices += mMeshLOD[MESH_ID_LOWER_BODY]->render(mAdjustedPixelArea, first_pass, mIsDummy); + first_pass = FALSE; + } + } + + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + + if (!LLDrawPoolAvatar::sSkipTransparent || LLPipeline::sImpostorRender) + { + LLGLState blend(GL_BLEND, !mIsDummy); + LLGLState test(GL_ALPHA_TEST, !mIsDummy); + num_indices += renderTransparent(first_pass); + } + } + + LLViewerJointMesh::sRenderPass = AVATAR_RENDER_PASS_SINGLE; + + //llinfos << "Avatar render: " << render_timer.getElapsedTimeF32() << llendl; + + //render_stat.addValue(render_timer.getElapsedTimeF32()*1000.f); + + return num_indices; +} + +U32 LLVOAvatar::renderTransparent(BOOL first_pass) +{ + U32 num_indices = 0; + if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (mIsDummy || isTextureVisible(TEX_SKIRT_BAKED)) ) + { + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f); + num_indices += mMeshLOD[MESH_ID_SKIRT]->render(mAdjustedPixelArea, FALSE); + first_pass = FALSE; + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + } + + if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) + { + if (LLPipeline::sImpostorRender) + { + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); + } + + if (isTextureVisible(TEX_HEAD_BAKED)) + { + num_indices += mMeshLOD[MESH_ID_EYELASH]->render(mAdjustedPixelArea, first_pass, mIsDummy); + first_pass = FALSE; + } + // Can't test for baked hair being defined, since that won't always be the case (not all viewers send baked hair) + // TODO: 1.25 will be able to switch this logic back to calling isTextureVisible(); + if (getImage(TEX_HAIR_BAKED, 0)->getID() != IMG_INVISIBLE || LLDrawPoolAlpha::sShowDebugAlpha) + { + num_indices += mMeshLOD[MESH_ID_HAIR]->render(mAdjustedPixelArea, first_pass, mIsDummy); + first_pass = FALSE; + } + if (LLPipeline::sImpostorRender) + { + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + } + } + + return num_indices; +} + +//----------------------------------------------------------------------------- +// renderRigid() +//----------------------------------------------------------------------------- +U32 LLVOAvatar::renderRigid() +{ + U32 num_indices = 0; + + if (!mIsBuilt) + { + return 0; + } + + if (isSelf() && (!gAgent.needsRenderAvatar() || !gAgent.needsRenderHead())) + { + return 0; + } + + if (!mIsBuilt) + { + return 0; + } + + bool should_alpha_mask = shouldAlphaMask(); + LLGLState test(GL_ALPHA_TEST, should_alpha_mask); + + if (should_alpha_mask) + { + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); + } + + if (isTextureVisible(TEX_EYES_BAKED) || mIsDummy) + { + num_indices += mMeshLOD[MESH_ID_EYEBALL_LEFT]->render(mAdjustedPixelArea, TRUE, mIsDummy); + num_indices += mMeshLOD[MESH_ID_EYEBALL_RIGHT]->render(mAdjustedPixelArea, TRUE, mIsDummy); + } + + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + + return num_indices; +} + +U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel) +{ + if (!mImpostor.isComplete()) + { + return 0; + } + + LLVector3 pos(getRenderPosition()+mImpostorOffset); + LLVector3 at = (pos - LLViewerCamera::getInstance()->getOrigin()); + at.normalize(); + LLVector3 left = LLViewerCamera::getInstance()->getUpAxis() % at; + LLVector3 up = at%left; + + left *= mImpostorDim.mV[0]; + up *= mImpostorDim.mV[1]; + + LLGLEnable test(GL_ALPHA_TEST); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f); + + gGL.color4ubv(color.mV); + gGL.getTexUnit(diffuse_channel)->bind(&mImpostor); + gGL.begin(LLRender::QUADS); + gGL.texCoord2f(0,0); + gGL.vertex3fv((pos+left-up).mV); + gGL.texCoord2f(1,0); + gGL.vertex3fv((pos-left-up).mV); + gGL.texCoord2f(1,1); + gGL.vertex3fv((pos-left+up).mV); + gGL.texCoord2f(0,1); + gGL.vertex3fv((pos+left+up).mV); + gGL.end(); + gGL.flush(); + + return 6; +} + +//------------------------------------------------------------------------ +// LLVOAvatar::updateTextures() +//------------------------------------------------------------------------ +void LLVOAvatar::updateTextures() +{ + BOOL render_avatar = TRUE; + + if (mIsDummy || gNoRender) + { + return; + } + + if( isSelf() ) + { + render_avatar = TRUE; + } + else + { + if(!isVisible()) + { + return ;//do not update for invisible avatar. + } + + render_avatar = !mCulled; //visible and not culled. + } + + std::vector layer_baked; + // GL NOT ACTIVE HERE - *TODO + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + layer_baked.push_back(isTextureDefined(mBakedTextureDatas[i].mTextureIndex)); + // bind the texture so that they'll be decoded slightly + // inefficient, we can short-circuit this if we have to + if (render_avatar && !gGLManager.mIsDisabled) + { + if (layer_baked[i] && !mBakedTextureDatas[i].mIsLoaded) + { + gGL.getTexUnit(0)->bind(getImage( mBakedTextureDatas[i].mTextureIndex, 0 )); + } + } + } + + mMaxPixelArea = 0.f; + mMinPixelArea = 99999999.f; + mHasGrey = FALSE; // debug + for (U32 texture_index = 0; texture_index < getNumTEs(); texture_index++) + { + LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType((ETextureIndex)texture_index); + U32 num_wearables = gAgentWearables.getWearableCount(wearable_type); + const LLTextureEntry *te = getTE(texture_index); + const F32 texel_area_ratio = fabs(te->mScaleS * te->mScaleT); + LLViewerFetchedTexture *imagep = NULL; + for (U32 wearable_index = 0; wearable_index < num_wearables; wearable_index++) + { + imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index, wearable_index), TRUE); + if (imagep) + { + const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture((ETextureIndex)texture_index); + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + if (texture_dict->mIsLocalTexture) + { + addLocalTextureStats((ETextureIndex)texture_index, imagep, texel_area_ratio, render_avatar, layer_baked[baked_index]); + } + } + } + if (isIndexBakedTexture((ETextureIndex) texture_index) && render_avatar) + { + const S32 boost_level = getAvatarBakedBoostLevel(); + imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE); + // Spam if this is a baked texture, not set to default image, without valid host info + if (isIndexBakedTexture((ETextureIndex)texture_index) + && imagep->getID() != IMG_DEFAULT_AVATAR + && imagep->getID() != IMG_INVISIBLE + && !imagep->getTargetHost().isOk()) + { + LL_WARNS_ONCE("Texture") << "LLVOAvatar::updateTextures No host for texture " + << imagep->getID() << " for avatar " + << (isSelf() ? "" : getID().asString()) + << " on host " << getRegion()->getHost() << llendl; + } + + addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); + } + } + + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) + { + setDebugText(llformat("%4.0f:%4.0f", (F32) sqrt(mMinPixelArea),(F32) sqrt(mMaxPixelArea))); + } +} + + +void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture* imagep, + F32 texel_area_ratio, BOOL render_avatar, BOOL covered_by_baked, U32 index ) +{ + // No local texture stats for non-self avatars + return; +} + +const S32 MAX_TEXTURE_UPDATE_INTERVAL = 64 ; //need to call updateTextures() at least every 32 frames. +const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = S32_MAX ; //frames +void LLVOAvatar::checkTextureLoading() +{ + static const F32 MAX_INVISIBLE_WAITING_TIME = 15.f ; //seconds + + BOOL pause = !isVisible() ; + if(!pause) + { + mInvisibleTimer.reset() ; + } + if(mLoadedCallbacksPaused == pause) + { + return ; + } + + if(mCallbackTextureList.empty()) //when is self or no callbacks. Note: this list for self is always empty. + { + mLoadedCallbacksPaused = pause ; + return ; //nothing to check. + } + + if(pause && mInvisibleTimer.getElapsedTimeF32() < MAX_INVISIBLE_WAITING_TIME) + { + return ; //have not been invisible for enough time. + } + + for(LLLoadedCallbackEntry::source_callback_list_t::iterator iter = mCallbackTextureList.begin(); + iter != mCallbackTextureList.end(); ++iter) + { + LLViewerFetchedTexture* tex = gTextureList.findImage(*iter) ; + if(tex) + { + if(pause)//pause texture fetching. + { + tex->pauseLoadedCallbacks(&mCallbackTextureList) ; + + //set to terminate texture fetching after MAX_TEXTURE_UPDATE_INTERVAL frames. + tex->setMaxVirtualSizeResetInterval(MAX_TEXTURE_UPDATE_INTERVAL); + tex->resetMaxVirtualSizeResetCounter() ; + } + else//unpause + { + static const F32 START_AREA = 100.f ; + + tex->unpauseLoadedCallbacks(&mCallbackTextureList) ; + tex->addTextureStats(START_AREA); //jump start the fetching again + } + } + } + + if(!pause) + { + updateTextures() ; //refresh texture stats. + } + mLoadedCallbacksPaused = pause ; + return ; +} + +const F32 SELF_ADDITIONAL_PRI = 0.75f ; +const F32 ADDITIONAL_PRI = 0.5f; +void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level) +{ + //Note: + //if this function is not called for the last MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL frames, + //the texture pipeline will stop fetching this texture. + + imagep->resetTextureStats(); + imagep->setCanUseHTTP(false) ; //turn off http fetching for baked textures. + imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); + imagep->resetMaxVirtualSizeResetCounter() ; + + mMaxPixelArea = llmax(pixel_area, mMaxPixelArea); + mMinPixelArea = llmin(pixel_area, mMinPixelArea); + imagep->addTextureStats(pixel_area / texel_area_ratio); + imagep->setBoostLevel(boost_level); + + if(boost_level != LLViewerTexture::BOOST_AVATAR_BAKED_SELF) + { + imagep->setAdditionalDecodePriority(ADDITIONAL_PRI) ; + } + else + { + imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ; + } +} + +//virtual +void LLVOAvatar::setImage(const U8 te, LLViewerTexture *imagep, const U32 index) +{ + setTEImage(te, imagep); +} + +//virtual +LLViewerTexture* LLVOAvatar::getImage(const U8 te, const U32 index) const +{ + return getTEImage(te); +} +//virtual +const LLTextureEntry* LLVOAvatar::getTexEntry(const U8 te_num) const +{ + return getTE(te_num); +} + +//virtual +void LLVOAvatar::setTexEntry(const U8 index, const LLTextureEntry &te) +{ + setTE(index, te); +} + +//----------------------------------------------------------------------------- +// resolveHeight() +//----------------------------------------------------------------------------- + +void LLVOAvatar::resolveHeightAgent(const LLVector3 &in_pos_agent, LLVector3 &out_pos_agent, LLVector3 &out_norm) +{ + LLVector3d in_pos_global, out_pos_global; + + in_pos_global = gAgent.getPosGlobalFromAgent(in_pos_agent); + resolveHeightGlobal(in_pos_global, out_pos_global, out_norm); + out_pos_agent = gAgent.getPosAgentFromGlobal(out_pos_global); +} + + +void LLVOAvatar::resolveRayCollisionAgent(const LLVector3d start_pt, const LLVector3d end_pt, LLVector3d &out_pos, LLVector3 &out_norm) +{ + LLViewerObject *obj; + LLWorld::getInstance()->resolveStepHeightGlobal(this, start_pt, end_pt, out_pos, out_norm, &obj); +} + + +void LLVOAvatar::resolveHeightGlobal(const LLVector3d &inPos, LLVector3d &outPos, LLVector3 &outNorm) +{ + LLVector3d zVec(0.0f, 0.0f, 0.5f); + LLVector3d p0 = inPos + zVec; + LLVector3d p1 = inPos - zVec; + LLViewerObject *obj; + LLWorld::getInstance()->resolveStepHeightGlobal(this, p0, p1, outPos, outNorm, &obj); + if (!obj) + { + mStepOnLand = TRUE; + mStepMaterial = 0; + mStepObjectVelocity.setVec(0.0f, 0.0f, 0.0f); + } + else + { + mStepOnLand = FALSE; + mStepMaterial = obj->getMaterial(); + + // We want the primitive velocity, not our velocity... (which actually subtracts the + // step object velocity) + LLVector3 angularVelocity = obj->getAngularVelocity(); + LLVector3 relativePos = gAgent.getPosAgentFromGlobal(outPos) - obj->getPositionAgent(); + + LLVector3 linearComponent = angularVelocity % relativePos; +// llinfos << "Linear Component of Rotation Velocity " << linearComponent << llendl; + mStepObjectVelocity = obj->getVelocity() + linearComponent; + } +} + + +//----------------------------------------------------------------------------- +// getStepSound() +//----------------------------------------------------------------------------- +const LLUUID& LLVOAvatar::getStepSound() const +{ + if ( mStepOnLand ) + { + return sStepSoundOnLand; + } + + return sStepSounds[mStepMaterial]; +} + + +//----------------------------------------------------------------------------- +// processAnimationStateChanges() +//----------------------------------------------------------------------------- +void LLVOAvatar::processAnimationStateChanges() +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + if (gNoRender) + { + return; + } + + if ( isAnyAnimationSignaled(AGENT_WALK_ANIMS, NUM_AGENT_WALK_ANIMS) ) + { + startMotion(ANIM_AGENT_WALK_ADJUST); + stopMotion(ANIM_AGENT_FLY_ADJUST); + } + else if (mInAir && !mIsSitting) + { + stopMotion(ANIM_AGENT_WALK_ADJUST); + startMotion(ANIM_AGENT_FLY_ADJUST); + } + else + { + stopMotion(ANIM_AGENT_WALK_ADJUST); + stopMotion(ANIM_AGENT_FLY_ADJUST); + } + + if ( isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) ) + { + startMotion(ANIM_AGENT_TARGET); + stopMotion(ANIM_AGENT_BODY_NOISE); + } + else + { + stopMotion(ANIM_AGENT_TARGET); + startMotion(ANIM_AGENT_BODY_NOISE); + } + + // clear all current animations + AnimIterator anim_it; + for (anim_it = mPlayingAnimations.begin(); anim_it != mPlayingAnimations.end();) + { + AnimIterator found_anim = mSignaledAnimations.find(anim_it->first); + + // playing, but not signaled, so stop + if (found_anim == mSignaledAnimations.end()) + { + processSingleAnimationStateChange(anim_it->first, FALSE); + mPlayingAnimations.erase(anim_it++); + continue; + } + + ++anim_it; + } + + // start up all new anims + for (anim_it = mSignaledAnimations.begin(); anim_it != mSignaledAnimations.end();) + { + AnimIterator found_anim = mPlayingAnimations.find(anim_it->first); + + // signaled but not playing, or different sequence id, start motion + if (found_anim == mPlayingAnimations.end() || found_anim->second != anim_it->second) + { + if (processSingleAnimationStateChange(anim_it->first, TRUE)) + { + mPlayingAnimations[anim_it->first] = anim_it->second; + ++anim_it; + continue; + } + } + + ++anim_it; + } + + // clear source information for animations which have been stopped + if (isSelf()) + { + AnimSourceIterator source_it = mAnimationSources.begin(); + + for (source_it = mAnimationSources.begin(); source_it != mAnimationSources.end();) + { + if (mSignaledAnimations.find(source_it->second) == mSignaledAnimations.end()) + { + mAnimationSources.erase(source_it++); + } + else + { + ++source_it; + } + } + } + + stop_glerror(); +} + + +//----------------------------------------------------------------------------- +// processSingleAnimationStateChange(); +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL start ) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + BOOL result = FALSE; + + if ( start ) // start animation + { + if (anim_id == ANIM_AGENT_TYPE) + { + if (gAudiop) + { + LLVector3d char_pos_global = gAgent.getPosGlobalFromAgent(getCharacterPosition()); + if (LLViewerParcelMgr::getInstance()->canHearSound(char_pos_global) + && !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds)) + { + // RN: uncomment this to play on typing sound at fixed volume once sound engine is fixed + // to support both spatialized and non-spatialized instances of the same sound + //if (isSelf()) + //{ + // gAudiop->triggerSound(LLUUID(gSavedSettings.getString("UISndTyping")), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); + //} + //else + { + LLUUID sound_id = LLUUID(gSavedSettings.getString("UISndTyping")); + gAudiop->triggerSound(sound_id, getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_SFX, char_pos_global); + } + } + } + } + else if (anim_id == ANIM_AGENT_SIT_GROUND_CONSTRAINED) + { + sitDown(TRUE); + } + + + if (startMotion(anim_id)) + { + result = TRUE; + } + else + { + llwarns << "Failed to start motion!" << llendl; + } + } + else //stop animation + { + if (anim_id == ANIM_AGENT_SIT_GROUND_CONSTRAINED) + { + sitDown(FALSE); + } + stopMotion(anim_id); + result = TRUE; + } + + return result; +} + +//----------------------------------------------------------------------------- +// isAnyAnimationSignaled() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::isAnyAnimationSignaled(const LLUUID *anim_array, const S32 num_anims) const +{ + for (S32 i = 0; i < num_anims; i++) + { + if(mSignaledAnimations.find(anim_array[i]) != mSignaledAnimations.end()) + { + return TRUE; + } + } + return FALSE; +} + +//----------------------------------------------------------------------------- +// resetAnimations() +//----------------------------------------------------------------------------- +void LLVOAvatar::resetAnimations() +{ + LLKeyframeMotion::flushKeyframeCache(); + flushAllMotions(); +} + +// Override selectively based on avatar sex and whether we're using new +// animations. +LLUUID LLVOAvatar::remapMotionID(const LLUUID& id) +{ + BOOL use_new_walk_run = gSavedSettings.getBOOL("UseNewWalkRun"); + LLUUID result = id; + + // start special case female walk for female avatars + if (getSex() == SEX_FEMALE) + { + if (id == ANIM_AGENT_WALK) + { + if (use_new_walk_run) + result = ANIM_AGENT_FEMALE_WALK_NEW; + else + result = ANIM_AGENT_FEMALE_WALK; + } + else if (id == ANIM_AGENT_RUN) + { + // There is no old female run animation, so only override + // in one case. + if (use_new_walk_run) + result = ANIM_AGENT_FEMALE_RUN_NEW; + } + else if (id == ANIM_AGENT_SIT) + { + result = ANIM_AGENT_SIT_FEMALE; + } + } + else + { + // Male avatar. + if (id == ANIM_AGENT_WALK) + { + if (use_new_walk_run) + result = ANIM_AGENT_WALK_NEW; + } + else if (id == ANIM_AGENT_RUN) + { + if (use_new_walk_run) + result = ANIM_AGENT_RUN_NEW; + } + + } + + return result; + +} + +//----------------------------------------------------------------------------- +// startMotion() +// id is the asset if of the animation to start +// time_offset is the offset into the animation at which to start playing +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl; + + LLUUID remap_id = remapMotionID(id); + + if (remap_id != id) + { + lldebugs << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << llendl; + } + + if (isSelf() && remap_id == ANIM_AGENT_AWAY) + { + gAgent.setAFK(); + } + + return LLCharacter::startMotion(remap_id, time_offset); +} + +//----------------------------------------------------------------------------- +// stopMotion() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::stopMotion(const LLUUID& id, BOOL stop_immediate) +{ + lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl; + + LLUUID remap_id = remapMotionID(id); + + if (remap_id != id) + { + lldebugs << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << llendl; + } + + if (isSelf()) + { + gAgent.onAnimStop(remap_id); + } + + return LLCharacter::stopMotion(remap_id, stop_immediate); +} + +//----------------------------------------------------------------------------- +// stopMotionFromSource() +//----------------------------------------------------------------------------- +// virtual +void LLVOAvatar::stopMotionFromSource(const LLUUID& source_id) +{ +} + +//----------------------------------------------------------------------------- +// getVolumePos() +//----------------------------------------------------------------------------- +LLVector3 LLVOAvatar::getVolumePos(S32 joint_index, LLVector3& volume_offset) +{ + if (joint_index > mNumCollisionVolumes) + { + return LLVector3::zero; + } + + return mCollisionVolumes[joint_index].getVolumePos(volume_offset); +} + +//----------------------------------------------------------------------------- +// findCollisionVolume() +//----------------------------------------------------------------------------- +LLJoint* LLVOAvatar::findCollisionVolume(U32 volume_id) +{ + if ((S32)volume_id > mNumCollisionVolumes) + { + return NULL; + } + + return &mCollisionVolumes[volume_id]; +} + +//----------------------------------------------------------------------------- +// findCollisionVolume() +//----------------------------------------------------------------------------- +S32 LLVOAvatar::getCollisionVolumeID(std::string &name) +{ + for (S32 i = 0; i < mNumCollisionVolumes; i++) + { + if (mCollisionVolumes[i].getName() == name) + { + return i; + } + } + + return -1; +} + +//----------------------------------------------------------------------------- +// addDebugText() +//----------------------------------------------------------------------------- +void LLVOAvatar::addDebugText(const std::string& text) +{ + mDebugText.append(1, '\n'); + mDebugText.append(text); +} + +//----------------------------------------------------------------------------- +// getID() +//----------------------------------------------------------------------------- +const LLUUID& LLVOAvatar::getID() +{ + return mID; +} + +//----------------------------------------------------------------------------- +// getJoint() +//----------------------------------------------------------------------------- +// RN: avatar joints are multi-rooted to include screen-based attachments +LLJoint *LLVOAvatar::getJoint( const std::string &name ) +{ + LLJoint* jointp = mRoot.findJoint(name); + return jointp; +} + +//----------------------------------------------------------------------------- +// resetJointPositions +//----------------------------------------------------------------------------- +void LLVOAvatar::resetJointPositions( void ) +{ + for(S32 i = 0; i < (S32)mNumJoints; ++i) + { + mSkeleton[i].restoreOldXform(); + mSkeleton[i].setId( LLUUID::null ); + } + mHasPelvisOffset = false; +} +//----------------------------------------------------------------------------- +// resetSpecificJointPosition +//----------------------------------------------------------------------------- +void LLVOAvatar::resetSpecificJointPosition( const std::string& name ) +{ + LLJoint* pJoint = mRoot.findJoint( name ); + + if ( pJoint && pJoint->doesJointNeedToBeReset() ) + { + pJoint->restoreOldXform(); + pJoint->setId( LLUUID::null ); + //If we're reseting the pelvis position make sure not to apply offset + if ( name == "mPelvis" ) + { + mHasPelvisOffset = false; + } + } + else + { + llinfos<<"Did not find "<< name.c_str()<setPosition( avPos + pPelvis->getPosition() ); + } + else + { + llwarns<<"Can't get pelvis joint."<doesJointNeedToBeReset() ) + { + + pJoint->setId( LLUUID::null ); + //restore joints to default positions, however skip over the pelvis + if ( pJoint && pPelvis != pJoint ) + { + pJoint->restoreOldXform(); + } + } + } + //make sure we don't apply the joint offset + mHasPelvisOffset = false; + postPelvisSetRecalc(); +} +//----------------------------------------------------------------------------- +// getCharacterPosition() +//----------------------------------------------------------------------------- +LLVector3 LLVOAvatar::getCharacterPosition() +{ + if (mDrawable.notNull()) + { + return mDrawable->getPositionAgent(); + } + else + { + return getPositionAgent(); + } +} + + +//----------------------------------------------------------------------------- +// LLVOAvatar::getCharacterRotation() +//----------------------------------------------------------------------------- +LLQuaternion LLVOAvatar::getCharacterRotation() +{ + return getRotation(); +} + + +//----------------------------------------------------------------------------- +// LLVOAvatar::getCharacterVelocity() +//----------------------------------------------------------------------------- +LLVector3 LLVOAvatar::getCharacterVelocity() +{ + return getVelocity() - mStepObjectVelocity; +} + + +//----------------------------------------------------------------------------- +// LLVOAvatar::getCharacterAngularVelocity() +//----------------------------------------------------------------------------- +LLVector3 LLVOAvatar::getCharacterAngularVelocity() +{ + return getAngularVelocity(); +} + +//----------------------------------------------------------------------------- +// LLVOAvatar::getGround() +//----------------------------------------------------------------------------- +void LLVOAvatar::getGround(const LLVector3 &in_pos_agent, LLVector3 &out_pos_agent, LLVector3 &outNorm) +{ + LLVector3d z_vec(0.0f, 0.0f, 1.0f); + LLVector3d p0_global, p1_global; + + if (gNoRender || mIsDummy) + { + outNorm.setVec(z_vec); + out_pos_agent = in_pos_agent; + return; + } + + p0_global = gAgent.getPosGlobalFromAgent(in_pos_agent) + z_vec; + p1_global = gAgent.getPosGlobalFromAgent(in_pos_agent) - z_vec; + LLViewerObject *obj; + LLVector3d out_pos_global; + LLWorld::getInstance()->resolveStepHeightGlobal(this, p0_global, p1_global, out_pos_global, outNorm, &obj); + out_pos_agent = gAgent.getPosAgentFromGlobal(out_pos_global); +} + +//----------------------------------------------------------------------------- +// LLVOAvatar::getTimeDilation() +//----------------------------------------------------------------------------- +F32 LLVOAvatar::getTimeDilation() +{ + return mTimeDilation; +} + + +//----------------------------------------------------------------------------- +// LLVOAvatar::getPixelArea() +//----------------------------------------------------------------------------- +F32 LLVOAvatar::getPixelArea() const +{ + if (mIsDummy) + { + return 100000.f; + } + return mPixelArea; +} + + +//----------------------------------------------------------------------------- +// LLVOAvatar::getHeadMesh() +//----------------------------------------------------------------------------- +LLPolyMesh* LLVOAvatar::getHeadMesh() +{ + return mMeshLOD[MESH_ID_HEAD]->mMeshParts[0]->getMesh(); +} + + +//----------------------------------------------------------------------------- +// LLVOAvatar::getUpperBodyMesh() +//----------------------------------------------------------------------------- +LLPolyMesh* LLVOAvatar::getUpperBodyMesh() +{ + return mMeshLOD[MESH_ID_UPPER_BODY]->mMeshParts[0]->getMesh(); +} + + +//----------------------------------------------------------------------------- +// LLVOAvatar::getPosGlobalFromAgent() +//----------------------------------------------------------------------------- +LLVector3d LLVOAvatar::getPosGlobalFromAgent(const LLVector3 &position) +{ + return gAgent.getPosGlobalFromAgent(position); +} + +//----------------------------------------------------------------------------- +// getPosAgentFromGlobal() +//----------------------------------------------------------------------------- +LLVector3 LLVOAvatar::getPosAgentFromGlobal(const LLVector3d &position) +{ + return gAgent.getPosAgentFromGlobal(position); +} + +//----------------------------------------------------------------------------- +// allocateCharacterJoints() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::allocateCharacterJoints( U32 num ) +{ + deleteAndClearArray(mSkeleton); + mNumJoints = 0; + + mSkeleton = new LLViewerJoint[num]; + + for(S32 joint_num = 0; joint_num < (S32)num; joint_num++) + { + mSkeleton[joint_num].setJointNum(joint_num); + } + + if (!mSkeleton) + { + return FALSE; + } + + mNumJoints = num; + return TRUE; +} + +//----------------------------------------------------------------------------- +// allocateCollisionVolumes() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::allocateCollisionVolumes( U32 num ) +{ + deleteAndClearArray(mCollisionVolumes); + mNumCollisionVolumes = 0; + + mCollisionVolumes = new LLViewerJointCollisionVolume[num]; + if (!mCollisionVolumes) + { + return FALSE; + } + + mNumCollisionVolumes = num; + return TRUE; +} + + +//----------------------------------------------------------------------------- +// getCharacterJoint() +//----------------------------------------------------------------------------- +LLJoint *LLVOAvatar::getCharacterJoint( U32 num ) +{ + if ((S32)num >= mNumJoints + || (S32)num < 0) + { + return NULL; + } + return (LLJoint*)&mSkeleton[num]; +} + +//----------------------------------------------------------------------------- +// requestStopMotion() +//----------------------------------------------------------------------------- +// virtual +void LLVOAvatar::requestStopMotion( LLMotion* motion ) +{ + // Only agent avatars should handle the stop motion notifications. +} + +//----------------------------------------------------------------------------- +// loadAvatar() +//----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_LOAD_AVATAR("Load Avatar"); + +BOOL LLVOAvatar::loadAvatar() +{ +// LLFastTimer t(FTM_LOAD_AVATAR); + + // avatar_skeleton.xml + if( !buildSkeleton(sAvatarSkeletonInfo) ) + { + llwarns << "avatar file: buildSkeleton() failed" << llendl; + return FALSE; + } + + // avatar_lad.xml : + if( !loadSkeletonNode() ) + { + llwarns << "avatar file: loadNodeSkeleton() failed" << llendl; + return FALSE; + } + + // avatar_lad.xml : + if( !loadMeshNodes() ) + { + llwarns << "avatar file: loadNodeMesh() failed" << llendl; + return FALSE; + } + + // avatar_lad.xml : + if( sAvatarXmlInfo->mTexSkinColorInfo ) + { + mTexSkinColor = new LLTexGlobalColor( this ); + if( !mTexSkinColor->setInfo( sAvatarXmlInfo->mTexSkinColorInfo ) ) + { + llwarns << "avatar file: mTexSkinColor->setInfo() failed" << llendl; + return FALSE; + } + } + else + { + llwarns << " name=\"skin_color\" not found" << llendl; + return FALSE; + } + if( sAvatarXmlInfo->mTexHairColorInfo ) + { + mTexHairColor = new LLTexGlobalColor( this ); + if( !mTexHairColor->setInfo( sAvatarXmlInfo->mTexHairColorInfo ) ) + { + llwarns << "avatar file: mTexHairColor->setInfo() failed" << llendl; + return FALSE; + } + } + else + { + llwarns << " name=\"hair_color\" not found" << llendl; + return FALSE; + } + if( sAvatarXmlInfo->mTexEyeColorInfo ) + { + mTexEyeColor = new LLTexGlobalColor( this ); + if( !mTexEyeColor->setInfo( sAvatarXmlInfo->mTexEyeColorInfo ) ) + { + llwarns << "avatar file: mTexEyeColor->setInfo() failed" << llendl; + return FALSE; + } + } + else + { + llwarns << " name=\"eye_color\" not found" << llendl; + return FALSE; + } + + // avatar_lad.xml : + if (sAvatarXmlInfo->mLayerInfoList.empty()) + { + llwarns << "avatar file: missing node" << llendl; + return FALSE; + } + + if (sAvatarXmlInfo->mMorphMaskInfoList.empty()) + { + llwarns << "avatar file: missing node" << llendl; + return FALSE; + } + + // avatar_lad.xml : + for (LLVOAvatarXmlInfo::morph_info_list_t::iterator iter = sAvatarXmlInfo->mMorphMaskInfoList.begin(); + iter != sAvatarXmlInfo->mMorphMaskInfoList.end(); + ++iter) + { + LLVOAvatarXmlInfo::LLVOAvatarMorphInfo *info = *iter; + + EBakedTextureIndex baked = LLVOAvatarDictionary::findBakedByRegionName(info->mRegion); + if (baked != BAKED_NUM_INDICES) + { + LLPolyMorphTarget *morph_param; + const std::string *name = &info->mName; + morph_param = (LLPolyMorphTarget *)(getVisualParam(name->c_str())); + if (morph_param) + { + BOOL invert = info->mInvert; + addMaskedMorph(baked, morph_param, invert, info->mLayer); + } + } + + } + + loadLayersets(); + + // avatar_lad.xml : + for (LLVOAvatarXmlInfo::driver_info_list_t::iterator iter = sAvatarXmlInfo->mDriverInfoList.begin(); + iter != sAvatarXmlInfo->mDriverInfoList.end(); + ++iter) + { + LLDriverParamInfo *info = *iter; + LLDriverParam* driver_param = new LLDriverParam( this ); + if (driver_param->setInfo(info)) + { + addVisualParam( driver_param ); + LLVisualParam*(LLVOAvatar::*avatar_function)(S32)const = &LLVOAvatar::getVisualParam; + if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLVOAvatar*)this,_1 ), false)) + { + llwarns << "could not link driven params for avatar " << this->getFullname() << " id: " << driver_param->getID() << llendl; + continue; + } + } + else + { + delete driver_param; + llwarns << "avatar file: driver_param->parseData() failed" << llendl; + return FALSE; + } + } + + // Uncomment to enable avatar_lad.xml debugging. + std::ofstream file; + file.open("avatar_lad.log"); + for( LLViewerVisualParam* param = (LLViewerVisualParam*) getFirstVisualParam(); + param; + param = (LLViewerVisualParam*) getNextVisualParam() ) + { + param->getInfo()->toStream(file); + file << std::endl; + } + + file.close(); + + return TRUE; +} + +//----------------------------------------------------------------------------- +// loadSkeletonNode(): loads node from XML tree +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::loadSkeletonNode () +{ + mRoot.addChild( &mSkeleton[0] ); + + for (std::vector::iterator iter = mMeshLOD.begin(); + iter != mMeshLOD.end(); + ++iter) + { + LLViewerJoint *joint = (LLViewerJoint *) *iter; + joint->mUpdateXform = FALSE; + joint->setMeshesToChildren(); + } + + mRoot.addChild(mMeshLOD[MESH_ID_HEAD]); + mRoot.addChild(mMeshLOD[MESH_ID_EYELASH]); + mRoot.addChild(mMeshLOD[MESH_ID_UPPER_BODY]); + mRoot.addChild(mMeshLOD[MESH_ID_LOWER_BODY]); + mRoot.addChild(mMeshLOD[MESH_ID_SKIRT]); + mRoot.addChild(mMeshLOD[MESH_ID_HEAD]); + + LLViewerJoint *skull = (LLViewerJoint*)mRoot.findJoint("mSkull"); + if (skull) + { + skull->addChild(mMeshLOD[MESH_ID_HAIR] ); + } + + LLViewerJoint *eyeL = (LLViewerJoint*)mRoot.findJoint("mEyeLeft"); + if (eyeL) + { + eyeL->addChild( mMeshLOD[MESH_ID_EYEBALL_LEFT] ); + } + + LLViewerJoint *eyeR = (LLViewerJoint*)mRoot.findJoint("mEyeRight"); + if (eyeR) + { + eyeR->addChild( mMeshLOD[MESH_ID_EYEBALL_RIGHT] ); + } + + // SKELETAL DISTORTIONS + { + LLVOAvatarXmlInfo::skeletal_distortion_info_list_t::iterator iter; + for (iter = sAvatarXmlInfo->mSkeletalDistortionInfoList.begin(); + iter != sAvatarXmlInfo->mSkeletalDistortionInfoList.end(); + ++iter) + { + LLPolySkeletalDistortionInfo *info = *iter; + LLPolySkeletalDistortion *param = new LLPolySkeletalDistortion(this); + if (!param->setInfo(info)) + { + delete param; + return FALSE; + } + else + { + addVisualParam(param); + } + } + } + + // ATTACHMENTS + { + LLVOAvatarXmlInfo::attachment_info_list_t::iterator iter; + for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin(); + iter != sAvatarXmlInfo->mAttachmentInfoList.end(); + ++iter) + { + LLVOAvatarXmlInfo::LLVOAvatarAttachmentInfo *info = *iter; + if (!isSelf() && info->mJointName == "mScreen") + { //don't process screen joint for other avatars + continue; + } + + LLViewerJointAttachment* attachment = new LLViewerJointAttachment(); + + attachment->setName(info->mName); + LLJoint *parentJoint = getJoint(info->mJointName); + if (!parentJoint) + { + llwarns << "No parent joint by name " << info->mJointName << " found for attachment point " << info->mName << llendl; + delete attachment; + continue; + } + + if (info->mHasPosition) + { + attachment->setOriginalPosition(info->mPosition); + } + + if (info->mHasRotation) + { + LLQuaternion rotation; + rotation.setQuat(info->mRotationEuler.mV[VX] * DEG_TO_RAD, + info->mRotationEuler.mV[VY] * DEG_TO_RAD, + info->mRotationEuler.mV[VZ] * DEG_TO_RAD); + attachment->setRotation(rotation); + } + + int group = info->mGroup; + if (group >= 0) + { + if (group < 0 || group >= 9) + { + llwarns << "Invalid group number (" << group << ") for attachment point " << info->mName << llendl; + } + else + { + attachment->setGroup(group); + } + } + + S32 attachmentID = info->mAttachmentID; + if (attachmentID < 1 || attachmentID > 255) + { + llwarns << "Attachment point out of range [1-255]: " << attachmentID << " on attachment point " << info->mName << llendl; + delete attachment; + continue; + } + if (mAttachmentPoints.find(attachmentID) != mAttachmentPoints.end()) + { + llwarns << "Attachment point redefined with id " << attachmentID << " on attachment point " << info->mName << llendl; + delete attachment; + continue; + } + + attachment->setPieSlice(info->mPieMenuSlice); + attachment->setVisibleInFirstPerson(info->mVisibleFirstPerson); + attachment->setIsHUDAttachment(info->mIsHUDAttachment); + + mAttachmentPoints[attachmentID] = attachment; + + // now add attachment joint + parentJoint->addChild(attachment); + } + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// loadMeshNodes(): loads nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::loadMeshNodes() +{ + for (LLVOAvatarXmlInfo::mesh_info_list_t::const_iterator meshinfo_iter = sAvatarXmlInfo->mMeshInfoList.begin(); + meshinfo_iter != sAvatarXmlInfo->mMeshInfoList.end(); + ++meshinfo_iter) + { + const LLVOAvatarXmlInfo::LLVOAvatarMeshInfo *info = *meshinfo_iter; + const std::string &type = info->mType; + S32 lod = info->mLOD; + + LLViewerJointMesh* mesh = NULL; + U8 mesh_id = 0; + BOOL found_mesh_id = FALSE; + + /* if (type == "hairMesh") + switch(lod) + case 0: + mesh = &mHairMesh0; */ + for (LLVOAvatarDictionary::Meshes::const_iterator mesh_iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin(); + mesh_iter != LLVOAvatarDictionary::getInstance()->getMeshes().end(); + ++mesh_iter) + { + const EMeshIndex mesh_index = mesh_iter->first; + const LLVOAvatarDictionary::MeshEntry *mesh_dict = mesh_iter->second; + if (type.compare(mesh_dict->mName) == 0) + { + mesh_id = mesh_index; + found_mesh_id = TRUE; + break; + } + } + + if (found_mesh_id) + { + if (lod < (S32)mMeshLOD[mesh_id]->mMeshParts.size()) + { + mesh = mMeshLOD[mesh_id]->mMeshParts[lod]; + } + else + { + llwarns << "Avatar file: has invalid lod setting " << lod << llendl; + return FALSE; + } + } + else + { + llwarns << "Ignoring unrecognized mesh type: " << type << llendl; + return FALSE; + } + + // llinfos << "Parsing mesh data for " << type << "..." << llendl; + + // If this isn't set to white (1.0), avatars will *ALWAYS* be darker than their surroundings. + // Do not touch!!! + mesh->setColor( 1.0f, 1.0f, 1.0f, 1.0f ); + + LLPolyMesh *poly_mesh = NULL; + + if (!info->mReferenceMeshName.empty()) + { + polymesh_map_t::const_iterator polymesh_iter = mMeshes.find(info->mReferenceMeshName); + if (polymesh_iter != mMeshes.end()) + { + poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName, polymesh_iter->second); + poly_mesh->setAvatar(this); + } + else + { + // This should never happen + LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL; + } + } + else + { + poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName); + poly_mesh->setAvatar(this); + } + + if( !poly_mesh ) + { + llwarns << "Failed to load mesh of type " << type << llendl; + return FALSE; + } + + // Multimap insert + mMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh)); + + mesh->setMesh( poly_mesh ); + mesh->setLOD( info->mMinPixelArea ); + + for (LLVOAvatarXmlInfo::LLVOAvatarMeshInfo::morph_info_list_t::const_iterator xmlinfo_iter = info->mPolyMorphTargetInfoList.begin(); + xmlinfo_iter != info->mPolyMorphTargetInfoList.end(); + ++xmlinfo_iter) + { + const LLVOAvatarXmlInfo::LLVOAvatarMeshInfo::morph_info_pair_t *info_pair = &(*xmlinfo_iter); + LLPolyMorphTarget *param = new LLPolyMorphTarget(mesh->getMesh()); + if (!param->setInfo(info_pair->first)) + { + delete param; + return FALSE; + } + else + { + if (info_pair->second) + { + addSharedVisualParam(param); + } + else + { + addVisualParam(param); + } + } + } + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// loadLayerSets() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::loadLayersets() +{ + BOOL success = TRUE; + for (LLVOAvatarXmlInfo::layer_info_list_t::const_iterator layerset_iter = sAvatarXmlInfo->mLayerInfoList.begin(); + layerset_iter != sAvatarXmlInfo->mLayerInfoList.end(); + ++layerset_iter) + { + // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such. + LLTexLayerSetInfo *layerset_info = *layerset_iter; + layerset_info->createVisualParams(this); + } + return success; +} + +//----------------------------------------------------------------------------- +// updateVisualParams() +//----------------------------------------------------------------------------- +void LLVOAvatar::updateVisualParams() +{ + if (gNoRender) + { + return; + } + + setSex( (getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE ); + + LLCharacter::updateVisualParams(); + + if (mLastSkeletonSerialNum != mSkeletonSerialNum) + { + computeBodySize(); + mLastSkeletonSerialNum = mSkeletonSerialNum; + mRoot.updateWorldMatrixChildren(); + } + + dirtyMesh(); + updateHeadOffset(); +} + +//----------------------------------------------------------------------------- +// isActive() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::isActive() const +{ + return TRUE; +} + +//----------------------------------------------------------------------------- +// setPixelAreaAndAngle() +//----------------------------------------------------------------------------- +void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + if (mDrawable.isNull()) + { + return; + } + + const LLVector4a* ext = mDrawable->getSpatialExtents(); + LLVector4a center; + center.setAdd(ext[1], ext[0]); + center.mul(0.5f); + LLVector4a size; + size.setSub(ext[1], ext[0]); + size.mul(0.5f); + + mImpostorPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance()); + + F32 range = mDrawable->mDistanceWRTCamera; + + if (range < 0.001f) // range == zero + { + mAppAngle = 180.f; + } + else + { + F32 radius = size.getLength3().getF32(); + mAppAngle = (F32) atan2( radius, range) * RAD_TO_DEG; + } + + // We always want to look good to ourselves + if( isSelf() ) + { + mPixelArea = llmax( mPixelArea, F32(getTexImageSize() / 16) ); + } +} + +//----------------------------------------------------------------------------- +// updateJointLODs() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::updateJointLODs() +{ + const F32 MAX_PIXEL_AREA = 100000000.f; + F32 lod_factor = (sLODFactor * AVATAR_LOD_TWEAK_RANGE + (1.f - AVATAR_LOD_TWEAK_RANGE)); + F32 avatar_num_min_factor = clamp_rescale(sLODFactor, 0.f, 1.f, 0.25f, 0.6f); + F32 avatar_num_factor = clamp_rescale((F32)sNumVisibleAvatars, 8, 25, 1.f, avatar_num_min_factor); + F32 area_scale = 0.16f; + + { + if (isSelf()) + { + if(gAgentCamera.cameraCustomizeAvatar() || gAgentCamera.cameraMouselook()) + { + mAdjustedPixelArea = MAX_PIXEL_AREA; + } + else + { + mAdjustedPixelArea = mPixelArea*area_scale; + } + } + else if (mIsDummy) + { + mAdjustedPixelArea = MAX_PIXEL_AREA; + } + else + { + // reported avatar pixel area is dependent on avatar render load, based on number of visible avatars + mAdjustedPixelArea = (F32)mPixelArea * area_scale * lod_factor * lod_factor * avatar_num_factor * avatar_num_factor; + } + + // now select meshes to render based on adjusted pixel area + BOOL res = mRoot.updateLOD(mAdjustedPixelArea, TRUE); + if (res) + { + sNumLODChangesThisFrame++; + dirtyMesh(2); + return TRUE; + } + } + + return FALSE; +} + +//----------------------------------------------------------------------------- +// createDrawable() +//----------------------------------------------------------------------------- +LLDrawable *LLVOAvatar::createDrawable(LLPipeline *pipeline) +{ + pipeline->allocDrawable(this); + mDrawable->setLit(FALSE); + + LLDrawPoolAvatar *poolp = (LLDrawPoolAvatar*) gPipeline.getPool(LLDrawPool::POOL_AVATAR); + + // Only a single face (one per avatar) + //this face will be splitted into several if its vertex buffer is too long. + mDrawable->setState(LLDrawable::ACTIVE); + mDrawable->addFace(poolp, NULL); + mDrawable->setRenderType(LLPipeline::RENDER_TYPE_AVATAR); + + mNumInitFaces = mDrawable->getNumFaces() ; + + dirtyMesh(2); + return mDrawable; +} + + +void LLVOAvatar::updateGL() +{ + if (mMeshTexturesDirty) + { + updateMeshTextures(); + mMeshTexturesDirty = FALSE; + } +} + +//----------------------------------------------------------------------------- +// updateGeometry() +//----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_UPDATE_AVATAR("Update Avatar"); +BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable) +{ + LLFastTimer ftm(FTM_UPDATE_AVATAR); + if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR))) + { + return TRUE; + } + + if (!mMeshValid) + { + return TRUE; + } + + if (!drawable) + { + llerrs << "LLVOAvatar::updateGeometry() called with NULL drawable" << llendl; + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// updateSexDependentLayerSets() +//----------------------------------------------------------------------------- +void LLVOAvatar::updateSexDependentLayerSets( BOOL upload_bake ) +{ + invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); + invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake ); + invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake ); +} + +//----------------------------------------------------------------------------- +// dirtyMesh() +//----------------------------------------------------------------------------- +void LLVOAvatar::dirtyMesh() +{ + dirtyMesh(1); +} +void LLVOAvatar::dirtyMesh(S32 priority) +{ + mDirtyMesh = llmax(mDirtyMesh, priority); +} +//----------------------------------------------------------------------------- +// hideSkirt() +//----------------------------------------------------------------------------- +void LLVOAvatar::hideSkirt() +{ + mMeshLOD[MESH_ID_SKIRT]->setVisible(FALSE, TRUE); +} + +BOOL LLVOAvatar::setParent(LLViewerObject* parent) +{ + BOOL ret ; + if (parent == NULL) + { + getOffObject(); + ret = LLViewerObject::setParent(parent); + if (isSelf()) + { + gAgentCamera.resetCamera(); + } + } + else + { + ret = LLViewerObject::setParent(parent); + if(ret) + { + sitOnObject(parent); + } + } + return ret ; +} + +void LLVOAvatar::addChild(LLViewerObject *childp) +{ + childp->extractAttachmentItemID(); // find the inventory item this object is associated with. + LLViewerObject::addChild(childp); + if (childp->mDrawable) + { + attachObject(childp); + } + else + { + mPendingAttachment.push_back(childp); + } +} + +void LLVOAvatar::removeChild(LLViewerObject *childp) +{ + LLViewerObject::removeChild(childp); + if (!detachObject(childp)) + { + llwarns << "Calling detach on non-attached object " << llendl; + } +} + +LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object) +{ + S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState()); + + // This should never happen unless the server didn't process the attachment point + // correctly, but putting this check in here to be safe. + if (attachmentID & ATTACHMENT_ADD) + { + llwarns << "Got an attachment with ATTACHMENT_ADD mask, removing ( attach pt:" << attachmentID << " )" << llendl; attachmentID &= ~ATTACHMENT_ADD; + } + + LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); + + if (!attachment) + { + llwarns << "Object attachment point invalid: " << attachmentID << llendl; + attachment = get_if_there(mAttachmentPoints, 1, (LLViewerJointAttachment*)NULL); // Arbitrary using 1 (chest) + } + + return attachment; +} + +//----------------------------------------------------------------------------- +// attachObject() +//----------------------------------------------------------------------------- +const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_object) +{ + LLViewerJointAttachment* attachment = getTargetAttachmentPoint(viewer_object); + + if (!attachment || !attachment->addObject(viewer_object)) + { + return 0; + } + + if (viewer_object->isSelected()) + { + LLSelectMgr::getInstance()->updateSelectionCenter(); + LLSelectMgr::getInstance()->updatePointAt(); + } + + return attachment; +} + +//----------------------------------------------------------------------------- +// attachObject() +//----------------------------------------------------------------------------- +U32 LLVOAvatar::getNumAttachments() const +{ + U32 num_attachments = 0; + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + const LLViewerJointAttachment *attachment_pt = (*iter).second; + num_attachments += attachment_pt->getNumObjects(); + } + return num_attachments; +} + +//----------------------------------------------------------------------------- +// canAttachMoreObjects() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::canAttachMoreObjects() const +{ + return (getNumAttachments() < MAX_AGENT_ATTACHMENTS); +} + +//----------------------------------------------------------------------------- +// canAttachMoreObjects() +// Returns true if we can attach more objects. +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const +{ + return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS; +} + +//----------------------------------------------------------------------------- +// lazyAttach() +//----------------------------------------------------------------------------- +void LLVOAvatar::lazyAttach() +{ + std::vector > still_pending; + + for (U32 i = 0; i < mPendingAttachment.size(); i++) + { + if (mPendingAttachment[i]->mDrawable) + { + attachObject(mPendingAttachment[i]); + } + else + { + still_pending.push_back(mPendingAttachment[i]); + } + } + + mPendingAttachment = still_pending; +} + +void LLVOAvatar::resetHUDAttachments() +{ + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (attachment->getIsHUDAttachment()) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object && attached_object->mDrawable.notNull()) + { + gPipeline.markMoved(attached_object->mDrawable); + } + } + } + } +} + +void LLVOAvatar::rebuildRiggedAttachments( void ) +{ + for ( attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter ) + { + LLViewerJointAttachment* pAttachment = iter->second; + LLViewerJointAttachment::attachedobjs_vec_t::iterator attachmentIterEnd = pAttachment->mAttachedObjects.end(); + + for ( LLViewerJointAttachment::attachedobjs_vec_t::iterator attachmentIter = pAttachment->mAttachedObjects.begin(); + attachmentIter != attachmentIterEnd; ++attachmentIter) + { + const LLViewerObject* pAttachedObject = *attachmentIter; + if ( pAttachment && pAttachedObject->mDrawable.notNull() ) + { + gPipeline.markRebuild(pAttachedObject->mDrawable); + } + } + } +} +//----------------------------------------------------------------------------- +// cleanupAttachedMesh() +//----------------------------------------------------------------------------- +void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO ) +{ + //If a VO has a skin that we'll reset the joint positions to their default + if ( pVO && pVO->mDrawable ) + { + LLVOVolume* pVObj = pVO->mDrawable->getVOVolume(); + if ( pVObj ) + { + const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID() ); + if ( pSkinData ) + { + const int jointCnt = pSkinData->mJointNames.size(); + bool fullRig = ( jointCnt>=20 ) ? true : false; + if ( fullRig ) + { + const int bindCnt = pSkinData->mAlternateBindMatrix.size(); + if ( bindCnt > 0 ) + { + LLVOAvatar::resetJointPositionsToDefault(); + } + } + } + } + } +} +//----------------------------------------------------------------------------- +// detachObject() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) +{ + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + + if (attachment->isObjectAttached(viewer_object)) + { + cleanupAttachedMesh( viewer_object ); + attachment->removeObject(viewer_object); + lldebugs << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << llendl; + return TRUE; + } + } + + std::vector >::iterator iter = std::find(mPendingAttachment.begin(), mPendingAttachment.end(), viewer_object); + if (iter != mPendingAttachment.end()) + { + mPendingAttachment.erase(iter); + return TRUE; + } + + return FALSE; +} + +//----------------------------------------------------------------------------- +// sitDown() +//----------------------------------------------------------------------------- +void LLVOAvatar::sitDown(BOOL bSitting) +{ + mIsSitting = bSitting; + if (isSelf()) + { + // Update Movement Controls according to own Sitting mode + LLFloaterMove::setSittingMode(bSitting); + } +} + +//----------------------------------------------------------------------------- +// sitOnObject() +//----------------------------------------------------------------------------- +void LLVOAvatar::sitOnObject(LLViewerObject *sit_object) +{ + if (isSelf()) + { + // Might be first sit + //LLFirstUse::useSit(); + + gAgent.setFlying(FALSE); + gAgentCamera.setThirdPersonHeadOffset(LLVector3::zero); + //interpolate to new camera position + gAgentCamera.startCameraAnimation(); + // make sure we are not trying to autopilot + gAgent.stopAutoPilot(); + gAgentCamera.setupSitCamera(); + if (gAgentCamera.getForceMouselook()) + { + gAgentCamera.changeCameraToMouselook(); + } + } + + if (mDrawable.isNull()) + { + return; + } + LLQuaternion inv_obj_rot = ~sit_object->getRenderRotation(); + LLVector3 obj_pos = sit_object->getRenderPosition(); + + LLVector3 rel_pos = getRenderPosition() - obj_pos; + rel_pos.rotVec(inv_obj_rot); + + mDrawable->mXform.setPosition(rel_pos); + mDrawable->mXform.setRotation(mDrawable->getWorldRotation() * inv_obj_rot); + + gPipeline.markMoved(mDrawable, TRUE); + // Notice that removing sitDown() from here causes avatars sitting on + // objects to be not rendered for new arrivals. See EXT-6835 and EXT-1655. + sitDown(TRUE); + mRoot.getXform()->setParent(&sit_object->mDrawable->mXform); // LLVOAvatar::sitOnObject + mRoot.setPosition(getPosition()); + mRoot.updateWorldMatrixChildren(); + + stopMotion(ANIM_AGENT_BODY_NOISE); + +} + +//----------------------------------------------------------------------------- +// getOffObject() +//----------------------------------------------------------------------------- +void LLVOAvatar::getOffObject() +{ + if (mDrawable.isNull()) + { + return; + } + + LLViewerObject* sit_object = (LLViewerObject*)getParent(); + + if (sit_object) + { + stopMotionFromSource(sit_object->getID()); + LLFollowCamMgr::setCameraActive(sit_object->getID(), FALSE); + + LLViewerObject::const_child_list_t& child_list = sit_object->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); ++iter) + { + LLViewerObject* child_objectp = *iter; + + stopMotionFromSource(child_objectp->getID()); + LLFollowCamMgr::setCameraActive(child_objectp->getID(), FALSE); + } + } + + // assumes that transform will not be updated with drawable still having a parent + LLVector3 cur_position_world = mDrawable->getWorldPosition(); + LLQuaternion cur_rotation_world = mDrawable->getWorldRotation(); + + // set *local* position based on last *world* position, since we're unparenting the avatar + mDrawable->mXform.setPosition(cur_position_world); + mDrawable->mXform.setRotation(cur_rotation_world); + + gPipeline.markMoved(mDrawable, TRUE); + + sitDown(FALSE); + + mRoot.getXform()->setParent(NULL); // LLVOAvatar::getOffObject + mRoot.setPosition(cur_position_world); + mRoot.setRotation(cur_rotation_world); + mRoot.getXform()->update(); + + startMotion(ANIM_AGENT_BODY_NOISE); + + if (isSelf()) + { + LLQuaternion av_rot = gAgent.getFrameAgent().getQuaternion(); + LLQuaternion obj_rot = sit_object ? sit_object->getRenderRotation() : LLQuaternion::DEFAULT; + av_rot = av_rot * obj_rot; + LLVector3 at_axis = LLVector3::x_axis; + at_axis = at_axis * av_rot; + at_axis.mV[VZ] = 0.f; + at_axis.normalize(); + gAgent.resetAxes(at_axis); + + //reset orientation +// mRoot.setRotation(avWorldRot); + gAgentCamera.setThirdPersonHeadOffset(LLVector3(0.f, 0.f, 1.f)); + + gAgentCamera.setSitCamera(LLUUID::null); + } +} + +//----------------------------------------------------------------------------- +// findAvatarFromAttachment() +//----------------------------------------------------------------------------- +// static +LLVOAvatar* LLVOAvatar::findAvatarFromAttachment( LLViewerObject* obj ) +{ + if( obj->isAttachment() ) + { + do + { + obj = (LLViewerObject*) obj->getParent(); + } + while( obj && !obj->isAvatar() ); + + if( obj && !obj->isDead() ) + { + return (LLVOAvatar*)obj; + } + } + return NULL; +} + +// warning: order(N) not order(1) +S32 LLVOAvatar::getAttachmentCount() +{ + S32 count = mAttachmentPoints.size(); + return count; +} + +LLColor4 LLVOAvatar::getGlobalColor( const std::string& color_name ) const +{ + if (color_name=="skin_color" && mTexSkinColor) + { + return mTexSkinColor->getColor(); + } + else if(color_name=="hair_color" && mTexHairColor) + { + return mTexHairColor->getColor(); + } + if(color_name=="eye_color" && mTexEyeColor) + { + return mTexEyeColor->getColor(); + } + else + { +// return LLColor4( .5f, .5f, .5f, .5f ); + return LLColor4( 0.f, 1.f, 1.f, 1.f ); // good debugging color + } +} + +// virtual +void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result ) +{ +} + +void LLVOAvatar::invalidateAll() +{ +} + +void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake ) +{ + if (global_color == mTexSkinColor) + { + invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); + invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake ); + invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake ); + } + else if (global_color == mTexHairColor) + { + invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); + invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet, upload_bake ); + + // ! BACKWARDS COMPATIBILITY ! + // Fix for dealing with avatars from viewers that don't bake hair. + if (!isTextureDefined(mBakedTextureDatas[BAKED_HAIR].mTextureIndex)) + { + LLColor4 color = mTexHairColor->getColor(); + for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++) + { + mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( color.mV[VX], color.mV[VY], color.mV[VZ], color.mV[VW] ); + } + } + } + else if (global_color == mTexEyeColor) + { +// llinfos << "invalidateComposite cause: onGlobalColorChanged( eyecolor )" << llendl; + invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet, upload_bake ); + } + updateMeshTextures(); +} + +BOOL LLVOAvatar::isVisible() const +{ + return mDrawable.notNull() + && (mDrawable->isVisible() || mIsDummy); +} + +// Determine if we have enough avatar data to render +BOOL LLVOAvatar::getIsCloud() +{ + // Do we have a shape? + if (visualParamWeightsAreDefault()) + { + return TRUE; + } + + if (!isTextureDefined(TEX_LOWER_BAKED) || + !isTextureDefined(TEX_UPPER_BAKED) || + !isTextureDefined(TEX_HEAD_BAKED)) + { + return TRUE; + } + return FALSE; +} + +// call periodically to keep isFullyLoaded up to date. +// returns true if the value has changed. +BOOL LLVOAvatar::updateIsFullyLoaded() +{ + const BOOL loading = getIsCloud(); + updateRuthTimer(loading); + return processFullyLoadedChange(loading); +} + +void LLVOAvatar::updateRuthTimer(bool loading) +{ + if (isSelf() || !loading) + { + return; + } + + if (mPreviousFullyLoaded) + { + mRuthTimer.reset(); + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' became cloud." << llendl; + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezCloudNotification",args); + } + mRuthDebugTimer.reset(); + } + + const F32 LOADING_TIMEOUT__SECONDS = 120.f; + if (mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT__SECONDS) + { + llinfos << "Ruth Timer timeout: Missing texture data for '" << getFullname() << "' " + << "( Params loaded : " << !visualParamWeightsAreDefault() << " ) " + << "( Lower : " << isTextureDefined(TEX_LOWER_BAKED) << " ) " + << "( Upper : " << isTextureDefined(TEX_UPPER_BAKED) << " ) " + << "( Head : " << isTextureDefined(TEX_HEAD_BAKED) << " )." + << llendl; + + LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); + mRuthTimer.reset(); + } +} + +BOOL LLVOAvatar::processFullyLoadedChange(bool loading) +{ + // we wait a little bit before giving the all clear, + // to let textures settle down + const F32 PAUSE = 1.f; + if (loading) + mFullyLoadedTimer.reset(); + + mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > PAUSE); + + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + if (!mPreviousFullyLoaded && !loading && mFullyLoaded) + { + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' resolved in " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl; + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezNotification",args); + } + } + + // did our loading state "change" from last call? + const S32 UPDATE_RATE = 30; + BOOL changed = + ((mFullyLoaded != mPreviousFullyLoaded) || // if the value is different from the previous call + (!mFullyLoadedInitialized) || // if we've never been called before + (mFullyLoadedFrameCounter % UPDATE_RATE == 0)); // every now and then issue a change + + mPreviousFullyLoaded = mFullyLoaded; + mFullyLoadedInitialized = TRUE; + mFullyLoadedFrameCounter++; + + return changed; +} + +BOOL LLVOAvatar::isFullyLoaded() const +{ + if (gSavedSettings.getBOOL("RenderUnloadedAvatar")) + return TRUE; + else + return mFullyLoaded; +} + + +//----------------------------------------------------------------------------- +// findMotion() +//----------------------------------------------------------------------------- +LLMotion* LLVOAvatar::findMotion(const LLUUID& id) const +{ + return mMotionController.findMotion(id); +} + +//----------------------------------------------------------------------------- +// updateMeshTextures() +// Uses the current TE values to set the meshes' and layersets' textures. +//----------------------------------------------------------------------------- +void LLVOAvatar::updateMeshTextures() +{ + // llinfos << "updateMeshTextures" << llendl; + if (gNoRender) return; + + // if user has never specified a texture, assign the default + for (U32 i=0; i < getNumTEs(); i++) + { + const LLViewerTexture* te_image = getImage(i, 0); + if(!te_image || te_image->getID().isNull() || (te_image->getID() == IMG_DEFAULT)) + { + setImage(i, LLViewerTextureManager::getFetchedTexture(i == TEX_HAIR ? IMG_DEFAULT : IMG_DEFAULT_AVATAR), 0); // IMG_DEFAULT_AVATAR = a special texture that's never rendered. + } + } + + const BOOL self_customizing = isSelf() && gAgentCamera.cameraCustomizeAvatar(); // During face edit mode, we don't use baked textures + const BOOL other_culled = !isSelf() && mCulled; + LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ; + BOOL paused = FALSE; + if(!isSelf()) + { + src_callback_list = &mCallbackTextureList ; + paused = mLoadedCallbacksPaused ; + } + + std::vector is_layer_baked; + is_layer_baked.resize(mBakedTextureDatas.size(), false); + + std::vector use_lkg_baked_layer; // lkg = "last known good" + use_lkg_baked_layer.resize(mBakedTextureDatas.size(), false); + + for (U32 i=0; i < mBakedTextureDatas.size(); i++) + { + is_layer_baked[i] = isTextureDefined(mBakedTextureDatas[i].mTextureIndex); + + if (!other_culled) + { + // When an avatar is changing clothes and not in Appearance mode, + // use the last-known good baked texture until it finish the first + // render of the new layerset. + + const BOOL layerset_invalid = mBakedTextureDatas[i].mTexLayerSet + && ( !mBakedTextureDatas[i].mTexLayerSet->getComposite()->isInitialized() + || !mBakedTextureDatas[i].mTexLayerSet->isLocalTextureDataAvailable() ); + + use_lkg_baked_layer[i] = (!is_layer_baked[i] + && (mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR) + && layerset_invalid); + if (use_lkg_baked_layer[i]) + { + mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled(TRUE); + } + } + else + { + use_lkg_baked_layer[i] = (!is_layer_baked[i] + && mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR); + if (mBakedTextureDatas[i].mTexLayerSet) + { + mBakedTextureDatas[i].mTexLayerSet->destroyComposite(); + } + } + + } + + // Turn on alpha masking correctly for yourself and other avatars on 1.23+ + mSupportsAlphaLayers = isSelf() || is_layer_baked[BAKED_HAIR]; + + // Baked textures should be requested from the sim this avatar is on. JC + const LLHost target_host = getObjectHost(); + if (!target_host.isOk()) + { + llwarns << "updateMeshTextures: invalid host for object: " << getID() << llendl; + } + + for (U32 i=0; i < mBakedTextureDatas.size(); i++) + { + if (use_lkg_baked_layer[i] && !self_customizing ) + { + LLViewerFetchedTexture* baked_img = LLViewerTextureManager::getFetchedTextureFromHost( mBakedTextureDatas[i].mLastTextureIndex, target_host ); + mBakedTextureDatas[i].mIsUsed = TRUE; + for (U32 k=0; k < mBakedTextureDatas[i].mMeshes.size(); k++) + { + mBakedTextureDatas[i].mMeshes[k]->setTexture( baked_img ); + } + } + else if (!self_customizing && is_layer_baked[i]) + { + LLViewerFetchedTexture* baked_img = LLViewerTextureManager::staticCastToFetchedTexture(getImage( mBakedTextureDatas[i].mTextureIndex, 0 ), TRUE) ; + if( baked_img->getID() == mBakedTextureDatas[i].mLastTextureIndex ) + { + // Even though the file may not be finished loading, we'll consider it loaded and use it (rather than doing compositing). + useBakedTexture( baked_img->getID() ); + } + else + { + mBakedTextureDatas[i].mIsLoaded = FALSE; + if ( (baked_img->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) ) + { + baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), + src_callback_list, paused); + } + baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ), + src_callback_list, paused ); + } + } + else if (mBakedTextureDatas[i].mTexLayerSet + && !other_culled) + { + mBakedTextureDatas[i].mTexLayerSet->createComposite(); + mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled( TRUE ); + mBakedTextureDatas[i].mIsUsed = FALSE; + for (U32 k=0; k < mBakedTextureDatas[i].mMeshes.size(); k++) + { + mBakedTextureDatas[i].mMeshes[k]->setLayerSet( mBakedTextureDatas[i].mTexLayerSet ); + } + } + } + + // set texture and color of hair manually if we are not using a baked image. + // This can happen while loading hair for yourself, or for clients that did not + // bake a hair texture. Still needed for yourself after 1.22 is depricated. + if (!is_layer_baked[BAKED_HAIR] || self_customizing) + { + const LLColor4 color = mTexHairColor ? mTexHairColor->getColor() : LLColor4(1,1,1,1); + LLViewerTexture* hair_img = getImage( TEX_HAIR, 0 ); + for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++) + { + mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( color.mV[VX], color.mV[VY], color.mV[VZ], color.mV[VW] ); + mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setTexture( hair_img ); + } + } + + + for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); + baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); + ++baked_iter) + { + const EBakedTextureIndex baked_index = baked_iter->first; + const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second; + + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + ++local_tex_iter) + { + const ETextureIndex texture_index = *local_tex_iter; + const BOOL is_baked_ready = (is_layer_baked[baked_index] && mBakedTextureDatas[baked_index].mIsLoaded) || other_culled; + if (isSelf()) + { + setBakedReady(texture_index, is_baked_ready); + } + } + } + removeMissingBakedTextures(); +} + +// virtual +//----------------------------------------------------------------------------- +// setLocalTexture() +//----------------------------------------------------------------------------- +void LLVOAvatar::setLocalTexture( ETextureIndex type, LLViewerTexture* in_tex, BOOL baked_version_ready, U32 index ) +{ + // invalid for anyone but self + llassert(0); +} + +//virtual +void LLVOAvatar::setBakedReady(LLVOAvatarDefines::ETextureIndex type, BOOL baked_version_exists, U32 index) +{ + // invalid for anyone but self + llassert(0); +} + +void LLVOAvatar::addChat(const LLChat& chat) +{ + std::deque::iterator chat_iter; + + mChats.push_back(chat); + + S32 chat_length = 0; + for( chat_iter = mChats.begin(); chat_iter != mChats.end(); ++chat_iter) + { + chat_length += chat_iter->mText.size(); + } + + // remove any excess chat + chat_iter = mChats.begin(); + while ((chat_length > MAX_BUBBLE_CHAT_LENGTH || mChats.size() > MAX_BUBBLE_CHAT_UTTERANCES) && chat_iter != mChats.end()) + { + chat_length -= chat_iter->mText.size(); + mChats.pop_front(); + chat_iter = mChats.begin(); + } + + mChatTimer.reset(); +} + +void LLVOAvatar::clearChat() +{ + mChats.clear(); +} + +// adds a morph mask to the appropriate baked texture structure +void LLVOAvatar::addMaskedMorph(EBakedTextureIndex index, LLPolyMorphTarget* morph_target, BOOL invert, std::string layer) +{ + if (index < BAKED_NUM_INDICES) + { + LLMaskedMorph *morph = new LLMaskedMorph(morph_target, invert, layer); + mBakedTextureDatas[index].mMaskedMorphs.push_front(morph); + } +} + +// returns TRUE if morph masks are present and not valid for a given baked texture, FALSE otherwise +BOOL LLVOAvatar::morphMaskNeedsUpdate(LLVOAvatarDefines::EBakedTextureIndex index) +{ + if (index >= BAKED_NUM_INDICES) + { + return FALSE; + } + + if (!mBakedTextureDatas[index].mMaskedMorphs.empty()) + { + if (isSelf()) + { + LLTexLayerSet *layer_set = mBakedTextureDatas[index].mTexLayerSet; + if (layer_set) + { + return !layer_set->isMorphValid(); + } + } + else + { + return FALSE; + } + } + + return FALSE; +} + +void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLVOAvatarDefines::EBakedTextureIndex index) +{ + if (index >= BAKED_NUM_INDICES) + { + llwarns << "invalid baked texture index passed to applyMorphMask" << llendl; + return; + } + + for (morph_list_t::const_iterator iter = mBakedTextureDatas[index].mMaskedMorphs.begin(); + iter != mBakedTextureDatas[index].mMaskedMorphs.end(); ++iter) + { + const LLMaskedMorph* maskedMorph = (*iter); + maskedMorph->mMorphTarget->applyMask(tex_data, width, height, num_components, maskedMorph->mInvert); + } +} + + +//----------------------------------------------------------------------------- +// releaseComponentTextures() +// release any component texture UUIDs for which we have a baked texture +// ! BACKWARDS COMPATIBILITY ! +// This is only called for non-self avatars, it can be taken out once component +// textures aren't communicated by non-self avatars. +//----------------------------------------------------------------------------- +void LLVOAvatar::releaseComponentTextures() +{ + // ! BACKWARDS COMPATIBILITY ! + // Detect if the baked hair texture actually wasn't sent, and if so set to default + if (isTextureDefined(TEX_HAIR_BAKED) && getImage(TEX_HAIR_BAKED,0)->getID() == getImage(TEX_SKIRT_BAKED,0)->getID()) + { + if (getImage(TEX_HAIR_BAKED,0)->getID() != IMG_INVISIBLE) + { + // Regression case of messaging system. Expected 21 textures, received 20. last texture is not valid so set to default + setTETexture(TEX_HAIR_BAKED, IMG_DEFAULT_AVATAR); + } + } + + for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) + { + const LLVOAvatarDictionary::BakedEntry * bakedDicEntry = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); + // skip if this is a skirt and av is not wearing one, or if we don't have a baked texture UUID + if (!isTextureDefined(bakedDicEntry->mTextureIndex) + && ( (baked_index != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) )) + { + continue; + } + + for (U8 texture = 0; texture < bakedDicEntry->mLocalTextures.size(); texture++) + { + const U8 te = (ETextureIndex)bakedDicEntry->mLocalTextures[texture]; + setTETexture(te, IMG_DEFAULT_AVATAR); + } + } +} + +//static +BOOL LLVOAvatar::teToColorParams( ETextureIndex te, U32 *param_name ) +{ + switch( te ) + { + case TEX_UPPER_SHIRT: + param_name[0] = 803; //"shirt_red"; + param_name[1] = 804; //"shirt_green"; + param_name[2] = 805; //"shirt_blue"; + break; + + case TEX_LOWER_PANTS: + param_name[0] = 806; //"pants_red"; + param_name[1] = 807; //"pants_green"; + param_name[2] = 808; //"pants_blue"; + break; + + case TEX_LOWER_SHOES: + param_name[0] = 812; //"shoes_red"; + param_name[1] = 813; //"shoes_green"; + param_name[2] = 817; //"shoes_blue"; + break; + + case TEX_LOWER_SOCKS: + param_name[0] = 818; //"socks_red"; + param_name[1] = 819; //"socks_green"; + param_name[2] = 820; //"socks_blue"; + break; + + case TEX_UPPER_JACKET: + case TEX_LOWER_JACKET: + param_name[0] = 834; //"jacket_red"; + param_name[1] = 835; //"jacket_green"; + param_name[2] = 836; //"jacket_blue"; + break; + + case TEX_UPPER_GLOVES: + param_name[0] = 827; //"gloves_red"; + param_name[1] = 829; //"gloves_green"; + param_name[2] = 830; //"gloves_blue"; + break; + + case TEX_UPPER_UNDERSHIRT: + param_name[0] = 821; //"undershirt_red"; + param_name[1] = 822; //"undershirt_green"; + param_name[2] = 823; //"undershirt_blue"; + break; + + case TEX_LOWER_UNDERPANTS: + param_name[0] = 824; //"underpants_red"; + param_name[1] = 825; //"underpants_green"; + param_name[2] = 826; //"underpants_blue"; + break; + + case TEX_SKIRT: + param_name[0] = 921; //"skirt_red"; + param_name[1] = 922; //"skirt_green"; + param_name[2] = 923; //"skirt_blue"; + break; + + case TEX_HEAD_TATTOO: + case TEX_LOWER_TATTOO: + case TEX_UPPER_TATTOO: + param_name[0] = 1071; //"tattoo_red"; + param_name[1] = 1072; //"tattoo_green"; + param_name[2] = 1073; //"tattoo_blue"; + break; + + default: + llassert(0); + return FALSE; + } + + return TRUE; +} + +void LLVOAvatar::setClothesColor( ETextureIndex te, const LLColor4& new_color, BOOL upload_bake ) +{ + U32 param_name[3]; + if( teToColorParams( te, param_name ) ) + { + setVisualParamWeight( param_name[0], new_color.mV[VX], upload_bake ); + setVisualParamWeight( param_name[1], new_color.mV[VY], upload_bake ); + setVisualParamWeight( param_name[2], new_color.mV[VZ], upload_bake ); + } +} + +LLColor4 LLVOAvatar::getClothesColor( ETextureIndex te ) +{ + LLColor4 color; + U32 param_name[3]; + if( teToColorParams( te, param_name ) ) + { + color.mV[VX] = getVisualParamWeight( param_name[0] ); + color.mV[VY] = getVisualParamWeight( param_name[1] ); + color.mV[VZ] = getVisualParamWeight( param_name[2] ); + } + return color; +} + +// static +LLColor4 LLVOAvatar::getDummyColor() +{ + return DUMMY_COLOR; +} + +void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const +{ + llinfos << (isSelf() ? "Self: " : "Other: ") << context << llendl; + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + ++iter) + { + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + // TODO: MULTI-WEARABLE: handle multiple textures for self + const LLViewerTexture* te_image = getImage(iter->first,0); + if( !te_image ) + { + llinfos << " " << texture_dict->mName << ": null ptr" << llendl; + } + else if( te_image->getID().isNull() ) + { + llinfos << " " << texture_dict->mName << ": null UUID" << llendl; + } + else if( te_image->getID() == IMG_DEFAULT ) + { + llinfos << " " << texture_dict->mName << ": IMG_DEFAULT" << llendl; + } + else if( te_image->getID() == IMG_DEFAULT_AVATAR ) + { + llinfos << " " << texture_dict->mName << ": IMG_DEFAULT_AVATAR" << llendl; + } + else + { + llinfos << " " << texture_dict->mName << ": " << te_image->getID() << llendl; + } + } +} + +// Unlike most wearable functions, this works for both self and other. +BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const +{ + if (mIsDummy) return TRUE; + + switch(type) + { + case LLWearableType::WT_SHAPE: + case LLWearableType::WT_SKIN: + case LLWearableType::WT_HAIR: + case LLWearableType::WT_EYES: + return TRUE; // everyone has all bodyparts + default: + break; // Do nothing + } + + /* switch(type) + case LLWearableType::WT_SHIRT: + indicator_te = TEX_UPPER_SHIRT; */ + for (LLVOAvatarDictionary::Textures::const_iterator tex_iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + tex_iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + ++tex_iter) + { + const LLVOAvatarDictionary::TextureEntry *texture_dict = tex_iter->second; + if (texture_dict->mWearableType == type) + { + // If you're checking another avatar's clothing, you don't have component textures. + // Thus, you must check to see if the corresponding baked texture is defined. + // NOTE: this is a poor substitute if you actually want to know about individual pieces of clothing + // this works for detecting a skirt (most important), but is ineffective at any piece of clothing that + // gets baked into a texture that always exists (upper or lower). + if (texture_dict->mIsUsedByBakedTexture) + { + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + return isTextureDefined(LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex); + } + return FALSE; + } + } + return FALSE; +} + +//----------------------------------------------------------------------------- +// clampAttachmentPositions() +//----------------------------------------------------------------------------- +void LLVOAvatar::clampAttachmentPositions() +{ + if (isDead()) + { + return; + } + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (attachment) + { + attachment->clampObjectPosition(); + } + } +} + +BOOL LLVOAvatar::hasHUDAttachment() const +{ + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (attachment->getIsHUDAttachment() && attachment->getNumObjects() > 0) + { + return TRUE; + } + } + return FALSE; +} + +LLBBox LLVOAvatar::getHUDBBox() const +{ + LLBBox bbox; + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (attachment->getIsHUDAttachment()) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object == NULL) + { + llwarns << "HUD attached object is NULL!" << llendl; + continue; + } + // initialize bounding box to contain identity orientation and center point for attached object + bbox.addPointLocal(attached_object->getPosition()); + // add rotated bounding box for attached object + bbox.addBBoxAgent(attached_object->getBoundingBoxAgent()); + LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); + ++iter) + { + const LLViewerObject* child_objectp = *iter; + bbox.addBBoxAgent(child_objectp->getBoundingBoxAgent()); + } + } + } + } + + return bbox; +} + +void LLVOAvatar::rebuildHUD() +{ +} + +//----------------------------------------------------------------------------- +// onFirstTEMessageReceived() +//----------------------------------------------------------------------------- +void LLVOAvatar::onFirstTEMessageReceived() +{ + if( !mFirstTEMessageReceived ) + { + mFirstTEMessageReceived = TRUE; + + LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ; + BOOL paused = FALSE ; + if(!isSelf()) + { + src_callback_list = &mCallbackTextureList ; + paused = mLoadedCallbacksPaused ; + } + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + const BOOL layer_baked = isTextureDefined(mBakedTextureDatas[i].mTextureIndex); + + // Use any baked textures that we have even if they haven't downloaded yet. + // (That is, don't do a transition from unbaked to baked.) + if (layer_baked) + { + LLViewerFetchedTexture* image = LLViewerTextureManager::staticCastToFetchedTexture(getImage( mBakedTextureDatas[i].mTextureIndex, 0 ), TRUE) ; + mBakedTextureDatas[i].mLastTextureIndex = image->getID(); + // If we have more than one texture for the other baked layers, we'll want to call this for them too. + if ( (image->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) ) + { + image->setLoadedCallback( onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), + src_callback_list, paused); + } + image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ), + src_callback_list, paused ); + } + } + + mMeshTexturesDirty = TRUE; + gPipeline.markGLRebuild(this); + } +} + +//----------------------------------------------------------------------------- +// bool visualParamWeightsAreDefault() +//----------------------------------------------------------------------------- +bool LLVOAvatar::visualParamWeightsAreDefault() +{ + bool rtn = true; + + bool is_wearing_skirt = isWearingWearableType(LLWearableType::WT_SKIRT); + for (LLVisualParam *param = getFirstVisualParam(); + param; + param = getNextVisualParam()) + { + if (param->isTweakable()) + { + LLViewerVisualParam* vparam = dynamic_cast(param); + llassert(vparam); + bool is_skirt_param = vparam && + LLWearableType::WT_SKIRT == vparam->getWearableType(); + if (param->getWeight() != param->getDefaultWeight() && + // we have to not care whether skirt weights are default, if we're not actually wearing a skirt + (is_wearing_skirt || !is_skirt_param)) + { + //llinfos << "param '" << param->getName() << "'=" << param->getWeight() << " which differs from default=" << param->getDefaultWeight() << llendl; + rtn = false; + break; + } + } + } + + //llinfos << "params are default ? " << int(rtn) << llendl; + + return rtn; +} + + +//----------------------------------------------------------------------------- +// processAvatarAppearance() +//----------------------------------------------------------------------------- +void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) +{ + if (gSavedSettings.getBOOL("BlockAvatarAppearanceMessages")) + { + llwarns << "Blocking AvatarAppearance message" << llendl; + return; + } + + LLMemType mt(LLMemType::MTYPE_AVATAR); + +// llinfos << "processAvatarAppearance start " << mID << llendl; + BOOL is_first_appearance_message = !mFirstAppearanceMessageReceived; + + mFirstAppearanceMessageReceived = TRUE; + + if( isSelf() ) + { + llwarns << "Received AvatarAppearance for self" << llendl; + if( mFirstTEMessageReceived ) + { +// llinfos << "processAvatarAppearance end " << mID << llendl; + return; + } + } + + if (gNoRender) + { + return; + } + + ESex old_sex = getSex(); + +// llinfos << "LLVOAvatar::processAvatarAppearance()" << llendl; +// dumpAvatarTEs( "PRE processAvatarAppearance()" ); + unpackTEMessage(mesgsys, _PREHASH_ObjectData); +// dumpAvatarTEs( "POST processAvatarAppearance()" ); + + // prevent the overwriting of valid baked textures with invalid baked textures + for (U8 baked_index = 0; baked_index < mBakedTextureDatas.size(); baked_index++) + { + if (!isTextureDefined(mBakedTextureDatas[baked_index].mTextureIndex) + && mBakedTextureDatas[baked_index].mLastTextureIndex != IMG_DEFAULT + && baked_index != BAKED_SKIRT) + { + setTEImage(mBakedTextureDatas[baked_index].mTextureIndex, + LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureIndex, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); + } + } + + + if( !is_first_appearance_message ) + { + onFirstTEMessageReceived(); + } + + setCompositeUpdatesEnabled( FALSE ); + mMeshTexturesDirty = TRUE; + gPipeline.markGLRebuild(this); + + // ! BACKWARDS COMPATIBILITY ! + // Non-self avatars will no longer have component textures + if (!isSelf()) + { + releaseComponentTextures(); + } + + // parse visual params + S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam); + bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing + if( num_blocks > 1 && !drop_visual_params_debug) + { + BOOL params_changed = FALSE; + BOOL interp_params = FALSE; + + LLVisualParam* param = getFirstVisualParam(); + llassert(param); // if this ever fires, we should do the same as when num_blocks<=1 + if (!param) + { + llwarns << "No visual params!" << llendl; + } + else + { + for( S32 i = 0; i < num_blocks; i++ ) + { + while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + { + param = getNextVisualParam(); + } + + if( !param ) + { + // more visual params supplied than expected - just process what we know about + break; + } + + U8 value; + mesgsys->getU8Fast(_PREHASH_VisualParam, _PREHASH_ParamValue, value, i); + F32 newWeight = U8_to_F32(value, param->getMinWeight(), param->getMaxWeight()); + + if (is_first_appearance_message || (param->getWeight() != newWeight)) + { + //llinfos << "Received update for param " << param->getDisplayName() << " at value " << newWeight << llendl; + params_changed = TRUE; + if(is_first_appearance_message) + { + param->setWeight(newWeight, FALSE); + } + else + { + interp_params = TRUE; + param->setAnimationTarget(newWeight, FALSE); + } + } + param = getNextVisualParam(); + } + } + + const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + if (num_blocks != expected_tweakable_count) + { + llinfos << "Number of params in AvatarAppearance msg (" << num_blocks << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << llendl; + } + + if (params_changed) + { + if (interp_params) + { + startAppearanceAnimation(); + } + updateVisualParams(); + + ESex new_sex = getSex(); + if( old_sex != new_sex ) + { + updateSexDependentLayerSets( FALSE ); + } + } + + llassert( getSex() == ((getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE) ); + } + else + { + // AvatarAppearance message arrived without visual params + if (drop_visual_params_debug) + { + llinfos << "Debug-faked lack of parameters on AvatarAppearance for object: " << getID() << llendl; + } + else + { + llinfos << "AvatarAppearance msg received without any parameters, object: " << getID() << llendl; + } + + const F32 LOADING_TIMEOUT_SECONDS = 60.f; + // this isn't really a problem if we already have a non-default shape + if (visualParamWeightsAreDefault() && mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT_SECONDS) + { + // re-request appearance, hoping that it comes back with a shape next time + llinfos << "Re-requesting AvatarAppearance for object: " << getID() << llendl; + LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); + mRuthTimer.reset(); + } + else + { + llinfos << "That's okay, we already have a non-default shape for object: " << getID() << llendl; + // we don't really care. + } + } + + setCompositeUpdatesEnabled( TRUE ); + + // If all of the avatars are completely baked, release the global image caches to conserve memory. + LLVOAvatar::cullAvatarsByPixelArea(); + +// llinfos << "processAvatarAppearance end " << mID << llendl; +} + +// static +void LLVOAvatar::getAnimLabels( LLDynamicArray* labels ) +{ + S32 i; + for( i = 0; i < gUserAnimStatesCount; i++ ) + { + labels->put( LLAnimStateLabels::getStateLabel( gUserAnimStates[i].mName ) ); + } + + // Special case to trigger away (AFK) state + labels->put( "Away From Keyboard" ); +} + +// static +void LLVOAvatar::getAnimNames( LLDynamicArray* names ) +{ + S32 i; + + for( i = 0; i < gUserAnimStatesCount; i++ ) + { + names->put( std::string(gUserAnimStates[i].mName) ); + } + + // Special case to trigger away (AFK) state + names->put( "enter_away_from_keyboard_state" ); +} + +void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) +{ + if (!userdata) return; + + //llinfos << "onBakedTextureMasksLoaded: " << src_vi->getID() << llendl; + const LLMemType mt(LLMemType::MTYPE_AVATAR); + const LLUUID id = src_vi->getID(); + + LLTextureMaskData* maskData = (LLTextureMaskData*) userdata; + LLVOAvatar* self = (LLVOAvatar*) gObjectList.findObject( maskData->mAvatarID ); + + // if discard level is 2 less than last discard level we processed, or we hit 0, + // then generate morph masks + if(self && success && (discard_level < maskData->mLastDiscardLevel - 2 || discard_level == 0)) + { + if(aux_src && aux_src->getComponents() == 1) + { + if (!aux_src->getData()) + { + llerrs << "No auxiliary source data for onBakedTextureMasksLoaded" << llendl; + return; + } + + U32 gl_name; + LLImageGL::generateTextures(1, &gl_name ); + stop_glerror(); + + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name); + stop_glerror(); + + LLImageGL::setManualImage( + GL_TEXTURE_2D, 0, GL_ALPHA8, + aux_src->getWidth(), aux_src->getHeight(), + GL_ALPHA, GL_UNSIGNED_BYTE, aux_src->getData()); + stop_glerror(); + + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + + /* if( id == head_baked->getID() ) + if (self->mBakedTextureDatas[BAKED_HEAD].mTexLayerSet) + //llinfos << "onBakedTextureMasksLoaded for head " << id << " discard = " << discard_level << llendl; + self->mBakedTextureDatas[BAKED_HEAD].mTexLayerSet->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1); + maskData->mLastDiscardLevel = discard_level; */ + BOOL found_texture_id = false; + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + ++iter) + { + + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + if (texture_dict->mIsUsedByBakedTexture) + { + const ETextureIndex texture_index = iter->first; + const LLViewerTexture *baked_img = self->getImage(texture_index, 0); + if (baked_img && id == baked_img->getID()) + { + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + self->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1, baked_index); + maskData->mLastDiscardLevel = discard_level; + if (self->mBakedTextureDatas[baked_index].mMaskTexName) + { + LLImageGL::deleteTextures(1, &(self->mBakedTextureDatas[baked_index].mMaskTexName)); + } + self->mBakedTextureDatas[baked_index].mMaskTexName = gl_name; + found_texture_id = true; + break; + } + } + } + if (!found_texture_id) + { + llinfos << "onBakedTextureMasksLoaded(): unexpected image id: " << id << llendl; + } + self->dirtyMesh(); + } + else + { + // this can happen when someone uses an old baked texture possibly provided by + // viewer-side baked texture caching + llwarns << "Masks loaded callback but NO aux source!" << llendl; + } + } + + if (final || !success) + { + delete maskData; + } +} + +// static +void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) +{ + LLUUID *avatar_idp = (LLUUID *)userdata; + LLVOAvatar *selfp = (LLVOAvatar *)gObjectList.findObject(*avatar_idp); + + if (!success && selfp) + { + selfp->removeMissingBakedTextures(); + } + if (final || !success ) + { + delete avatar_idp; + } +} + +void LLVOAvatar::onBakedTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) +{ + //llinfos << "onBakedTextureLoaded: " << src_vi->getID() << llendl; + + LLUUID id = src_vi->getID(); + LLUUID *avatar_idp = (LLUUID *)userdata; + LLVOAvatar *selfp = (LLVOAvatar *)gObjectList.findObject(*avatar_idp); + + if (selfp && !success) + { + selfp->removeMissingBakedTextures(); + } + + if( final || !success ) + { + delete avatar_idp; + } + + if( selfp && success && final ) + { + selfp->useBakedTexture( id ); + } +} + + +// Called when baked texture is loaded and also when we start up with a baked texture +void LLVOAvatar::useBakedTexture( const LLUUID& id ) +{ + /* if(id == head_baked->getID()) + mHeadBakedLoaded = TRUE; + mLastHeadBakedID = id; + mHeadMesh0.setTexture( head_baked ); + mHeadMesh1.setTexture( head_baked ); */ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + LLViewerTexture* image_baked = getImage( mBakedTextureDatas[i].mTextureIndex, 0 ); + if (id == image_baked->getID()) + { + mBakedTextureDatas[i].mIsLoaded = true; + mBakedTextureDatas[i].mLastTextureIndex = id; + mBakedTextureDatas[i].mIsUsed = true; + for (U32 k = 0; k < mBakedTextureDatas[i].mMeshes.size(); k++) + { + mBakedTextureDatas[i].mMeshes[k]->setTexture( image_baked ); + } + if (mBakedTextureDatas[i].mTexLayerSet) + { + //mBakedTextureDatas[i].mTexLayerSet->destroyComposite(); + } + const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + ++local_tex_iter) + { + if (isSelf()) setBakedReady(*local_tex_iter, TRUE); + } + + // ! BACKWARDS COMPATIBILITY ! + // Workaround for viewing avatars from old viewers that haven't baked hair textures. + // This is paired with similar code in updateMeshTextures that sets hair mesh color. + if (i == BAKED_HAIR) + { + for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++) + { + mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( 1.f, 1.f, 1.f, 1.f ); + } + } + } + } + + dirtyMesh(); +} + +// static +void LLVOAvatar::dumpArchetypeXML( void* ) +{ + LLAPRFile outfile; + outfile.open(gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,"new archetype.xml"), LL_APR_WB ); + apr_file_t* file = outfile.getFileHandle() ; + if (!file) + { + return; + } + + apr_file_printf( file, "\n" ); + apr_file_printf( file, "\n" ); + apr_file_printf( file, "\n\t\n" ); + + // only body parts, not clothing. + for (S32 type = LLWearableType::WT_SHAPE; type <= LLWearableType::WT_EYES; type++) + { + const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type); + apr_file_printf( file, "\n\t\t\n", wearable_name.c_str() ); + + for (LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->getNextVisualParam()) + { + LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param; + if( (viewer_param->getWearableType() == type) && + (viewer_param->isTweakable() ) ) + { + apr_file_printf(file, "\t\t\n", + viewer_param->getID(), viewer_param->getName().c_str(), viewer_param->getWeight()); + } + } + + for (U8 te = 0; te < TEX_NUM_INDICES; te++) + { + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex)te) == type) + { + // MULTIPLE_WEARABLES: extend to multiple wearables? + LLViewerTexture* te_image = ((LLVOAvatar *)(gAgentAvatarp))->getImage((ETextureIndex)te, 0); + if( te_image ) + { + std::string uuid_str; + te_image->getID().toString( uuid_str ); + apr_file_printf( file, "\t\t\n", te, uuid_str.c_str()); + } + } + } + } + apr_file_printf( file, "\t\n" ); + apr_file_printf( file, "\n\n" ); +} + + +void LLVOAvatar::setVisibilityRank(U32 rank) +{ + if (mDrawable.isNull() || mDrawable->isDead()) + { + // do nothing + return; + } + mVisibilityRank = rank; +} + +// Assumes LLVOAvatar::sInstances has already been sorted. +S32 LLVOAvatar::getUnbakedPixelAreaRank() +{ + S32 rank = 1; + for (std::vector::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { + LLVOAvatar* inst = (LLVOAvatar*) *iter; + if (inst == this) + { + return rank; + } + else if (!inst->isDead() && !inst->isFullyBaked()) + { + rank++; + } + } + + llassert(0); + return 0; +} + +struct CompareScreenAreaGreater +{ + BOOL operator()(const LLCharacter* const& lhs, const LLCharacter* const& rhs) + { + return lhs->getPixelArea() > rhs->getPixelArea(); + } +}; + +// static +void LLVOAvatar::cullAvatarsByPixelArea() +{ + std::sort(LLCharacter::sInstances.begin(), LLCharacter::sInstances.end(), CompareScreenAreaGreater()); + + // Update the avatars that have changed status + U32 rank = 2; //1 is reserved for self. + for (std::vector::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { + LLVOAvatar* inst = (LLVOAvatar*) *iter; + BOOL culled; + if (inst->isSelf() || inst->isFullyBaked()) + { + culled = FALSE; + } + else + { + culled = TRUE; + } + + if (inst->mCulled != culled) + { + inst->mCulled = culled; + lldebugs << "avatar " << inst->getID() << (culled ? " start culled" : " start not culled" ) << llendl; + inst->updateMeshTextures(); + } + + if (inst->isSelf()) + { + inst->setVisibilityRank(1); + } + else if (inst->mDrawable.notNull() && inst->mDrawable->isVisible()) + { + inst->setVisibilityRank(rank++); + } + } + + S32 grey_avatars = 0; + if (LLVOAvatar::areAllNearbyInstancesBaked(grey_avatars)) + { + LLVOAvatar::deleteCachedImages(false); + } + else + { + if (gFrameTimeSeconds != sUnbakedUpdateTime) // only update once per frame + { + sUnbakedUpdateTime = gFrameTimeSeconds; + sUnbakedTime += gFrameIntervalSeconds; + } + if (grey_avatars > 0) + { + if (gFrameTimeSeconds != sGreyUpdateTime) // only update once per frame + { + sGreyUpdateTime = gFrameTimeSeconds; + sGreyTime += gFrameIntervalSeconds; + } + } + } +} + +void LLVOAvatar::startAppearanceAnimation() +{ + if(!mAppearanceAnimating) + { + mAppearanceAnimating = TRUE; + mAppearanceMorphTimer.reset(); + mLastAppearanceBlendTime = 0.f; + } +} + +// virtual +void LLVOAvatar::removeMissingBakedTextures() +{ +} + +//----------------------------------------------------------------------------- +// LLVOAvatarXmlInfo +//----------------------------------------------------------------------------- + +LLVOAvatar::LLVOAvatarXmlInfo::LLVOAvatarXmlInfo() + : mTexSkinColorInfo(0), mTexHairColorInfo(0), mTexEyeColorInfo(0) +{ +} + +LLVOAvatar::LLVOAvatarXmlInfo::~LLVOAvatarXmlInfo() +{ + std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer()); + std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer()); + std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer()); + deleteAndClear(mTexSkinColorInfo); + deleteAndClear(mTexHairColorInfo); + deleteAndClear(mTexEyeColorInfo); + std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer()); + std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer()); + std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer()); +} + +//----------------------------------------------------------------------------- +// LLVOAvatarBoneInfo::parseXml() +//----------------------------------------------------------------------------- +BOOL LLVOAvatarBoneInfo::parseXml(LLXmlTreeNode* node) +{ + if (node->hasName("bone")) + { + mIsJoint = TRUE; + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if (!node->getFastAttributeString(name_string, mName)) + { + llwarns << "Bone without name" << llendl; + return FALSE; + } + } + else if (node->hasName("collision_volume")) + { + mIsJoint = FALSE; + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if (!node->getFastAttributeString(name_string, mName)) + { + mName = "Collision Volume"; + } + } + else + { + llwarns << "Invalid node " << node->getName() << llendl; + return FALSE; + } + + static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos"); + if (!node->getFastAttributeVector3(pos_string, mPos)) + { + llwarns << "Bone without position" << llendl; + return FALSE; + } + + static LLStdStringHandle rot_string = LLXmlTree::addAttributeString("rot"); + if (!node->getFastAttributeVector3(rot_string, mRot)) + { + llwarns << "Bone without rotation" << llendl; + return FALSE; + } + + static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale"); + if (!node->getFastAttributeVector3(scale_string, mScale)) + { + llwarns << "Bone without scale" << llendl; + return FALSE; + } + + if (mIsJoint) + { + static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot"); + if (!node->getFastAttributeVector3(pivot_string, mPivot)) + { + llwarns << "Bone without pivot" << llendl; + return FALSE; + } + } + + // parse children + LLXmlTreeNode* child; + for( child = node->getFirstChild(); child; child = node->getNextChild() ) + { + LLVOAvatarBoneInfo *child_info = new LLVOAvatarBoneInfo; + if (!child_info->parseXml(child)) + { + delete child_info; + return FALSE; + } + mChildList.push_back(child_info); + } + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLVOAvatarSkeletonInfo::parseXml() +//----------------------------------------------------------------------------- +BOOL LLVOAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node) +{ + static LLStdStringHandle num_bones_string = LLXmlTree::addAttributeString("num_bones"); + if (!node->getFastAttributeS32(num_bones_string, mNumBones)) + { + llwarns << "Couldn't find number of bones." << llendl; + return FALSE; + } + + static LLStdStringHandle num_collision_volumes_string = LLXmlTree::addAttributeString("num_collision_volumes"); + node->getFastAttributeS32(num_collision_volumes_string, mNumCollisionVolumes); + + LLXmlTreeNode* child; + for( child = node->getFirstChild(); child; child = node->getNextChild() ) + { + LLVOAvatarBoneInfo *info = new LLVOAvatarBoneInfo; + if (!info->parseXml(child)) + { + delete info; + llwarns << "Error parsing bone in skeleton file" << llendl; + return FALSE; + } + mBoneInfoList.push_back(info); + } + return TRUE; +} + +//----------------------------------------------------------------------------- +// parseXmlSkeletonNode(): parses nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* root) +{ + LLXmlTreeNode* node = root->getChildByName( "skeleton" ); + if( !node ) + { + llwarns << "avatar file: missing " << llendl; + return FALSE; + } + + LLXmlTreeNode* child; + + // SKELETON DISTORTIONS + for (child = node->getChildByName( "param" ); + child; + child = node->getNextNamedChild()) + { + if (!child->getChildByName("param_skeleton")) + { + if (child->getChildByName("param_morph")) + { + llwarns << "Can't specify morph param in skeleton definition." << llendl; + } + else + { + llwarns << "Unknown param type." << llendl; + } + continue; + } + + LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo; + if (!info->parseXml(child)) + { + delete info; + return FALSE; + } + + mSkeletalDistortionInfoList.push_back(info); + } + + // ATTACHMENT POINTS + for (child = node->getChildByName( "attachment_point" ); + child; + child = node->getNextNamedChild()) + { + LLVOAvatarAttachmentInfo* info = new LLVOAvatarAttachmentInfo(); + + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if (!child->getFastAttributeString(name_string, info->mName)) + { + llwarns << "No name supplied for attachment point." << llendl; + delete info; + continue; + } + + static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint"); + if (!child->getFastAttributeString(joint_string, info->mJointName)) + { + llwarns << "No bone declared in attachment point " << info->mName << llendl; + delete info; + continue; + } + + static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position"); + if (child->getFastAttributeVector3(position_string, info->mPosition)) + { + info->mHasPosition = TRUE; + } + + static LLStdStringHandle rotation_string = LLXmlTree::addAttributeString("rotation"); + if (child->getFastAttributeVector3(rotation_string, info->mRotationEuler)) + { + info->mHasRotation = TRUE; + } + static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group"); + if (child->getFastAttributeS32(group_string, info->mGroup)) + { + if (info->mGroup == -1) + info->mGroup = -1111; // -1 = none parsed, < -1 = bad value + } + + static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id"); + if (!child->getFastAttributeS32(id_string, info->mAttachmentID)) + { + llwarns << "No id supplied for attachment point " << info->mName << llendl; + delete info; + continue; + } + + static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice"); + child->getFastAttributeS32(slot_string, info->mPieMenuSlice); + + static LLStdStringHandle visible_in_first_person_string = LLXmlTree::addAttributeString("visible_in_first_person"); + child->getFastAttributeBOOL(visible_in_first_person_string, info->mVisibleFirstPerson); + + static LLStdStringHandle hud_attachment_string = LLXmlTree::addAttributeString("hud"); + child->getFastAttributeBOOL(hud_attachment_string, info->mIsHUDAttachment); + + mAttachmentInfoList.push_back(info); + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// parseXmlMeshNodes(): parses nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root) +{ + for (LLXmlTreeNode* node = root->getChildByName( "mesh" ); + node; + node = root->getNextNamedChild()) + { + LLVOAvatarMeshInfo *info = new LLVOAvatarMeshInfo; + + // attribute: type + static LLStdStringHandle type_string = LLXmlTree::addAttributeString("type"); + if( !node->getFastAttributeString( type_string, info->mType ) ) + { + llwarns << "Avatar file: is missing type attribute. Ignoring element. " << llendl; + delete info; + return FALSE; // Ignore this element + } + + static LLStdStringHandle lod_string = LLXmlTree::addAttributeString("lod"); + if (!node->getFastAttributeS32( lod_string, info->mLOD )) + { + llwarns << "Avatar file: is missing lod attribute. Ignoring element. " << llendl; + delete info; + return FALSE; // Ignore this element + } + + static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name"); + if( !node->getFastAttributeString( file_name_string, info->mMeshFileName ) ) + { + llwarns << "Avatar file: is missing file_name attribute. Ignoring: " << info->mType << llendl; + delete info; + return FALSE; // Ignore this element + } + + static LLStdStringHandle reference_string = LLXmlTree::addAttributeString("reference"); + node->getFastAttributeString( reference_string, info->mReferenceMeshName ); + + // attribute: min_pixel_area + static LLStdStringHandle min_pixel_area_string = LLXmlTree::addAttributeString("min_pixel_area"); + static LLStdStringHandle min_pixel_width_string = LLXmlTree::addAttributeString("min_pixel_width"); + if (!node->getFastAttributeF32( min_pixel_area_string, info->mMinPixelArea )) + { + F32 min_pixel_area = 0.1f; + if (node->getFastAttributeF32( min_pixel_width_string, min_pixel_area )) + { + // this is square root of pixel area (sensible to use linear space in defining lods) + min_pixel_area = min_pixel_area * min_pixel_area; + } + info->mMinPixelArea = min_pixel_area; + } + + // Parse visual params for this node only if we haven't already + for (LLXmlTreeNode* child = node->getChildByName( "param" ); + child; + child = node->getNextNamedChild()) + { + if (!child->getChildByName("param_morph")) + { + if (child->getChildByName("param_skeleton")) + { + llwarns << "Can't specify skeleton param in a mesh definition." << llendl; + } + else + { + llwarns << "Unknown param type." << llendl; + } + continue; + } + + LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo(); + if (!morphinfo->parseXml(child)) + { + delete morphinfo; + delete info; + return -1; + } + BOOL shared = FALSE; + static LLStdStringHandle shared_string = LLXmlTree::addAttributeString("shared"); + child->getFastAttributeBOOL(shared_string, shared); + + info->mPolyMorphTargetInfoList.push_back(LLVOAvatarMeshInfo::morph_info_pair_t(morphinfo, shared)); + } + + mMeshInfoList.push_back(info); + } + return TRUE; +} + +//----------------------------------------------------------------------------- +// parseXmlColorNodes(): parses nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root) +{ + for (LLXmlTreeNode* color_node = root->getChildByName( "global_color" ); + color_node; + color_node = root->getNextNamedChild()) + { + std::string global_color_name; + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if (color_node->getFastAttributeString( name_string, global_color_name ) ) + { + if( global_color_name == "skin_color" ) + { + if (mTexSkinColorInfo) + { + llwarns << "avatar file: multiple instances of skin_color" << llendl; + return FALSE; + } + mTexSkinColorInfo = new LLTexGlobalColorInfo; + if( !mTexSkinColorInfo->parseXml( color_node ) ) + { + deleteAndClear(mTexSkinColorInfo); + llwarns << "avatar file: mTexSkinColor->parseXml() failed" << llendl; + return FALSE; + } + } + else if( global_color_name == "hair_color" ) + { + if (mTexHairColorInfo) + { + llwarns << "avatar file: multiple instances of hair_color" << llendl; + return FALSE; + } + mTexHairColorInfo = new LLTexGlobalColorInfo; + if( !mTexHairColorInfo->parseXml( color_node ) ) + { + deleteAndClear(mTexHairColorInfo); + llwarns << "avatar file: mTexHairColor->parseXml() failed" << llendl; + return FALSE; + } + } + else if( global_color_name == "eye_color" ) + { + if (mTexEyeColorInfo) + { + llwarns << "avatar file: multiple instances of eye_color" << llendl; + return FALSE; + } + mTexEyeColorInfo = new LLTexGlobalColorInfo; + if( !mTexEyeColorInfo->parseXml( color_node ) ) + { + llwarns << "avatar file: mTexEyeColor->parseXml() failed" << llendl; + return FALSE; + } + } + } + } + return TRUE; +} + +//----------------------------------------------------------------------------- +// parseXmlLayerNodes(): parses nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root) +{ + for (LLXmlTreeNode* layer_node = root->getChildByName( "layer_set" ); + layer_node; + layer_node = root->getNextNamedChild()) + { + LLTexLayerSetInfo* layer_info = new LLTexLayerSetInfo(); + if( layer_info->parseXml( layer_node ) ) + { + mLayerInfoList.push_back(layer_info); + } + else + { + delete layer_info; + llwarns << "avatar file: layer_set->parseXml() failed" << llendl; + return FALSE; + } + } + return TRUE; +} + +//----------------------------------------------------------------------------- +// parseXmlDriverNodes(): parses nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root) +{ + LLXmlTreeNode* driver = root->getChildByName( "driver_parameters" ); + if( driver ) + { + for (LLXmlTreeNode* grand_child = driver->getChildByName( "param" ); + grand_child; + grand_child = driver->getNextNamedChild()) + { + if( grand_child->getChildByName( "param_driver" ) ) + { + LLDriverParamInfo* driver_info = new LLDriverParamInfo(); + if( driver_info->parseXml( grand_child ) ) + { + mDriverInfoList.push_back(driver_info); + } + else + { + delete driver_info; + llwarns << "avatar file: driver_param->parseXml() failed" << llendl; + return FALSE; + } + } + } + } + return TRUE; +} + +//----------------------------------------------------------------------------- +// parseXmlDriverNodes(): parses nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root) +{ + LLXmlTreeNode* masks = root->getChildByName( "morph_masks" ); + if( !masks ) + { + return FALSE; + } + + for (LLXmlTreeNode* grand_child = masks->getChildByName( "mask" ); + grand_child; + grand_child = masks->getNextNamedChild()) + { + LLVOAvatarMorphInfo* info = new LLVOAvatarMorphInfo(); + + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("morph_name"); + if (!grand_child->getFastAttributeString(name_string, info->mName)) + { + llwarns << "No name supplied for morph mask." << llendl; + delete info; + continue; + } + + static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region"); + if (!grand_child->getFastAttributeString(region_string, info->mRegion)) + { + llwarns << "No region supplied for morph mask." << llendl; + delete info; + continue; + } + + static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer"); + if (!grand_child->getFastAttributeString(layer_string, info->mLayer)) + { + llwarns << "No layer supplied for morph mask." << llendl; + delete info; + continue; + } + + // optional parameter. don't throw a warning if not present. + static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert"); + grand_child->getFastAttributeBOOL(invert_string, info->mInvert); + + mMorphMaskInfoList.push_back(info); + } + + return TRUE; +} + +//virtual +void LLVOAvatar::updateRegion(LLViewerRegion *regionp) +{ + LLViewerObject::updateRegion(regionp); +} + +std::string LLVOAvatar::getFullname() const +{ + std::string name; + + LLNameValue* first = getNVPair("FirstName"); + LLNameValue* last = getNVPair("LastName"); + if (first && last) + { + name = LLCacheName::buildFullName( first->getString(), last->getString() ); + } + + return name; +} + +LLHost LLVOAvatar::getObjectHost() const +{ + LLViewerRegion* region = getRegion(); + if (region && !isDead()) + { + return region->getHost(); + } + else + { + return LLHost::invalid; + } +} + +//static +void LLVOAvatar::updateFreezeCounter(S32 counter) +{ + if(counter) + { + sFreezeCounter = counter; + } + else if(sFreezeCounter > 0) + { + sFreezeCounter--; + } + else + { + sFreezeCounter = 0; + } +} + +BOOL LLVOAvatar::updateLOD() +{ + if (isImpostor()) + { + return TRUE; + } + + BOOL res = updateJointLODs(); + + LLFace* facep = mDrawable->getFace(0); + if (facep->mVertexBuffer.isNull()) + { + dirtyMesh(2); + } + + if (mDirtyMesh >= 2 || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY)) + { //LOD changed or new mesh created, allocate new vertex buffer if needed + updateMeshData(); + mDirtyMesh = 0; + mNeedsSkin = TRUE; + mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY); + } + updateVisibility(); + + return res; +} + +void LLVOAvatar::updateLODRiggedAttachments( void ) +{ + updateLOD(); + rebuildRiggedAttachments(); +} +U32 LLVOAvatar::getPartitionType() const +{ + // Avatars merely exist as drawables in the bridge partition + return LLViewerRegion::PARTITION_BRIDGE; +} + +//static +void LLVOAvatar::updateImpostors() +{ + for (std::vector::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { + LLVOAvatar* avatar = (LLVOAvatar*) *iter; + if (!avatar->isDead() && avatar->needsImpostorUpdate() && avatar->isVisible() && avatar->isImpostor()) + { + gPipeline.generateImpostor(avatar); + } + } +} + +BOOL LLVOAvatar::isImpostor() const +{ + return (sUseImpostors && mUpdatePeriod >= IMPOSTOR_PERIOD) ? TRUE : FALSE; +} + + +BOOL LLVOAvatar::needsImpostorUpdate() const +{ + return mNeedsImpostorUpdate; +} + +const LLVector3& LLVOAvatar::getImpostorOffset() const +{ + return mImpostorOffset; +} + +const LLVector2& LLVOAvatar::getImpostorDim() const +{ + return mImpostorDim; +} + +void LLVOAvatar::setImpostorDim(const LLVector2& dim) +{ + mImpostorDim = dim; +} + +void LLVOAvatar::cacheImpostorValues() +{ + getImpostorValues(mImpostorExtents, mImpostorAngle, mImpostorDistance); +} + +void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& distance) const +{ + const LLVector4a* ext = mDrawable->getSpatialExtents(); + extents[0] = ext[0]; + extents[1] = ext[1]; + + LLVector3 at = LLViewerCamera::getInstance()->getOrigin()-(getRenderPosition()+mImpostorOffset); + distance = at.normalize(); + F32 da = 1.f - (at*LLViewerCamera::getInstance()->getAtAxis()); + angle.mV[0] = LLViewerCamera::getInstance()->getYaw()*da; + angle.mV[1] = LLViewerCamera::getInstance()->getPitch()*da; + angle.mV[2] = da; +} + +void LLVOAvatar::idleUpdateRenderCost() +{ + static const U32 ARC_BODY_PART_COST = 20; + static const U32 ARC_LIMIT = 2048; + + static std::set all_textures; + + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME)) + { + return; + } + + U32 cost = 0; + std::set textures; + + for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) + { + const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); + ETextureIndex tex_index = baked_dict->mTextureIndex; + if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT))) + { + if (isTextureVisible(tex_index)) + { + cost +=ARC_BODY_PART_COST; + } + } + } + + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object && !attached_object->isHUDAttachment()) + { + const LLDrawable* drawable = attached_object->mDrawable; + if (drawable) + { + const LLVOVolume* volume = drawable->getVOVolume(); + if (volume) + { + cost += volume->getRenderCost(textures); + } + } + } + } + + } + + // Diagnostic output to identify all avatar-related textures. + // Does not affect rendering cost calculation. + // Could be wrapped in a debug option if output becomes problematic. + if (isSelf()) + { + // print any attachment textures we didn't already know about. + for (std::set::iterator it = textures.begin(); it != textures.end(); ++it) + { + LLUUID image_id = *it; + if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) + continue; + if (all_textures.find(image_id) == all_textures.end()) + { + // attachment texture not previously seen. + llinfos << "attachment_texture: " << image_id.asString() << llendl; + all_textures.insert(image_id); + } + } + + // print any avatar textures we didn't already know about + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + ++iter) + { + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + // TODO: MULTI-WEARABLE: handle multiple textures for self + const LLViewerTexture* te_image = getImage(iter->first,0); + if (!te_image) + continue; + LLUUID image_id = te_image->getID(); + if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) + continue; + if (all_textures.find(image_id) == all_textures.end()) + { + llinfos << "local_texture: " << texture_dict->mName << ": " << image_id << llendl; + all_textures.insert(image_id); + } + } + } + + cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST; + + setDebugText(llformat("%d", cost)); + F32 green = 1.f-llclamp(((F32) cost-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f); + F32 red = llmin((F32) cost/(F32)ARC_LIMIT, 1.f); + mText->setColor(LLColor4(red,green,0,1)); +} + +// static +BOOL LLVOAvatar::isIndexLocalTexture(ETextureIndex index) +{ + if (index < 0 || index >= TEX_NUM_INDICES) return false; + return LLVOAvatarDictionary::getInstance()->getTexture(index)->mIsLocalTexture; +} + +// static +BOOL LLVOAvatar::isIndexBakedTexture(ETextureIndex index) +{ + if (index < 0 || index >= TEX_NUM_INDICES) return false; + return LLVOAvatarDictionary::getInstance()->getTexture(index)->mIsBakedTexture; +} + +const std::string LLVOAvatar::getBakedStatusForPrintout() const +{ + std::string line; + + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + ++iter) + { + const ETextureIndex index = iter->first; + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + if (texture_dict->mIsBakedTexture) + { + line += texture_dict->mName; + if (isTextureDefined(index)) + { + line += "_baked"; + } + line += " "; + } + } + return line; +} + + + +//virtual +S32 LLVOAvatar::getTexImageSize() const +{ + return TEX_IMAGE_SIZE_OTHER; +} + +//----------------------------------------------------------------------------- +// Utility functions +//----------------------------------------------------------------------------- + +F32 calc_bouncy_animation(F32 x) +{ + return -(cosf(x * F_PI * 2.5f - F_PI_BY_TWO))*(0.4f + x * -0.1f) + x * 1.3f; +} + +//virtual +BOOL LLVOAvatar::isTextureDefined(LLVOAvatarDefines::ETextureIndex te, U32 index ) const +{ + if (isIndexLocalTexture(te)) + { + return FALSE; + } + + return (getImage(te, index)->getID() != IMG_DEFAULT_AVATAR && + getImage(te, index)->getID() != IMG_DEFAULT); +} + +//virtual +BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index) const +{ + if (isIndexLocalTexture(type)) + { + return isTextureDefined(type, index); + } + else + { + // baked textures can use TE images directly + return ((isTextureDefined(type) || isSelf()) + && (getTEImage(type)->getID() != IMG_INVISIBLE + || LLDrawPoolAlpha::sShowDebugAlpha)); + } +} + +//virtual +BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const +{ + // non-self avatars don't have wearables + return FALSE; +} + -- cgit v1.2.3 From 79e8ef7f5133225cc77a751a0909c446a4e14605 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Wed, 16 Feb 2011 14:45:41 -0800 Subject: SH-957 Turning off Atmospheric Shaders greys out Lighting and Shadows options in preferences but does not turn off shadows inworld --- indra/newview/llviewermenu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index cfcce3e7bb..37aa080228 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -2069,7 +2069,7 @@ class LLAdvancedEnableRenderDeferred: public view_listener_t { bool handleEvent(const LLSD& userdata) { - bool new_value = gGLManager.mHasFramebufferObject && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT > 0) && + bool new_value = gGLManager.mHasFramebufferObject && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1 && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0; return new_value; } @@ -2082,7 +2082,7 @@ class LLAdvancedEnableRenderDeferredOptions: public view_listener_t { bool handleEvent(const LLSD& userdata) { - bool new_value = gGLManager.mHasFramebufferObject && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT > 0) && + bool new_value = gGLManager.mHasFramebufferObject && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1 && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0 && gSavedSettings.getBOOL("RenderDeferred"); return new_value; } -- cgit v1.2.3 From fcde7004475089985822867fa1ebd64202a3154d Mon Sep 17 00:00:00 2001 From: prep Date: Wed, 16 Feb 2011 17:55:02 -0500 Subject: Fix for problem with pelvis offset --- indra/newview/llvoavatar.cpp | 58 ++++++++++++++++++++++++-------------------- indra/newview/llvoavatar.h | 3 ++- indra/newview/llvovolume.cpp | 13 ++++------ 3 files changed, 39 insertions(+), 35 deletions(-) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index b1a5ea0fd6..439584c7e8 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -760,6 +760,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mRuthDebugTimer.reset(); mDebugExistenceTimer.reset(); mPelvisOffset = LLVector3(0.0f,0.0f,0.0f); + mLastPelvisToFoot = 0.0f; } //------------------------------------------------------------------------ @@ -1331,7 +1332,20 @@ const LLVector3 LLVOAvatar::getRenderPosition() const } else if (isRoot()) { - return mDrawable->getPositionAgent(); + if ( mHasPelvisOffset ) + { + LLVector3 returnVec( mDrawable->getPositionAgent() ); + //1. Move the pelvis down by the old amount + returnVec[VZ] -= (mLastPelvisToFoot); + //2. Now move the pelvis up by the new amount + returnVec[VZ] += mPelvisToFoot; + //3. Return the fixed up pelvis position + return returnVec; + } + else + { + return mDrawable->getPositionAgent(); + } } else { @@ -3454,20 +3468,13 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) if (isSelf()) { - if ( !mHasPelvisOffset ) - { - gAgent.setPositionAgent(getRenderPosition()); - } - else - { - gAgent.setPositionAgent( getRenderPosition() + mPelvisOffset ); - } + gAgent.setPositionAgent(getRenderPosition()); } root_pos = gAgent.getPosGlobalFromAgent(getRenderPosition()); resolveHeightGlobal(root_pos, ground_under_pelvis, normal); - F32 foot_to_ground = (F32) (root_pos.mdV[VZ] - mPelvisToFoot - ground_under_pelvis.mdV[VZ]); + F32 foot_to_ground = (F32) (root_pos.mdV[VZ] - mPelvisToFoot - ground_under_pelvis.mdV[VZ]); BOOL in_air = ((!LLWorld::getInstance()->getRegionFromPosGlobal(ground_under_pelvis)) || foot_to_ground > FOOT_GROUND_COLLISION_TOLERANCE); @@ -3479,22 +3486,21 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) // correct for the fact that the pelvis is not necessarily the center // of the agent's physical representation - root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot; - + if ( !mHasPelvisOffset ) + { + root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot; + } + else + { + root_pos.mdV[VZ] -= (0.65f * mBodySize.mV[VZ]) - mPelvisToFoot; + } + LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos); if (newPosition != mRoot.getXform()->getWorldPosition()) { - if ( !mHasPelvisOffset ) - { - mRoot.touch(); - mRoot.setWorldPosition( newPosition ); // regular update - } - else - { - mRoot.touch(); - mRoot.setWorldPosition( newPosition + mPelvisOffset ); - } + mRoot.touch(); + mRoot.setWorldPosition( newPosition ); // regular update } @@ -3770,7 +3776,6 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) return TRUE; } - //----------------------------------------------------------------------------- // updateHeadOffset() //----------------------------------------------------------------------------- @@ -3803,6 +3808,7 @@ void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount mHasPelvisOffset = hasOffset; if ( mHasPelvisOffset ) { + mLastPelvisToFoot = mPelvisToFoot; mPelvisOffset = offsetAmount; } } @@ -3810,9 +3816,10 @@ void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount // postPelvisSetRecalc //------------------------------------------------------------------------ void LLVOAvatar::postPelvisSetRecalc( void ) -{ +{ computeBodySize(); - mRoot.updateWorldMatrixChildren(); + mRoot.touch(); + mRoot.updateWorldMatrixChildren(); dirtyMesh(); updateHeadOffset(); } @@ -4543,7 +4550,6 @@ void LLVOAvatar::resolveRayCollisionAgent(const LLVector3d start_pt, const LLVec LLWorld::getInstance()->resolveStepHeightGlobal(this, start_pt, end_pt, out_pos, out_norm, &obj); } - void LLVOAvatar::resolveHeightGlobal(const LLVector3d &inPos, LLVector3d &outPos, LLVector3 &outNorm) { LLVector3d zVec(0.0f, 0.0f, 0.5f); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 99d0ed76e5..1152475383 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -298,7 +298,7 @@ public: bool mHasPelvisOffset; LLVector3 mPelvisOffset; - + F32 mLastPelvisToFoot; LLVector3 mHeadOffset; // current head position LLViewerJoint mRoot; @@ -805,6 +805,7 @@ protected: //-------------------------------------------------------------------- public: void resolveHeightGlobal(const LLVector3d &inPos, LLVector3d &outPos, LLVector3 &outNorm); + bool distanceToGround( const LLVector3d &startPoint, LLVector3d &collisionPoint, F32 distToIntersectionAlongRay ); void resolveHeightAgent(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm); void resolveRayCollisionAgent(const LLVector3d start_pt, const LLVector3d end_pt, LLVector3d &out_pos, LLVector3 &out_norm); void slamPosition(); // Slam position to transmitted position (for teleport); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index be987a2310..1b7cd801da 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3919,22 +3919,19 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { pJoint->setId( currentId ); const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation(); - //If joint is a pelvis then handle by setting avPos+offset + //Set the joint position + pJoint->storeCurrentXform( jointPos ); + //If joint is a pelvis then handle old/new pelvis to foot values if ( lookingForJoint == "mPelvis" ) { - //Apply av pos + offset + pJoint->storeCurrentXform( jointPos ); if ( !pAvatarVO->hasPelvisOffset() ) { pAvatarVO->setPelvisOffset( true, jointPos ); //Trigger to rebuild viewer AV pelvisGotSet = true; } - } - else - { - //Straight set for ALL joints except pelvis - pJoint->storeCurrentXform( jointPos ); - } + } } } } -- cgit v1.2.3 From f41f7cb607b57a2ba78412e75e754d96a60a06fc Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Wed, 16 Feb 2011 15:24:11 -0800 Subject: SH-512 [REGRESSION] Linden trees scale up to 200m on Mesh regions SH-943 10 meters maximum Prim/Mesh size in latest Mesh Viewers --- indra/newview/llmanipscale.cpp | 20 +++++++++++--------- indra/newview/llmanipscale.h | 2 +- indra/newview/llpanelobject.cpp | 3 ++- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index d16c4c3bd0..683f455179 100644 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -85,9 +85,11 @@ const LLManip::EManipPart MANIPULATOR_IDS[NUM_MANIPULATORS] = }; -F32 get_default_max_prim_scale() +F32 get_default_max_prim_scale(bool is_flora) { - if (gSavedSettings.getBOOL("MeshEnabled")) + // a bit of a hack, but if it's foilage, we don't want to use the + // new larger scale which would result in giant trees and grass + if (gSavedSettings.getBOOL("MeshEnabled") && !is_flora) { return DEFAULT_MAX_PRIM_SCALE; } @@ -960,9 +962,9 @@ void LLManipScale::dragCorner( S32 x, S32 y ) { mInSnapRegime = FALSE; } - - F32 max_scale_factor = DEFAULT_MAX_PRIM_SCALE_NO_MESH / MIN_PRIM_SCALE; - F32 min_scale_factor = MIN_PRIM_SCALE / DEFAULT_MAX_PRIM_SCALE_NO_MESH; + + F32 max_scale_factor = get_default_max_prim_scale() / MIN_PRIM_SCALE; + F32 min_scale_factor = MIN_PRIM_SCALE / get_default_max_prim_scale(); // find max and min scale factors that will make biggest object hit max absolute scale and smallest object hit min absolute scale for (LLObjectSelection::iterator iter = mObjectSelection->begin(); @@ -974,7 +976,7 @@ void LLManipScale::dragCorner( S32 x, S32 y ) { const LLVector3& scale = selectNode->mSavedScale; - F32 cur_max_scale_factor = llmin( DEFAULT_MAX_PRIM_SCALE_NO_MESH / scale.mV[VX], DEFAULT_MAX_PRIM_SCALE_NO_MESH / scale.mV[VY], DEFAULT_MAX_PRIM_SCALE_NO_MESH / scale.mV[VZ] ); + F32 cur_max_scale_factor = llmin( get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VX], get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VY], get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VZ] ); max_scale_factor = llmin( max_scale_factor, cur_max_scale_factor ); F32 cur_min_scale_factor = llmax( MIN_PRIM_SCALE / scale.mV[VX], MIN_PRIM_SCALE / scale.mV[VY], MIN_PRIM_SCALE / scale.mV[VZ] ); @@ -1271,7 +1273,7 @@ void LLManipScale::stretchFace( const LLVector3& drag_start_agent, const LLVecto F32 denom = axis * dir_local; F32 desired_delta_size = is_approx_zero(denom) ? 0.f : (delta_local_mag / denom); // in meters - F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE_NO_MESH); + F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, get_default_max_prim_scale(LLPickInfo::isFlora(cur))); // propagate scale constraint back to position offset desired_delta_size = desired_scale - selectNode->mSavedScale.mV[axis_index]; // propagate constraint back to position @@ -1971,7 +1973,7 @@ F32 LLManipScale::partToMaxScale( S32 part, const LLBBox &bbox ) const max_extent = bbox_extents.mV[i]; } } - max_scale_factor = bbox_extents.magVec() * DEFAULT_MAX_PRIM_SCALE_NO_MESH / max_extent; + max_scale_factor = bbox_extents.magVec() * get_default_max_prim_scale() / max_extent; if (getUniform()) { @@ -1986,7 +1988,7 @@ F32 LLManipScale::partToMinScale( S32 part, const LLBBox &bbox ) const { LLVector3 bbox_extents = unitVectorToLocalBBoxExtent( partToUnitVector( part ), bbox ); bbox_extents.abs(); - F32 min_extent = DEFAULT_MAX_PRIM_SCALE_NO_MESH; + F32 min_extent = get_default_max_prim_scale(); for (U32 i = VX; i <= VZ; i++) { if (bbox_extents.mV[i] > 0.f && bbox_extents.mV[i] < min_extent) diff --git a/indra/newview/llmanipscale.h b/indra/newview/llmanipscale.h index 2762433abf..5cb8898fd0 100644 --- a/indra/newview/llmanipscale.h +++ b/indra/newview/llmanipscale.h @@ -40,7 +40,7 @@ #include "llbbox.h" -F32 get_default_max_prim_scale(); +F32 get_default_max_prim_scale(bool is_flora = false); class LLToolComposite; class LLColor4; diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 8fa6beb474..42da966b92 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1934,7 +1934,8 @@ void LLPanelObject::refresh() getChildView("Physics Density")->setVisible(enable_mesh); getChildView("Physics Restitution")->setVisible(enable_mesh); - F32 max_scale = DEFAULT_MAX_PRIM_SCALE_NO_MESH; + F32 max_scale = get_default_max_prim_scale(LLPickInfo::isFlora(mObject)); + getChild("Scale X")->setMaxValue(max_scale); getChild("Scale Y")->setMaxValue(max_scale); getChild("Scale Z")->setMaxValue(max_scale); -- cgit v1.2.3 From 800e93110462e1d6b91c09f1efe3164733006fc6 Mon Sep 17 00:00:00 2001 From: prep Date: Thu, 17 Feb 2011 13:01:29 -0500 Subject: Another part of the pelvis fix. Sh-634 --- indra/newview/llvoavatar.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 439584c7e8..b90c136b21 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1332,14 +1332,26 @@ const LLVector3 LLVOAvatar::getRenderPosition() const } else if (isRoot()) { + //Rebase the pelvis position if the avatar contains a pelvis offset if ( mHasPelvisOffset ) { LLVector3 returnVec( mDrawable->getPositionAgent() ); - //1. Move the pelvis down by the old amount - returnVec[VZ] -= (mLastPelvisToFoot); - //2. Now move the pelvis up by the new amount - returnVec[VZ] += mPelvisToFoot; - //3. Return the fixed up pelvis position + if ( mLastPelvisToFoot > mPelvisToFoot ) + { + F32 diff = mLastPelvisToFoot - mPelvisToFoot; + //1. Move the pelvis down by the difference of the old amount and the new pelvis to foot amount + returnVec[VZ] -= (diff); + //2. Now move the pelvis up by the new pelvis to foot amount + returnVec[VZ] += mPelvisToFoot; + } + else + { + //1. Move the pelvis down by the old pelvis to foot amount + returnVec[VZ] -= (mLastPelvisToFoot); + //2. Now move the pelvis up by the new pelvis to foot amount + returnVec[VZ] += mPelvisToFoot; + } + //Return the fixed up pelvis position return returnVec; } else -- cgit v1.2.3 From 019585ed6c761a32b5d06990d7cf55388905113a Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Thu, 17 Feb 2011 13:52:58 -0500 Subject: SH-959 FIX crash in llflexibleobject.cpp Crash was a result of one of two possibilities: 1) trying to update geometry when it wasn't visible 2) mSimulateRes was non-zero when mInitialized was 0 Put code to handle both cases - initialize if mSimulateRes is 0 OR mInitialized is 0 But only do so if the object is visible. If the object is not visible, early out. Code reviewed by davep --- indra/newview/llflexibleobject.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index 689fa72958..bd939d8636 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -366,7 +366,7 @@ void LLVolumeImplFlexible::doFlexibleUpdate() LLFastTimer ftm(FTM_DO_FLEXIBLE_UPDATE); LLVolume* volume = mVO->getVolume(); LLPath *path = &volume->getPath(); - if (mSimulateRes == 0 && mVO->mDrawable->isVisible()) + if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible()) { mVO->markForUpdate(TRUE); if (!doIdleUpdate(gAgent, *LLWorld::getInstance(), 0.0)) @@ -375,6 +375,11 @@ void LLVolumeImplFlexible::doFlexibleUpdate() } } + if (!mVO->mDrawable->isVisible()) + { + return; + } + llassert_always(mInitialized); S32 num_sections = 1 << mSimulateRes; -- cgit v1.2.3 From cd582e3364c012aed3e87d2bd4dfacad761b015c Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 17 Feb 2011 16:06:34 -0600 Subject: SH-547 Use appropriate texture channel for rendering avatars into their impostor map. --- indra/newview/lldrawpoolavatar.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index ae3421a019..fbf39ee91e 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -1030,6 +1030,7 @@ void LLDrawPoolAvatar::beginDeferredSkinned() sVertexProgram->bind(); + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]); gGL.getTexUnit(0)->activate(); @@ -1042,6 +1043,8 @@ void LLDrawPoolAvatar::endDeferredSkinned() disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]); sVertexProgram->unbind(); + sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + sShaderLevel = mVertexShaderLevel; gGL.getTexUnit(0)->activate(); -- cgit v1.2.3 From 9e0ee4dff0109326c31425581437a44351d08344 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 17 Feb 2011 17:18:57 -0600 Subject: SH-1006 Quick pass at cutting down the number of redundant GL calls based on data from gDEBugger. Reviewed by Nyx. --- indra/llmath/m4math.h | 25 ++++ indra/llrender/llglstates.h | 32 ++--- indra/llrender/llrender.cpp | 188 ++++++++++++++++++++++--- indra/llrender/llrender.h | 39 ++++++ indra/llrender/llvertexbuffer.cpp | 2 +- indra/newview/lldrawpoolavatar.cpp | 7 +- indra/newview/lldrawpoolwlsky.cpp | 2 +- indra/newview/llspatialpartition.h | 12 ++ indra/newview/llviewerjointmesh.cpp | 2 +- indra/newview/llvovolume.cpp | 4 + indra/newview/pipeline.cpp | 269 ++++++++++++++++++------------------ 11 files changed, 399 insertions(+), 183 deletions(-) diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h index 10c88464e5..3588f36758 100644 --- a/indra/llmath/m4math.h +++ b/indra/llmath/m4math.h @@ -132,6 +132,7 @@ public: // various useful matrix functions const LLMatrix4& setIdentity(); // Load identity matrix + bool isIdentity() const; const LLMatrix4& setZero(); // Clears matrix to all zeros. const LLMatrix4& initRotation(const F32 angle, const F32 x, const F32 y, const F32 z); // Calculate rotation matrix by rotating angle radians about (x, y, z) @@ -262,6 +263,30 @@ inline const LLMatrix4& LLMatrix4::setIdentity() return (*this); } +inline bool LLMatrix4::isIdentity() const +{ + return + mMatrix[0][0] == 1.f && + mMatrix[0][1] == 0.f && + mMatrix[0][2] == 0.f && + mMatrix[0][3] == 0.f && + + mMatrix[1][0] == 0.f && + mMatrix[1][1] == 1.f && + mMatrix[1][2] == 0.f && + mMatrix[1][3] == 0.f && + + mMatrix[2][0] == 0.f && + mMatrix[2][1] == 0.f && + mMatrix[2][2] == 1.f && + mMatrix[2][3] == 0.f && + + mMatrix[3][0] == 0.f && + mMatrix[3][1] == 0.f && + mMatrix[3][2] == 0.f && + mMatrix[3][3] == 1.f; +} + /* inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b) diff --git a/indra/llrender/llglstates.h b/indra/llrender/llglstates.h index d5a29dcd0c..e26aead676 100644 --- a/indra/llrender/llglstates.h +++ b/indra/llrender/llglstates.h @@ -238,9 +238,11 @@ public: class LLGLSSpecular { public: + F32 mShininess; LLGLSSpecular(const LLColor4& color, F32 shininess) { - if (shininess > 0.0f) + mShininess = shininess; + if (mShininess > 0.0f) { glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color.mV); S32 shiny = (S32)(shininess*128.f); @@ -250,32 +252,14 @@ public: } ~LLGLSSpecular() { - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, LLColor4(0.f,0.f,0.f,0.f).mV); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0); + if (mShininess > 0.f) + { + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, LLColor4(0.f,0.f,0.f,0.f).mV); + glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0); + } } }; //---------------------------------------------------------------------------- - -class LLGLSBlendFunc : public LLGLSPipeline { -protected: - GLint mSavedSrc, mSavedDst; - LLGLEnable mBlend; - -public: - LLGLSBlendFunc(GLenum srcFunc, GLenum dstFunc) : - mBlend(GL_BLEND) - { - glGetIntegerv(GL_BLEND_SRC, &mSavedSrc); - glGetIntegerv(GL_BLEND_DST, &mSavedDst); - glBlendFunc(srcFunc, dstFunc); - } - - ~LLGLSBlendFunc(void) { - glBlendFunc(mSavedSrc, mSavedDst); - } -}; - - #endif diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index fb2d0bc7a7..49e10c4790 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -47,6 +47,7 @@ U32 LLRender::sUICalls = 0; U32 LLRender::sUIVerts = 0; static const U32 LL_NUM_TEXTURE_LAYERS = 16; +static const U32 LL_NUM_LIGHT_UNITS = 8; static GLenum sGLTextureType[] = { @@ -747,6 +748,130 @@ void LLTexUnit::debugTextureUnit(void) } } +LLLightState::LLLightState(S32 index) +: mIndex(index), + mEnabled(false), + mConstantAtten(1.f), + mLinearAtten(0.f), + mQuadraticAtten(0.f), + mSpotExponent(0.f), + mSpotCutoff(180.f) +{ + if (mIndex == 0) + { + mDiffuse.set(1,1,1,1); + mSpecular.set(1,1,1,1); + } + + mAmbient.set(0,0,0,1); + mPosition.set(0,0,1,0); + mSpotDirection.set(0,0,-1); + +} + +void LLLightState::enable() +{ + if (!mEnabled) + { + glEnable(GL_LIGHT0+mIndex); + mEnabled = true; + } +} + +void LLLightState::disable() +{ + if (mEnabled) + { + glDisable(GL_LIGHT0+mIndex); + mEnabled = false; + } +} + +void LLLightState::setDiffuse(const LLColor4& diffuse) +{ + if (mDiffuse != diffuse) + { + mDiffuse = diffuse; + glLightfv(GL_LIGHT0+mIndex, GL_DIFFUSE, mDiffuse.mV); + } +} + +void LLLightState::setAmbient(const LLColor4& ambient) +{ + if (mAmbient != ambient) + { + mAmbient = ambient; + glLightfv(GL_LIGHT0+mIndex, GL_AMBIENT, mAmbient.mV); + } +} + +void LLLightState::setSpecular(const LLColor4& specular) +{ + if (mSpecular != specular) + { + mSpecular = specular; + glLightfv(GL_LIGHT0+mIndex, GL_SPECULAR, mSpecular.mV); + } +} + +void LLLightState::setPosition(const LLVector4& position) +{ + //always set position because modelview matrix may have changed + mPosition = position; + glLightfv(GL_LIGHT0+mIndex, GL_POSITION, mPosition.mV); +} + +void LLLightState::setConstantAttenuation(const F32& atten) +{ + if (mConstantAtten != atten) + { + mConstantAtten = atten; + glLightf(GL_LIGHT0+mIndex, GL_CONSTANT_ATTENUATION, atten); + } +} + +void LLLightState::setLinearAttenuation(const F32& atten) +{ + if (mLinearAtten != atten) + { + mLinearAtten = atten; + glLightf(GL_LIGHT0+mIndex, GL_LINEAR_ATTENUATION, atten); + } +} + +void LLLightState::setQuadraticAttenuation(const F32& atten) +{ + if (mQuadraticAtten != atten) + { + mQuadraticAtten = atten; + glLightf(GL_LIGHT0+mIndex, GL_QUADRATIC_ATTENUATION, atten); + } +} + +void LLLightState::setSpotExponent(const F32& exponent) +{ + if (mSpotExponent != exponent) + { + mSpotExponent = exponent; + glLightf(GL_LIGHT0+mIndex, GL_SPOT_EXPONENT, exponent); + } +} + +void LLLightState::setSpotCutoff(const F32& cutoff) +{ + if (mSpotCutoff != cutoff) + { + mSpotCutoff = cutoff; + glLightf(GL_LIGHT0+mIndex, GL_SPOT_CUTOFF, cutoff); + } +} + +void LLLightState::setSpotDirection(const LLVector3& direction) +{ + //always set direction because modelview matrix may have changed + mSpotDirection = direction; + glLightfv(GL_LIGHT0+mIndex, GL_SPOT_DIRECTION, direction.mV); +} LLRender::LLRender() : mDirty(false), @@ -768,6 +893,11 @@ LLRender::LLRender() } mDummyTexUnit = new LLTexUnit(-1); + for (U32 i = 0; i < LL_NUM_LIGHT_UNITS; ++i) + { + mLightState.push_back(new LLLightState(i)); + } + for (U32 i = 0; i < 4; i++) { mCurrColorMask[i] = true; @@ -795,6 +925,12 @@ void LLRender::shutdown() mTexUnits.clear(); delete mDummyTexUnit; mDummyTexUnit = NULL; + + for (U32 i = 0; i < mLightState.size(); ++i) + { + delete mLightState[i]; + } + mLightState.clear(); } void LLRender::refreshState(void) @@ -932,15 +1068,21 @@ void LLRender::setColorMask(bool writeColorR, bool writeColorG, bool writeColorB { flush(); - mCurrColorMask[0] = writeColorR; - mCurrColorMask[1] = writeColorG; - mCurrColorMask[2] = writeColorB; - mCurrColorMask[3] = writeAlpha; + if (mCurrColorMask[0] != writeColorR || + mCurrColorMask[1] != writeColorG || + mCurrColorMask[2] != writeColorB || + mCurrColorMask[3] != writeAlpha) + { + mCurrColorMask[0] = writeColorR; + mCurrColorMask[1] = writeColorG; + mCurrColorMask[2] = writeColorB; + mCurrColorMask[3] = writeAlpha; - glColorMask(writeColorR ? GL_TRUE : GL_FALSE, - writeColorG ? GL_TRUE : GL_FALSE, - writeColorB ? GL_TRUE : GL_FALSE, - writeAlpha ? GL_TRUE : GL_FALSE); + glColorMask(writeColorR ? GL_TRUE : GL_FALSE, + writeColorG ? GL_TRUE : GL_FALSE, + writeColorB ? GL_TRUE : GL_FALSE, + writeAlpha ? GL_TRUE : GL_FALSE); + } } void LLRender::setSceneBlendType(eBlendType type) @@ -978,15 +1120,19 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value) { flush(); - mCurrAlphaFunc = func; - mCurrAlphaFuncVal = value; - if (func == CF_DEFAULT) - { - glAlphaFunc(GL_GREATER, 0.01f); - } - else + if (mCurrAlphaFunc != func || + mCurrAlphaFuncVal != value) { - glAlphaFunc(sGLCompareFunc[func], value); + mCurrAlphaFunc = func; + mCurrAlphaFuncVal = value; + if (func == CF_DEFAULT) + { + glAlphaFunc(GL_GREATER, 0.01f); + } + else + { + glAlphaFunc(sGLCompareFunc[func], value); + } } } @@ -1045,6 +1191,16 @@ LLTexUnit* LLRender::getTexUnit(U32 index) } } +LLLightState* LLRender::getLight(U32 index) +{ + if (index < mLightState.size()) + { + return mLightState[index]; + } + + return NULL; +} + bool LLRender::verifyTexUnitActive(U32 unitToVerify) { if (mCurrTextureUnitIndex == unitToVerify) diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 2767aa64a8..7ba14f7b40 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -37,6 +37,7 @@ #include "v2math.h" #include "v3math.h" #include "v4coloru.h" +#include "v4math.h" #include "llstrider.h" #include "llpointer.h" #include "llglheaders.h" @@ -212,6 +213,41 @@ protected: void setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha = false); }; +class LLLightState +{ +public: + LLLightState(S32 index); + + void enable(); + void disable(); + void setDiffuse(const LLColor4& diffuse); + void setAmbient(const LLColor4& ambient); + void setSpecular(const LLColor4& specular); + void setPosition(const LLVector4& position); + void setConstantAttenuation(const F32& atten); + void setLinearAttenuation(const F32& atten); + void setQuadraticAttenuation(const F32& atten); + void setSpotExponent(const F32& exponent); + void setSpotCutoff(const F32& cutoff); + void setSpotDirection(const LLVector3& direction); + +protected: + S32 mIndex; + bool mEnabled; + LLColor4 mDiffuse; + LLColor4 mAmbient; + LLColor4 mSpecular; + LLVector4 mPosition; + LLVector3 mSpotDirection; + + F32 mConstantAtten; + F32 mLinearAtten; + F32 mQuadraticAtten; + + F32 mSpotExponent; + F32 mSpotCutoff; +}; + class LLRender { friend class LLTexUnit; @@ -327,6 +363,8 @@ public: void blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor, eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor); + LLLightState* getLight(U32 index); + LLTexUnit* getTexUnit(U32 index); U32 getCurrentTexUnitIndex(void) const { return mCurrTextureUnitIndex; } @@ -363,6 +401,7 @@ private: LLStrider mColorsp; std::vector mTexUnits; LLTexUnit* mDummyTexUnit; + std::vector mLightState; eBlendFactor mCurrBlendColorSFactor; eBlendFactor mCurrBlendColorDFactor; diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 07ec31dbd5..51870515f2 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -143,7 +143,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) } else { //was disabled - if (data_mask & mask[i]) + if (data_mask & mask[i] && i > 0) { //needs to be enabled glEnableClientState(array[i]); } diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index ae3421a019..49c5f6eae9 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -507,6 +507,11 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass) //reset vertex buffer mappings LLVertexBuffer::unbind(); + if (pass == 0) + { //make sure no stale colors are left over from a previous render + glColor4f(1,1,1,1); + } + if (LLPipeline::sImpostorRender) { //impostor render does not have impostors or rigid rendering pass += 2; @@ -1126,8 +1131,6 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) return; } - LLOverrideFaceColor color(this, 1.0f, 1.0f, 1.0f, 1.0f); - if (pass == 0) { if (!LLPipeline::sReflectionRender) diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp index eaa6aa7e37..696c2d1abd 100644 --- a/indra/newview/lldrawpoolwlsky.cpp +++ b/indra/newview/lldrawpoolwlsky.cpp @@ -192,7 +192,7 @@ void LLDrawPoolWLSky::renderSkyClouds(F32 camHeightLocal) const &gWLCloudProgram; LLGLEnable blend(GL_BLEND); - LLGLSBlendFunc blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gGL.setSceneBlendType(LLRender::BT_ALPHA); gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); gGL.getTexUnit(0)->bind(sCloudNoiseTexture); diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 664d957e49..0d9cad914a 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -148,6 +148,17 @@ public: }; + struct CompareMatrixTexturePtr + { + bool operator()(const LLPointer& lhs, const LLPointer& rhs) + { + return lhs.get() != rhs.get() + && (lhs.isNull() || (rhs.notNull() && (lhs->mModelMatrix > rhs->mModelMatrix || + (lhs->mModelMatrix == rhs->mModelMatrix && lhs->mTexture.get() > rhs->mTexture.get())))); + } + + }; + struct CompareBump { bool operator()(const LLPointer& lhs, const LLPointer& rhs) @@ -532,6 +543,7 @@ public: sg_list_t::iterator beginAlphaGroups(); sg_list_t::iterator endAlphaGroups(); + bool hasOcclusionGroups() { return mOcclusionGroupsSize > 0; } sg_list_t::iterator beginOcclusionGroups(); sg_list_t::iterator endOcclusionGroups(); diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index 14b9a03fd5..aa6da5c9f3 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -533,7 +533,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) stop_glerror(); - LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), mShiny && !(mFace->getPool()->getVertexShaderLevel() > 0)); + LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), mFace->getPool()->getVertexShaderLevel() > 0 ? 0.f : mShiny); //---------------------------------------------------------------- // setup current texture diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index be987a2310..3e2b7d7596 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3691,6 +3691,10 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, else { model_mat = &(drawable->getRegion()->mRenderMatrix); + if (model_mat->isIdentity()) + { + model_mat = NULL; + } } U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 9d7af4aace..221960ba0f 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -2079,33 +2079,34 @@ void LLPipeline::markOccluder(LLSpatialGroup* group) void LLPipeline::doOcclusion(LLCamera& camera) { - LLVertexBuffer::unbind(); - - if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION)) - { - gGL.setColorMask(true, false, false, false); - } - else + if (LLPipeline::sUseOcclusion > 1 && sCull->hasOcclusionGroups()) { - gGL.setColorMask(false, false); - } - LLGLDisable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLDepthTest depth(GL_TRUE, GL_FALSE); + LLVertexBuffer::unbind(); - LLGLDisable cull(GL_CULL_FACE); - if (LLPipeline::sUseOcclusion > 1) - { + if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION)) + { + gGL.setColorMask(true, false, false, false); + } + else + { + gGL.setColorMask(false, false); + } + LLGLDisable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + + LLGLDisable cull(GL_CULL_FACE); + for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter) { LLSpatialGroup* group = *iter; group->doOcclusion(&camera); group->clearOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION); } + + gGL.setColorMask(true, false); } - - gGL.setColorMask(true, false); } BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority) @@ -2941,21 +2942,6 @@ void LLPipeline::postSort(LLCamera& camera) //rebuild groups sCull->assertDrawMapsEmpty(); - /*LLSpatialGroup::sNoDelete = FALSE; - for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) - { - LLSpatialGroup* group = *i; - if (sUseOcclusion && - group->isState(LLSpatialGroup::OCCLUDED)) - { - continue; - } - - group->rebuildGeom(); - } - LLSpatialGroup::sNoDelete = TRUE;*/ - - rebuildPriorityGroups(); llpushcallstacks ; @@ -4625,16 +4611,19 @@ void LLPipeline::setupAvatarLights(BOOL for_edit) light_pos.normalize(); + LLLightState* light = gGL.getLight(1); + mHWLightColors[1] = diffuse; - glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse.mV); - glLightfv(GL_LIGHT1, GL_AMBIENT, LLColor4::black.mV); - glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV); - glLightfv(GL_LIGHT1, GL_POSITION, light_pos.mV); - glLightf (GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.0f); - glLightf (GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.0f); - glLightf (GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.0f); - glLightf (GL_LIGHT1, GL_SPOT_EXPONENT, 0.0f); - glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 180.0f); + + light->setDiffuse(diffuse); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + light->setPosition(light_pos); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); } else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini) { @@ -4665,22 +4654,28 @@ void LLPipeline::setupAvatarLights(BOOL for_edit) backlight_diffuse *= backlight_mag / max_component; mHWLightColors[1] = backlight_diffuse; - glLightfv(GL_LIGHT1, GL_POSITION, backlight_pos.mV); // this is just sun/moon direction - glLightfv(GL_LIGHT1, GL_DIFFUSE, backlight_diffuse.mV); - glLightfv(GL_LIGHT1, GL_AMBIENT, LLColor4::black.mV); - glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV); - glLightf (GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.0f); - glLightf (GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.0f); - glLightf (GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.0f); - glLightf (GL_LIGHT1, GL_SPOT_EXPONENT, 0.0f); - glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 180.0f); + + LLLightState* light = gGL.getLight(1); + + light->setPosition(backlight_pos); + light->setDiffuse(backlight_diffuse); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); } else { + LLLightState* light = gGL.getLight(1); + mHWLightColors[1] = LLColor4::black; - glLightfv(GL_LIGHT1, GL_DIFFUSE, LLColor4::black.mV); - glLightfv(GL_LIGHT1, GL_AMBIENT, LLColor4::black.mV); - glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV); + + light->setDiffuse(LLColor4::black); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); } } @@ -4861,15 +4856,17 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) LLVector4 light_pos(mSunDir, 0.0f); LLColor4 light_diffuse = mSunDiffuse; mHWLightColors[0] = light_diffuse; - glLightfv(GL_LIGHT0, GL_POSITION, light_pos.mV); // this is just sun/moon direction - glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse.mV); - glLightfv(GL_LIGHT0, GL_AMBIENT, LLColor4::black.mV); - glLightfv(GL_LIGHT0, GL_SPECULAR, LLColor4::black.mV); - glLightf (GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0f); - glLightf (GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.0f); - glLightf (GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.0f); - glLightf (GL_LIGHT0, GL_SPOT_EXPONENT, 0.0f); - glLightf (GL_LIGHT0, GL_SPOT_CUTOFF, 180.0f); + + LLLightState* light = gGL.getLight(0); + light->setPosition(light_pos); + light->setDiffuse(light_diffuse); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); } // Light 1 = Backlight (for avatars) @@ -4927,13 +4924,15 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) float linatten = x / (light_radius); // % of brightness at radius mHWLightColors[cur_light] = light_color; - S32 gllight = GL_LIGHT0+cur_light; - glLightfv(gllight, GL_POSITION, light_pos_gl.mV); - glLightfv(gllight, GL_DIFFUSE, light_color.mV); - glLightfv(gllight, GL_AMBIENT, LLColor4::black.mV); - glLightf (gllight, GL_CONSTANT_ATTENUATION, 0.0f); - glLightf (gllight, GL_LINEAR_ATTENUATION, linatten); - glLightf (gllight, GL_QUADRATIC_ATTENUATION, 0.0f); + LLLightState* light_state = gGL.getLight(cur_light); + + light_state->setPosition(light_pos_gl); + light_state->setDiffuse(light_color); + light_state->setAmbient(LLColor4::black); + light_state->setConstantAttenuation(0.f); + light_state->setLinearAttenuation(linatten); + light_state->setQuadraticAttenuation(0.f); + if (light->isLightSpotlight() // directional (spot-)light && (LLPipeline::sRenderDeferred || gSavedSettings.getBOOL("RenderSpotLightsInNondeferred"))) // these are only rendered as GL spotlights if we're in deferred rendering mode *or* the setting forces them on { @@ -4941,22 +4940,21 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) LLQuaternion quat = light->getRenderRotation(); LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction at_axis *= quat; - //llinfos << "SPOT!!!!!!! fov: " << spotparams.mV[0] << " focus: " << spotparams.mV[1] << " dir: " << at_axis << llendl; - glLightfv(gllight, GL_SPOT_DIRECTION, at_axis.mV); - glLightf (gllight, GL_SPOT_EXPONENT, 2.0f); // 2.0 = good old dot product ^ 2 - glLightf (gllight, GL_SPOT_CUTOFF, 90.0f); // hemisphere - const float specular[] = {0.f, 0.f, 0.f, 0.f}; - glLightfv(gllight, GL_SPECULAR, specular); + + light_state->setSpotDirection(at_axis); + light_state->setSpotCutoff(90.f); + light_state->setSpotExponent(2.f); + + light_state->setSpecular(LLColor4::black); } else // omnidirectional (point) light { - glLightf (gllight, GL_SPOT_EXPONENT, 0.0f); - glLightf (gllight, GL_SPOT_CUTOFF, 180.0f); - + light_state->setSpotExponent(0.f); + light_state->setSpotCutoff(180.f); + // we use specular.w = 1.0 as a cheap hack for the shaders to know that this is omnidirectional rather than a spotlight - const float specular[] = {0.f, 0.f, 0.f, 1.f}; - glLightfv(gllight, GL_SPECULAR, specular); - //llinfos << "boring light" << llendl; + const LLColor4 specular(0.f, 0.f, 0.f, 1.f); + light_state->setSpecular(specular); } cur_light++; if (cur_light >= 8) @@ -4968,10 +4966,11 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) for ( ; cur_light < 8 ; cur_light++) { mHWLightColors[cur_light] = LLColor4::black; - S32 gllight = GL_LIGHT0+cur_light; - glLightfv(gllight, GL_DIFFUSE, LLColor4::black.mV); - glLightfv(gllight, GL_AMBIENT, LLColor4::black.mV); - glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV); + LLLightState* light = gGL.getLight(cur_light); + + light->setDiffuse(LLColor4::black); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); } if (gAgentAvatarp && gAgentAvatarp->mSpecialRenderMode == 3) @@ -4988,23 +4987,24 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) float linatten = x / (light_radius); // % of brightness at radius mHWLightColors[2] = light_color; - S32 gllight = GL_LIGHT2; - glLightfv(gllight, GL_POSITION, light_pos_gl.mV); - glLightfv(gllight, GL_DIFFUSE, light_color.mV); - glLightfv(gllight, GL_AMBIENT, LLColor4::black.mV); - glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV); - glLightf (gllight, GL_CONSTANT_ATTENUATION, 0.0f); - glLightf (gllight, GL_LINEAR_ATTENUATION, linatten); - glLightf (gllight, GL_QUADRATIC_ATTENUATION, 0.0f); - glLightf (gllight, GL_SPOT_EXPONENT, 0.0f); - glLightf (gllight, GL_SPOT_CUTOFF, 180.0f); + LLLightState* light = gGL.getLight(2); + + light->setPosition(light_pos_gl); + light->setDiffuse(light_color); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + light->setQuadraticAttenuation(0.f); + light->setConstantAttenuation(0.f); + light->setLinearAttenuation(linatten); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); } // Init GL state glDisable(GL_LIGHTING); - for (S32 gllight=GL_LIGHT0; gllight<=GL_LIGHT7; gllight++) + for (S32 i = 0; i < 8; ++i) { - glDisable(gllight); + gGL.getLight(i)->disable(); } mLightMask = 0; } @@ -5029,15 +5029,16 @@ void LLPipeline::enableLights(U32 mask) stop_glerror(); for (S32 i=0; i<8; i++) { + LLLightState* light = gGL.getLight(i); if (mask & (1<enable(); + light->setDiffuse(mHWLightColors[i]); } else { - glDisable(GL_LIGHT0 + i); - glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, LLColor4::black.mV); + light->disable(); + light->setDiffuse(LLColor4::black); } } stop_glerror(); @@ -5061,7 +5062,6 @@ void LLPipeline::enableLightsStatic() if (mLightingDetail >= 2) { mask |= mLightMovingMask; // Hardware moving lights - glColor4f(0.f, 0.f, 0.f, 1.0f); // no local lighting by default } else { @@ -5075,11 +5075,7 @@ void LLPipeline::enableLightsDynamic() assertInitialized(); U32 mask = 0xff & (~2); // Local lights enableLights(mask); - if (mLightingDetail >= 2) - { - glColor4f(0.f, 0.f, 0.f, 1.f); // no local lighting by default - } - + if (isAgentAvatarValid() && getLightingDetail() <= 0) { if (gAgentAvatarp->mSpecialRenderMode == 0) // normal @@ -5125,33 +5121,37 @@ void LLPipeline::enableLightsPreview() dir2.normVec(); LLVector4 light_pos(dir0, 0.0f); - glEnable(GL_LIGHT0); - glLightfv(GL_LIGHT0, GL_POSITION, light_pos.mV); - glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0.mV); - glLightfv(GL_LIGHT0, GL_AMBIENT, LLColor4::black.mV); - glLightfv(GL_LIGHT0, GL_SPECULAR, specular0.mV); - glLightf (GL_LIGHT0, GL_SPOT_EXPONENT, 0.0f); - glLightf (GL_LIGHT0, GL_SPOT_CUTOFF, 180.0f); - light_pos = LLVector4(dir1, 0.f); - glEnable(GL_LIGHT1); - glLightfv(GL_LIGHT1, GL_POSITION, light_pos.mV); - glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1.mV); - glLightfv(GL_LIGHT1, GL_AMBIENT, LLColor4::black.mV); - glLightfv(GL_LIGHT1, GL_SPECULAR, specular1.mV); - glLightf (GL_LIGHT1, GL_SPOT_EXPONENT, 0.0f); - glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 180.0f); + LLLightState* light = gGL.getLight(0); - light_pos = LLVector4(dir2, 0.f); - glEnable(GL_LIGHT2); - glLightfv(GL_LIGHT2, GL_POSITION, light_pos.mV); - glLightfv(GL_LIGHT2, GL_DIFFUSE, diffuse2.mV); - glLightfv(GL_LIGHT2, GL_AMBIENT, LLColor4::black.mV); - glLightfv(GL_LIGHT2, GL_SPECULAR, specular2.mV); - glLightf (GL_LIGHT2, GL_SPOT_EXPONENT, 0.0f); - glLightf (GL_LIGHT2, GL_SPOT_CUTOFF, 180.0f); + light->enable(); + light->setPosition(light_pos); + light->setDiffuse(diffuse0); + light->setAmbient(LLColor4::black); + light->setSpecular(specular0); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + + light_pos = LLVector4(dir1, 0.f); + light = gGL.getLight(1); + light->enable(); + light->setPosition(light_pos); + light->setDiffuse(diffuse1); + light->setAmbient(LLColor4::black); + light->setSpecular(specular1); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + light_pos = LLVector4(dir2, 0.f); + light = gGL.getLight(2); + light->enable(); + light->setPosition(light_pos); + light->setDiffuse(diffuse2); + light->setAmbient(LLColor4::black); + light->setSpecular(specular2); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); } @@ -5171,16 +5171,11 @@ void LLPipeline::enableLightsFullbright(const LLColor4& color) enableLights(mask); glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV); - /*if (mLightingDetail >= 2) - { - glColor4f(0.f, 0.f, 0.f, 1.f); // no local lighting by default - }*/ } void LLPipeline::disableLights() { enableLights(0); // no lighting (full bright) - glColor4f(1.f, 1.f, 1.f, 1.f); // lighting color = white by default } //============================================================================ @@ -5969,8 +5964,6 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) tc2 /= (F32) res_mod; } - gGL.setColorMask(true, true); - LLFastTimer ftm(FTM_RENDER_BLOOM); gGL.color4f(1,1,1,1); LLGLDepthTest depth(GL_FALSE); -- cgit v1.2.3 From cfb3ee50c23c32dc0470d8e6bf1a2527d2d425bd Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 18 Feb 2011 13:52:40 -0600 Subject: SH-948 don't occlusion cull everything when deferred rendering is enabled --- indra/newview/llviewerdisplay.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 97d6a222c5..b45d1aa3a6 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -616,10 +616,10 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) && gSavedSettings.getBOOL("UseOcclusion") && gGLManager.mHasOcclusionQuery) ? 2 : 0; - if (LLPipeline::sUseOcclusion && LLPipeline::sRenderDeferred) - { //force occlusion on for all render types if doing deferred render + /*if (LLPipeline::sUseOcclusion && LLPipeline::sRenderDeferred) + { //force occlusion on for all render types if doing deferred render (tighter shadow frustum) LLPipeline::sUseOcclusion = 3; - } + }*/ LLPipeline::sAutoMaskAlphaDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaDeferred"); LLPipeline::sAutoMaskAlphaNonDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaNonDeferred"); -- cgit v1.2.3 From b53ffe4eae9700ad78f01cfec3458b5611330027 Mon Sep 17 00:00:00 2001 From: prep linden Date: Fri, 18 Feb 2011 17:43:08 -0500 Subject: Code cleanup and removed hacky code support for some old legacy rig types --- indra/newview/llvoavatar.cpp | 38 +++----------------------------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index b90c136b21..e982df1c92 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1332,32 +1332,7 @@ const LLVector3 LLVOAvatar::getRenderPosition() const } else if (isRoot()) { - //Rebase the pelvis position if the avatar contains a pelvis offset - if ( mHasPelvisOffset ) - { - LLVector3 returnVec( mDrawable->getPositionAgent() ); - if ( mLastPelvisToFoot > mPelvisToFoot ) - { - F32 diff = mLastPelvisToFoot - mPelvisToFoot; - //1. Move the pelvis down by the difference of the old amount and the new pelvis to foot amount - returnVec[VZ] -= (diff); - //2. Now move the pelvis up by the new pelvis to foot amount - returnVec[VZ] += mPelvisToFoot; - } - else - { - //1. Move the pelvis down by the old pelvis to foot amount - returnVec[VZ] -= (mLastPelvisToFoot); - //2. Now move the pelvis up by the new pelvis to foot amount - returnVec[VZ] += mPelvisToFoot; - } - //Return the fixed up pelvis position - return returnVec; - } - else - { - return mDrawable->getPositionAgent(); - } + return mDrawable->getPositionAgent(); } else { @@ -3498,15 +3473,8 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) // correct for the fact that the pelvis is not necessarily the center // of the agent's physical representation - if ( !mHasPelvisOffset ) - { - root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot; - } - else - { - root_pos.mdV[VZ] -= (0.65f * mBodySize.mV[VZ]) - mPelvisToFoot; - } - + root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot; + LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos); if (newPosition != mRoot.getXform()->getWorldPosition()) -- cgit v1.2.3 From c690c30ec173faf8d8087ecb38cadbb9dd1adb4e Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 22 Feb 2011 18:33:33 -0600 Subject: SH-438 Use node name instead of mesh name for object names when importing meshes. --- indra/newview/llfloatermodelpreview.cpp | 187 +------------------------------- indra/newview/llfloatermodelpreview.h | 2 +- indra/newview/llmeshrepository.cpp | 2 +- indra/newview/llmeshrepository.h | 8 +- 4 files changed, 10 insertions(+), 189 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index dde470693c..cf7ac354b6 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1653,7 +1653,7 @@ void LLModelLoader::run() std::vector materials; materials.resize(model->getNumVolumeFaces()); - mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); + mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); } } @@ -1944,7 +1944,8 @@ void LLModelLoader::processElement(daeElement* element) mesh_scale *= transformation; transformation = mesh_scale; - mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); + std::string label = getElementLabel(instance_geo); + mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials)); stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); } @@ -2615,188 +2616,6 @@ void LLModelPreview::generateNormals() } -void LLModelPreview::consolidate() -{ - std::map > composite; - - LLMatrix4 identity; - - //bake out each node in current scene to composite - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { //for each transform in current scene - LLMatrix4 mat = iter->first; - glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose(); - LLMatrix4 norm_mat(inv_trans.m); - - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with that transform - LLModelInstance& source_instance = *model_iter; - LLModel* source = source_instance.mModel; - - if (!validate_model(source)) - { - llerrs << "Invalid model found!" << llendl; - } - - for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) - { //for each face in instance - const LLVolumeFace& src_face = source->getVolumeFace(i); - LLImportMaterial& source_material = source_instance.mMaterial[i]; - - //get model in composite that is composite for this material - LLModel* model = NULL; - - if (composite.find(source_material) != composite.end()) - { - model = composite[source_material].rbegin()->mModel; - if (model->getVolumeFace(0).mNumVertices + src_face.mNumVertices > 65535) - { - model = NULL; - } - } - - if (model == NULL) - { //no model found, make new model - std::vector materials; - materials.push_back(source_material); - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - model = new LLModel(volume_params, 0.f); - model->mLabel = source->mLabel; - model->setNumVolumeFaces(0); - composite[source_material].push_back(LLModelInstance(model, identity, materials)); - } - - model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat); - } - } - } - - - //condense composite into as few LLModel instances as possible - LLModelLoader::model_list new_model; - std::vector instance_list; - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - - std::vector empty_material; - LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material); - cur_instance.mModel->setNumVolumeFaces(0); - - BOOL first_transform = TRUE; - - LLModelLoader::scene new_scene; - LLVector3 min,max; - - for (std::map >::iterator iter = composite.begin(); - iter != composite.end(); - ++iter) - { - std::map >::iterator next_iter = iter; ++next_iter; - - for (std::vector::iterator instance_iter = iter->second.begin(); - instance_iter != iter->second.end(); - ++instance_iter) - { - LLModel* source = instance_iter->mModel; - - if (instance_iter->mMaterial.size() != 1) - { - llerrs << "WTF?" << llendl; - } - - if (source->getNumVolumeFaces() != 1) - { - llerrs << "WTF?" << llendl; - } - - if (source->mMaterialList.size() != 1) - { - llerrs << "WTF?" << llendl; - } - - cur_instance.mModel->addFace(source->getVolumeFace(0)); - cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]); - cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]); - - BOOL last_model = FALSE; - - std::vector::iterator next_instance = instance_iter; ++next_instance; - - if (next_iter == composite.end() && - next_instance == iter->second.end()) - { - last_model = TRUE; - } - - if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES) - { - cur_instance.mModel->mLabel = source->mLabel; - - cur_instance.mModel->optimizeVolumeFaces(); - cur_instance.mModel->normalizeVolumeFaces(); - - if (!validate_model(cur_instance.mModel)) - { - llerrs << "Invalid model detected." << llendl; - } - - new_model.push_back(cur_instance.mModel); - - LLMatrix4 transformation = LLMatrix4(); - - // adjust the transformation to compensate for mesh normalization - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - cur_instance.mTransform = transformation; - - new_scene[transformation].push_back(cur_instance); - stretch_extents(cur_instance.mModel, transformation, min, max, first_transform); - - if (!last_model) - { - cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material); - cur_instance.mModel->setNumVolumeFaces(0); - } - } - } - } - - mScene[mPreviewLOD] = new_scene; - mModel[mPreviewLOD] = new_model; - mVertexBuffer[mPreviewLOD].clear(); - - if (mPreviewLOD == LLModel::LOD_HIGH) - { - mBaseScene = new_scene; - mBaseModel = new_model; - clearGLODGroup(); - mVertexBuffer[5].clear(); - } - - mPreviewTarget = (min+max)*0.5f; - mPreviewScale = (max-min)*0.5f; - setPreviewTarget(mPreviewScale.magVec()*2.f); - - clearIncompatible(mPreviewLOD); - - mResourceCost = calcResourceCost(); - refresh(); -} - void LLModelPreview::clearMaterials() { for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 8fc85cebb9..e1c520134b 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -279,7 +279,7 @@ public: void loadModelCallback(S32 lod); void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); void generateNormals(); - void consolidate(); + void clearMaterials(); U32 calcResourceCost(); void rebuildUploadData(); diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index a2b0ac09af..b6e3626cba 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2981,7 +2981,7 @@ LLSD LLMeshUploadThread::createObject(LLModelInstance& instance) object_params["pos"] = ll_sd_from_vector3(position + mOrigin); object_params["rotation"] = ll_sd_from_quaternion(quat_rotation); object_params["scale"] = ll_sd_from_vector3(scale); - object_params["name"] = instance.mModel->getName(); + object_params["name"] = instance.mLabel; // load material from dae file object_params["facelist"] = LLSD::emptyArray(); diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index b642a89192..0fcb2213de 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -108,14 +108,16 @@ class LLModelInstance public: LLPointer mModel; LLPointer mLOD[5]; - + + std::string mLabel; + LLUUID mMeshID; LLMatrix4 mTransform; std::vector mMaterial; - LLModelInstance(LLModel* model, LLMatrix4& transform, std::vector& materials) - : mModel(model), mTransform(transform), mMaterial(materials) + LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::vector& materials) + : mModel(model), mLabel(label), mTransform(transform), mMaterial(materials) { } }; -- cgit v1.2.3 From e55e91a5a546832b79643fdcd2208b5e4f62b6df Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 22 Feb 2011 18:36:50 -0600 Subject: SH-874 Better VBO usage hints, most notably don't use VBOs for occlusion queries if GL is set to not use VBOs for stream draw. --- indra/llrender/llvertexbuffer.cpp | 7 +- indra/llrender/llvertexbuffer.h | 1 + indra/newview/app_settings/settings.xml | 13 +++- indra/newview/lldrawable.cpp | 2 +- indra/newview/llspatialpartition.cpp | 132 +++++++++++++++++++------------- indra/newview/llviewercontrol.cpp | 12 +-- indra/newview/llvopartgroup.cpp | 2 +- indra/newview/llvotree.cpp | 2 +- indra/newview/llvowater.cpp | 2 +- indra/newview/pipeline.cpp | 21 +---- indra/newview/pipeline.h | 1 - 11 files changed, 103 insertions(+), 92 deletions(-) diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 51870515f2..f5e85aecda 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -58,6 +58,7 @@ BOOL LLVertexBuffer::sIBOActive = FALSE; U32 LLVertexBuffer::sAllocatedBytes = 0; BOOL LLVertexBuffer::sMapped = FALSE; BOOL LLVertexBuffer::sUseStreamDraw = TRUE; +BOOL LLVertexBuffer::sPreferStreamDraw = FALSE; S32 LLVertexBuffer::sWeight4Loc = -1; std::vector LLVertexBuffer::sDeleteList; @@ -147,7 +148,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) { //needs to be enabled glEnableClientState(array[i]); } - else if (gDebugGL && glIsEnabled(array[i])) + else if (gDebugGL && i > 0 && glIsEnabled(array[i])) { //needs to be disabled, make sure it was (DEBUG TEMPORARY) if (gDebugSession) { @@ -427,9 +428,9 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : mUsage = 0; } - if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw) + if (mUsage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw) { - mUsage = 0; + mUsage = GL_STREAM_DRAW_ARB; } //zero out offsets diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index f40f013306..77c9da2d6c 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -92,6 +92,7 @@ public: static S32 sWeight4Loc; static BOOL sUseStreamDraw; + static BOOL sPreferStreamDraw; static void initClass(bool use_vbo); static void cleanupClass(); diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index d71b84739c..ec6b942e3e 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8810,7 +8810,18 @@ Value 1 - RenderVolumeLODFactor + RenderPreferStreamDraw + + Comment + Use GL_STREAM_DRAW in place of GL_DYNAMIC_DRAW + Persist + 1 + Type + Boolean + Value + 0 + + RenderVolumeLODFactor Comment Controls level of detail of primitives (multiplier for current screen area when calculated level of detail) diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index cbee800acb..d370c72a04 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -1052,7 +1052,7 @@ BOOL LLDrawable::isVisible() const //======================================= LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask) -: LLSpatialPartition(data_mask, render_by_group, FALSE) +: LLSpatialPartition(data_mask, render_by_group, GL_STREAM_DRAW_ARB) { mDrawable = root; root->setSpatialBridge(this); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 5dd1b5ba7e..14775f0f21 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -252,11 +252,15 @@ U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center) } +static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion"); + void LLSpatialGroup::buildOcclusion() { if (mOcclusionVerts.isNull()) { - mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, GL_DYNAMIC_DRAW_ARB); + + mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, + LLVertexBuffer::sUseStreamDraw ? mBufferUsage : 0); //if GL has a hard time with VBOs, don't use them for occlusion culling. mOcclusionVerts->allocateBuffer(8, 64, true); LLStrider idx; @@ -275,40 +279,47 @@ void LLSpatialGroup::buildOcclusion() LLStrider pos; - mOcclusionVerts->getVertexStrider(pos); - - LLVector4a* v = (LLVector4a*) pos.get(); - - const LLVector4a& c = mBounds[0]; - const LLVector4a& s = r; - - static const LLVector4a octant[] = { - LLVector4a(-1.f, -1.f, -1.f), - LLVector4a(-1.f, -1.f, 1.f), - LLVector4a(-1.f, 1.f, -1.f), - LLVector4a(-1.f, 1.f, 1.f), + LLFastTimer t(FTM_BUILD_OCCLUSION); + mOcclusionVerts->getVertexStrider(pos); + } - LLVector4a(1.f, -1.f, -1.f), - LLVector4a(1.f, -1.f, 1.f), - LLVector4a(1.f, 1.f, -1.f), - LLVector4a(1.f, 1.f, 1.f), - }; + { + LLVector4a* v = (LLVector4a*) pos.get(); - //vertex positions are encoded so the 3 bits of their vertex index - //correspond to their axis facing, with bit position 3,2,1 matching - //axis facing x,y,z, bit set meaning positive facing, bit clear - //meaning negative facing + const LLVector4a& c = mBounds[0]; + const LLVector4a& s = r; + + static const LLVector4a octant[] = + { + LLVector4a(-1.f, -1.f, -1.f), + LLVector4a(-1.f, -1.f, 1.f), + LLVector4a(-1.f, 1.f, -1.f), + LLVector4a(-1.f, 1.f, 1.f), + + LLVector4a(1.f, -1.f, -1.f), + LLVector4a(1.f, -1.f, 1.f), + LLVector4a(1.f, 1.f, -1.f), + LLVector4a(1.f, 1.f, 1.f), + }; + + //vertex positions are encoded so the 3 bits of their vertex index + //correspond to their axis facing, with bit position 3,2,1 matching + //axis facing x,y,z, bit set meaning positive facing, bit clear + //meaning negative facing + + for (S32 i = 0; i < 8; ++i) + { + LLVector4a p; + p.setMul(s, octant[i]); + p.add(c); + v[i] = p; + } + } - for (S32 i = 0; i < 8; ++i) { - LLVector4a p; - p.setMul(s, octant[i]); - p.add(c); - v[i] = p; + mOcclusionVerts->setBuffer(0); } - - mOcclusionVerts->setBuffer(0); clearState(LLSpatialGroup::OCCLUSION_DIRTY); } @@ -1189,7 +1200,7 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : mOctreeNode(node), mSpatialPartition(part), mVertexBuffer(NULL), - mBufferUsage(GL_STATIC_DRAW_ARB), + mBufferUsage(part->mBufferUsage), mDistance(0.f), mDepth(0.f), mLastUpdateDistance(-1.f), @@ -1616,6 +1627,10 @@ void LLSpatialGroup::checkOcclusion() } } +static LLFastTimer::DeclareTimer FTM_PUSH_OCCLUSION_VERTS("Push Occlusion"); +static LLFastTimer::DeclareTimer FTM_SET_OCCLUSION_STATE("Occlusion State"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail"); + void LLSpatialGroup::doOcclusion(LLCamera* camera) { if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1) @@ -1623,6 +1638,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) // Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension if (earlyFail(camera, this)) { + LLFastTimer t(FTM_OCCLUSION_EARLY_FAIL); setOcclusionState(LLSpatialGroup::DISCARD_QUERY); assert_states_valid(this); clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); @@ -1664,41 +1680,47 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]); #endif - glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); + { + LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS); + glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); - mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); + mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); - if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER) - { - LLGLSquashToFarClip squash(glh_get_current_projection(), 1); - if (camera->getOrigin().isExactlyZero()) - { //origin is invalid, draw entire box - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); - } - else + if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER) { - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); - } - } - else - { - if (camera->getOrigin().isExactlyZero()) - { //origin is invalid, draw entire box - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); + LLGLSquashToFarClip squash(glh_get_current_projection(), 1); + if (camera->getOrigin().isExactlyZero()) + { //origin is invalid, draw entire box + mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); + mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); + } + else + { + mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); + } } else { - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); + if (camera->getOrigin().isExactlyZero()) + { //origin is invalid, draw entire box + mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); + mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); + } + else + { + mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); + } } - } - glEndQueryARB(mode); + glEndQueryARB(mode); + } } - setOcclusionState(LLSpatialGroup::QUERY_PENDING); - clearOcclusionState(LLSpatialGroup::DISCARD_QUERY); + { + LLFastTimer t(FTM_SET_OCCLUSION_STATE); + setOcclusionState(LLSpatialGroup::QUERY_PENDING); + clearOcclusionState(LLSpatialGroup::DISCARD_QUERY); + } } } } diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 414036c597..46aa44b2bb 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -339,15 +339,6 @@ static bool handleNumpadControlChanged(const LLSD& newvalue) return true; } -static bool handleRenderUseVBOChanged(const LLSD& newvalue) -{ - if (gPipeline.isInit()) - { - gPipeline.setUseVBO(newvalue.asBoolean()); - } - return true; -} - static bool handleWLSkyDetailChanged(const LLSD&) { if (gSky.mVOWLSkyp.notNull()) @@ -636,8 +627,9 @@ void settings_setup_listeners() gSavedSettings.getControl("MuteVoice")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); gSavedSettings.getControl("MuteAmbient")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); gSavedSettings.getControl("MuteUI")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); - gSavedSettings.getControl("RenderVBOEnable")->getSignal()->connect(boost::bind(&handleRenderUseVBOChanged, _2)); + gSavedSettings.getControl("RenderVBOEnable")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderUseStreamVBO")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); + gSavedSettings.getControl("RenderPreferStreamDraw")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("WLSkyDetail")->getSignal()->connect(boost::bind(&handleWLSkyDetailChanged, _2)); gSavedSettings.getControl("NumpadControl")->getSignal()->connect(boost::bind(&handleNumpadControlChanged, _2)); gSavedSettings.getControl("JoystickAxis0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index d966bd1614..f762f04d8e 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -360,7 +360,7 @@ U32 LLVOPartGroup::getPartitionType() const } LLParticlePartition::LLParticlePartition() -: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB) +: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK, TRUE, GL_STREAM_DRAW_ARB) { mRenderPass = LLRenderPass::PASS_ALPHA; mDrawableType = LLPipeline::RENDER_TYPE_PARTICLES; diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 20ca02efda..1b5aed804f 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -1330,7 +1330,7 @@ U32 LLVOTree::getPartitionType() const } LLTreePartition::LLTreePartition() -: LLSpatialPartition(0, FALSE, 0) +: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB) { mDrawableType = LLPipeline::RENDER_TYPE_TREE; mPartitionType = LLViewerRegion::PARTITION_TREE; diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index 9f3ec9cadc..77875859e9 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -289,7 +289,7 @@ U32 LLVOVoidWater::getPartitionType() const } LLWaterPartition::LLWaterPartition() -: LLSpatialPartition(0, FALSE, 0) +: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB) { mInfiniteFarClip = TRUE; mDrawableType = LLPipeline::RENDER_TYPE_WATER; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 221960ba0f..a8e36df294 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -383,6 +383,7 @@ void LLPipeline::init() sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips"); LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO"); + LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw"); sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); @@ -5795,6 +5796,8 @@ void LLPipeline::resetVertexBuffers() sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips"); LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO"); + LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw"); + LLVertexBuffer::sEnableVBOs = gSavedSettings.getBOOL("RenderVBOEnable"); sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight"); sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha"); @@ -5853,24 +5856,6 @@ void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture) gGLLastMatrix = NULL; } -void LLPipeline::setUseVBO(BOOL use_vbo) -{ - if (use_vbo != LLVertexBuffer::sEnableVBOs) - { - if (use_vbo) - { - llinfos << "Enabling VBO." << llendl; - } - else - { - llinfos << "Disabling VBO." << llendl; - } - - resetVertexBuffers(); - LLVertexBuffer::initClass(use_vbo); - } -} - void apply_cube_face_rotation(U32 face) { switch (face) diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 0eb020605e..32ac93388d 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -119,7 +119,6 @@ public: void allocatePhysicsBuffer(); void resetVertexBuffers(LLDrawable* drawable); - void setUseVBO(BOOL use_vbo); void generateImpostor(LLVOAvatar* avatar); void bindScreenToTexture(); void renderBloom(BOOL for_snapshot, F32 zoom_factor = 1.f, int subfield = 0); -- cgit v1.2.3 From 701b665ee567c8ff639fbc4b8794b9b0912a5256 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Wed, 23 Feb 2011 13:22:51 -0500 Subject: Fixes from merge of viewer-development -> mesh-development. --- indra/newview/pipeline.cpp | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 5d32360394..998fa88925 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -5856,10 +5856,6 @@ void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture) gGLLastMatrix = NULL; } - LLVertexBuffer::initClass(use_vbo, gSavedSettings.getBOOL("RenderVBOMappingDisable")); - } -} - void LLPipeline::setDisableVBOMapping(BOOL no_vbo_mapping) { if (LLVertexBuffer::sEnableVBOs && no_vbo_mapping != LLVertexBuffer::sDisableVBOMapping) @@ -5875,31 +5871,6 @@ void LLPipeline::setDisableVBOMapping(BOOL no_vbo_mapping) resetVertexBuffers(); LLVertexBuffer::initClass(true, no_vbo_mapping); -void apply_cube_face_rotation(U32 face) -{ - switch (face) - { - case 0: - glRotatef(90.f, 0, 1, 0); - glRotatef(180.f, 1, 0, 0); - break; - case 2: - glRotatef(-90.f, 1, 0, 0); - break; - case 4: - glRotatef(180.f, 0, 1, 0); - glRotatef(180.f, 0, 0, 1); - break; - case 1: - glRotatef(-90.f, 0, 1, 0); - glRotatef(180.f, 1, 0, 0); - break; - case 3: - glRotatef(90, 1, 0, 0); - break; - case 5: - glRotatef(180, 0, 0, 1); - break; } } -- cgit v1.2.3 From c2e55df3e533c78bf08f1769502477bb7a73a161 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 23 Feb 2011 14:17:24 -0600 Subject: SH-1019 Attempt at removing dependency on .net framework from colladadom.dll --- install.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.xml b/install.xml index 88a6a7ce90..06495b952d 100755 --- a/install.xml +++ b/install.xml @@ -280,9 +280,9 @@ windows md5sum - 041ac5d31331eb7358af71f7390f5dce + fbb784f39e82e052de462e48e167d69e url - http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/colladadom-2.1-windows-20101119.tar.bz2 + http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/colladadom-2.1-windows-20110223.tar.bz2 -- cgit v1.2.3 From 3d77dd6b5806bededd6b71402f71b9f0675c27c7 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Wed, 23 Feb 2011 16:24:47 -0500 Subject: Merge: Backed out changes for STORM-336 for merge due to complexity, will need to apply these manually. --- indra/llrender/llvertexbuffer.cpp | 160 +- indra/llrender/llvertexbuffer.h | 567 +- indra/newview/app_settings/settings.xml | 11 - indra/newview/llviewercontrol.cpp | 10 - indra/newview/llviewerwindow.cpp | 2 +- indra/newview/pipeline.cpp | 19248 +++++++++++++++--------------- indra/newview/pipeline.h | 1 - 7 files changed, 9945 insertions(+), 10054 deletions(-) diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 7a1ccb0cb4..f5e85aecda 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -49,7 +49,6 @@ U32 LLVertexBuffer::sSetCount = 0; S32 LLVertexBuffer::sCount = 0; S32 LLVertexBuffer::sGLCount = 0; S32 LLVertexBuffer::sMappedCount = 0; -BOOL LLVertexBuffer::sDisableVBOMapping = FALSE ; BOOL LLVertexBuffer::sEnableVBOs = TRUE; U32 LLVertexBuffer::sGLRenderBuffer = 0; U32 LLVertexBuffer::sGLRenderIndices = 0; @@ -298,7 +297,6 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const { llassert(mRequestedNumIndices >= 0); - if (indices_offset >= (U32) mRequestedNumIndices || indices_offset + count > (U32) mRequestedNumIndices) { @@ -330,7 +328,6 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const { llassert(mRequestedNumVerts >= 0); - if (first >= (U32) mRequestedNumVerts || first + count > (U32) mRequestedNumVerts) { @@ -354,10 +351,9 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const } //static -void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping) +void LLVertexBuffer::initClass(bool use_vbo) { sEnableVBOs = use_vbo; - sDisableVBOMapping = sEnableVBOs && no_vbo_mapping ; LLGLNamePool::registerPool(&sDynamicVBOPool); LLGLNamePool::registerPool(&sDynamicIBOPool); LLGLNamePool::registerPool(&sStreamVBOPool); @@ -501,8 +497,6 @@ LLVertexBuffer::~LLVertexBuffer() destroyGLBuffer(); destroyGLIndices(); sCount--; - - llassert_always(!mMappedData && !mMappedIndexData) ; }; //---------------------------------------------------------------------------- @@ -651,8 +645,6 @@ void LLVertexBuffer::destroyGLBuffer() { if (useVBOs()) { - freeClientBuffer() ; - if (mMappedData || mMappedIndexData) { llerrs << "Vertex buffer destroyed while mapped!" << llendl; @@ -680,13 +672,11 @@ void LLVertexBuffer::destroyGLIndices() { if (useVBOs()) { - freeClientBuffer() ; - if (mMappedData || mMappedIndexData) { llerrs << "Vertex buffer destroyed while mapped." << llendl; } - releaseIndices(); + releaseIndices(); } else { @@ -858,7 +848,6 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) if (mResized && useVBOs()) { - freeClientBuffer() ; setBuffer(0); } } @@ -882,36 +871,6 @@ BOOL LLVertexBuffer::useVBOs() const } //---------------------------------------------------------------------------- -void LLVertexBuffer::freeClientBuffer() -{ - if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData)) - { - delete[] mMappedData ; - delete[] mMappedIndexData ; - mMappedData = NULL ; - mMappedIndexData = NULL ; - } -} - -void LLVertexBuffer::allocateClientVertexBuffer() -{ - if(!mMappedData) - { - U32 size = getSize() ; - mMappedData = new U8[size]; - memset(mMappedData, 0, size); - } -} - -void LLVertexBuffer::allocateClientIndexBuffer() -{ - if(!mMappedIndexData) - { - U32 size = getIndicesSize(); - mMappedIndexData = new U8[size]; - memset(mMappedIndexData, 0, size); - } -} // Map for data access U8* LLVertexBuffer::mapBuffer(S32 access) @@ -934,14 +893,10 @@ U8* LLVertexBuffer::mapBuffer(S32 access) mLocked = TRUE; stop_glerror(); - if(sDisableVBOMapping) - { - allocateClientVertexBuffer() ; - } - else - { - mMappedData = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - } + U8* src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + mMappedData = LL_NEXT_ALIGNED_ADDRESS(src); + mAlignedOffset = mMappedData - src; + stop_glerror(); } { @@ -950,14 +905,6 @@ U8* LLVertexBuffer::mapBuffer(S32 access) mMappedIndexData = LL_NEXT_ALIGNED_ADDRESS(src); mAlignedIndexOffset = mMappedIndexData - src; - if(sDisableVBOMapping) - { - allocateClientIndexBuffer() ; - } - else - { - mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - } stop_glerror(); } @@ -971,51 +918,37 @@ U8* LLVertexBuffer::mapBuffer(S32 access) llinfos << "Available physical mwmory(KB): " << avail_phy_mem << llendl ; llinfos << "Available virtual memory(KB): " << avail_vir_mem << llendl; - if(!sDisableVBOMapping) - { - //-------------------- - //print out more debug info before crash - llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl ; - GLint size ; - glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size) ; - llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl ; - //-------------------- + //-------------------- + //print out more debug info before crash + llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl ; + GLint size ; + glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size) ; + llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl ; + //-------------------- - GLint buff; - glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLBuffer) - { - llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; - } - - - llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl; - } - else + GLint buff; + glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); + if ((GLuint)buff != mGLBuffer) { - llerrs << "memory allocation for vertex data failed." << llendl ; + llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; } + + + llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl; } if (!mMappedIndexData) { log_glerror(); - if(!sDisableVBOMapping) - { - GLint buff; - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLIndices) - { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; - } - - llerrs << "glMapBuffer returned NULL (no index data)" << llendl; - } - else + GLint buff; + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); + if ((GLuint)buff != mGLIndices) { - llerrs << "memory allocation for Index data failed. " << llendl ; + llerrs << "Invalid GL index buffer bound: " << buff << llendl; } + + llerrs << "glMapBuffer returned NULL (no index data)" << llendl; } sMappedCount++; @@ -1031,29 +964,11 @@ void LLVertexBuffer::unmapBuffer() { if (useVBOs() && mLocked) { - if(sDisableVBOMapping) - { - if(mMappedData) - { - stop_glerror(); - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), mMappedData); - stop_glerror(); - } - if(mMappedIndexData) - { - stop_glerror(); - glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), mMappedIndexData); - stop_glerror(); - } - } - else - { - stop_glerror(); - glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); - stop_glerror(); - glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); - stop_glerror(); - } + stop_glerror(); + glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); + stop_glerror(); + glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); + stop_glerror(); /*if (!sMapped) { @@ -1067,22 +982,15 @@ void LLVertexBuffer::unmapBuffer() //throw out client data (we won't be using it again) mEmpty = TRUE; mFinal = TRUE; - - if(sDisableVBOMapping) - { - freeClientBuffer() ; - } } else { mEmpty = FALSE; } - if(!sDisableVBOMapping) - { - mMappedIndexData = NULL; - mMappedData = NULL; - } + mMappedIndexData = NULL; + mMappedData = NULL; + mLocked = FALSE; } } diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index fb81720c86..77c9da2d6c 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -1,286 +1,281 @@ -/** - * @file llvertexbuffer.h - * @brief LLVertexBuffer wrapper for OpengGL vertex buffer objects - * - * $LicenseInfo:firstyear=2003&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_LLVERTEXBUFFER_H -#define LL_LLVERTEXBUFFER_H - -#include "llgl.h" -#include "v2math.h" -#include "v3math.h" -#include "v4math.h" -#include "v4coloru.h" -#include "llstrider.h" -#include "llrender.h" -#include -#include -#include - -//============================================================================ -// NOTES -// Threading: -// All constructors should take an 'create' paramater which should only be -// 'true' when called from the main thread. Otherwise createGLBuffer() will -// be called as soon as getVertexPointer(), etc is called (which MUST ONLY be -// called from the main (i.e OpenGL) thread) - - -//============================================================================ -// gl name pools for dynamic and streaming buffers - -class LLVBOPool : public LLGLNamePool -{ -protected: - virtual GLuint allocateName() - { - GLuint name; - glGenBuffersARB(1, &name); - return name; - } - - virtual void releaseName(GLuint name) - { - glDeleteBuffersARB(1, &name); - } -}; - - -//============================================================================ -// base class - -class LLVertexBuffer : public LLRefCount -{ -public: - LLVertexBuffer(const LLVertexBuffer& rhs) - { - *this = rhs; - } - - const LLVertexBuffer& operator=(const LLVertexBuffer& rhs) - { - llerrs << "Illegal operation!" << llendl; - return *this; - } - - static LLVBOPool sStreamVBOPool; - static LLVBOPool sDynamicVBOPool; - static LLVBOPool sStreamIBOPool; - static LLVBOPool sDynamicIBOPool; - - static S32 sWeight4Loc; - - static BOOL sUseStreamDraw; - static BOOL sPreferStreamDraw; - - static void initClass(bool use_vbo, bool no_vbo_mapping); - static void cleanupClass(); - static void setupClientArrays(U32 data_mask); - static void clientCopy(F64 max_time = 0.005); //copy data from client to GL - static void unbind(); //unbind any bound vertex buffer - - //get the size of a vertex with the given typemask - static S32 calcVertexSize(const U32& typemask); - - //get the size of a buffer with the given typemask and vertex count - //fill offsets with the offset of each vertex component array into the buffer - // indexed by the following enum - static S32 calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices); - - - enum { - TYPE_VERTEX, - TYPE_NORMAL, - TYPE_TEXCOORD0, - TYPE_TEXCOORD1, - TYPE_TEXCOORD2, - TYPE_TEXCOORD3, - TYPE_COLOR, - // These use VertexAttribPointer and should possibly be made generic - TYPE_BINORMAL, - TYPE_WEIGHT, - TYPE_WEIGHT4, - TYPE_CLOTHWEIGHT, - TYPE_MAX, - TYPE_INDEX, - }; - enum { - MAP_VERTEX = (1<getVertexBuffer(verts); - // vb->getNormalStrider(norms); - // setVertsNorms(verts, norms); - // vb->unmapBuffer(); - bool getVertexStrider(LLStrider& strider, S32 index=0); - bool getIndexStrider(LLStrider& strider, S32 index=0); - bool getTexCoord0Strider(LLStrider& strider, S32 index=0); - bool getTexCoord1Strider(LLStrider& strider, S32 index=0); - bool getNormalStrider(LLStrider& strider, S32 index=0); - bool getBinormalStrider(LLStrider& strider, S32 index=0); - bool getColorStrider(LLStrider& strider, S32 index=0); - bool getWeightStrider(LLStrider& strider, S32 index=0); - bool getWeight4Strider(LLStrider& strider, S32 index=0); - bool getClothWeightStrider(LLStrider& strider, S32 index=0); - - BOOL isEmpty() const { return mEmpty; } - BOOL isLocked() const { return mLocked; } - S32 getNumVerts() const { return mNumVerts; } - S32 getNumIndices() const { return mNumIndices; } - S32 getRequestedVerts() const { return mRequestedNumVerts; } - S32 getRequestedIndices() const { return mRequestedNumIndices; } - - U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; } - U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; } - U32 getTypeMask() const { return mTypeMask; } - bool hasDataType(S32 type) const { return ((1 << type) & getTypeMask()); } - S32 getSize() const; - S32 getIndicesSize() const { return mNumIndices * sizeof(U16); } - U8* getMappedData() const { return mMappedData; } - U8* getMappedIndices() const { return mMappedIndexData; } - S32 getOffset(S32 type) const { return mOffsets[type]; } - S32 getUsage() const { return mUsage; } - - void markDirty(U32 vert_index, U32 vert_count, U32 indices_index, U32 indices_count); - - void draw(U32 mode, U32 count, U32 indices_offset) const; - void drawArrays(U32 mode, U32 offset, U32 count) const; - void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const; - - //for debugging, validate data in given range is valid - void validateRange(U32 start, U32 end, U32 count, U32 offset) const; - - - -protected: - S32 mNumVerts; // Number of vertices allocated - S32 mNumIndices; // Number of indices allocated - S32 mRequestedNumVerts; // Number of vertices requested - S32 mRequestedNumIndices; // Number of indices requested - - ptrdiff_t mAlignedOffset; - ptrdiff_t mAlignedIndexOffset; - S32 mSize; - U32 mTypeMask; - S32 mUsage; // GL usage - U32 mGLBuffer; // GL VBO handle - U32 mGLIndices; // GL IBO handle - U8* mMappedData; // pointer to currently mapped data (NULL if unmapped) - U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped) - BOOL mLocked; // if TRUE, buffer is being or has been written to in client memory - BOOL mFinal; // if TRUE, buffer can not be mapped again - BOOL mFilthy; // if TRUE, entire buffer must be copied (used to prevent redundant dirty flags) - BOOL mEmpty; // if TRUE, client buffer is empty (or NULL). Old values have been discarded. - S32 mOffsets[TYPE_MAX]; - BOOL mResized; // if TRUE, client buffer has been resized and GL buffer has not - BOOL mDynamicSize; // if TRUE, buffer has been resized at least once (and should be padded) - - class DirtyRegion - { - public: - U32 mIndex; - U32 mCount; - U32 mIndicesIndex; - U32 mIndicesCount; - - DirtyRegion(U32 vi, U32 vc, U32 ii, U32 ic) - : mIndex(vi), mCount(vc), mIndicesIndex(ii), mIndicesCount(ic) - { } - }; - - std::vector mDirtyRegions; //vector of dirty regions to rebuild - -public: - static S32 sCount; - static S32 sGLCount; - static S32 sMappedCount; - static BOOL sMapped; - static std::vector sDeleteList; - typedef std::list buffer_list_t; - - static BOOL sDisableVBOMapping; //disable glMapBufferARB - static BOOL sEnableVBOs; - static S32 sTypeSize[TYPE_MAX]; - static BOOL sVBOActive; - static BOOL sIBOActive; - static U32 sGLMode[LLRender::NUM_MODES]; - static U32 sGLRenderBuffer; - static U32 sGLRenderIndices; - static U32 sLastMask; - static U32 sAllocatedBytes; - static U32 sBindCount; - static U32 sSetCount; -}; - - -#endif // LL_LLVERTEXBUFFER_H +/** + * @file llvertexbuffer.h + * @brief LLVertexBuffer wrapper for OpengGL vertex buffer objects + * + * $LicenseInfo:firstyear=2003&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_LLVERTEXBUFFER_H +#define LL_LLVERTEXBUFFER_H + +#include "llgl.h" +#include "v2math.h" +#include "v3math.h" +#include "v4math.h" +#include "v4coloru.h" +#include "llstrider.h" +#include "llrender.h" +#include +#include +#include + +//============================================================================ +// NOTES +// Threading: +// All constructors should take an 'create' paramater which should only be +// 'true' when called from the main thread. Otherwise createGLBuffer() will +// be called as soon as getVertexPointer(), etc is called (which MUST ONLY be +// called from the main (i.e OpenGL) thread) + + +//============================================================================ +// gl name pools for dynamic and streaming buffers + +class LLVBOPool : public LLGLNamePool +{ +protected: + virtual GLuint allocateName() + { + GLuint name; + glGenBuffersARB(1, &name); + return name; + } + + virtual void releaseName(GLuint name) + { + glDeleteBuffersARB(1, &name); + } +}; + + +//============================================================================ +// base class + +class LLVertexBuffer : public LLRefCount +{ +public: + LLVertexBuffer(const LLVertexBuffer& rhs) + { + *this = rhs; + } + + const LLVertexBuffer& operator=(const LLVertexBuffer& rhs) + { + llerrs << "Illegal operation!" << llendl; + return *this; + } + + static LLVBOPool sStreamVBOPool; + static LLVBOPool sDynamicVBOPool; + static LLVBOPool sStreamIBOPool; + static LLVBOPool sDynamicIBOPool; + + static S32 sWeight4Loc; + + static BOOL sUseStreamDraw; + static BOOL sPreferStreamDraw; + + static void initClass(bool use_vbo); + static void cleanupClass(); + static void setupClientArrays(U32 data_mask); + static void clientCopy(F64 max_time = 0.005); //copy data from client to GL + static void unbind(); //unbind any bound vertex buffer + + //get the size of a vertex with the given typemask + static S32 calcVertexSize(const U32& typemask); + + //get the size of a buffer with the given typemask and vertex count + //fill offsets with the offset of each vertex component array into the buffer + // indexed by the following enum + static S32 calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices); + + + enum { + TYPE_VERTEX, + TYPE_NORMAL, + TYPE_TEXCOORD0, + TYPE_TEXCOORD1, + TYPE_TEXCOORD2, + TYPE_TEXCOORD3, + TYPE_COLOR, + // These use VertexAttribPointer and should possibly be made generic + TYPE_BINORMAL, + TYPE_WEIGHT, + TYPE_WEIGHT4, + TYPE_CLOTHWEIGHT, + TYPE_MAX, + TYPE_INDEX, + }; + enum { + MAP_VERTEX = (1<getVertexBuffer(verts); + // vb->getNormalStrider(norms); + // setVertsNorms(verts, norms); + // vb->unmapBuffer(); + bool getVertexStrider(LLStrider& strider, S32 index=0); + bool getIndexStrider(LLStrider& strider, S32 index=0); + bool getTexCoord0Strider(LLStrider& strider, S32 index=0); + bool getTexCoord1Strider(LLStrider& strider, S32 index=0); + bool getNormalStrider(LLStrider& strider, S32 index=0); + bool getBinormalStrider(LLStrider& strider, S32 index=0); + bool getColorStrider(LLStrider& strider, S32 index=0); + bool getWeightStrider(LLStrider& strider, S32 index=0); + bool getWeight4Strider(LLStrider& strider, S32 index=0); + bool getClothWeightStrider(LLStrider& strider, S32 index=0); + + BOOL isEmpty() const { return mEmpty; } + BOOL isLocked() const { return mLocked; } + S32 getNumVerts() const { return mNumVerts; } + S32 getNumIndices() const { return mNumIndices; } + S32 getRequestedVerts() const { return mRequestedNumVerts; } + S32 getRequestedIndices() const { return mRequestedNumIndices; } + + U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; } + U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; } + U32 getTypeMask() const { return mTypeMask; } + bool hasDataType(S32 type) const { return ((1 << type) & getTypeMask()); } + S32 getSize() const; + S32 getIndicesSize() const { return mNumIndices * sizeof(U16); } + U8* getMappedData() const { return mMappedData; } + U8* getMappedIndices() const { return mMappedIndexData; } + S32 getOffset(S32 type) const { return mOffsets[type]; } + S32 getUsage() const { return mUsage; } + + void markDirty(U32 vert_index, U32 vert_count, U32 indices_index, U32 indices_count); + + void draw(U32 mode, U32 count, U32 indices_offset) const; + void drawArrays(U32 mode, U32 offset, U32 count) const; + void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const; + + //for debugging, validate data in given range is valid + void validateRange(U32 start, U32 end, U32 count, U32 offset) const; + + + +protected: + S32 mNumVerts; // Number of vertices allocated + S32 mNumIndices; // Number of indices allocated + S32 mRequestedNumVerts; // Number of vertices requested + S32 mRequestedNumIndices; // Number of indices requested + + ptrdiff_t mAlignedOffset; + ptrdiff_t mAlignedIndexOffset; + S32 mSize; + U32 mTypeMask; + S32 mUsage; // GL usage + U32 mGLBuffer; // GL VBO handle + U32 mGLIndices; // GL IBO handle + U8* mMappedData; // pointer to currently mapped data (NULL if unmapped) + U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped) + BOOL mLocked; // if TRUE, buffer is being or has been written to in client memory + BOOL mFinal; // if TRUE, buffer can not be mapped again + BOOL mFilthy; // if TRUE, entire buffer must be copied (used to prevent redundant dirty flags) + BOOL mEmpty; // if TRUE, client buffer is empty (or NULL). Old values have been discarded. + S32 mOffsets[TYPE_MAX]; + BOOL mResized; // if TRUE, client buffer has been resized and GL buffer has not + BOOL mDynamicSize; // if TRUE, buffer has been resized at least once (and should be padded) + + class DirtyRegion + { + public: + U32 mIndex; + U32 mCount; + U32 mIndicesIndex; + U32 mIndicesCount; + + DirtyRegion(U32 vi, U32 vc, U32 ii, U32 ic) + : mIndex(vi), mCount(vc), mIndicesIndex(ii), mIndicesCount(ic) + { } + }; + + std::vector mDirtyRegions; //vector of dirty regions to rebuild + +public: + static S32 sCount; + static S32 sGLCount; + static S32 sMappedCount; + static BOOL sMapped; + static std::vector sDeleteList; + typedef std::list buffer_list_t; + + static BOOL sEnableVBOs; + static S32 sTypeSize[TYPE_MAX]; + static U32 sGLMode[LLRender::NUM_MODES]; + static U32 sGLRenderBuffer; + static U32 sGLRenderIndices; + static BOOL sVBOActive; + static BOOL sIBOActive; + static U32 sLastMask; + static U32 sAllocatedBytes; + static U32 sBindCount; + static U32 sSetCount; +}; + + +#endif // LL_LLVERTEXBUFFER_H diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 71a611ba90..ec6b942e3e 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8799,17 +8799,6 @@ Value 1 - RenderVBOMappingDisable - - Comment - Disable VBO glMapBufferARB - Persist - 1 - Type - Boolean - Value - 1 - RenderUseStreamVBO Comment diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 075f32be24..46aa44b2bb 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -339,15 +339,6 @@ static bool handleNumpadControlChanged(const LLSD& newvalue) return true; } -static bool handleRenderUseVBOMappingChanged(const LLSD& newvalue) -{ - if (gPipeline.isInit()) - { - gPipeline.setDisableVBOMapping(newvalue.asBoolean()); - } - return true; -} - static bool handleWLSkyDetailChanged(const LLSD&) { if (gSky.mVOWLSkyp.notNull()) @@ -637,7 +628,6 @@ void settings_setup_listeners() gSavedSettings.getControl("MuteAmbient")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); gSavedSettings.getControl("MuteUI")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); gSavedSettings.getControl("RenderVBOEnable")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); - gSavedSettings.getControl("RenderVBOMappingDisable")->getSignal()->connect(boost::bind(&handleRenderUseVBOMappingChanged, _2)); gSavedSettings.getControl("RenderUseStreamVBO")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderPreferStreamDraw")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("WLSkyDetail")->getSignal()->connect(boost::bind(&handleWLSkyDetailChanged, _2)); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 94fb0b7d31..d5008c12b0 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1552,7 +1552,7 @@ LLViewerWindow::LLViewerWindow( { gSavedSettings.setBOOL("RenderVBOEnable", FALSE); } - LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable")); + LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable")); if (LLFeatureManager::getInstance()->isSafe() || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion()) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 998fa88925..a8e36df294 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1,9619 +1,9629 @@ -/** - * @file pipeline.cpp - * @brief Rendering pipeline. - * - * $LicenseInfo:firstyear=2005&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 "llviewerprecompiledheaders.h" - -#include "pipeline.h" - -// library includes -#include "llaudioengine.h" // For debugging. -#include "imageids.h" -#include "llerror.h" -#include "llviewercontrol.h" -#include "llfasttimer.h" -#include "llfontgl.h" -#include "llmemtype.h" -#include "llnamevalue.h" -#include "llpointer.h" -#include "llprimitive.h" -#include "llvolume.h" -#include "material_codes.h" -#include "timing.h" -#include "v3color.h" -#include "llui.h" -#include "llglheaders.h" -#include "llrender.h" -#include "llwindow.h" // swapBuffers() - -// newview includes -#include "llagent.h" -#include "llagentcamera.h" -#include "lldrawable.h" -#include "lldrawpoolalpha.h" -#include "lldrawpoolavatar.h" -#include "lldrawpoolground.h" -#include "lldrawpoolbump.h" -#include "lldrawpooltree.h" -#include "lldrawpoolwater.h" -#include "llface.h" -#include "llfeaturemanager.h" -#include "llfloatertelehub.h" -#include "llfloaterreg.h" -#include "llgldbg.h" -#include "llhudmanager.h" -#include "llhudnametag.h" -#include "llhudtext.h" -#include "lllightconstants.h" -#include "llmeshrepository.h" -#include "llresmgr.h" -#include "llselectmgr.h" -#include "llsky.h" -#include "lltracker.h" -#include "lltool.h" -#include "lltoolmgr.h" -#include "llviewercamera.h" -#include "llviewertexturelist.h" -#include "llviewerobject.h" -#include "llviewerobjectlist.h" -#include "llviewerparcelmgr.h" -#include "llviewerregion.h" // for audio debugging. -#include "llviewerwindow.h" // For getSpinAxis -#include "llvoavatarself.h" -#include "llvoground.h" -#include "llvosky.h" -#include "llvotree.h" -#include "llvovolume.h" -#include "llvosurfacepatch.h" -#include "llvowater.h" -#include "llvotree.h" -#include "llvopartgroup.h" -#include "llworld.h" -#include "llcubemap.h" -#include "llviewershadermgr.h" -#include "llviewerstats.h" -#include "llviewerjoystick.h" -#include "llviewerdisplay.h" -#include "llwlparammanager.h" -#include "llwaterparammanager.h" -#include "llspatialpartition.h" -#include "llmutelist.h" -#include "lltoolpie.h" -#include "llcurl.h" - - -void check_stack_depth(S32 stack_depth) -{ - if (gDebugGL || gDebugSession) - { - GLint depth; - glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth); - if (depth != stack_depth) - { - if (gDebugSession) - { - ll_fail("GL matrix stack corrupted."); - } - else - { - llerrs << "GL matrix stack corrupted!" << llendl; - } - } - } -} - -#ifdef _DEBUG -// Debug indices is disabled for now for debug performance - djs 4/24/02 -//#define DEBUG_INDICES -#else -//#define DEBUG_INDICES -#endif - -const F32 BACKLIGHT_DAY_MAGNITUDE_AVATAR = 0.2f; -const F32 BACKLIGHT_NIGHT_MAGNITUDE_AVATAR = 0.1f; -const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f; -const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f; -const S32 MAX_OFFSCREEN_GEOMETRY_CHANGES_PER_FRAME = 10; -const U32 REFLECTION_MAP_RES = 128; - -// Max number of occluders to search for. JC -const S32 MAX_OCCLUDER_COUNT = 2; - -extern S32 gBoxFrame; -//extern BOOL gHideSelectedObjects; -extern BOOL gDisplaySwapBuffers; -extern BOOL gDebugGL; - -// hack counter for rendering a fixed number of frames after toggling -// fullscreen to work around DEV-5361 -static S32 sDelayedVBOEnable = 0; - -BOOL gAvatarBacklight = FALSE; - -BOOL gDebugPipeline = FALSE; -LLPipeline gPipeline; -const LLMatrix4* gGLLastMatrix = NULL; - -LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry"); -LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass"); -LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible"); -LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion"); -LLFastTimer::DeclareTimer FTM_RENDER_SHINY("Shiny"); -LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE("Simple"); -LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN("Terrain"); -LLFastTimer::DeclareTimer FTM_RENDER_TREES("Trees"); -LLFastTimer::DeclareTimer FTM_RENDER_UI("UI"); -LLFastTimer::DeclareTimer FTM_RENDER_WATER("Water"); -LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky"); -LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects"); -LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars"); -LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump"); -LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright"); -LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow"); -LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update"); -LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool"); -LLFastTimer::DeclareTimer FTM_POOLS("Pools"); -LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO"); -LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State"); -LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline"); -LLFastTimer::DeclareTimer FTM_CLIENT_COPY("Client Copy"); -LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading"); - - -static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables"); -static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort"); - -//---------------------------------------- -std::string gPoolNames[] = -{ - // Correspond to LLDrawpool enum render type - "NONE", - "POOL_SIMPLE", - "POOL_TERRAIN", - "POOL_BUMP", - "POOL_TREE", - "POOL_SKY", - "POOL_WL_SKY", - "POOL_GROUND", - "POOL_INVISIBLE", - "POOL_AVATAR", - "POOL_WATER", - "POOL_GRASS", - "POOL_FULLBRIGHT", - "POOL_GLOW", - "POOL_ALPHA", -}; - -void drawBox(const LLVector3& c, const LLVector3& r); -void drawBoxOutline(const LLVector3& pos, const LLVector3& size); - -U32 nhpo2(U32 v) -{ - U32 r = 1; - while (r < v) { - r *= 2; - } - return r; -} - -glh::matrix4f glh_copy_matrix(GLdouble* src) -{ - glh::matrix4f ret; - for (U32 i = 0; i < 16; i++) - { - ret.m[i] = (F32) src[i]; - } - return ret; -} - -glh::matrix4f glh_get_current_modelview() -{ - return glh_copy_matrix(gGLModelView); -} - -glh::matrix4f glh_get_current_projection() -{ - return glh_copy_matrix(gGLProjection); -} - -void glh_copy_matrix(const glh::matrix4f& src, GLdouble* dst) -{ - for (U32 i = 0; i < 16; i++) - { - dst[i] = src.m[i]; - } -} - -void glh_set_current_modelview(const glh::matrix4f& mat) -{ - glh_copy_matrix(mat, gGLModelView); -} - -void glh_set_current_projection(glh::matrix4f& mat) -{ - glh_copy_matrix(mat, gGLProjection); -} - -glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar) -{ - glh::matrix4f ret( - 2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left), - 0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom), - 0.f, 0.f, -2.f/(zfar-znear), -(zfar+znear)/(zfar-znear), - 0.f, 0.f, 0.f, 1.f); - - return ret; -} - -void display_update_camera(); -//---------------------------------------- - -S32 LLPipeline::sCompiles = 0; - -BOOL LLPipeline::sPickAvatar = TRUE; -BOOL LLPipeline::sDynamicLOD = TRUE; -BOOL LLPipeline::sShowHUDAttachments = TRUE; -BOOL LLPipeline::sRenderPhysicalBeacons = TRUE; -BOOL LLPipeline::sRenderScriptedBeacons = FALSE; -BOOL LLPipeline::sRenderScriptedTouchBeacons = TRUE; -BOOL LLPipeline::sRenderParticleBeacons = FALSE; -BOOL LLPipeline::sRenderSoundBeacons = FALSE; -BOOL LLPipeline::sRenderBeacons = FALSE; -BOOL LLPipeline::sRenderHighlight = TRUE; -BOOL LLPipeline::sForceOldBakedUpload = FALSE; -S32 LLPipeline::sUseOcclusion = 0; -BOOL LLPipeline::sDelayVBUpdate = TRUE; -BOOL LLPipeline::sAutoMaskAlphaDeferred = TRUE; -BOOL LLPipeline::sAutoMaskAlphaNonDeferred = FALSE; -BOOL LLPipeline::sDisableShaders = FALSE; -BOOL LLPipeline::sRenderBump = TRUE; -BOOL LLPipeline::sBakeSunlight = FALSE; -BOOL LLPipeline::sNoAlpha = FALSE; -BOOL LLPipeline::sUseTriStrips = TRUE; -BOOL LLPipeline::sUseFarClip = TRUE; -BOOL LLPipeline::sShadowRender = FALSE; -BOOL LLPipeline::sWaterReflections = FALSE; -BOOL LLPipeline::sRenderGlow = FALSE; -BOOL LLPipeline::sReflectionRender = FALSE; -BOOL LLPipeline::sImpostorRender = FALSE; -BOOL LLPipeline::sUnderWaterRender = FALSE; -BOOL LLPipeline::sTextureBindTest = FALSE; -BOOL LLPipeline::sRenderFrameTest = FALSE; -BOOL LLPipeline::sRenderAttachedLights = TRUE; -BOOL LLPipeline::sRenderAttachedParticles = TRUE; -BOOL LLPipeline::sRenderDeferred = FALSE; -S32 LLPipeline::sVisibleLightCount = 0; -F32 LLPipeline::sMinRenderSize = 0.f; - - -static LLCullResult* sCull = NULL; - -static const U32 gl_cube_face[] = -{ - GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, -}; - -void validate_framebuffer_object(); - - -void addDeferredAttachments(LLRenderTarget& target) -{ - target.addColorAttachment(GL_RGBA); //specular - target.addColorAttachment(GL_RGBA); //normal+z -} - -LLPipeline::LLPipeline() : - mBackfaceCull(FALSE), - mBatchCount(0), - mMatrixOpCount(0), - mTextureMatrixOps(0), - mMaxBatchSize(0), - mMinBatchSize(0), - mMeanBatchSize(0), - mTrianglesDrawn(0), - mNumVisibleNodes(0), - mVerticesRelit(0), - mLightingChanges(0), - mGeometryChanges(0), - mNumVisibleFaces(0), - - mInitialized(FALSE), - mVertexShadersEnabled(FALSE), - mVertexShadersLoaded(0), - mRenderDebugFeatureMask(0), - mRenderDebugMask(0), - mOldRenderDebugMask(0), - mGroupQ1Locked(false), - mGroupQ2Locked(false), - mLastRebuildPool(NULL), - mAlphaPool(NULL), - mSkyPool(NULL), - mTerrainPool(NULL), - mWaterPool(NULL), - mGroundPool(NULL), - mSimplePool(NULL), - mFullbrightPool(NULL), - mInvisiblePool(NULL), - mGlowPool(NULL), - mBumpPool(NULL), - mWLSkyPool(NULL), - mLightMask(0), - mLightMovingMask(0), - mLightingDetail(0), - mScreenWidth(0), - mScreenHeight(0) -{ - mNoiseMap = 0; - mTrueNoiseMap = 0; - mLightFunc = 0; -} - -void LLPipeline::init() -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_INIT); - - sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD"); - sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); - sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips"); - LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO"); - LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw"); - sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); - sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); - - mInitialized = TRUE; - - stop_glerror(); - - //create render pass pools - getPool(LLDrawPool::POOL_ALPHA); - getPool(LLDrawPool::POOL_SIMPLE); - getPool(LLDrawPool::POOL_GRASS); - getPool(LLDrawPool::POOL_FULLBRIGHT); - getPool(LLDrawPool::POOL_INVISIBLE); - getPool(LLDrawPool::POOL_BUMP); - getPool(LLDrawPool::POOL_GLOW); - - LLViewerStats::getInstance()->mTrianglesDrawnStat.reset(); - resetFrameStats(); - - for (U32 i = 0; i < NUM_RENDER_TYPES; ++i) - { - mRenderTypeEnabled[i] = TRUE; //all rendering types start enabled - } - - mRenderDebugFeatureMask = 0xffffffff; // All debugging features on - mRenderDebugMask = 0; // All debug starts off - - // Don't turn on ground when this is set - // Mac Books with intel 950s need this - if(!gSavedSettings.getBOOL("RenderGround")) - { - toggleRenderType(RENDER_TYPE_GROUND); - } - - // make sure RenderPerformanceTest persists (hackity hack hack) - // disables non-object rendering (UI, sky, water, etc) - if (gSavedSettings.getBOOL("RenderPerformanceTest")) - { - gSavedSettings.setBOOL("RenderPerformanceTest", FALSE); - gSavedSettings.setBOOL("RenderPerformanceTest", TRUE); - } - - mOldRenderDebugMask = mRenderDebugMask; - - mBackfaceCull = TRUE; - - stop_glerror(); - - // Enable features - - LLViewerShaderMgr::instance()->setShaders(); - - stop_glerror(); - - for (U32 i = 0; i < 2; ++i) - { - mSpotLightFade[i] = 1.f; - } - - setLightingDetail(-1); -} - -LLPipeline::~LLPipeline() -{ - -} - -void LLPipeline::cleanup() -{ - assertInitialized(); - - mGroupQ1.clear() ; - mGroupQ2.clear() ; - - for(pool_set_t::iterator iter = mPools.begin(); - iter != mPools.end(); ) - { - pool_set_t::iterator curiter = iter++; - LLDrawPool* poolp = *curiter; - if (poolp->isFacePool()) - { - LLFacePool* face_pool = (LLFacePool*) poolp; - if (face_pool->mReferences.empty()) - { - mPools.erase(curiter); - removeFromQuickLookup( poolp ); - delete poolp; - } - } - else - { - mPools.erase(curiter); - removeFromQuickLookup( poolp ); - delete poolp; - } - } - - if (!mTerrainPools.empty()) - { - llwarns << "Terrain Pools not cleaned up" << llendl; - } - if (!mTreePools.empty()) - { - llwarns << "Tree Pools not cleaned up" << llendl; - } - - delete mAlphaPool; - mAlphaPool = NULL; - delete mSkyPool; - mSkyPool = NULL; - delete mTerrainPool; - mTerrainPool = NULL; - delete mWaterPool; - mWaterPool = NULL; - delete mGroundPool; - mGroundPool = NULL; - delete mSimplePool; - mSimplePool = NULL; - delete mFullbrightPool; - mFullbrightPool = NULL; - delete mInvisiblePool; - mInvisiblePool = NULL; - delete mGlowPool; - mGlowPool = NULL; - delete mBumpPool; - mBumpPool = NULL; - // don't delete wl sky pool it was handled above in the for loop - //delete mWLSkyPool; - mWLSkyPool = NULL; - - releaseGLBuffers(); - - mFaceSelectImagep = NULL; - - mMovedBridge.clear(); - - mInitialized = FALSE; -} - -//============================================================================ - -void LLPipeline::destroyGL() -{ - stop_glerror(); - unloadShaders(); - mHighlightFaces.clear(); - - resetDrawOrders(); - - resetVertexBuffers(); - - releaseGLBuffers(); - - if (LLVertexBuffer::sEnableVBOs) - { - // render 30 frames after switching to work around DEV-5361 - sDelayedVBOEnable = 30; - LLVertexBuffer::sEnableVBOs = FALSE; - } -} - -static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture"); - -void LLPipeline::resizeScreenTexture() -{ - LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE); - if (gPipeline.canUseVertexShaders() && assertInitialized()) - { - GLuint resX = gViewerWindow->getWorldViewWidthRaw(); - GLuint resY = gViewerWindow->getWorldViewHeightRaw(); - - allocateScreenBuffer(resX,resY); - } -} - -void LLPipeline::allocatePhysicsBuffer() -{ - GLuint resX = gViewerWindow->getWorldViewWidthRaw(); - GLuint resY = gViewerWindow->getWorldViewHeightRaw(); - - if (mPhysicsDisplay.getWidth() != resX || mPhysicsDisplay.getHeight() != resY) - { - mPhysicsDisplay.allocate(resX, resY, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); - if (mSampleBuffer.getWidth() == mPhysicsDisplay.getWidth() && - mSampleBuffer.getHeight() == mPhysicsDisplay.getHeight()) - { - mPhysicsDisplay.setSampleBuffer(&mSampleBuffer); - } - } -} - -void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY) -{ - // remember these dimensions - mScreenWidth = resX; - mScreenHeight = resY; - - //never use more than 4 samples for render targets - U32 samples = llmin(gSavedSettings.getU32("RenderFSAASamples"), (U32) 4); - if (gGLManager.mIsATI) - { //disable multisampling of render targets where ATI is involved - samples = 0; - } - - U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor"); - - if (res_mod > 1 && res_mod < resX && res_mod < resY) - { - resX /= res_mod; - resY /= res_mod; - } - - if (gSavedSettings.getBOOL("RenderUIBuffer")) - { - mUIScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); - } - - if (LLPipeline::sRenderDeferred) - { - S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail"); - BOOL ssao = gSavedSettings.getBOOL("RenderDeferredSSAO"); - bool gi = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED); - - //allocate deferred rendering color buffers - mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE); - mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); - addDeferredAttachments(mDeferredScreen); - - mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); - mEdgeMap.allocate(resX, resY, GL_ALPHA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); - - if (shadow_detail > 0 || ssao) - { //only need mDeferredLight[0] for shadows OR ssao - mDeferredLight[0].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE); - } - else - { - mDeferredLight[0].release(); - } - - if (ssao) - { //only need mDeferredLight[1] for ssao - mDeferredLight[1].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE); - } - else - { - mDeferredLight[1].release(); - } - - if (gi) - { //only need mDeferredLight[2] and mGIMapPost for gi - mDeferredLight[2].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE); - for (U32 i = 0; i < 2; i++) - { - mGIMapPost[i].allocate(resX,resY, GL_RGB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE); - } - } - else - { - mDeferredLight[2].release(); - - for (U32 i = 0; i < 2; i++) - { - mGIMapPost[i].release(); - } - } - - F32 scale = gSavedSettings.getF32("RenderShadowResolutionScale"); - - //HACK: make alpha masking work on ATI depth shadows (work around for ATI driver bug) - U32 shadow_fmt = gGLManager.mIsATI ? GL_ALPHA : 0; - - if (shadow_detail > 0) - { //allocate 4 sun shadow maps - for (U32 i = 0; i < 4; i++) - { - mShadow[i].allocate(U32(resX*scale),U32(resY*scale), shadow_fmt, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE); - } - } - else - { - for (U32 i = 0; i < 4; i++) - { - mShadow[i].release(); - } - } - - U32 width = nhpo2(U32(resX*scale))/2; - U32 height = width; - - if (shadow_detail > 1) - { //allocate two spot shadow maps - for (U32 i = 4; i < 6; i++) - { - mShadow[i].allocate(width, height, shadow_fmt, TRUE, FALSE); - } - } - else - { - for (U32 i = 4; i < 6; i++) - { - mShadow[i].release(); - } - } - - width = nhpo2(resX)/2; - height = nhpo2(resY)/2; - mLuminanceMap.allocate(width,height, GL_RGBA, FALSE, FALSE); - } - else - { - for (U32 i = 0; i < 3; i++) - { - mDeferredLight[i].release(); - } - for (U32 i = 0; i < 2; i++) - { - mGIMapPost[i].release(); - } - for (U32 i = 0; i < 6; i++) - { - mShadow[i].release(); - } - mScreen.release(); - mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first - mDeferredDepth.release(); - mEdgeMap.release(); - mLuminanceMap.release(); - - mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE); - } - - if (LLRenderTarget::sUseFBO && samples > 1) - { - mSampleBuffer.allocate(resX,resY,GL_RGBA,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples); - if (LLPipeline::sRenderDeferred) - { - addDeferredAttachments(mSampleBuffer); - mDeferredScreen.setSampleBuffer(&mSampleBuffer); - mEdgeMap.setSampleBuffer(&mSampleBuffer); - } - - mScreen.setSampleBuffer(&mSampleBuffer); - - stop_glerror(); - } - else - { - mSampleBuffer.release(); - } - - if (LLPipeline::sRenderDeferred) - { //share depth buffer between deferred targets - mDeferredScreen.shareDepthBuffer(mScreen); - for (U32 i = 0; i < 3; i++) - { //share stencil buffer with screen space lightmap to stencil out sky - if (mDeferredLight[i].getTexture(0)) - { - mDeferredScreen.shareDepthBuffer(mDeferredLight[i]); - } - } - } - - gGL.getTexUnit(0)->disable(); - - stop_glerror(); - -} - -//static -void LLPipeline::updateRenderDeferred() -{ - BOOL deferred = ((gSavedSettings.getBOOL("RenderDeferred") && - LLRenderTarget::sUseFBO && - LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && - gSavedSettings.getBOOL("VertexShaderEnable") && - gSavedSettings.getBOOL("RenderAvatarVP") && - gSavedSettings.getBOOL("WindLightUseAtmosShaders")) ? TRUE : FALSE) && - !gUseWireframe; - - sRenderDeferred = deferred; - if (deferred) - { //must render glow when rendering deferred since post effect pass is needed to present any lighting at all - sRenderGlow = TRUE; - } -} - -void LLPipeline::releaseGLBuffers() -{ - assertInitialized(); - - if (mNoiseMap) - { - LLImageGL::deleteTextures(1, &mNoiseMap); - mNoiseMap = 0; - } - - if (mTrueNoiseMap) - { - LLImageGL::deleteTextures(1, &mTrueNoiseMap); - mTrueNoiseMap = 0; - } - - if (mLightFunc) - { - LLImageGL::deleteTextures(1, &mLightFunc); - mLightFunc = 0; - } - - mWaterRef.release(); - mWaterDis.release(); - mScreen.release(); - mPhysicsDisplay.release(); - mUIScreen.release(); - mSampleBuffer.release(); - mDeferredScreen.release(); - mDeferredDepth.release(); - for (U32 i = 0; i < 3; i++) - { - mDeferredLight[i].release(); - } - - mEdgeMap.release(); - mGIMap.release(); - mGIMapPost[0].release(); - mGIMapPost[1].release(); - mHighlight.release(); - mLuminanceMap.release(); - - for (U32 i = 0; i < 6; i++) - { - mShadow[i].release(); - } - - for (U32 i = 0; i < 3; i++) - { - mGlow[i].release(); - } - - LLVOAvatar::resetImpostors(); -} - -void LLPipeline::createGLBuffers() -{ - LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS); - assertInitialized(); - - updateRenderDeferred(); - - if (LLPipeline::sWaterReflections) - { //water reflection texture - U32 res = (U32) gSavedSettings.getS32("RenderWaterRefResolution"); - - mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE); - mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE); - } - - mHighlight.allocate(256,256,GL_RGBA, FALSE, FALSE); - - stop_glerror(); - - GLuint resX = gViewerWindow->getWorldViewWidthRaw(); - GLuint resY = gViewerWindow->getWorldViewHeightRaw(); - - if (LLPipeline::sRenderGlow) - { //screen space glow buffers - const U32 glow_res = llmax(1, - llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow"))); - - for (U32 i = 0; i < 3; i++) - { - mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE,FALSE); - } - - allocateScreenBuffer(resX,resY); - mScreenWidth = 0; - mScreenHeight = 0; - } - - if (sRenderDeferred) - { - if (!mNoiseMap) - { - const U32 noiseRes = 128; - LLVector3 noise[noiseRes*noiseRes]; - - F32 scaler = gSavedSettings.getF32("RenderDeferredNoise")/100.f; - for (U32 i = 0; i < noiseRes*noiseRes; ++i) - { - noise[i] = LLVector3(ll_frand()-0.5f, ll_frand()-0.5f, 0.f); - noise[i].normVec(); - noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f; - } - - LLImageGL::generateTextures(1, &mNoiseMap); - - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap); - LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - if (!mTrueNoiseMap) - { - const U32 noiseRes = 128; - F32 noise[noiseRes*noiseRes*3]; - for (U32 i = 0; i < noiseRes*noiseRes*3; i++) - { - noise[i] = ll_frand()*2.0-1.0; - } - - LLImageGL::generateTextures(1, &mTrueNoiseMap); - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap); - LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - if (!mLightFunc) - { - U32 lightResX = gSavedSettings.getU32("RenderSpecularResX"); - U32 lightResY = gSavedSettings.getU32("RenderSpecularResY"); - U8* lg = new U8[lightResX*lightResY]; - - for (U32 y = 0; y < lightResY; ++y) - { - for (U32 x = 0; x < lightResX; ++x) - { - //spec func - F32 sa = (F32) x/(lightResX-1); - F32 spec = (F32) y/(lightResY-1); - //lg[y*lightResX+x] = (U8) (powf(sa, 128.f*spec*spec)*255); - - //F32 sp = acosf(sa)/(1.f-spec); - - sa = powf(sa, gSavedSettings.getF32("RenderSpecularExponent")); - F32 a = acosf(sa*0.25f+0.75f); - F32 m = llmax(0.5f-spec*0.5f, 0.001f); - F32 t2 = tanf(a)/m; - t2 *= t2; - - F32 c4a = (3.f+4.f*cosf(2.f*a)+cosf(4.f*a))/8.f; - F32 bd = 1.f/(4.f*m*m*c4a)*powf(F_E, -t2); - - lg[y*lightResX+x] = (U8) (llclamp(bd, 0.f, 1.f)*255); - } - } - - LLImageGL::generateTextures(1, &mLightFunc); - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); - LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_ALPHA, lightResX, lightResY, GL_ALPHA, GL_UNSIGNED_BYTE, lg); - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR); - - delete [] lg; - } - - if (gSavedSettings.getBOOL("RenderDeferredGI")) - { - mGIMap.allocate(512,512,GL_RGBA, TRUE, FALSE); - addDeferredAttachments(mGIMap); - } - } -} - -void LLPipeline::restoreGL() -{ - LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_RESTORE_GL); - assertInitialized(); - - if (mVertexShadersEnabled) - { - LLViewerShaderMgr::instance()->setShaders(); - } - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - part->restoreGL(); - } - } - } -} - - -BOOL LLPipeline::canUseVertexShaders() -{ - if (sDisableShaders || - !gGLManager.mHasVertexShader || - !gGLManager.mHasFragmentShader || - !LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") || - (assertInitialized() && mVertexShadersLoaded != 1) ) - { - return FALSE; - } - else - { - return TRUE; - } -} - -BOOL LLPipeline::canUseWindLightShaders() const -{ - return (!LLPipeline::sDisableShaders && - gWLSkyProgram.mProgramObject != 0 && - LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1); -} - -BOOL LLPipeline::canUseWindLightShadersOnObjects() const -{ - return (canUseWindLightShaders() - && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0); -} - -BOOL LLPipeline::canUseAntiAliasing() const -{ - return TRUE; -} - -void LLPipeline::unloadShaders() -{ - LLMemType mt_us(LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS); - LLViewerShaderMgr::instance()->unloadShaders(); - - mVertexShadersLoaded = 0; -} - -void LLPipeline::assertInitializedDoError() -{ - llerrs << "LLPipeline used when uninitialized." << llendl; -} - -//============================================================================ - -void LLPipeline::enableShadows(const BOOL enable_shadows) -{ - //should probably do something here to wrangle shadows.... -} - -S32 LLPipeline::getMaxLightingDetail() const -{ - /*if (mVertexShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS) - { - return 3; - } - else*/ - { - return 1; - } -} - -S32 LLPipeline::setLightingDetail(S32 level) -{ - LLMemType mt_ld(LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL); - - if (level < 0) - { - if (gSavedSettings.getBOOL("RenderLocalLights")) - { - level = 1; - } - else - { - level = 0; - } - } - level = llclamp(level, 0, getMaxLightingDetail()); - mLightingDetail = level; - - return mLightingDetail; -} - -class LLOctreeDirtyTexture : public LLOctreeTraveler -{ -public: - const std::set& mTextures; - - LLOctreeDirtyTexture(const std::set& textures) : mTextures(textures) { } - - virtual void visit(const LLOctreeNode* node) - { - LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - - if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->getData().empty()) - { - for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) - { - for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) - { - LLDrawInfo* params = *j; - LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params->mTexture); - if (tex && mTextures.find(tex) != mTextures.end()) - { - group->setState(LLSpatialGroup::GEOM_DIRTY); - } - } - } - } - - for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i) - { - LLSpatialBridge* bridge = *i; - traverse(bridge->mOctree); - } - } -}; - -// Called when a texture changes # of channels (causes faces to move to alpha pool) -void LLPipeline::dirtyPoolObjectTextures(const std::set& textures) -{ - assertInitialized(); - - // *TODO: This is inefficient and causes frame spikes; need a better way to do this - // Most of the time is spent in dirty.traverse. - - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - if (poolp->isFacePool()) - { - ((LLFacePool*) poolp)->dirtyTextures(textures); - } - } - - LLOctreeDirtyTexture dirty(textures); - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - dirty.traverse(part->mOctree); - } - } - } -} - -LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0) -{ - assertInitialized(); - - LLDrawPool *poolp = NULL; - switch( type ) - { - case LLDrawPool::POOL_SIMPLE: - poolp = mSimplePool; - break; - - case LLDrawPool::POOL_GRASS: - poolp = mGrassPool; - break; - - case LLDrawPool::POOL_FULLBRIGHT: - poolp = mFullbrightPool; - break; - - case LLDrawPool::POOL_INVISIBLE: - poolp = mInvisiblePool; - break; - - case LLDrawPool::POOL_GLOW: - poolp = mGlowPool; - break; - - case LLDrawPool::POOL_TREE: - poolp = get_if_there(mTreePools, (uintptr_t)tex0, (LLDrawPool*)0 ); - break; - - case LLDrawPool::POOL_TERRAIN: - poolp = get_if_there(mTerrainPools, (uintptr_t)tex0, (LLDrawPool*)0 ); - break; - - case LLDrawPool::POOL_BUMP: - poolp = mBumpPool; - break; - - case LLDrawPool::POOL_ALPHA: - poolp = mAlphaPool; - break; - - case LLDrawPool::POOL_AVATAR: - break; // Do nothing - - case LLDrawPool::POOL_SKY: - poolp = mSkyPool; - break; - - case LLDrawPool::POOL_WATER: - poolp = mWaterPool; - break; - - case LLDrawPool::POOL_GROUND: - poolp = mGroundPool; - break; - - case LLDrawPool::POOL_WL_SKY: - poolp = mWLSkyPool; - break; - - default: - llassert(0); - llerrs << "Invalid Pool Type in LLPipeline::findPool() type=" << type << llendl; - break; - } - - return poolp; -} - - -LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerTexture *tex0) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE); - LLDrawPool *poolp = findPool(type, tex0); - if (poolp) - { - return poolp; - } - - LLDrawPool *new_poolp = LLDrawPool::createPool(type, tex0); - addPool( new_poolp ); - - return new_poolp; -} - - -// static -LLDrawPool* LLPipeline::getPoolFromTE(const LLTextureEntry* te, LLViewerTexture* imagep) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE); - U32 type = getPoolTypeFromTE(te, imagep); - return gPipeline.getPool(type, imagep); -} - -//static -U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* imagep) -{ - LLMemType mt_gpt(LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE); - - if (!te || !imagep) - { - return 0; - } - - bool alpha = te->getColor().mV[3] < 0.999f; - if (imagep) - { - alpha = alpha || (imagep->getComponents() == 4 && imagep->getType() != LLViewerTexture::MEDIA_TEXTURE) || (imagep->getComponents() == 2); - } - - if (alpha) - { - return LLDrawPool::POOL_ALPHA; - } - else if ((te->getBumpmap() || te->getShiny())) - { - return LLDrawPool::POOL_BUMP; - } - else - { - return LLDrawPool::POOL_SIMPLE; - } -} - - -void LLPipeline::addPool(LLDrawPool *new_poolp) -{ - LLMemType mt_a(LLMemType::MTYPE_PIPELINE_ADD_POOL); - assertInitialized(); - mPools.insert(new_poolp); - addToQuickLookup( new_poolp ); -} - -void LLPipeline::allocDrawable(LLViewerObject *vobj) -{ - LLMemType mt_ad(LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE); - LLDrawable *drawable = new LLDrawable(); - vobj->mDrawable = drawable; - - drawable->mVObjp = vobj; - - //encompass completely sheared objects by taking - //the most extreme point possible (<1,1,0.5>) - drawable->setRadius(LLVector3(1,1,0.5f).scaleVec(vobj->getScale()).length()); - if (vobj->isOrphaned()) - { - drawable->setState(LLDrawable::FORCE_INVISIBLE); - } - drawable->updateXform(TRUE); -} - - -static LLFastTimer::DeclareTimer FTM_UNLINK("Unlink"); -static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_MOVE_LIST("Movelist"); -static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition"); -static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_LIGHT_SET("Light Set"); -static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set"); - -void LLPipeline::unlinkDrawable(LLDrawable *drawable) -{ - LLFastTimer t(FTM_UNLINK); - - assertInitialized(); - - LLPointer drawablep = drawable; // make sure this doesn't get deleted before we are done - - // Based on flags, remove the drawable from the queues that it's on. - if (drawablep->isState(LLDrawable::ON_MOVE_LIST)) - { - LLFastTimer t(FTM_REMOVE_FROM_MOVE_LIST); - LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep); - if (iter != mMovedList.end()) - { - mMovedList.erase(iter); - } - } - - if (drawablep->getSpatialGroup()) - { - LLFastTimer t(FTM_REMOVE_FROM_SPATIAL_PARTITION); - if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup())) - { -#ifdef LL_RELEASE_FOR_DOWNLOAD - llwarns << "Couldn't remove object from spatial group!" << llendl; -#else - llerrs << "Couldn't remove object from spatial group!" << llendl; -#endif - } - } - - { - LLFastTimer t(FTM_REMOVE_FROM_LIGHT_SET); - mLights.erase(drawablep); - - for (light_set_t::iterator iter = mNearbyLights.begin(); - iter != mNearbyLights.end(); iter++) - { - if (iter->drawable == drawablep) - { - mNearbyLights.erase(iter); - break; - } - } - } - - { - LLFastTimer t(FTM_REMOVE_FROM_HIGHLIGHT_SET); - HighlightItem item(drawablep); - mHighlightSet.erase(item); - - if (mHighlightObject == drawablep) - { - mHighlightObject = NULL; - } - } - - for (U32 i = 0; i < 2; ++i) - { - if (mShadowSpotLight[i] == drawablep) - { - mShadowSpotLight[i] = NULL; - } - - if (mTargetShadowSpotLight[i] == drawablep) - { - mTargetShadowSpotLight[i] = NULL; - } - } - - -} - -U32 LLPipeline::addObject(LLViewerObject *vobj) -{ - LLMemType mt_ao(LLMemType::MTYPE_PIPELINE_ADD_OBJECT); - if (gNoRender) - { - return 0; - } - - if (gSavedSettings.getBOOL("RenderDelayCreation")) - { - mCreateQ.push_back(vobj); - } - else - { - createObject(vobj); - } - - return 1; -} - -void LLPipeline::createObjects(F32 max_dtime) -{ - LLFastTimer ftm(FTM_GEO_UPDATE); - LLMemType mt(LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS); - - LLTimer update_timer; - - while (!mCreateQ.empty() && update_timer.getElapsedTimeF32() < max_dtime) - { - LLViewerObject* vobj = mCreateQ.front(); - if (!vobj->isDead()) - { - createObject(vobj); - } - mCreateQ.pop_front(); - } - - //for (LLViewerObject::vobj_list_t::iterator iter = mCreateQ.begin(); iter != mCreateQ.end(); ++iter) - //{ - // createObject(*iter); - //} - - //mCreateQ.clear(); -} - -void LLPipeline::createObject(LLViewerObject* vobj) -{ - LLDrawable* drawablep = vobj->mDrawable; - - if (!drawablep) - { - drawablep = vobj->createDrawable(this); - } - else - { - llerrs << "Redundant drawable creation!" << llendl; - } - - llassert(drawablep); - - if (vobj->getParent()) - { - vobj->setDrawableParent(((LLViewerObject*)vobj->getParent())->mDrawable); // LLPipeline::addObject 1 - } - else - { - vobj->setDrawableParent(NULL); // LLPipeline::addObject 2 - } - - markRebuild(drawablep, LLDrawable::REBUILD_ALL, TRUE); - - if (drawablep->getVOVolume() && gSavedSettings.getBOOL("RenderAnimateRes")) - { - // fun animated res - drawablep->updateXform(TRUE); - drawablep->clearState(LLDrawable::MOVE_UNDAMPED); - drawablep->setScale(LLVector3(0,0,0)); - drawablep->makeActive(); - } -} - - -void LLPipeline::resetFrameStats() -{ - assertInitialized(); - - LLViewerStats::getInstance()->mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f); - - if (mBatchCount > 0) - { - mMeanBatchSize = gPipeline.mTrianglesDrawn/gPipeline.mBatchCount; - } - mTrianglesDrawn = 0; - sCompiles = 0; - mVerticesRelit = 0; - mLightingChanges = 0; - mGeometryChanges = 0; - mNumVisibleFaces = 0; - - if (mOldRenderDebugMask != mRenderDebugMask) - { - gObjectList.clearDebugText(); - mOldRenderDebugMask = mRenderDebugMask; - } - -} - -//external functions for asynchronous updating -void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep) -{ - if (gSavedSettings.getBOOL("FreezeTime")) - { - return; - } - if (!drawablep) - { - llerrs << "updateMove called with NULL drawablep" << llendl; - return; - } - if (drawablep->isState(LLDrawable::EARLY_MOVE)) - { - return; - } - - assertInitialized(); - - // update drawable now - drawablep->clearState(LLDrawable::MOVE_UNDAMPED); // force to DAMPED - drawablep->updateMove(); // returns done - drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame - // Put on move list so that EARLY_MOVE gets cleared - if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) - { - mMovedList.push_back(drawablep); - drawablep->setState(LLDrawable::ON_MOVE_LIST); - } -} - -void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep) -{ - if (gSavedSettings.getBOOL("FreezeTime")) - { - return; - } - if (!drawablep) - { - llerrs << "updateMove called with NULL drawablep" << llendl; - return; - } - if (drawablep->isState(LLDrawable::EARLY_MOVE)) - { - return; - } - - assertInitialized(); - - // update drawable now - drawablep->setState(LLDrawable::MOVE_UNDAMPED); // force to UNDAMPED - drawablep->updateMove(); - drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame - // Put on move list so that EARLY_MOVE gets cleared - if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) - { - mMovedList.push_back(drawablep); - drawablep->setState(LLDrawable::ON_MOVE_LIST); - } -} - -void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list) -{ - for (LLDrawable::drawable_vector_t::iterator iter = moved_list.begin(); - iter != moved_list.end(); ) - { - LLDrawable::drawable_vector_t::iterator curiter = iter++; - LLDrawable *drawablep = *curiter; - BOOL done = TRUE; - if (!drawablep->isDead() && (!drawablep->isState(LLDrawable::EARLY_MOVE))) - { - done = drawablep->updateMove(); - } - drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED); - if (done) - { - drawablep->clearState(LLDrawable::ON_MOVE_LIST); - iter = moved_list.erase(curiter); - } - } -} - -static LLFastTimer::DeclareTimer FTM_OCTREE_BALANCE("Balance Octree"); -static LLFastTimer::DeclareTimer FTM_UPDATE_MOVE("Update Move"); - -void LLPipeline::updateMove() -{ - LLFastTimer t(FTM_UPDATE_MOVE); - LLMemType mt_um(LLMemType::MTYPE_PIPELINE_UPDATE_MOVE); - - if (gSavedSettings.getBOOL("FreezeTime")) - { - return; - } - - assertInitialized(); - - { - static LLFastTimer::DeclareTimer ftm("Retexture"); - LLFastTimer t(ftm); - - for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin(); - iter != mRetexturedList.end(); ++iter) - { - LLDrawable* drawablep = *iter; - if (drawablep && !drawablep->isDead()) - { - drawablep->updateTexture(); - } - } - mRetexturedList.clear(); - } - - { - static LLFastTimer::DeclareTimer ftm("Moved List"); - LLFastTimer t(ftm); - updateMovedList(mMovedList); - } - - //balance octrees - { - LLFastTimer ot(FTM_OCTREE_BALANCE); - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - part->mOctree->balance(); - } - } - } - } -} - -///////////////////////////////////////////////////////////////////////////// -// Culling and occlusion testing -///////////////////////////////////////////////////////////////////////////// - -//static -F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera) -{ - LLVector3 lookAt = center - camera.getOrigin(); - F32 dist = lookAt.length(); - - //ramp down distance for nearby objects - //shrink dist by dist/16. - if (dist < 16.f) - { - dist /= 16.f; - dist *= dist; - dist *= 16.f; - } - - //get area of circle around node - F32 app_angle = atanf(size.length()/dist); - F32 radius = app_angle*LLDrawable::sCurPixelAngle; - return radius*radius * F_PI; -} - -//static -F32 LLPipeline::calcPixelArea(const LLVector4a& center, const LLVector4a& size, LLCamera &camera) -{ - LLVector4a origin; - origin.load3(camera.getOrigin().mV); - - LLVector4a lookAt; - lookAt.setSub(center, origin); - F32 dist = lookAt.getLength3().getF32(); - - //ramp down distance for nearby objects - //shrink dist by dist/16. - if (dist < 16.f) - { - dist /= 16.f; - dist *= dist; - dist *= 16.f; - } - - //get area of circle around node - F32 app_angle = atanf(size.getLength3().getF32()/dist); - F32 radius = app_angle*LLDrawable::sCurPixelAngle; - return radius*radius * F_PI; -} - -void LLPipeline::grabReferences(LLCullResult& result) -{ - sCull = &result; -} - -void LLPipeline::clearReferences() -{ - sCull = NULL; -} - -void check_references(LLSpatialGroup* group, LLDrawable* drawable) -{ - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) - { - if (drawable == *i) - { - llerrs << "LLDrawable deleted while actively reference by LLPipeline." << llendl; - } - } -} - -void check_references(LLDrawable* drawable, LLFace* face) -{ - for (S32 i = 0; i < drawable->getNumFaces(); ++i) - { - if (drawable->getFace(i) == face) - { - llerrs << "LLFace deleted while actively referenced by LLPipeline." << llendl; - } - } -} - -void check_references(LLSpatialGroup* group, LLFace* face) -{ - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) - { - LLDrawable* drawable = *i; - check_references(drawable, face); - } -} - -void LLPipeline::checkReferences(LLFace* face) -{ -#if 0 - if (sCull) - { - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, face); - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, face); - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, face); - } - - for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) - { - LLDrawable* drawable = *iter; - check_references(drawable, face); - } - } -#endif -} - -void LLPipeline::checkReferences(LLDrawable* drawable) -{ -#if 0 - if (sCull) - { - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, drawable); - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, drawable); - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, drawable); - } - - for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) - { - if (drawable == *iter) - { - llerrs << "LLDrawable deleted while actively referenced by LLPipeline." << llendl; - } - } - } -#endif -} - -void check_references(LLSpatialGroup* group, LLDrawInfo* draw_info) -{ - for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) - { - LLSpatialGroup::drawmap_elem_t& draw_vec = i->second; - for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j) - { - LLDrawInfo* params = *j; - if (params == draw_info) - { - llerrs << "LLDrawInfo deleted while actively referenced by LLPipeline." << llendl; - } - } - } -} - - -void LLPipeline::checkReferences(LLDrawInfo* draw_info) -{ -#if 0 - if (sCull) - { - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, draw_info); - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, draw_info); - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, draw_info); - } - } -#endif -} - -void LLPipeline::checkReferences(LLSpatialGroup* group) -{ -#if 0 - if (sCull) - { - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) - { - if (group == *iter) - { - llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; - } - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) - { - if (group == *iter) - { - llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; - } - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) - { - if (group == *iter) - { - llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; - } - } - } -#endif -} - - -BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera) -{ - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - if (hasRenderType(part->mDrawableType)) - { - if (part->visibleObjectsInFrustum(camera)) - { - return TRUE; - } - } - } - } - } - - return FALSE; -} - -BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& max) -{ - const F32 X = 65536.f; - - min = LLVector3(X,X,X); - max = LLVector3(-X,-X,-X); - - U32 saved_camera_id = LLViewerCamera::sCurCameraID; - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; - - BOOL res = TRUE; - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - if (hasRenderType(part->mDrawableType)) - { - if (!part->getVisibleExtents(camera, min, max)) - { - res = FALSE; - } - } - } - } - } - - LLViewerCamera::sCurCameraID = saved_camera_id; - - return res; -} - -static LLFastTimer::DeclareTimer FTM_CULL("Object Culling"); - -void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip) -{ - LLFastTimer t(FTM_CULL); - LLMemType mt_uc(LLMemType::MTYPE_PIPELINE_UPDATE_CULL); - - grabReferences(result); - - sCull->clear(); - - BOOL to_texture = LLPipeline::sUseOcclusion > 1 && - !hasRenderType(LLPipeline::RENDER_TYPE_HUD) && - LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && - gPipeline.canUseVertexShaders() && - sRenderGlow; - - if (to_texture) - { - mScreen.bindTarget(); - } - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadMatrixd(gGLLastProjection); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - gGLLastMatrix = NULL; - glLoadMatrixd(gGLLastModelView); - - - LLVertexBuffer::unbind(); - LLGLDisable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - if (sUseOcclusion > 1) - { - gGL.setColorMask(false, false); - } - - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - if (water_clip != 0) - { - LLPlane plane(LLVector3(0,0, (F32) -water_clip), (F32) water_clip*region->getWaterHeight()); - camera.setUserClipPlane(plane); - } - else - { - camera.disableUserClipPlane(); - } - - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - if (hasRenderType(part->mDrawableType)) - { - part->cull(camera); - } - } - } - } - - camera.disableUserClipPlane(); - - if (hasRenderType(LLPipeline::RENDER_TYPE_SKY) && - gSky.mVOSkyp.notNull() && - gSky.mVOSkyp->mDrawable.notNull()) - { - gSky.mVOSkyp->mDrawable->setVisible(camera); - sCull->pushDrawable(gSky.mVOSkyp->mDrawable); - gSky.updateCull(); - stop_glerror(); - } - - if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) && - !gPipeline.canUseWindLightShaders() && - gSky.mVOGroundp.notNull() && - gSky.mVOGroundp->mDrawable.notNull() && - !LLPipeline::sWaterReflections) - { - gSky.mVOGroundp->mDrawable->setVisible(camera); - sCull->pushDrawable(gSky.mVOGroundp->mDrawable); - } - - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - if (sUseOcclusion > 1) - { - gGL.setColorMask(true, false); - } - - if (to_texture) - { - mScreen.flush(); - } -} - -void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera) -{ - if (group->getData().empty()) - { - return; - } - - group->setVisible(); - - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) - { - group->updateDistance(camera); - } - - const F32 MINIMUM_PIXEL_AREA = 16.f; - - if (group->mPixelArea < MINIMUM_PIXEL_AREA) - { - return; - } - - if (sMinRenderSize > 0.f && - llmax(llmax(group->mBounds[1][0], group->mBounds[1][1]), group->mBounds[1][2]) < sMinRenderSize) - { - return; - } - - assertInitialized(); - - if (!group->mSpatialPartition->mRenderByGroup) - { //render by drawable - sCull->pushDrawableGroup(group); - } - else - { //render by group - sCull->pushVisibleGroup(group); - } - - mNumVisibleNodes++; -} - -void LLPipeline::markOccluder(LLSpatialGroup* group) -{ - if (sUseOcclusion > 1 && group && !group->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION)) - { - LLSpatialGroup* parent = group->getParent(); - - if (!parent || !parent->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { //only mark top most occluders as active occlusion - sCull->pushOcclusionGroup(group); - group->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION); - - if (parent && - !parent->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION) && - parent->getElementCount() == 0 && - parent->needsUpdate()) - { - sCull->pushOcclusionGroup(group); - parent->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION); - } - } - } -} - -void LLPipeline::doOcclusion(LLCamera& camera) -{ - if (LLPipeline::sUseOcclusion > 1 && sCull->hasOcclusionGroups()) - { - LLVertexBuffer::unbind(); - - if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION)) - { - gGL.setColorMask(true, false, false, false); - } - else - { - gGL.setColorMask(false, false); - } - LLGLDisable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - - LLGLDisable cull(GL_CULL_FACE); - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - group->doOcclusion(&camera); - group->clearOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION); - } - - gGL.setColorMask(true, false); - } -} - -BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority) -{ - BOOL update_complete = drawablep->updateGeometry(priority); - if (update_complete && assertInitialized()) - { - drawablep->setState(LLDrawable::BUILT); - mGeometryChanges++; - } - return update_complete; -} - -void LLPipeline::updateGL() -{ - while (!LLGLUpdate::sGLQ.empty()) - { - LLGLUpdate* glu = LLGLUpdate::sGLQ.front(); - glu->updateGL(); - glu->mInQ = FALSE; - LLGLUpdate::sGLQ.pop_front(); - } -} - -void LLPipeline::rebuildPriorityGroups() -{ - LLTimer update_timer; - LLMemType mt(LLMemType::MTYPE_PIPELINE); - - assertInitialized(); - - gMeshRepo.notifyLoadedMeshes(); - - mGroupQ1Locked = true; - // Iterate through all drawables on the priority build queue, - for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ1.begin(); - iter != mGroupQ1.end(); ++iter) - { - LLSpatialGroup* group = *iter; - group->rebuildGeom(); - group->clearState(LLSpatialGroup::IN_BUILD_Q1); - } - - mGroupQ1.clear(); - mGroupQ1Locked = false; - -} - -void LLPipeline::rebuildGroups() -{ - if (mGroupQ2.empty()) - { - return; - } - - mGroupQ2Locked = true; - // Iterate through some drawables on the non-priority build queue - S32 size = (S32) mGroupQ2.size(); - S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size); - - S32 count = 0; - - std::sort(mGroupQ2.begin(), mGroupQ2.end(), LLSpatialGroup::CompareUpdateUrgency()); - - LLSpatialGroup::sg_vector_t::iterator iter; - LLSpatialGroup::sg_vector_t::iterator last_iter = mGroupQ2.begin(); - - for (iter = mGroupQ2.begin(); - iter != mGroupQ2.end() && count <= min_count; ++iter) - { - LLSpatialGroup* group = *iter; - last_iter = iter; - - if (!group->isDead()) - { - group->rebuildGeom(); - - if (group->mSpatialPartition->mRenderByGroup) - { - count++; - } - } - - group->clearState(LLSpatialGroup::IN_BUILD_Q2); - } - - mGroupQ2.erase(mGroupQ2.begin(), ++last_iter); - - mGroupQ2Locked = false; - - updateMovedList(mMovedBridge); -} - -void LLPipeline::updateGeom(F32 max_dtime) -{ - LLTimer update_timer; - LLMemType mt(LLMemType::MTYPE_PIPELINE_UPDATE_GEOM); - LLPointer drawablep; - - LLFastTimer t(FTM_GEO_UPDATE); - - assertInitialized(); - - if (sDelayedVBOEnable > 0) - { - if (--sDelayedVBOEnable <= 0) - { - resetVertexBuffers(); - LLVertexBuffer::sEnableVBOs = TRUE; - } - } - - // notify various object types to reset internal cost metrics, etc. - // for now, only LLVOVolume does this to throttle LOD changes - LLVOVolume::preUpdateGeom(); - - // Iterate through all drawables on the priority build queue, - for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin(); - iter != mBuildQ1.end();) - { - LLDrawable::drawable_list_t::iterator curiter = iter++; - LLDrawable* drawablep = *curiter; - if (drawablep && !drawablep->isDead()) - { - if (drawablep->isState(LLDrawable::IN_REBUILD_Q2)) - { - drawablep->clearState(LLDrawable::IN_REBUILD_Q2); - LLDrawable::drawable_list_t::iterator find = std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep); - if (find != mBuildQ2.end()) - { - mBuildQ2.erase(find); - } - } - - if (updateDrawableGeom(drawablep, TRUE)) - { - drawablep->clearState(LLDrawable::IN_REBUILD_Q1); - mBuildQ1.erase(curiter); - } - } - else - { - mBuildQ1.erase(curiter); - } - } - - // Iterate through some drawables on the non-priority build queue - S32 min_count = 16; - S32 size = (S32) mBuildQ2.size(); - if (size > 1024) - { - min_count = llclamp((S32) (size * (F32) size/4096), 16, size); - } - - S32 count = 0; - - max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, max_dtime); - LLSpatialGroup* last_group = NULL; - LLSpatialBridge* last_bridge = NULL; - - for (LLDrawable::drawable_list_t::iterator iter = mBuildQ2.begin(); - iter != mBuildQ2.end(); ) - { - LLDrawable::drawable_list_t::iterator curiter = iter++; - LLDrawable* drawablep = *curiter; - - LLSpatialBridge* bridge = drawablep->isRoot() ? drawablep->getSpatialBridge() : - drawablep->getParent()->getSpatialBridge(); - - if (drawablep->getSpatialGroup() != last_group && - (!last_bridge || bridge != last_bridge) && - (update_timer.getElapsedTimeF32() >= max_dtime) && count > min_count) - { - break; - } - - //make sure updates don't stop in the middle of a spatial group - //to avoid thrashing (objects are enqueued by group) - last_group = drawablep->getSpatialGroup(); - last_bridge = bridge; - - BOOL update_complete = TRUE; - if (!drawablep->isDead()) - { - update_complete = updateDrawableGeom(drawablep, FALSE); - count++; - } - if (update_complete) - { - drawablep->clearState(LLDrawable::IN_REBUILD_Q2); - mBuildQ2.erase(curiter); - } - } - - updateMovedList(mMovedBridge); -} - -void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_VISIBLE); - - if(drawablep && !drawablep->isDead()) - { - if (drawablep->isSpatialBridge()) - { - const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable; - llassert(root); // trying to catch a bad assumption - if (root && // // this test may not be needed, see above - root->getVObj()->isAttachment()) - { - LLDrawable* rootparent = root->getParent(); - if (rootparent) // this IS sometimes NULL - { - LLViewerObject *vobj = rootparent->getVObj(); - llassert(vobj); // trying to catch a bad assumption - if (vobj) // this test may not be needed, see above - { - const LLVOAvatar* av = vobj->asAvatar(); - if (av && av->isImpostor()) - { - return; - } - } - } - } - sCull->pushBridge((LLSpatialBridge*) drawablep); - } - else - { - sCull->pushDrawable(drawablep); - } - - drawablep->setVisible(camera); - } -} - -void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion) -{ - LLMemType mt_mm(LLMemType::MTYPE_PIPELINE_MARK_MOVED); - - if (!drawablep) - { - //llerrs << "Sending null drawable to moved list!" << llendl; - return; - } - - if (drawablep->isDead()) - { - llwarns << "Marking NULL or dead drawable moved!" << llendl; - return; - } - - if (drawablep->getParent()) - { - //ensure that parent drawables are moved first - markMoved(drawablep->getParent(), damped_motion); - } - - assertInitialized(); - - if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) - { - if (drawablep->isSpatialBridge()) - { - mMovedBridge.push_back(drawablep); - } - else - { - mMovedList.push_back(drawablep); - } - drawablep->setState(LLDrawable::ON_MOVE_LIST); - } - if (damped_motion == FALSE) - { - drawablep->setState(LLDrawable::MOVE_UNDAMPED); // UNDAMPED trumps DAMPED - } - else if (drawablep->isState(LLDrawable::MOVE_UNDAMPED)) - { - drawablep->clearState(LLDrawable::MOVE_UNDAMPED); - } -} - -void LLPipeline::markShift(LLDrawable *drawablep) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_SHIFT); - - if (!drawablep || drawablep->isDead()) - { - return; - } - - assertInitialized(); - - if (!drawablep->isState(LLDrawable::ON_SHIFT_LIST)) - { - drawablep->getVObj()->setChanged(LLXform::SHIFTED | LLXform::SILHOUETTE); - if (drawablep->getParent()) - { - markShift(drawablep->getParent()); - } - mShiftList.push_back(drawablep); - drawablep->setState(LLDrawable::ON_SHIFT_LIST); - } -} - -void LLPipeline::shiftObjects(const LLVector3 &offset) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS); - - assertInitialized(); - - glClear(GL_DEPTH_BUFFER_BIT); - gDepthDirty = TRUE; - - LLVector4a offseta; - offseta.load3(offset.mV); - - for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin(); - iter != mShiftList.end(); iter++) - { - LLDrawable *drawablep = *iter; - if (drawablep->isDead()) - { - continue; - } - drawablep->shiftPos(offseta); - drawablep->clearState(LLDrawable::ON_SHIFT_LIST); - } - mShiftList.resize(0); - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - part->shift(offseta); - } - } - } - - LLHUDText::shiftAll(offset); - LLHUDNameTag::shiftAll(offset); - display_update_camera(); -} - -void LLPipeline::markTextured(LLDrawable *drawablep) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_TEXTURED); - - if (drawablep && !drawablep->isDead() && assertInitialized()) - { - mRetexturedList.insert(drawablep); - } -} - -void LLPipeline::markGLRebuild(LLGLUpdate* glu) -{ - if (glu && !glu->mInQ) - { - LLGLUpdate::sGLQ.push_back(glu); - glu->mInQ = TRUE; - } -} - -void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE); - - if (group && !group->isDead() && group->mSpatialPartition) - { - if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD) - { - priority = TRUE; - } - - if (priority) - { - if (!group->isState(LLSpatialGroup::IN_BUILD_Q1)) - { - llassert_always(!mGroupQ1Locked); - - mGroupQ1.push_back(group); - group->setState(LLSpatialGroup::IN_BUILD_Q1); - - if (group->isState(LLSpatialGroup::IN_BUILD_Q2)) - { - LLSpatialGroup::sg_vector_t::iterator iter = std::find(mGroupQ2.begin(), mGroupQ2.end(), group); - if (iter != mGroupQ2.end()) - { - mGroupQ2.erase(iter); - } - group->clearState(LLSpatialGroup::IN_BUILD_Q2); - } - } - } - else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1)) - { - llassert_always(!mGroupQ2Locked); - mGroupQ2.push_back(group); - group->setState(LLSpatialGroup::IN_BUILD_Q2); - - } - } -} - -void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag, BOOL priority) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD); - - if (drawablep && !drawablep->isDead() && assertInitialized()) - { - if (!drawablep->isState(LLDrawable::BUILT)) - { - priority = TRUE; - } - if (priority) - { - if (!drawablep->isState(LLDrawable::IN_REBUILD_Q1)) - { - mBuildQ1.push_back(drawablep); - drawablep->setState(LLDrawable::IN_REBUILD_Q1); // mark drawable as being in priority queue - } - } - else if (!drawablep->isState(LLDrawable::IN_REBUILD_Q2)) - { - mBuildQ2.push_back(drawablep); - drawablep->setState(LLDrawable::IN_REBUILD_Q2); // need flag here because it is just a list - } - if (flag & (LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION)) - { - drawablep->getVObj()->setChanged(LLXform::SILHOUETTE); - } - drawablep->setState(flag); - } -} - -static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order"); - -void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) -{ - if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR, - LLPipeline::RENDER_TYPE_GROUND, - LLPipeline::RENDER_TYPE_TERRAIN, - LLPipeline::RENDER_TYPE_TREE, - LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_VOIDWATER, - LLPipeline::RENDER_TYPE_WATER, - LLPipeline::END_RENDER_TYPES)) - { - //clear faces from face pools - LLFastTimer t(FTM_RESET_DRAWORDER); - gPipeline.resetDrawOrders(); - } - - LLFastTimer ftm(FTM_STATESORT); - LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); - - //LLVertexBuffer::unbind(); - - grabReferences(result); - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - group->checkOcclusion(); - if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - markOccluder(group); - } - else - { - group->setVisible(); - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) - { - markVisible(*i, camera); - } - } - } - - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) - { - LLSpatialGroup* last_group = NULL; - for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) - { - LLCullResult::bridge_list_t::iterator cur_iter = i; - LLSpatialBridge* bridge = *cur_iter; - LLSpatialGroup* group = bridge->getSpatialGroup(); - - if (last_group == NULL) - { - last_group = group; - } - - if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - stateSort(bridge, camera); - } - - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && - last_group != group && last_group->changeLOD()) - { - last_group->mLastUpdateDistance = last_group->mDistance; - } - - last_group = group; - } - - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && - last_group && last_group->changeLOD()) - { - last_group->mLastUpdateDistance = last_group->mDistance; - } - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - group->checkOcclusion(); - if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - markOccluder(group); - } - else - { - group->setVisible(); - stateSort(group, camera); - } - } - - { - LLFastTimer ftm(FTM_STATESORT_DRAWABLE); - for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); - iter != sCull->endVisibleList(); ++iter) - { - LLDrawable *drawablep = *iter; - if (!drawablep->isDead()) - { - stateSort(drawablep, camera); - } - } - } - { - LLFastTimer ftm(FTM_CLIENT_COPY); - LLVertexBuffer::clientCopy(); - } - - postSort(camera); -} - -void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); - if (group->changeLOD()) - { - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) - { - LLDrawable* drawablep = *i; - stateSort(drawablep, camera); - } - - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) - { //avoid redundant stateSort calls - group->mLastUpdateDistance = group->mDistance; - } - } - -} - -void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); - if (bridge->getSpatialGroup()->changeLOD()) - { - bool force_update = false; - bridge->updateDistance(camera, force_update); - } -} - -void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); - - if (!drawablep - || drawablep->isDead() - || !hasRenderType(drawablep->getRenderType())) - { - return; - } - - if (LLSelectMgr::getInstance()->mHideSelectedObjects) - { - if (drawablep->getVObj().notNull() && - drawablep->getVObj()->isSelected()) - { - return; - } - } - - if (drawablep->isAvatar()) - { //don't draw avatars beyond render distance or if we don't have a spatial group. - if ((drawablep->getSpatialGroup() == NULL) || - (drawablep->getSpatialGroup()->mDistance > LLVOAvatar::sRenderDistance)) - { - return; - } - - LLVOAvatar* avatarp = (LLVOAvatar*) drawablep->getVObj().get(); - if (!avatarp->isVisible()) - { - return; - } - } - - assertInitialized(); - - if (hasRenderType(drawablep->mRenderType)) - { - if (!drawablep->isState(LLDrawable::INVISIBLE|LLDrawable::FORCE_INVISIBLE)) - { - drawablep->setVisible(camera, NULL, FALSE); - } - else if (drawablep->isState(LLDrawable::CLEAR_INVISIBLE)) - { - // clear invisible flag here to avoid single frame glitch - drawablep->clearState(LLDrawable::FORCE_INVISIBLE|LLDrawable::CLEAR_INVISIBLE); - } - } - - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) - { - if (drawablep->isVisible()) - { - if (!drawablep->isActive()) - { - bool force_update = false; - drawablep->updateDistance(camera, force_update); - } - else if (drawablep->isAvatar()) - { - bool force_update = false; - drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility() - } - } - } - - if (!drawablep->getVOVolume()) - { - for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin(); - iter != drawablep->mFaces.end(); iter++) - { - LLFace* facep = *iter; - - if (facep->hasGeometry()) - { - if (facep->getPool()) - { - facep->getPool()->enqueue(facep); - } - else - { - break; - } - } - } - } - - - mNumVisibleFaces += drawablep->getNumFaces(); -} - - -void forAllDrawables(LLCullResult::sg_list_t::iterator begin, - LLCullResult::sg_list_t::iterator end, - void (*func)(LLDrawable*)) -{ - for (LLCullResult::sg_list_t::iterator i = begin; i != end; ++i) - { - for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j) - { - func(*j); - } - } -} - -void LLPipeline::forAllVisibleDrawables(void (*func)(LLDrawable*)) -{ - forAllDrawables(sCull->beginDrawableGroups(), sCull->endDrawableGroups(), func); - forAllDrawables(sCull->beginVisibleGroups(), sCull->endVisibleGroups(), func); -} - -//function for creating scripted beacons -void renderScriptedBeacons(LLDrawable* drawablep) -{ - LLViewerObject *vobj = drawablep->getVObj(); - if (vobj - && !vobj->isAvatar() - && !vobj->getParent() - && vobj->flagScripted()) - { - if (gPipeline.sRenderBeacons) - { - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); - } - - if (gPipeline.sRenderHighlight) - { - S32 face_id; - S32 count = drawablep->getNumFaces(); - for (face_id = 0; face_id < count; face_id++) - { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); - } - } - } -} - -void renderScriptedTouchBeacons(LLDrawable* drawablep) -{ - LLViewerObject *vobj = drawablep->getVObj(); - if (vobj - && !vobj->isAvatar() - && !vobj->getParent() - && vobj->flagScripted() - && vobj->flagHandleTouch()) - { - if (gPipeline.sRenderBeacons) - { - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); - } - - if (gPipeline.sRenderHighlight) - { - S32 face_id; - S32 count = drawablep->getNumFaces(); - for (face_id = 0; face_id < count; face_id++) - { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); - } - } - } -} - -void renderPhysicalBeacons(LLDrawable* drawablep) -{ - LLViewerObject *vobj = drawablep->getVObj(); - if (vobj - && !vobj->isAvatar() - //&& !vobj->getParent() - && vobj->usePhysics()) - { - if (gPipeline.sRenderBeacons) - { - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); - } - - if (gPipeline.sRenderHighlight) - { - S32 face_id; - S32 count = drawablep->getNumFaces(); - for (face_id = 0; face_id < count; face_id++) - { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); - } - } - } -} - -void renderParticleBeacons(LLDrawable* drawablep) -{ - // Look for attachments, objects, etc. - LLViewerObject *vobj = drawablep->getVObj(); - if (vobj - && vobj->isParticleSource()) - { - if (gPipeline.sRenderBeacons) - { - LLColor4 light_blue(0.5f, 0.5f, 1.f, 0.5f); - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); - } - - if (gPipeline.sRenderHighlight) - { - S32 face_id; - S32 count = drawablep->getNumFaces(); - for (face_id = 0; face_id < count; face_id++) - { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); - } - } - } -} - -void renderSoundHighlights(LLDrawable* drawablep) -{ - // Look for attachments, objects, etc. - LLViewerObject *vobj = drawablep->getVObj(); - if (vobj && vobj->isAudioSource()) - { - if (gPipeline.sRenderHighlight) - { - S32 face_id; - S32 count = drawablep->getNumFaces(); - for (face_id = 0; face_id < count; face_id++) - { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); - } - } - } -} - -void LLPipeline::postSort(LLCamera& camera) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_POST_SORT); - LLFastTimer ftm(FTM_STATESORT_POSTSORT); - - assertInitialized(); - - llpushcallstacks ; - //rebuild drawable geometry - for (LLCullResult::sg_list_t::iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i) - { - LLSpatialGroup* group = *i; - if (!sUseOcclusion || - !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - group->rebuildGeom(); - } - } - llpushcallstacks ; - //rebuild groups - sCull->assertDrawMapsEmpty(); - - rebuildPriorityGroups(); - llpushcallstacks ; - - const S32 bin_count = 1024*8; - - static LLCullResult::drawinfo_list_t alpha_bins[bin_count]; - static U32 bin_size[bin_count]; - - //clear one bin per frame to avoid memory bloat - static S32 clear_idx = 0; - clear_idx = (1+clear_idx)%bin_count; - alpha_bins[clear_idx].clear(); - - for (U32 j = 0; j < bin_count; j++) - { - bin_size[j] = 0; - } - - //build render map - for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) - { - LLSpatialGroup* group = *i; - if (sUseOcclusion && - group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - continue; - } - - if (group->isState(LLSpatialGroup::NEW_DRAWINFO) && group->isState(LLSpatialGroup::GEOM_DIRTY)) - { //no way this group is going to be drawable without a rebuild - group->rebuildGeom(); - } - - for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j) - { - LLSpatialGroup::drawmap_elem_t& src_vec = j->second; - if (!hasRenderType(j->first)) - { - continue; - } - - for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k) - { - if (sMinRenderSize > 0.f) - { - LLVector4a bounds; - bounds.setSub((*k)->mExtents[1],(*k)->mExtents[0]); - - if (llmax(llmax(bounds[0], bounds[1]), bounds[2]) > sMinRenderSize) - { - sCull->pushDrawInfo(j->first, *k); - } - } - else - { - sCull->pushDrawInfo(j->first, *k); - } - } - } - - if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA)) - { - LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA); - - if (alpha != group->mDrawMap.end()) - { //store alpha groups for sorting - LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) - { - if (bridge) - { - LLCamera trans_camera = bridge->transformCamera(camera); - group->updateDistance(trans_camera); - } - else - { - group->updateDistance(camera); - } - } - - if (hasRenderType(LLDrawPool::POOL_ALPHA)) - { - sCull->pushAlphaGroup(group); - } - } - } - } - - if (!sShadowRender) - { - //sort by texture or bump map - for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; ++i) - { - if (i == LLRenderPass::PASS_BUMP) - { - std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareBump()); - } - else - { - std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareTexturePtrMatrix()); - } - } - - std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater()); - } - llpushcallstacks ; - // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus - if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender) - { - if (sRenderScriptedTouchBeacons) - { - // Only show the beacon on the root object. - forAllVisibleDrawables(renderScriptedTouchBeacons); - } - else - if (sRenderScriptedBeacons) - { - // Only show the beacon on the root object. - forAllVisibleDrawables(renderScriptedBeacons); - } - - if (sRenderPhysicalBeacons) - { - // Only show the beacon on the root object. - forAllVisibleDrawables(renderPhysicalBeacons); - } - - if (sRenderParticleBeacons) - { - forAllVisibleDrawables(renderParticleBeacons); - } - - // If god mode, also show audio cues - if (sRenderSoundBeacons && gAudiop) - { - // Walk all sound sources and render out beacons for them. Note, this isn't done in the ForAllVisibleDrawables function, because some are not visible. - LLAudioEngine::source_map::iterator iter; - for (iter = gAudiop->mAllSources.begin(); iter != gAudiop->mAllSources.end(); ++iter) - { - LLAudioSource *sourcep = iter->second; - - LLVector3d pos_global = sourcep->getPositionGlobal(); - LLVector3 pos = gAgent.getPosAgentFromGlobal(pos_global); - if (gPipeline.sRenderBeacons) - { - //pos += LLVector3(0.f, 0.f, 0.2f); - gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); - } - } - // now deal with highlights for all those seeable sound sources - forAllVisibleDrawables(renderSoundHighlights); - } - } - llpushcallstacks ; - // If managing your telehub, draw beacons at telehub and currently selected spawnpoint. - if (LLFloaterTelehub::renderBeacons()) - { - LLFloaterTelehub::addBeacons(); - } - - if (!sShadowRender) - { - mSelectedFaces.clear(); - - // Draw face highlights for selected faces. - if (LLSelectMgr::getInstance()->getTEMode()) - { - struct f : public LLSelectedTEFunctor - { - virtual bool apply(LLViewerObject* object, S32 te) - { - if (object->mDrawable) - { - gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te)); - } - return true; - } - } func; - LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func); - } - } - - //LLSpatialGroup::sNoDelete = FALSE; - llpushcallstacks ; -} - - -void render_hud_elements() -{ - LLMemType mt_rhe(LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS); - LLFastTimer t(FTM_RENDER_UI); - gPipeline.disableLights(); - - LLGLDisable fog(GL_FOG); - LLGLSUIDefault gls_ui; - - LLGLEnable stencil(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 255, 0xFFFFFFFF); - glStencilMask(0xFFFFFFFF); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - - gGL.color4f(1,1,1,1); - if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); - gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD version in render_ui_3d() - - // Draw the tracking overlays - LLTracker::render3D(); - - // Show the property lines - LLWorld::getInstance()->renderPropertyLines(); - LLViewerParcelMgr::getInstance()->render(); - LLViewerParcelMgr::getInstance()->renderParcelCollision(); - - // Render name tags. - LLHUDObject::renderAll(); - } - else if (gForceRenderLandFence) - { - // This is only set when not rendering the UI, for parcel snapshots - LLViewerParcelMgr::getInstance()->render(); - } - else if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) - { - LLHUDText::renderAllHUD(); - } - gGL.flush(); -} - -void LLPipeline::renderHighlights() -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_HL); - - assertInitialized(); - - // Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD) - // Render highlighted faces. - LLGLSPipelineAlpha gls_pipeline_alpha; - LLColor4 color(1.f, 1.f, 1.f, 0.5f); - LLGLEnable color_mat(GL_COLOR_MATERIAL); - disableLights(); - - if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && !mHighlightSet.empty()) - { //draw blurry highlight image over screen - LLGLEnable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - LLGLDisable test(GL_ALPHA_TEST); - - LLGLEnable stencil(GL_STENCIL_TEST); - gGL.flush(); - glStencilMask(0xFFFFFFFF); - glClearStencil(1); - glClear(GL_STENCIL_BUFFER_BIT); - - glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF); - glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); - - gGL.setColorMask(false, false); - for (std::set::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter) - { - renderHighlight(iter->mItem->getVObj(), 1.f); - } - gGL.setColorMask(true, false); - - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF); - - //gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - - gGL.pushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - gGL.pushMatrix(); - glLoadIdentity(); - - gGL.getTexUnit(0)->bind(&mHighlight); - - LLVector2 tc1; - LLVector2 tc2; - - tc1.setVec(0,0); - tc2.setVec(2,2); - - gGL.begin(LLRender::TRIANGLES); - - F32 scale = gSavedSettings.getF32("RenderHighlightBrightness"); - LLColor4 color = gSavedSettings.getColor4("RenderHighlightColor"); - F32 thickness = gSavedSettings.getF32("RenderHighlightThickness"); - - for (S32 pass = 0; pass < 2; ++pass) - { - if (pass == 0) - { - gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - } - else - { - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - - for (S32 i = 0; i < 8; ++i) - { - for (S32 j = 0; j < 8; ++j) - { - LLVector2 tc(i-4+0.5f, j-4+0.5f); - - F32 dist = 1.f-(tc.length()/sqrtf(32.f)); - dist *= scale/64.f; - - tc *= thickness; - tc.mV[0] = (tc.mV[0])/mHighlight.getWidth(); - tc.mV[1] = (tc.mV[1])/mHighlight.getHeight(); - - gGL.color4f(color.mV[0], - color.mV[1], - color.mV[2], - color.mV[3]*dist); - - gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc.mV[0]+tc2.mV[0], tc.mV[1]+tc1.mV[1]); - gGL.vertex2f(3,-1); - } - } - } - - gGL.end(); - - gGL.popMatrix(); - glMatrixMode(GL_MODELVIEW); - gGL.popMatrix(); - - //gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - - if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) - { - gHighlightProgram.bind(); - gHighlightProgram.vertexAttrib4f(LLViewerShaderMgr::MATERIAL_COLOR,1,1,1,0.5f); - } - - if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED)) - { - // Make sure the selection image gets downloaded and decoded - if (!mFaceSelectImagep) - { - mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT); - } - mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA); - - U32 count = mSelectedFaces.size(); - for (U32 i = 0; i < count; i++) - { - LLFace *facep = mSelectedFaces[i]; - if (!facep || facep->getDrawable()->isDead()) - { - llerrs << "Bad face on selection" << llendl; - return; - } - - facep->renderSelected(mFaceSelectImagep, color); - } - } - - if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED)) - { - // Paint 'em red! - color.setVec(1.f, 0.f, 0.f, 0.5f); - if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) - { - gHighlightProgram.vertexAttrib4f(LLViewerShaderMgr::MATERIAL_COLOR,1,0,0,0.5f); - } - int count = mHighlightFaces.size(); - for (S32 i = 0; i < count; i++) - { - LLFace* facep = mHighlightFaces[i]; - facep->renderSelected(LLViewerTexture::sNullImagep, color); - } - } - - // Contains a list of the faces of objects that are physical or - // have touch-handlers. - mHighlightFaces.clear(); - - if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0) - { - gHighlightProgram.unbind(); - } -} - -//debug use -U32 LLPipeline::sCurRenderPoolType = 0 ; - -void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_GEOM); - LLFastTimer t(FTM_RENDER_GEOMETRY); - - assertInitialized(); - - F64 saved_modelview[16]; - F64 saved_projection[16]; - - //HACK: preserve/restore matrices around HUD render - if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) - { - for (U32 i = 0; i < 16; i++) - { - saved_modelview[i] = gGLModelView[i]; - saved_projection[i] = gGLProjection[i]; - } - } - - S32 stack_depth = 0; - - if (gDebugGL) - { - glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &stack_depth); - } - - /////////////////////////////////////////// - // - // Sync and verify GL state - // - // - - stop_glerror(); - - LLVertexBuffer::unbind(); - - // Do verification of GL state - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - if (mRenderDebugMask & RENDER_DEBUG_VERIFY) - { - if (!verify()) - { - llerrs << "Pipeline verification failed!" << llendl; - } - } - - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:ForceVBO"); - - // Initialize lots of GL state to "safe" values - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - - LLGLSPipeline gls_pipeline; - LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); - - LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2); - - // Toggle backface culling for debugging - LLGLEnable cull_face(mBackfaceCull ? GL_CULL_FACE : 0); - // Set fog - BOOL use_fog = hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG); - LLGLEnable fog_enable(use_fog && - !gPipeline.canUseWindLightShadersOnObjects() ? GL_FOG : 0); - gSky.updateFog(camera.getFar()); - if (!use_fog) - { - sUnderWaterRender = FALSE; - } - - gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sDefaultImagep); - LLViewerFetchedTexture::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP); - - ////////////////////////////////////////////// - // - // Actually render all of the geometry - // - // - stop_glerror(); - - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPools"); - - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - if (hasRenderType(poolp->getType())) - { - poolp->prerender(); - } - } - - { - LLFastTimer t(FTM_POOLS); - - // HACK: don't calculate local lights if we're rendering the HUD! - // Removing this check will cause bad flickering when there are - // HUD elements being rendered AND the user is in flycam mode -nyx - if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) - { - calcNearbyLights(camera); - setupHWLights(NULL); - } - - BOOL occlude = sUseOcclusion > 1; - U32 cur_type = 0; - - pool_set_t::iterator iter1 = mPools.begin(); - while ( iter1 != mPools.end() ) - { - LLDrawPool *poolp = *iter1; - - cur_type = poolp->getType(); - - //debug use - sCurRenderPoolType = cur_type ; - - if (occlude && cur_type >= LLDrawPool::POOL_GRASS) - { - occlude = FALSE; - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); - doOcclusion(camera); - } - - pool_set_t::iterator iter2 = iter1; - if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0) - { - LLFastTimer t(FTM_POOLRENDER); - - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); - - for( S32 i = 0; i < poolp->getNumPasses(); i++ ) - { - LLVertexBuffer::unbind(); - poolp->beginRenderPass(i); - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - - p->render(i); - } - poolp->endRenderPass(i); - LLVertexBuffer::unbind(); - if (gDebugGL) - { - check_stack_depth(stack_depth); - std::string msg = llformat("%s pass %d", gPoolNames[cur_type].c_str(), i); - LLGLState::checkStates(msg); - LLGLState::checkTextureChannels(msg); - LLGLState::checkClientArrays(msg); - } - } - } - else - { - // Skip all pools of this type - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - } - } - iter1 = iter2; - stop_glerror(); - } - - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd"); - - LLVertexBuffer::unbind(); - - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); - - if (occlude) - { - occlude = FALSE; - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); - doOcclusion(camera); - } - } - - LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - - - - stop_glerror(); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderHighlights"); - - if (!sReflectionRender) - { - renderHighlights(); - } - - // Contains a list of the faces of objects that are physical or - // have touch-handlers. - mHighlightFaces.clear(); - - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDebug"); - - renderDebug(); - - LLVertexBuffer::unbind(); - - if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred) - { - if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - // Render debugging beacons. - gObjectList.renderObjectBeacons(); - gObjectList.resetObjectBeacons(); - } - else - { - // Make sure particle effects disappear - LLHUDObject::renderAllForTimer(); - } - } - else - { - // Make sure particle effects disappear - LLHUDObject::renderAllForTimer(); - } - - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomEnd"); - - //HACK: preserve/restore matrices around HUD render - if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) - { - for (U32 i = 0; i < 16; i++) - { - gGLModelView[i] = saved_modelview[i]; - gGLProjection[i] = saved_projection[i]; - } - } - - LLVertexBuffer::unbind(); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); -} - -void LLPipeline::renderGeomDeferred(LLCamera& camera) -{ - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred"); - - LLMemType mt_rgd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED); - LLFastTimer t(FTM_RENDER_GEOMETRY); - - LLFastTimer t2(FTM_POOLS); - - LLGLEnable cull(GL_CULL_FACE); - - LLGLEnable stencil(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF); - stop_glerror(); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - stop_glerror(); - - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - if (hasRenderType(poolp->getType())) - { - poolp->prerender(); - } - } - - LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); - - LLVertexBuffer::unbind(); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - - U32 cur_type = 0; - - gGL.setColorMask(true, true); - - pool_set_t::iterator iter1 = mPools.begin(); - - while ( iter1 != mPools.end() ) - { - LLDrawPool *poolp = *iter1; - - cur_type = poolp->getType(); - - pool_set_t::iterator iter2 = iter1; - if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0) - { - LLFastTimer t(FTM_POOLRENDER); - - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); - - for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ ) - { - LLVertexBuffer::unbind(); - poolp->beginDeferredPass(i); - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - - p->renderDeferred(i); - } - poolp->endDeferredPass(i); - LLVertexBuffer::unbind(); - - if (gDebugGL || gDebugPipeline) - { - GLint depth; - glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth); - if (depth > 3) - { - llerrs << "GL matrix stack corrupted!" << llendl; - } - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - } - } - } - else - { - // Skip all pools of this type - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - } - } - iter1 = iter2; - stop_glerror(); - } - - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); - - gGL.setColorMask(true, false); -} - -void LLPipeline::renderGeomPostDeferred(LLCamera& camera) -{ - LLMemType mt_rgpd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF); - LLFastTimer t(FTM_POOLS); - U32 cur_type = 0; - - LLGLEnable cull(GL_CULL_FACE); - - LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); - - calcNearbyLights(camera); - setupHWLights(NULL); - - gGL.setColorMask(true, false); - - pool_set_t::iterator iter1 = mPools.begin(); - BOOL occlude = LLPipeline::sUseOcclusion > 1; - - while ( iter1 != mPools.end() ) - { - LLDrawPool *poolp = *iter1; - - cur_type = poolp->getType(); - - if (occlude && cur_type >= LLDrawPool::POOL_GRASS) - { - occlude = FALSE; - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); - doOcclusion(camera); - gGL.setColorMask(true, false); - } - - pool_set_t::iterator iter2 = iter1; - if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0) - { - LLFastTimer t(FTM_POOLRENDER); - - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); - - for( S32 i = 0; i < poolp->getNumPostDeferredPasses(); i++ ) - { - LLVertexBuffer::unbind(); - poolp->beginPostDeferredPass(i); - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - - p->renderPostDeferred(i); - } - poolp->endPostDeferredPass(i); - LLVertexBuffer::unbind(); - - if (gDebugGL || gDebugPipeline) - { - GLint depth; - glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth); - if (depth > 3) - { - llerrs << "GL matrix stack corrupted!" << llendl; - } - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - } - } - } - else - { - // Skip all pools of this type - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - } - } - iter1 = iter2; - stop_glerror(); - } - - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); - - if (occlude) - { - occlude = FALSE; - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); - doOcclusion(camera); - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); - } -} - -void LLPipeline::renderGeomShadow(LLCamera& camera) -{ - LLMemType mt_rgs(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW); - U32 cur_type = 0; - - LLGLEnable cull(GL_CULL_FACE); - - LLVertexBuffer::unbind(); - - pool_set_t::iterator iter1 = mPools.begin(); - - while ( iter1 != mPools.end() ) - { - LLDrawPool *poolp = *iter1; - - cur_type = poolp->getType(); - - pool_set_t::iterator iter2 = iter1; - if (hasRenderType(poolp->getType()) && poolp->getNumShadowPasses() > 0) - { - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); - - for( S32 i = 0; i < poolp->getNumShadowPasses(); i++ ) - { - LLVertexBuffer::unbind(); - poolp->beginShadowPass(i); - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - - p->renderShadow(i); - } - poolp->endShadowPass(i); - LLVertexBuffer::unbind(); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - } - } - else - { - // Skip all pools of this type - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - } - } - iter1 = iter2; - stop_glerror(); - } - - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); -} - - -void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type) -{ - assertInitialized(); - S32 count = 0; - if (render_type == LLRender::TRIANGLE_STRIP) - { - count = index_count-2; - } - else - { - count = index_count/3; - } - - mTrianglesDrawn += count; - mBatchCount++; - mMaxBatchSize = llmax(mMaxBatchSize, count); - mMinBatchSize = llmin(mMinBatchSize, count); - - if (LLPipeline::sRenderFrameTest) - { - gViewerWindow->getWindow()->swapBuffers(); - ms_sleep(16); - } -} - -void LLPipeline::renderPhysicsDisplay() -{ - if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)) - { - return; - } - - allocatePhysicsBuffer(); - - gGL.flush(); - mPhysicsDisplay.bindTarget(); - glClearColor(0,0,0,1); - gGL.setColorMask(true, true); - mPhysicsDisplay.clear(); - glClearColor(0,0,0,0); - - gGL.setColorMask(true, false); - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - if (hasRenderType(part->mDrawableType)) - { - part->renderPhysicsShapes(); - } - } - } - } - - for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) - { - LLSpatialBridge* bridge = *i; - if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) - { - glPushMatrix(); - glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); - bridge->renderPhysicsShapes(); - glPopMatrix(); - } - } - - - gGL.flush(); - mPhysicsDisplay.flush(); -} - - -void LLPipeline::renderDebug() -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE); - - assertInitialized(); - - gGL.color4f(1,1,1,1); - - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); - gGL.setColorMask(true, false); - - // Debug stuff. - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - if (hasRenderType(part->mDrawableType)) - { - part->renderDebug(); - } - } - } - } - - for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) - { - LLSpatialBridge* bridge = *i; - if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) - { - glPushMatrix(); - glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); - bridge->renderDebug(); - glPopMatrix(); - } - } - - if (gSavedSettings.getBOOL("DebugShowUploadCost")) - { - std::set textures; - std::set sculpts; - std::set meshes; - - BOOL selected = TRUE; - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - selected = FALSE; - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - LLSpatialGroup::OctreeNode* node = group->mOctreeNode; - for (LLSpatialGroup::OctreeNode::element_iter elem = node->getData().begin(); elem != node->getData().end(); ++elem) - { - LLDrawable* drawable = *elem; - LLVOVolume* volume = drawable->getVOVolume(); - if (volume && volume->isSelected() == selected) - { - for (U32 i = 0; i < volume->getNumTEs(); ++i) - { - LLTextureEntry* te = volume->getTE(i); - textures.insert(te->getID()); - } - - if (volume->isSculpted()) - { - LLUUID sculpt_id = volume->getVolume()->getParams().getSculptID(); - if (volume->isMesh()) - { - meshes.insert(sculpt_id); - } - else - { - sculpts.insert(sculpt_id); - } - } - } - } - } - - gPipeline.mDebugTextureUploadCost = textures.size() * 10; - gPipeline.mDebugSculptUploadCost = sculpts.size()*10; - - U32 mesh_cost = 0; - - for (std::set::iterator iter = meshes.begin(); iter != meshes.end(); ++iter) - { - mesh_cost += gMeshRepo.getResourceCost(*iter)*10; - } - - gPipeline.mDebugMeshUploadCost = mesh_cost; - } - - if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - LLVertexBuffer::unbind(); - - LLGLEnable blend(GL_BLEND); - LLGLDepthTest depth(TRUE, FALSE); - LLGLDisable cull(GL_CULL_FACE); - - gGL.color4f(1,1,1,1); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - F32 a = 0.1f; - - F32 col[] = - { - 1,0,0,a, - 0,1,0,a, - 0,0,1,a, - 1,0,1,a, - - 1,1,0,a, - 0,1,1,a, - 1,1,1,a, - 1,0,1,a, - }; - - for (U32 i = 0; i < 8; i++) - { - LLVector3* frust = mShadowCamera[i].mAgentFrustum; - - if (i > 3) - { //render shadow frusta as volumes - if (mShadowFrustPoints[i-4].empty()) - { - continue; - } - - gGL.color4fv(col+(i-4)*4); - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); - gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV); - gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV); - gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV); - gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); - gGL.end(); - - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3fv(frust[0].mV); - gGL.vertex3fv(frust[1].mV); - gGL.vertex3fv(frust[3].mV); - gGL.vertex3fv(frust[2].mV); - gGL.end(); - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3fv(frust[4].mV); - gGL.vertex3fv(frust[5].mV); - gGL.vertex3fv(frust[7].mV); - gGL.vertex3fv(frust[6].mV); - gGL.end(); - } - - - if (i < 4) - { - - //if (i == 0 || !mShadowFrustPoints[i].empty()) - { - //render visible point cloud - gGL.flush(); - glPointSize(8.f); - gGL.begin(LLRender::POINTS); - - F32* c = col+i*4; - gGL.color3fv(c); - - for (U32 j = 0; j < mShadowFrustPoints[i].size(); ++j) - { - gGL.vertex3fv(mShadowFrustPoints[i][j].mV); - - } - gGL.end(); - - gGL.flush(); - glPointSize(1.f); - - LLVector3* ext = mShadowExtents[i]; - LLVector3 pos = (ext[0]+ext[1])*0.5f; - LLVector3 size = (ext[1]-ext[0])*0.5f; - drawBoxOutline(pos, size); - - //render camera frustum splits as outlines - gGL.begin(LLRender::LINES); - gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV); - gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV); - gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV); - gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV); - gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV); - gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV); - gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV); - gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV); - gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); - gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV); - gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV); - gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV); - gGL.end(); - } - } - - /*gGL.flush(); - glLineWidth(16-i*2); - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++) - { - LLSpatialPartition* part = region->getSpatialPartition(j); - if (part) - { - if (hasRenderType(part->mDrawableType)) - { - part->renderIntersectingBBoxes(&mShadowCamera[i]); - } - } - } - } - gGL.flush(); - glLineWidth(1.f);*/ - } - } - - if (mRenderDebugMask & RENDER_DEBUG_COMPOSITION) - { - // Debug composition layers - F32 x, y; - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - if (gAgent.getRegion()) - { - gGL.begin(LLRender::POINTS); - // Draw the composition layer for the region that I'm in. - for (x = 0; x <= 260; x++) - { - for (y = 0; y <= 260; y++) - { - if ((x > 255) || (y > 255)) - { - gGL.color4f(1.f, 0.f, 0.f, 1.f); - } - else - { - gGL.color4f(0.f, 0.f, 1.f, 1.f); - } - F32 z = gAgent.getRegion()->getCompositionXY((S32)x, (S32)y); - z *= 5.f; - z += 50.f; - gGL.vertex3f(x, y, z); - } - } - gGL.end(); - } - } - - if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_BUILD_QUEUE) - { - U32 count = 0; - U32 size = mGroupQ2.size(); - LLColor4 col; - - LLVertexBuffer::unbind(); - LLGLEnable blend(GL_BLEND); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); - - gGL.pushMatrix(); - glLoadMatrixd(gGLModelView); - gGLLastMatrix = NULL; - - for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ2.begin(); iter != mGroupQ2.end(); ++iter) - { - LLSpatialGroup* group = *iter; - if (group->isDead()) - { - continue; - } - - LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); - - if (bridge && (!bridge->mDrawable || bridge->mDrawable->isDead())) - { - continue; - } - - if (bridge) - { - gGL.pushMatrix(); - glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); - } - - F32 alpha = llclamp((F32) (size-count)/size, 0.f, 1.f); - - - LLVector2 c(1.f-alpha, alpha); - c.normVec(); - - - ++count; - col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.5f); - group->drawObjectBox(col); - - if (bridge) - { - gGL.popMatrix(); - } - } - - gGL.popMatrix(); - } - - gGL.flush(); - - gPipeline.renderPhysicsDisplay(); -} - -void LLPipeline::rebuildPools() -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_REBUILD_POOLS); - - assertInitialized(); - - S32 max_count = mPools.size(); - pool_set_t::iterator iter1 = mPools.upper_bound(mLastRebuildPool); - while(max_count > 0 && mPools.size() > 0) // && num_rebuilds < MAX_REBUILDS) - { - if (iter1 == mPools.end()) - { - iter1 = mPools.begin(); - } - LLDrawPool* poolp = *iter1; - - if (poolp->isDead()) - { - mPools.erase(iter1++); - removeFromQuickLookup( poolp ); - if (poolp == mLastRebuildPool) - { - mLastRebuildPool = NULL; - } - delete poolp; - } - else - { - mLastRebuildPool = poolp; - iter1++; - } - max_count--; - } - - if (isAgentAvatarValid()) - { - gAgentAvatarp->rebuildHUD(); - } -} - -void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP); - - assertInitialized(); - - switch( new_poolp->getType() ) - { - case LLDrawPool::POOL_SIMPLE: - if (mSimplePool) - { - llassert(0); - llwarns << "Ignoring duplicate simple pool." << llendl; - } - else - { - mSimplePool = (LLRenderPass*) new_poolp; - } - break; - - case LLDrawPool::POOL_GRASS: - if (mGrassPool) - { - llassert(0); - llwarns << "Ignoring duplicate grass pool." << llendl; - } - else - { - mGrassPool = (LLRenderPass*) new_poolp; - } - break; - - case LLDrawPool::POOL_FULLBRIGHT: - if (mFullbrightPool) - { - llassert(0); - llwarns << "Ignoring duplicate simple pool." << llendl; - } - else - { - mFullbrightPool = (LLRenderPass*) new_poolp; - } - break; - - case LLDrawPool::POOL_INVISIBLE: - if (mInvisiblePool) - { - llassert(0); - llwarns << "Ignoring duplicate simple pool." << llendl; - } - else - { - mInvisiblePool = (LLRenderPass*) new_poolp; - } - break; - - case LLDrawPool::POOL_GLOW: - if (mGlowPool) - { - llassert(0); - llwarns << "Ignoring duplicate glow pool." << llendl; - } - else - { - mGlowPool = (LLRenderPass*) new_poolp; - } - break; - - case LLDrawPool::POOL_TREE: - mTreePools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ; - break; - - case LLDrawPool::POOL_TERRAIN: - mTerrainPools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ; - break; - - case LLDrawPool::POOL_BUMP: - if (mBumpPool) - { - llassert(0); - llwarns << "Ignoring duplicate bump pool." << llendl; - } - else - { - mBumpPool = new_poolp; - } - break; - - case LLDrawPool::POOL_ALPHA: - if( mAlphaPool ) - { - llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << llendl; - } - else - { - mAlphaPool = new_poolp; - } - break; - - case LLDrawPool::POOL_AVATAR: - break; // Do nothing - - case LLDrawPool::POOL_SKY: - if( mSkyPool ) - { - llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate Sky pool" << llendl; - } - else - { - mSkyPool = new_poolp; - } - break; - - case LLDrawPool::POOL_WATER: - if( mWaterPool ) - { - llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate Water pool" << llendl; - } - else - { - mWaterPool = new_poolp; - } - break; - - case LLDrawPool::POOL_GROUND: - if( mGroundPool ) - { - llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate Ground Pool" << llendl; - } - else - { - mGroundPool = new_poolp; - } - break; - - case LLDrawPool::POOL_WL_SKY: - if( mWLSkyPool ) - { - llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate WLSky Pool" << llendl; - } - else - { - mWLSkyPool = new_poolp; - } - break; - - default: - llassert(0); - llwarns << "Invalid Pool Type in LLPipeline::addPool()" << llendl; - break; - } -} - -void LLPipeline::removePool( LLDrawPool* poolp ) -{ - assertInitialized(); - removeFromQuickLookup(poolp); - mPools.erase(poolp); - delete poolp; -} - -void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) -{ - assertInitialized(); - LLMemType mt(LLMemType::MTYPE_PIPELINE); - switch( poolp->getType() ) - { - case LLDrawPool::POOL_SIMPLE: - llassert(mSimplePool == poolp); - mSimplePool = NULL; - break; - - case LLDrawPool::POOL_GRASS: - llassert(mGrassPool == poolp); - mGrassPool = NULL; - break; - - case LLDrawPool::POOL_FULLBRIGHT: - llassert(mFullbrightPool == poolp); - mFullbrightPool = NULL; - break; - - case LLDrawPool::POOL_INVISIBLE: - llassert(mInvisiblePool == poolp); - mInvisiblePool = NULL; - break; - - case LLDrawPool::POOL_WL_SKY: - llassert(mWLSkyPool == poolp); - mWLSkyPool = NULL; - break; - - case LLDrawPool::POOL_GLOW: - llassert(mGlowPool == poolp); - mGlowPool = NULL; - break; - - case LLDrawPool::POOL_TREE: - #ifdef _DEBUG - { - BOOL found = mTreePools.erase( (uintptr_t)poolp->getTexture() ); - llassert( found ); - } - #else - mTreePools.erase( (uintptr_t)poolp->getTexture() ); - #endif - break; - - case LLDrawPool::POOL_TERRAIN: - #ifdef _DEBUG - { - BOOL found = mTerrainPools.erase( (uintptr_t)poolp->getTexture() ); - llassert( found ); - } - #else - mTerrainPools.erase( (uintptr_t)poolp->getTexture() ); - #endif - break; - - case LLDrawPool::POOL_BUMP: - llassert( poolp == mBumpPool ); - mBumpPool = NULL; - break; - - case LLDrawPool::POOL_ALPHA: - llassert( poolp == mAlphaPool ); - mAlphaPool = NULL; - break; - - case LLDrawPool::POOL_AVATAR: - break; // Do nothing - - case LLDrawPool::POOL_SKY: - llassert( poolp == mSkyPool ); - mSkyPool = NULL; - break; - - case LLDrawPool::POOL_WATER: - llassert( poolp == mWaterPool ); - mWaterPool = NULL; - break; - - case LLDrawPool::POOL_GROUND: - llassert( poolp == mGroundPool ); - mGroundPool = NULL; - break; - - default: - llassert(0); - llwarns << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << llendl; - break; - } -} - -void LLPipeline::resetDrawOrders() -{ - assertInitialized(); - // Iterate through all of the draw pools and rebuild them. - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - poolp->resetDrawOrders(); - } -} - -//============================================================================ -// Once-per-frame setup of hardware lights, -// including sun/moon, avatar backlight, and up to 6 local lights - -void LLPipeline::setupAvatarLights(BOOL for_edit) -{ - assertInitialized(); - - if (for_edit) - { - LLColor4 diffuse(1.f, 1.f, 1.f, 0.f); - LLVector4 light_pos_cam(-8.f, 0.25f, 10.f, 0.f); // w==0 => directional light - LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview(); - LLMatrix4 camera_rot(camera_mat.getMat3()); - camera_rot.invert(); - LLVector4 light_pos = light_pos_cam * camera_rot; - - light_pos.normalize(); - - LLLightState* light = gGL.getLight(1); - - mHWLightColors[1] = diffuse; - - light->setDiffuse(diffuse); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - light->setPosition(light_pos); - light->setConstantAttenuation(1.f); - light->setLinearAttenuation(0.f); - light->setQuadraticAttenuation(0.f); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - } - else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini) - { - LLVector3 opposite_pos = -1.f * mSunDir; - LLVector3 orthog_light_pos = mSunDir % LLVector3::z_axis; - LLVector4 backlight_pos = LLVector4(lerp(opposite_pos, orthog_light_pos, 0.3f), 0.0f); - backlight_pos.normalize(); - - LLColor4 light_diffuse = mSunDiffuse; - LLColor4 backlight_diffuse(1.f - light_diffuse.mV[VRED], 1.f - light_diffuse.mV[VGREEN], 1.f - light_diffuse.mV[VBLUE], 1.f); - F32 max_component = 0.001f; - for (S32 i = 0; i < 3; i++) - { - if (backlight_diffuse.mV[i] > max_component) - { - max_component = backlight_diffuse.mV[i]; - } - } - F32 backlight_mag; - if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS) - { - backlight_mag = BACKLIGHT_DAY_MAGNITUDE_OBJECT; - } - else - { - backlight_mag = BACKLIGHT_NIGHT_MAGNITUDE_OBJECT; - } - backlight_diffuse *= backlight_mag / max_component; - - mHWLightColors[1] = backlight_diffuse; - - LLLightState* light = gGL.getLight(1); - - light->setPosition(backlight_pos); - light->setDiffuse(backlight_diffuse); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - light->setConstantAttenuation(1.f); - light->setLinearAttenuation(0.f); - light->setQuadraticAttenuation(0.f); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - } - else - { - LLLightState* light = gGL.getLight(1); - - mHWLightColors[1] = LLColor4::black; - - light->setDiffuse(LLColor4::black); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - } -} - -static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_dist) -{ - F32 inten = light->getLightIntensity(); - if (inten < .001f) - { - return max_dist; - } - F32 radius = light->getLightRadius(); - BOOL selected = light->isSelected(); - LLVector3 dpos = light->getRenderPosition() - cam_pos; - F32 dist2 = dpos.lengthSquared(); - if (!selected && dist2 > (max_dist + radius)*(max_dist + radius)) - { - return max_dist; - } - F32 dist = (F32) sqrt(dist2); - dist *= 1.f / inten; - dist -= radius; - if (selected) - { - dist -= 10000.f; // selected lights get highest priority - } - if (light->mDrawable.notNull() && light->mDrawable->isState(LLDrawable::ACTIVE)) - { - // moving lights get a little higher priority (too much causes artifacts) - dist -= light->getLightRadius()*0.25f; - } - return dist; -} - -void LLPipeline::calcNearbyLights(LLCamera& camera) -{ - assertInitialized(); - - if (LLPipeline::sReflectionRender) - { - return; - } - - if (mLightingDetail >= 1) - { - // mNearbyLight (and all light_set_t's) are sorted such that - // begin() == the closest light and rbegin() == the farthest light - const S32 MAX_LOCAL_LIGHTS = 6; -// LLVector3 cam_pos = gAgent.getCameraPositionAgent(); - LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ? - camera.getOrigin() : - gAgent.getPositionAgent(); - - F32 max_dist = LIGHT_MAX_RADIUS * 4.f; // ignore enitrely lights > 4 * max light rad - - // UPDATE THE EXISTING NEARBY LIGHTS - light_set_t cur_nearby_lights; - for (light_set_t::iterator iter = mNearbyLights.begin(); - iter != mNearbyLights.end(); iter++) - { - const Light* light = &(*iter); - LLDrawable* drawable = light->drawable; - LLVOVolume* volight = drawable->getVOVolume(); - if (!volight || !drawable->isState(LLDrawable::LIGHT)) - { - drawable->clearState(LLDrawable::NEARBY_LIGHT); - continue; - } - if (light->fade <= -LIGHT_FADE_TIME) - { - drawable->clearState(LLDrawable::NEARBY_LIGHT); - continue; - } - if (!sRenderAttachedLights && volight && volight->isAttachment()) - { - drawable->clearState(LLDrawable::NEARBY_LIGHT); - continue; - } - - F32 dist = calc_light_dist(volight, cam_pos, max_dist); - cur_nearby_lights.insert(Light(drawable, dist, light->fade)); - } - mNearbyLights = cur_nearby_lights; - - // FIND NEW LIGHTS THAT ARE IN RANGE - light_set_t new_nearby_lights; - for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); - iter != mLights.end(); ++iter) - { - LLDrawable* drawable = *iter; - LLVOVolume* light = drawable->getVOVolume(); - if (!light || drawable->isState(LLDrawable::NEARBY_LIGHT)) - { - continue; - } - if (light->isHUDAttachment()) - { - continue; // no lighting from HUD objects - } - F32 dist = calc_light_dist(light, cam_pos, max_dist); - if (dist >= max_dist) - { - continue; - } - if (!sRenderAttachedLights && light && light->isAttachment()) - { - continue; - } - new_nearby_lights.insert(Light(drawable, dist, 0.f)); - if (new_nearby_lights.size() > (U32)MAX_LOCAL_LIGHTS) - { - new_nearby_lights.erase(--new_nearby_lights.end()); - const Light& last = *new_nearby_lights.rbegin(); - max_dist = last.dist; - } - } - - // INSERT ANY NEW LIGHTS - for (light_set_t::iterator iter = new_nearby_lights.begin(); - iter != new_nearby_lights.end(); iter++) - { - const Light* light = &(*iter); - if (mNearbyLights.size() < (U32)MAX_LOCAL_LIGHTS) - { - mNearbyLights.insert(*light); - ((LLDrawable*) light->drawable)->setState(LLDrawable::NEARBY_LIGHT); - } - else - { - // crazy cast so that we can overwrite the fade value - // even though gcc enforces sets as const - // (fade value doesn't affect sort so this is safe) - Light* farthest_light = ((Light*) (&(*(mNearbyLights.rbegin())))); - if (light->dist < farthest_light->dist) - { - if (farthest_light->fade >= 0.f) - { - farthest_light->fade = -gFrameIntervalSeconds; - } - } - else - { - break; // none of the other lights are closer - } - } - } - - } -} - -void LLPipeline::setupHWLights(LLDrawPool* pool) -{ - assertInitialized(); - - // Ambient - LLColor4 ambient = gSky.getTotalAmbientColor(); - glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV); - - // Light 0 = Sun or Moon (All objects) - { - if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS) - { - mSunDir.setVec(gSky.getSunDirection()); - mSunDiffuse.setVec(gSky.getSunDiffuseColor()); - } - else - { - mSunDir.setVec(gSky.getMoonDirection()); - mSunDiffuse.setVec(gSky.getMoonDiffuseColor()); - } - - F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]); - if (max_color > 1.f) - { - mSunDiffuse *= 1.f/max_color; - } - mSunDiffuse.clamp(); - - LLVector4 light_pos(mSunDir, 0.0f); - LLColor4 light_diffuse = mSunDiffuse; - mHWLightColors[0] = light_diffuse; - - LLLightState* light = gGL.getLight(0); - light->setPosition(light_pos); - light->setDiffuse(light_diffuse); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - light->setConstantAttenuation(1.f); - light->setLinearAttenuation(0.f); - light->setQuadraticAttenuation(0.f); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - } - - // Light 1 = Backlight (for avatars) - // (set by enableLightsAvatar) - - S32 cur_light = 2; - - // Nearby lights = LIGHT 2-7 - - mLightMovingMask = 0; - - if (mLightingDetail >= 1) - { - for (light_set_t::iterator iter = mNearbyLights.begin(); - iter != mNearbyLights.end(); ++iter) - { - LLDrawable* drawable = iter->drawable; - LLVOVolume* light = drawable->getVOVolume(); - if (!light) - { - continue; - } - if (drawable->isState(LLDrawable::ACTIVE)) - { - mLightMovingMask |= (1<getLightColor(); - light_color.mV[3] = 0.0f; - - F32 fade = iter->fade; - if (fade < LIGHT_FADE_TIME) - { - // fade in/out light - if (fade >= 0.f) - { - fade = fade / LIGHT_FADE_TIME; - ((Light*) (&(*iter)))->fade += gFrameIntervalSeconds; - } - else - { - fade = 1.f + fade / LIGHT_FADE_TIME; - ((Light*) (&(*iter)))->fade -= gFrameIntervalSeconds; - } - fade = llclamp(fade,0.f,1.f); - light_color *= fade; - } - - LLVector3 light_pos(light->getRenderPosition()); - LLVector4 light_pos_gl(light_pos, 1.0f); - - F32 light_radius = llmax(light->getLightRadius(), 0.001f); - - F32 x = (3.f * (1.f + light->getLightFalloff())); // why this magic? probably trying to match a historic behavior. - float linatten = x / (light_radius); // % of brightness at radius - - mHWLightColors[cur_light] = light_color; - LLLightState* light_state = gGL.getLight(cur_light); - - light_state->setPosition(light_pos_gl); - light_state->setDiffuse(light_color); - light_state->setAmbient(LLColor4::black); - light_state->setConstantAttenuation(0.f); - light_state->setLinearAttenuation(linatten); - light_state->setQuadraticAttenuation(0.f); - - if (light->isLightSpotlight() // directional (spot-)light - && (LLPipeline::sRenderDeferred || gSavedSettings.getBOOL("RenderSpotLightsInNondeferred"))) // these are only rendered as GL spotlights if we're in deferred rendering mode *or* the setting forces them on - { - LLVector3 spotparams = light->getSpotLightParams(); - LLQuaternion quat = light->getRenderRotation(); - LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction - at_axis *= quat; - - light_state->setSpotDirection(at_axis); - light_state->setSpotCutoff(90.f); - light_state->setSpotExponent(2.f); - - light_state->setSpecular(LLColor4::black); - } - else // omnidirectional (point) light - { - light_state->setSpotExponent(0.f); - light_state->setSpotCutoff(180.f); - - // we use specular.w = 1.0 as a cheap hack for the shaders to know that this is omnidirectional rather than a spotlight - const LLColor4 specular(0.f, 0.f, 0.f, 1.f); - light_state->setSpecular(specular); - } - cur_light++; - if (cur_light >= 8) - { - break; // safety - } - } - } - for ( ; cur_light < 8 ; cur_light++) - { - mHWLightColors[cur_light] = LLColor4::black; - LLLightState* light = gGL.getLight(cur_light); - - light->setDiffuse(LLColor4::black); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - } - if (gAgentAvatarp && - gAgentAvatarp->mSpecialRenderMode == 3) - { - LLColor4 light_color = LLColor4::white; - light_color.mV[3] = 0.0f; - - LLVector3 light_pos(LLViewerCamera::getInstance()->getOrigin()); - LLVector4 light_pos_gl(light_pos, 1.0f); - - F32 light_radius = 16.f; - - F32 x = 3.f; - float linatten = x / (light_radius); // % of brightness at radius - - mHWLightColors[2] = light_color; - LLLightState* light = gGL.getLight(2); - - light->setPosition(light_pos_gl); - light->setDiffuse(light_color); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - light->setQuadraticAttenuation(0.f); - light->setConstantAttenuation(0.f); - light->setLinearAttenuation(linatten); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - } - - // Init GL state - glDisable(GL_LIGHTING); - for (S32 i = 0; i < 8; ++i) - { - gGL.getLight(i)->disable(); - } - mLightMask = 0; -} - -void LLPipeline::enableLights(U32 mask) -{ - assertInitialized(); - - if (mLightingDetail == 0) - { - mask &= 0xf003; // sun and backlight only (and fullbright bit) - } - if (mLightMask != mask) - { - stop_glerror(); - if (!mLightMask) - { - glEnable(GL_LIGHTING); - } - if (mask) - { - stop_glerror(); - for (S32 i=0; i<8; i++) - { - LLLightState* light = gGL.getLight(i); - if (mask & (1<enable(); - light->setDiffuse(mHWLightColors[i]); - } - else - { - light->disable(); - light->setDiffuse(LLColor4::black); - } - } - stop_glerror(); - } - else - { - glDisable(GL_LIGHTING); - } - stop_glerror(); - mLightMask = mask; - LLColor4 ambient = gSky.getTotalAmbientColor(); - glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV); - stop_glerror(); - } -} - -void LLPipeline::enableLightsStatic() -{ - assertInitialized(); - U32 mask = 0x01; // Sun - if (mLightingDetail >= 2) - { - mask |= mLightMovingMask; // Hardware moving lights - } - else - { - mask |= 0xff & (~2); // Hardware local lights - } - enableLights(mask); -} - -void LLPipeline::enableLightsDynamic() -{ - assertInitialized(); - U32 mask = 0xff & (~2); // Local lights - enableLights(mask); - - if (isAgentAvatarValid() && getLightingDetail() <= 0) - { - if (gAgentAvatarp->mSpecialRenderMode == 0) // normal - { - gPipeline.enableLightsAvatar(); - } - else if (gAgentAvatarp->mSpecialRenderMode >= 1) // anim preview - { - gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f)); - } - } -} - -void LLPipeline::enableLightsAvatar() -{ - U32 mask = 0xff; // All lights - setupAvatarLights(FALSE); - enableLights(mask); -} - -void LLPipeline::enableLightsPreview() -{ - disableLights(); - - glEnable(GL_LIGHTING); - LLColor4 ambient = gSavedSettings.getColor4("PreviewAmbientColor"); - glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV); - - - LLColor4 diffuse0 = gSavedSettings.getColor4("PreviewDiffuse0"); - LLColor4 specular0 = gSavedSettings.getColor4("PreviewSpecular0"); - LLColor4 diffuse1 = gSavedSettings.getColor4("PreviewDiffuse1"); - LLColor4 specular1 = gSavedSettings.getColor4("PreviewSpecular1"); - LLColor4 diffuse2 = gSavedSettings.getColor4("PreviewDiffuse2"); - LLColor4 specular2 = gSavedSettings.getColor4("PreviewSpecular2"); - - LLVector3 dir0 = gSavedSettings.getVector3("PreviewDirection0"); - LLVector3 dir1 = gSavedSettings.getVector3("PreviewDirection1"); - LLVector3 dir2 = gSavedSettings.getVector3("PreviewDirection2"); - - dir0.normVec(); - dir1.normVec(); - dir2.normVec(); - - LLVector4 light_pos(dir0, 0.0f); - - LLLightState* light = gGL.getLight(0); - - light->enable(); - light->setPosition(light_pos); - light->setDiffuse(diffuse0); - light->setAmbient(LLColor4::black); - light->setSpecular(specular0); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - - light_pos = LLVector4(dir1, 0.f); - - light = gGL.getLight(1); - light->enable(); - light->setPosition(light_pos); - light->setDiffuse(diffuse1); - light->setAmbient(LLColor4::black); - light->setSpecular(specular1); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - - light_pos = LLVector4(dir2, 0.f); - light = gGL.getLight(2); - light->enable(); - light->setPosition(light_pos); - light->setDiffuse(diffuse2); - light->setAmbient(LLColor4::black); - light->setSpecular(specular2); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); -} - - -void LLPipeline::enableLightsAvatarEdit(const LLColor4& color) -{ - U32 mask = 0x2002; // Avatar backlight only, set ambient - setupAvatarLights(TRUE); - enableLights(mask); - - glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV); -} - -void LLPipeline::enableLightsFullbright(const LLColor4& color) -{ - assertInitialized(); - U32 mask = 0x1000; // Non-0 mask, set ambient - enableLights(mask); - - glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV); -} - -void LLPipeline::disableLights() -{ - enableLights(0); // no lighting (full bright) -} - -//============================================================================ - -class LLMenuItemGL; -class LLInvFVBridge; -struct cat_folder_pair; -class LLVOBranch; -class LLVOLeaf; - -void LLPipeline::findReferences(LLDrawable *drawablep) -{ - assertInitialized(); - if (mLights.find(drawablep) != mLights.end()) - { - llinfos << "In mLights" << llendl; - } - if (std::find(mMovedList.begin(), mMovedList.end(), drawablep) != mMovedList.end()) - { - llinfos << "In mMovedList" << llendl; - } - if (std::find(mShiftList.begin(), mShiftList.end(), drawablep) != mShiftList.end()) - { - llinfos << "In mShiftList" << llendl; - } - if (mRetexturedList.find(drawablep) != mRetexturedList.end()) - { - llinfos << "In mRetexturedList" << llendl; - } - - if (std::find(mBuildQ1.begin(), mBuildQ1.end(), drawablep) != mBuildQ1.end()) - { - llinfos << "In mBuildQ1" << llendl; - } - if (std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep) != mBuildQ2.end()) - { - llinfos << "In mBuildQ2" << llendl; - } - - S32 count; - - count = gObjectList.findReferences(drawablep); - if (count) - { - llinfos << "In other drawables: " << count << " references" << llendl; - } -} - -BOOL LLPipeline::verify() -{ - BOOL ok = assertInitialized(); - if (ok) - { - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - if (!poolp->verify()) - { - ok = FALSE; - } - } - } - - if (!ok) - { - llwarns << "Pipeline verify failed!" << llendl; - } - return ok; -} - -////////////////////////////// -// -// Collision detection -// -// - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/** - * A method to compute a ray-AABB intersection. - * Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990 - * Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500) - * Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only) - * - * Hence this version is faster as well as more robust than the original one. - * - * Should work provided: - * 1) the integer representation of 0.0f is 0x00000000 - * 2) the sign bit of the float is the most significant one - * - * Report bugs: p.terdiman@codercorner.com - * - * \param aabb [in] the axis-aligned bounding box - * \param origin [in] ray origin - * \param dir [in] ray direction - * \param coord [out] impact coordinates - * \return true if ray intersects AABB - */ -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//#define RAYAABB_EPSILON 0.00001f -#define IR(x) ((U32&)x) - -bool LLRayAABB(const LLVector3 ¢er, const LLVector3 &size, const LLVector3& origin, const LLVector3& dir, LLVector3 &coord, F32 epsilon) -{ - BOOL Inside = TRUE; - LLVector3 MinB = center - size; - LLVector3 MaxB = center + size; - LLVector3 MaxT; - MaxT.mV[VX]=MaxT.mV[VY]=MaxT.mV[VZ]=-1.0f; - - // Find candidate planes. - for(U32 i=0;i<3;i++) - { - if(origin.mV[i] < MinB.mV[i]) - { - coord.mV[i] = MinB.mV[i]; - Inside = FALSE; - - // Calculate T distances to candidate planes - if(IR(dir.mV[i])) MaxT.mV[i] = (MinB.mV[i] - origin.mV[i]) / dir.mV[i]; - } - else if(origin.mV[i] > MaxB.mV[i]) - { - coord.mV[i] = MaxB.mV[i]; - Inside = FALSE; - - // Calculate T distances to candidate planes - if(IR(dir.mV[i])) MaxT.mV[i] = (MaxB.mV[i] - origin.mV[i]) / dir.mV[i]; - } - } - - // Ray origin inside bounding box - if(Inside) - { - coord = origin; - return true; - } - - // Get largest of the maxT's for final choice of intersection - U32 WhichPlane = 0; - if(MaxT.mV[1] > MaxT.mV[WhichPlane]) WhichPlane = 1; - if(MaxT.mV[2] > MaxT.mV[WhichPlane]) WhichPlane = 2; - - // Check final candidate actually inside box - if(IR(MaxT.mV[WhichPlane])&0x80000000) return false; - - for(U32 i=0;i<3;i++) - { - if(i!=WhichPlane) - { - coord.mV[i] = origin.mV[i] + MaxT.mV[WhichPlane] * dir.mV[i]; - if (epsilon > 0) - { - if(coord.mV[i] < MinB.mV[i] - epsilon || coord.mV[i] > MaxB.mV[i] + epsilon) return false; - } - else - { - if(coord.mV[i] < MinB.mV[i] || coord.mV[i] > MaxB.mV[i]) return false; - } - } - } - return true; // ray hits box -} - -////////////////////////////// -// -// Macros, functions, and inline methods from other classes -// -// - -void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light) -{ - if (drawablep && assertInitialized()) - { - if (is_light) - { - mLights.insert(drawablep); - drawablep->setState(LLDrawable::LIGHT); - } - else - { - drawablep->clearState(LLDrawable::LIGHT); - mLights.erase(drawablep); - } - } -} - -//static -void LLPipeline::toggleRenderType(U32 type) -{ - gPipeline.mRenderTypeEnabled[type] = !gPipeline.mRenderTypeEnabled[type]; - if (type == LLPipeline::RENDER_TYPE_WATER) - { - gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER] = !gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER]; - } -} - -//static -void LLPipeline::toggleRenderTypeControl(void* data) -{ - U32 type = (U32)(intptr_t)data; - U32 bit = (1<inBuildMode() ? FALSE : TRUE; - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - - for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++) - { - if ((j == LLViewerRegion::PARTITION_VOLUME) || - (j == LLViewerRegion::PARTITION_BRIDGE) || - (j == LLViewerRegion::PARTITION_TERRAIN) || - (j == LLViewerRegion::PARTITION_TREE) || - (j == LLViewerRegion::PARTITION_GRASS)) // only check these partitions for now - { - LLSpatialPartition* part = region->getSpatialPartition(j); - if (part && hasRenderType(part->mDrawableType)) - { - LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal); - if (hit) - { - drawable = hit; - local_end = position; - } - } - } - } - } - - if (!sPickAvatar) - { - //save hit info in case we need to restore - //due to attachment override - LLVector3 local_normal; - LLVector3 local_binormal; - LLVector2 local_texcoord; - S32 local_face_hit = -1; - - if (face_hit) - { - local_face_hit = *face_hit; - } - if (tex_coord) - { - local_texcoord = *tex_coord; - } - if (bi_normal) - { - local_binormal = *bi_normal; - } - if (normal) - { - local_normal = *normal; - } - - const F32 ATTACHMENT_OVERRIDE_DIST = 0.1f; - - //check against avatars - sPickAvatar = TRUE; - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - - LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE); - if (part && hasRenderType(part->mDrawableType)) - { - LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal); - if (hit) - { - if (!drawable || - !drawable->getVObj()->isAttachment() || - (position-local_end).magVec() > ATTACHMENT_OVERRIDE_DIST) - { //avatar overrides if previously hit drawable is not an attachment or - //attachment is far enough away from detected intersection - drawable = hit; - local_end = position; - } - else - { //prioritize attachments over avatars - position = local_end; - - if (face_hit) - { - *face_hit = local_face_hit; - } - if (tex_coord) - { - *tex_coord = local_texcoord; - } - if (bi_normal) - { - *bi_normal = local_binormal; - } - if (normal) - { - *normal = local_normal; - } - } - } - } - } - } - - //check all avatar nametags (silly, isn't it?) - for (std::vector< LLCharacter* >::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); - ++iter) - { - LLVOAvatar* av = (LLVOAvatar*) *iter; - if (av->mNameText.notNull() - && av->mNameText->lineSegmentIntersect(start, local_end, position)) - { - drawable = av->mDrawable; - local_end = position; - } - } - - if (intersection) - { - *intersection = position; - } - - return drawable ? drawable->getVObj().get() : NULL; -} - -LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end, - BOOL pick_transparent, - S32* face_hit, - LLVector3* intersection, // return the intersection point - LLVector2* tex_coord, // return the texture coordinates of the intersection point - LLVector3* normal, // return the surface normal at the intersection point - LLVector3* bi_normal // return the surface bi-normal at the intersection point - ) -{ - LLDrawable* drawable = NULL; - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - - BOOL toggle = FALSE; - if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD)) - { - toggleRenderType(LLPipeline::RENDER_TYPE_HUD); - toggle = TRUE; - } - - LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_HUD); - if (part) - { - LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal); - if (hit) - { - drawable = hit; - } - } - - if (toggle) - { - toggleRenderType(LLPipeline::RENDER_TYPE_HUD); - } - } - return drawable ? drawable->getVObj().get() : NULL; -} - -LLSpatialPartition* LLPipeline::getSpatialPartition(LLViewerObject* vobj) -{ - if (vobj) - { - LLViewerRegion* region = vobj->getRegion(); - if (region) - { - return region->getSpatialPartition(vobj->getPartitionType()); - } - } - return NULL; -} - - -void LLPipeline::resetVertexBuffers(LLDrawable* drawable) -{ - if (!drawable || drawable->isDead()) - { - return; - } - - for (S32 i = 0; i < drawable->getNumFaces(); i++) - { - LLFace* facep = drawable->getFace(i); - facep->mVertexBuffer = NULL; - facep->mLastVertexBuffer = NULL; - } -} - -void LLPipeline::resetVertexBuffers() -{ - sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); - sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips"); - LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO"); - LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw"); - LLVertexBuffer::sEnableVBOs = gSavedSettings.getBOOL("RenderVBOEnable"); - sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight"); - sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha"); - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - part->resetVertexBuffers(); - } - } - } - - resetDrawOrders(); - - gSky.resetVertexBuffers(); - - if (LLVertexBuffer::sGLCount > 0) - { - LLVertexBuffer::cleanupClass(); - } - - //delete all name pool caches - LLGLNamePool::cleanupPools(); - - if (LLVertexBuffer::sGLCount > 0) - { - llwarns << "VBO wipe failed." << llendl; - } - - if (!LLVertexBuffer::sStreamIBOPool.mNameList.empty() || - !LLVertexBuffer::sStreamVBOPool.mNameList.empty() || - !LLVertexBuffer::sDynamicIBOPool.mNameList.empty() || - !LLVertexBuffer::sDynamicVBOPool.mNameList.empty()) - { - llwarns << "VBO name pool cleanup failed." << llendl; - } - - LLVertexBuffer::unbind(); - - LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind"); -} - -void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture) -{ - LLMemType mt_ro(LLMemType::MTYPE_PIPELINE_RENDER_OBJECTS); - assertInitialized(); - glLoadMatrixd(gGLModelView); - gGLLastMatrix = NULL; - mSimplePool->pushBatches(type, mask); - glLoadMatrixd(gGLModelView); - gGLLastMatrix = NULL; -} - -void LLPipeline::setDisableVBOMapping(BOOL no_vbo_mapping) -{ - if (LLVertexBuffer::sEnableVBOs && no_vbo_mapping != LLVertexBuffer::sDisableVBOMapping) - { - if (no_vbo_mapping) - { - llinfos << "Disabling VBO glMapBufferARB." << llendl; - } - else - { - llinfos << "Enabling VBO glMapBufferARB." << llendl; - } - - resetVertexBuffers(); - LLVertexBuffer::initClass(true, no_vbo_mapping); - } -} - -void validate_framebuffer_object() -{ - GLenum status; - status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT); - switch(status) - { - case GL_FRAMEBUFFER_COMPLETE: - //framebuffer OK, no error. - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - // frame buffer not OK: probably means unsupported depth buffer format - llerrs << "Framebuffer Incomplete Missing Attachment." << llendl; - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - // frame buffer not OK: probably means unsupported depth buffer format - llerrs << "Framebuffer Incomplete Attachment." << llendl; - break; - case GL_FRAMEBUFFER_UNSUPPORTED: - /* choose different formats */ - llerrs << "Framebuffer unsupported." << llendl; - break; - default: - llerrs << "Unknown framebuffer status." << llendl; - break; - } -} - -void LLPipeline::bindScreenToTexture() -{ - -} - -static LLFastTimer::DeclareTimer FTM_RENDER_BLOOM("Bloom"); - -void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) -{ - LLMemType mt_ru(LLMemType::MTYPE_PIPELINE_RENDER_BLOOM); - if (!(gPipeline.canUseVertexShaders() && - sRenderGlow)) - { - return; - } - - LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - - assertInitialized(); - - if (gUseWireframe) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - - U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor"); - - LLVector2 tc1(0,0); - LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2, - (F32) gViewerWindow->getWorldViewHeightRaw()*2); - - if (res_mod > 1) - { - tc2 /= (F32) res_mod; - } - - LLFastTimer ftm(FTM_RENDER_BLOOM); - gGL.color4f(1,1,1,1); - LLGLDepthTest depth(GL_FALSE); - LLGLDisable blend(GL_BLEND); - LLGLDisable cull(GL_CULL_FACE); - - enableLightsFullbright(LLColor4(1,1,1,1)); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - LLGLDisable test(GL_ALPHA_TEST); - - gGL.setColorMask(true, true); - glClearColor(0,0,0,0); - - /*if (for_snapshot) - { - gGL.getTexUnit(0)->bind(&mGlow[1]); - { - //LLGLEnable stencil(GL_STENCIL_TEST); - //glStencilFunc(GL_NOTEQUAL, 255, 0xFFFFFFFF); - //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - //LLGLDisable blend(GL_BLEND); - - // If the snapshot is constructed from tiles, calculate which - // tile we're in. - - //from LLViewerCamera::setPerpsective - if (zoom_factor > 1.f) - { - int pos_y = subfield / llceil(zoom_factor); - int pos_x = subfield - (pos_y*llceil(zoom_factor)); - F32 size = 1.f/zoom_factor; - - tc1.set(pos_x*size, pos_y*size); - tc2 = tc1 + LLVector2(size,size); - } - else - { - tc2.set(1,1); - } - - LLGLEnable blend(GL_BLEND); - gGL.setSceneBlendType(LLRender::BT_ADD); - - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.color4f(1,1,1,1); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,1); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(1,-1); - - gGL.texCoord2f(tc2.mV[0], tc2.mV[1]); - gGL.vertex2f(1,1); - - gGL.end(); - - gGL.flush(); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - - gGL.flush(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - return; - }*/ - - { - { - LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); - mGlow[2].bindTarget(); - mGlow[2].clear(); - } - - gGlowExtractProgram.bind(); - F32 minLum = llmax(gSavedSettings.getF32("RenderGlowMinLuminance"), 0.0f); - F32 maxAlpha = gSavedSettings.getF32("RenderGlowMaxExtractAlpha"); - F32 warmthAmount = gSavedSettings.getF32("RenderGlowWarmthAmount"); - LLVector3 lumWeights = gSavedSettings.getVector3("RenderGlowLumWeights"); - LLVector3 warmthWeights = gSavedSettings.getVector3("RenderGlowWarmthWeights"); - gGlowExtractProgram.uniform1f("minLuminance", minLum); - gGlowExtractProgram.uniform1f("maxExtractAlpha", maxAlpha); - gGlowExtractProgram.uniform3f("lumWeights", lumWeights.mV[0], lumWeights.mV[1], lumWeights.mV[2]); - gGlowExtractProgram.uniform3f("warmthWeights", warmthWeights.mV[0], warmthWeights.mV[1], warmthWeights.mV[2]); - gGlowExtractProgram.uniform1f("warmthAmount", warmthAmount); - LLGLEnable blend_on(GL_BLEND); - LLGLEnable test(GL_ALPHA_TEST); - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); - gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(0)->disable(); - gGL.getTexUnit(0)->enable(LLTexUnit::TT_RECT_TEXTURE); - gGL.getTexUnit(0)->bind(&mScreen); - - gGL.color4f(1,1,1,1); - gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); - - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - - mGlow[2].flush(); - } - - tc1.setVec(0,0); - tc2.setVec(2,2); - - // power of two between 1 and 1024 - U32 glowResPow = gSavedSettings.getS32("RenderGlowResolutionPow"); - const U32 glow_res = llmax(1, - llmin(1024, 1 << glowResPow)); - - S32 kernel = gSavedSettings.getS32("RenderGlowIterations")*2; - F32 delta = gSavedSettings.getF32("RenderGlowWidth") / glow_res; - // Use half the glow width if we have the res set to less than 9 so that it looks - // almost the same in either case. - if (glowResPow < 9) - { - delta *= 0.5f; - } - F32 strength = gSavedSettings.getF32("RenderGlowStrength"); - - gGlowProgram.bind(); - gGlowProgram.uniform1f("glowStrength", strength); - - for (S32 i = 0; i < kernel; i++) - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - { - LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); - mGlow[i%2].bindTarget(); - mGlow[i%2].clear(); - } - - if (i == 0) - { - gGL.getTexUnit(0)->bind(&mGlow[2]); - } - else - { - gGL.getTexUnit(0)->bind(&mGlow[(i-1)%2]); - } - - if (i%2 == 0) - { - gGlowProgram.uniform2f("glowDelta", delta, 0); - } - else - { - gGlowProgram.uniform2f("glowDelta", 0, delta); - } - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); - - mGlow[i%2].flush(); - } - - gGlowProgram.unbind(); - - if (LLRenderTarget::sUseFBO) - { - LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } - - gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; - gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; - gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); - gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); - - tc2.setVec((F32) gViewerWindow->getWorldViewWidthRaw(), - (F32) gViewerWindow->getWorldViewHeightRaw()); - - gGL.flush(); - - LLVertexBuffer::unbind(); - - if (LLPipeline::sRenderDeferred) - { - LLGLSLShader* shader = &gDeferredPostProgram; - if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) - { - shader = &gDeferredGIFinalProgram; - } - - LLGLDisable blend(GL_BLEND); - bindDeferredShader(*shader); - - //depth of field focal plane calculations - - F32 subject_distance = 16.f; - if (LLViewerJoystick::getInstance()->getOverrideCamera()) - { - //flycam mode, use mouse cursor as focus point - LLVector3 eye = LLViewerCamera::getInstance()->getOrigin(); - subject_distance = (eye-gDebugRaycastIntersection).magVec(); - } - else - { - LLViewerObject* obj = gAgentCamera.getFocusObject(); - if (obj) - { - LLVector3 focus = LLVector3(gAgentCamera.getFocusGlobal()-gAgent.getRegion()->getOriginGlobal()); - LLVector3 eye = LLViewerCamera::getInstance()->getOrigin(); - subject_distance = (focus-eye).magVec(); - } - } - - //convert to mm - subject_distance *= 1000.f; - F32 fnumber = gSavedSettings.getF32("CameraFNumber"); - const F32 default_focal_length = gSavedSettings.getF32("CameraFocalLength"); - - F32 fov = LLViewerCamera::getInstance()->getView(); - - const F32 default_fov = gSavedSettings.getF32("CameraFieldOfView") * F_PI/180.f; - //const F32 default_aspect_ratio = gSavedSettings.getF32("CameraAspectRatio"); - - //F32 aspect_ratio = (F32) mScreen.getWidth()/(F32)mScreen.getHeight(); - - F32 dv = 2.f*default_focal_length * tanf(default_fov/2.f); - //F32 dh = 2.f*default_focal_length * tanf(default_fov*default_aspect_ratio/2.f); - - F32 focal_length = dv/(2*tanf(fov/2.f)); - - //F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle); - - // from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f)) - // where N = fnumber - // s2 = dot distance - // s1 = subject distance - // f = focal length - // - - F32 blur_constant = focal_length*focal_length/(fnumber*(subject_distance-focal_length)); - blur_constant /= 1000.f; //convert to meters for shader - F32 magnification = focal_length/(subject_distance-focal_length); - - shader->uniform1f("focal_distance", -subject_distance/1000.f); - shader->uniform1f("blur_constant", blur_constant); - shader->uniform1f("tan_pixel_angle", tanf(1.f/LLDrawable::sCurPixelAngle)); - shader->uniform1f("magnification", magnification); - - S32 channel = shader->enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE); - if (channel > -1) - { - mScreen.bindTexture(0, channel); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - } - //channel = shader->enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE); - //if (channel > -1) - //{ - //gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - //} - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); - - unbindDeferredShader(*shader); - } - else - { - if (res_mod > 1) - { - tc2 /= (F32) res_mod; - } - - U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; - LLPointer buff = new LLVertexBuffer(mask, 0); - buff->allocateBuffer(3,0,TRUE); - - LLStrider v; - LLStrider uv1; - LLStrider uv2; - - buff->getVertexStrider(v); - buff->getTexCoord0Strider(uv1); - buff->getTexCoord1Strider(uv2); - - uv1[0] = LLVector2(0, 0); - uv1[1] = LLVector2(0, 2); - uv1[2] = LLVector2(2, 0); - - uv2[0] = LLVector2(0, 0); - uv2[1] = LLVector2(0, tc2.mV[1]*2.f); - uv2[2] = LLVector2(tc2.mV[0]*2.f, 0); - - v[0] = LLVector3(-1,-1,0); - v[1] = LLVector3(-1,3,0); - v[2] = LLVector3(3,-1,0); - - buff->setBuffer(0); - - LLGLDisable blend(GL_BLEND); - - //tex unit 0 - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR); - - gGL.getTexUnit(0)->bind(&mGlow[1]); - gGL.getTexUnit(1)->activate(); - gGL.getTexUnit(1)->enable(LLTexUnit::TT_RECT_TEXTURE); - - - //tex unit 1 - gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR); - - gGL.getTexUnit(1)->bind(&mScreen); - gGL.getTexUnit(1)->activate(); - - LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); - - buff->setBuffer(mask); - buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3); - - gGL.getTexUnit(1)->disable(); - gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT); - - gGL.getTexUnit(0)->activate(); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - } - - if (LLRenderTarget::sUseFBO) - { //copy depth buffer from mScreen to framebuffer - LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(), - 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); - } - - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)) - { - LLVector2 tc1(0,0); - LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2, - (F32) gViewerWindow->getWorldViewHeightRaw()*2); - - LLGLEnable blend(GL_BLEND); - gGL.color4f(1,1,1,0.75f); - - gGL.getTexUnit(0)->bind(&mPhysicsDisplay); - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); - gGL.flush(); - } - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - LLVertexBuffer::unbind(); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - -} - -static LLFastTimer::DeclareTimer FTM_BIND_DEFERRED("Bind Deferred"); - -void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, LLRenderTarget* gi_source, LLRenderTarget* last_gi_post, U32 noise_map) -{ - LLFastTimer t(FTM_BIND_DEFERRED); - - if (noise_map == 0xFFFFFFFF) - { - noise_map = mNoiseMap; - } - - LLGLState::checkTextureChannels(); - - shader.bind(); - S32 channel = 0; - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE); - if (channel > -1) - { - mDeferredScreen.bindTexture(0,channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE); - if (channel > -1) - { - mDeferredScreen.bindTexture(1, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE); - if (channel > -1) - { - mDeferredScreen.bindTexture(2, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - if (gi_source) - { - BOOL has_gi = FALSE; - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE); - if (channel > -1) - { - has_gi = TRUE; - gi_source->bindTexture(0, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR); - if (channel > -1) - { - has_gi = TRUE; - gi_source->bindTexture(1, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL); - if (channel > -1) - { - has_gi = TRUE; - gi_source->bindTexture(2, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS); - if (channel > -1) - { - has_gi = TRUE; - gi_source->bindTexture(1, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS); - if (channel > -1) - { - has_gi = TRUE; - gi_source->bindTexture(3, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE); - if (channel > -1) - { - has_gi = TRUE; - last_gi_post->bindTexture(0, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL); - if (channel > -1) - { - has_gi = TRUE; - last_gi_post->bindTexture(2, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS); - if (channel > -1) - { - has_gi = TRUE; - last_gi_post->bindTexture(1, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS); - if (channel > -1) - { - has_gi = TRUE; - last_gi_post->bindTexture(3, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH); - if (channel > -1) - { - has_gi = TRUE; - gGL.getTexUnit(channel)->bind(gi_source, TRUE); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - stop_glerror(); - - glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); - glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA); - - stop_glerror(); - } - - if (has_gi) - { - F32 range_x = llmin(mGIRange.mV[0], 1.f); - F32 range_y = llmin(mGIRange.mV[1], 1.f); - - LLVector2 scale(range_x,range_y); - - LLVector2 kern[25]; - - for (S32 i = 0; i < 5; ++i) - { - for (S32 j = 0; j < 5; ++j) - { - S32 idx = i*5+j; - kern[idx].mV[0] = (i-2)*0.5f; - kern[idx].mV[1] = (j-2)*0.5f; - kern[idx].scaleVec(scale); - } - } - - shader.uniform2fv("gi_kern", 25, (F32*) kern); - shader.uniformMatrix4fv("gi_mat", 1, FALSE, mGIMatrix.m); - shader.uniformMatrix4fv("gi_mat_proj", 1, FALSE, mGIMatrixProj.m); - shader.uniformMatrix4fv("gi_inv_proj", 1, FALSE, mGIInvProj.m); - shader.uniformMatrix4fv("gi_norm_mat", 1, FALSE, mGINormalMatrix.m); - } - } - - /*channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE); - if (channel > -1) - { - mDeferredScreen.bindTexture(3, channel); - }*/ - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE); - if (channel > -1) - { - gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - stop_glerror(); - - glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); - glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA); - - stop_glerror(); - - glh::matrix4f projection = glh_get_current_projection(); - glh::matrix4f inv_proj = projection.inverse(); - - shader.uniformMatrix4fv("inv_proj", 1, FALSE, inv_proj.m); - shader.uniform4f("viewport", (F32) gGLViewport[0], - (F32) gGLViewport[1], - (F32) gGLViewport[2], - (F32) gGLViewport[3]); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NOISE); - if (channel > -1) - { - gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, noise_map); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC); - if (channel > -1) - { - gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); - } - - stop_glerror(); - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE); - if (channel > -1) - { - mDeferredLight[light_index].bindTexture(0, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE); - if (channel > -1) - { - gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_BLOOM); - if (channel > -1) - { - mGlow[1].bindTexture(0, channel); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE); - if (channel > -1) - { - gi_source->bindTexture(0, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE); - if (channel > -1) - { - mEdgeMap.bindTexture(0, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE); - if (channel > -1) - { - mDeferredLight[1].bindTexture(0, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE); - if (channel > -1) - { - mDeferredLight[2].bindTexture(0, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - - stop_glerror(); - - for (U32 i = 0; i < 4; i++) - { - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE); - stop_glerror(); - if (channel > -1) - { - stop_glerror(); - gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - stop_glerror(); - - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); - stop_glerror(); - } - } - - for (U32 i = 4; i < 6; i++) - { - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i); - stop_glerror(); - if (channel > -1) - { - stop_glerror(); - gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - stop_glerror(); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); - stop_glerror(); - } - } - - stop_glerror(); - - F32 mat[16*6]; - for (U32 i = 0; i < 16; i++) - { - mat[i] = mSunShadowMatrix[0].m[i]; - mat[i+16] = mSunShadowMatrix[1].m[i]; - mat[i+32] = mSunShadowMatrix[2].m[i]; - mat[i+48] = mSunShadowMatrix[3].m[i]; - mat[i+64] = mSunShadowMatrix[4].m[i]; - mat[i+80] = mSunShadowMatrix[5].m[i]; - } - - shader.uniformMatrix4fv("shadow_matrix[0]", 6, FALSE, mat); - shader.uniformMatrix4fv("shadow_matrix", 6, FALSE, mat); - - stop_glerror(); - - channel = shader.enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - if (channel > -1) - { - LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; - if (cube_map) - { - cube_map->enable(channel); - cube_map->bind(); - F64* m = gGLModelView; - - - F32 mat[] = { m[0], m[1], m[2], - m[4], m[5], m[6], - m[8], m[9], m[10] }; - - shader.uniform3fv("env_mat[0]", 3, mat); - shader.uniform3fv("env_mat", 3, mat); - } - } - - shader.uniform4fv("shadow_clip", 1, mSunClipPlanes.mV); - shader.uniform1f("sun_wash", gSavedSettings.getF32("RenderDeferredSunWash")); - shader.uniform1f("shadow_noise", gSavedSettings.getF32("RenderShadowNoise")); - shader.uniform1f("blur_size", gSavedSettings.getF32("RenderShadowBlurSize")); - - shader.uniform1f("ssao_radius", gSavedSettings.getF32("RenderSSAOScale")); - shader.uniform1f("ssao_max_radius", gSavedSettings.getU32("RenderSSAOMaxScale")); - - F32 ssao_factor = gSavedSettings.getF32("RenderSSAOFactor"); - shader.uniform1f("ssao_factor", ssao_factor); - shader.uniform1f("ssao_factor_inv", 1.0/ssao_factor); - - LLVector3 ssao_effect = gSavedSettings.getVector3("RenderSSAOEffect"); - F32 matrix_diag = (ssao_effect[0] + 2.0*ssao_effect[1])/3.0; - F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1])/3.0; - // This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by - // value factor, and scales remainder by saturation factor - F32 ssao_effect_mat[] = { matrix_diag, matrix_nondiag, matrix_nondiag, - matrix_nondiag, matrix_diag, matrix_nondiag, - matrix_nondiag, matrix_nondiag, matrix_diag}; - shader.uniformMatrix3fv("ssao_effect_mat", 1, GL_FALSE, ssao_effect_mat); - - F32 shadow_offset_error = 1.f + gSavedSettings.getF32("RenderShadowOffsetError") * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]); - F32 shadow_bias_error = 1.f + gSavedSettings.getF32("RenderShadowBiasError") * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]); - - shader.uniform2f("screen_res", mDeferredScreen.getWidth(), mDeferredScreen.getHeight()); - shader.uniform1f("near_clip", LLViewerCamera::getInstance()->getNear()*2.f); - shader.uniform1f ("shadow_offset", gSavedSettings.getF32("RenderShadowOffset")*shadow_offset_error); - shader.uniform1f("shadow_bias", gSavedSettings.getF32("RenderShadowBias")*shadow_bias_error); - shader.uniform1f ("spot_shadow_offset", gSavedSettings.getF32("RenderSpotShadowOffset")); - shader.uniform1f("spot_shadow_bias", gSavedSettings.getF32("RenderSpotShadowBias")); - - shader.uniform1f("lum_scale", gSavedSettings.getF32("RenderLuminanceScale")); - shader.uniform1f("sun_lum_scale", gSavedSettings.getF32("RenderSunLuminanceScale")); - shader.uniform1f("sun_lum_offset", gSavedSettings.getF32("RenderSunLuminanceOffset")); - shader.uniform1f("lum_lod", gSavedSettings.getF32("RenderLuminanceDetail")); - shader.uniform1f("gi_range", gSavedSettings.getF32("RenderGIRange")); - shader.uniform1f("gi_brightness", gSavedSettings.getF32("RenderGIBrightness")); - shader.uniform1f("gi_luminance", gSavedSettings.getF32("RenderGILuminance")); - shader.uniform1f("gi_edge_weight", gSavedSettings.getF32("RenderGIBlurEdgeWeight")); - shader.uniform1f("gi_blur_brightness", gSavedSettings.getF32("RenderGIBlurBrightness")); - shader.uniform1f("gi_sample_width", mGILightRadius); - shader.uniform1f("gi_noise", gSavedSettings.getF32("RenderGINoise")); - shader.uniform1f("gi_attenuation", gSavedSettings.getF32("RenderGIAttenuation")); - shader.uniform1f("gi_ambiance", gSavedSettings.getF32("RenderGIAmbiance")); - shader.uniform2f("shadow_res", mShadow[0].getWidth(), mShadow[0].getHeight()); - shader.uniform2f("proj_shadow_res", mShadow[4].getWidth(), mShadow[4].getHeight()); - shader.uniform1f("depth_cutoff", gSavedSettings.getF32("RenderEdgeDepthCutoff")); - shader.uniform1f("norm_cutoff", gSavedSettings.getF32("RenderEdgeNormCutoff")); - - - if (shader.getUniformLocation("norm_mat") >= 0) - { - glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose(); - shader.uniformMatrix4fv("norm_mat", 1, FALSE, norm_mat.m); - } -} - -static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace"); -static LLFastTimer::DeclareTimer FTM_GI_GATHER("Gather"); -static LLFastTimer::DeclareTimer FTM_SUN_SHADOW("Shadow Map"); -static LLFastTimer::DeclareTimer FTM_SOFTEN_SHADOW("Shadow Soften"); -static LLFastTimer::DeclareTimer FTM_EDGE_DETECTION("Find Edges"); -static LLFastTimer::DeclareTimer FTM_LOCAL_LIGHTS("Local Lights"); -static LLFastTimer::DeclareTimer FTM_ATMOSPHERICS("Atmospherics"); -static LLFastTimer::DeclareTimer FTM_FULLSCREEN_LIGHTS("Fullscreen Lights"); -static LLFastTimer::DeclareTimer FTM_PROJECTORS("Projectors"); -static LLFastTimer::DeclareTimer FTM_POST("Post"); - - -void LLPipeline::renderDeferredLighting() -{ - if (!sCull) - { - return; - } - - { - LLFastTimer ftm(FTM_RENDER_DEFERRED); - - LLViewerCamera* camera = LLViewerCamera::getInstance(); - { - LLGLDepthTest depth(GL_TRUE); - mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), - 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); - } - - LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); - - if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) - { - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); - } - - //ati doesn't seem to love actually using the stencil buffer on FBO's - LLGLEnable stencil(GL_STENCIL_TEST); - glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - - gGL.setColorMask(true, true); - - //draw a cube around every light - LLVertexBuffer::unbind(); - - LLGLEnable cull(GL_CULL_FACE); - LLGLEnable blend(GL_BLEND); - - glh::matrix4f mat = glh_copy_matrix(gGLModelView); - - F32 vert[] = - { - -1,1, - -1,-3, - 3,1, - }; - glVertexPointer(2, GL_FLOAT, 0, vert); - glColor3f(1,1,1); - - { - setupHWLights(NULL); //to set mSunDir; - LLVector4 dir(mSunDir, 0.f); - glh::vec4f tc(dir.mV); - mat.mult_matrix_vec(tc); - glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], 0); - } - - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - if (gSavedSettings.getBOOL("RenderDeferredSSAO") || gSavedSettings.getS32("RenderShadowDetail") > 0) - { - mDeferredLight[0].bindTarget(); - { //paint shadow/SSAO light map (direct lighting lightmap) - LLFastTimer ftm(FTM_SUN_SHADOW); - bindDeferredShader(gDeferredSunProgram, 0); - - glClearColor(1,1,1,1); - mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT); - glClearColor(0,0,0,0); - - glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); - - const U32 slice = 32; - F32 offset[slice*3]; - for (U32 i = 0; i < 4; i++) - { - for (U32 j = 0; j < 8; j++) - { - glh::vec3f v; - v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i); - v.normalize(); - inv_trans.mult_matrix_vec(v); - v.normalize(); - offset[(i*8+j)*3+0] = v.v[0]; - offset[(i*8+j)*3+1] = v.v[2]; - offset[(i*8+j)*3+2] = v.v[1]; - } - } - - gDeferredSunProgram.uniform3fv("offset", slice, offset); - gDeferredSunProgram.uniform2f("screenRes", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight()); - - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); - stop_glerror(); - } - - unbindDeferredShader(gDeferredSunProgram); - } - mDeferredLight[0].flush(); - } - - { //global illumination specific block (still experimental) - if (gSavedSettings.getBOOL("RenderDeferredBlurLight") && - gSavedSettings.getBOOL("RenderDeferredGI")) - { - LLFastTimer ftm(FTM_EDGE_DETECTION); - //generate edge map - LLGLDisable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); - LLGLDepthTest depth(GL_FALSE); - LLGLDisable stencil(GL_STENCIL_TEST); - - { - gDeferredEdgeProgram.bind(); - mEdgeMap.bindTarget(); - bindDeferredShader(gDeferredEdgeProgram); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); - unbindDeferredShader(gDeferredEdgeProgram); - mEdgeMap.flush(); - } - } - - if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) - { - { //get luminance map from previous frame's light map - LLGLEnable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); - LLGLDepthTest depth(GL_FALSE); - LLGLDisable stencil(GL_STENCIL_TEST); - - //static F32 fade = 1.f; - - { - gGL.setSceneBlendType(LLRender::BT_ALPHA); - gLuminanceGatherProgram.bind(); - gLuminanceGatherProgram.uniform2f("screen_res", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight()); - mLuminanceMap.bindTarget(); - bindDeferredShader(gLuminanceGatherProgram); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); - unbindDeferredShader(gLuminanceGatherProgram); - mLuminanceMap.flush(); - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR); - glGenerateMipmap(GL_TEXTURE_2D); - } - } - - { //paint noisy GI map (bounce lighting lightmap) - LLFastTimer ftm(FTM_GI_TRACE); - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_FALSE); - LLGLDisable test(GL_ALPHA_TEST); - - mGIMapPost[0].bindTarget(); - - bindDeferredShader(gDeferredGIProgram, 0, &mGIMap, 0, mTrueNoiseMap); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); - unbindDeferredShader(gDeferredGIProgram); - mGIMapPost[0].flush(); - } - - U32 pass_count = 0; - if (gSavedSettings.getBOOL("RenderDeferredBlurLight")) - { - pass_count = llclamp(gSavedSettings.getU32("RenderGIBlurPasses"), (U32) 1, (U32) 128); - } - - for (U32 i = 0; i < pass_count; ++i) - { //gather/soften indirect lighting map - LLFastTimer ftm(FTM_GI_GATHER); - bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[0], NULL, mTrueNoiseMap); - F32 blur_size = gSavedSettings.getF32("RenderGIBlurSize")/((F32) i * gSavedSettings.getF32("RenderGIBlurIncrement")+1.f); - gDeferredPostGIProgram.uniform2f("delta", 1.f, 0.f); - gDeferredPostGIProgram.uniform1f("kern_scale", blur_size); - gDeferredPostGIProgram.uniform1f("gi_blur_brightness", gSavedSettings.getF32("RenderGIBlurBrightness")); - - mGIMapPost[1].bindTarget(); - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_FALSE); - stop_glerror(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); - stop_glerror(); - } - - mGIMapPost[1].flush(); - unbindDeferredShader(gDeferredPostGIProgram); - bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[1], NULL, mTrueNoiseMap); - mGIMapPost[0].bindTarget(); - - gDeferredPostGIProgram.uniform2f("delta", 0.f, 1.f); - - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_FALSE); - stop_glerror(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - stop_glerror(); - } - mGIMapPost[0].flush(); - unbindDeferredShader(gDeferredPostGIProgram); - } - } - } - - if (gSavedSettings.getBOOL("RenderDeferredSSAO")) - { //soften direct lighting lightmap - LLFastTimer ftm(FTM_SOFTEN_SHADOW); - //blur lightmap - mDeferredLight[1].bindTarget(); - - glClearColor(1,1,1,1); - mDeferredLight[1].clear(GL_COLOR_BUFFER_BIT); - glClearColor(0,0,0,0); - - bindDeferredShader(gDeferredBlurLightProgram); - - LLVector3 go = gSavedSettings.getVector3("RenderShadowGaussian"); - const U32 kern_length = 4; - F32 blur_size = gSavedSettings.getF32("RenderShadowBlurSize"); - F32 dist_factor = gSavedSettings.getF32("RenderShadowBlurDistFactor"); - - // sample symmetrically with the middle sample falling exactly on 0.0 - F32 x = 0.f; - - LLVector3 gauss[32]; // xweight, yweight, offset - - for (U32 i = 0; i < kern_length; i++) - { - gauss[i].mV[0] = llgaussian(x, go.mV[0]); - gauss[i].mV[1] = llgaussian(x, go.mV[1]); - gauss[i].mV[2] = x; - x += 1.f; - } - - gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f); - gDeferredBlurLightProgram.uniform1f("dist_factor", dist_factor); - gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV); - gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f)); - - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); - stop_glerror(); - } - - mDeferredLight[1].flush(); - unbindDeferredShader(gDeferredBlurLightProgram); - - bindDeferredShader(gDeferredBlurLightProgram, 1); - mDeferredLight[0].bindTarget(); - - gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f); - - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); - stop_glerror(); - } - mDeferredLight[0].flush(); - unbindDeferredShader(gDeferredBlurLightProgram); - } - - stop_glerror(); - glPopMatrix(); - stop_glerror(); - glMatrixMode(GL_MODELVIEW); - stop_glerror(); - glPopMatrix(); - stop_glerror(); - - //copy depth and stencil from deferred screen - //mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), - // 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); - - if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) - { - mDeferredLight[1].bindTarget(); - // clear color buffer here (GI) - zeroing alpha (glow) is important or it will accumulate against sky - glClearColor(0,0,0,0); - mScreen.clear(GL_COLOR_BUFFER_BIT); - } - else - { - mScreen.bindTarget(); - // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky - glClearColor(0,0,0,0); - mScreen.clear(GL_COLOR_BUFFER_BIT); - } - - if (gSavedSettings.getBOOL("RenderDeferredAtmospheric")) - { //apply sunlight contribution - LLFastTimer ftm(FTM_ATMOSPHERICS); - bindDeferredShader(gDeferredSoftenProgram, 0, &mGIMapPost[0]); - { - LLGLDepthTest depth(GL_FALSE); - LLGLDisable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); - - //full screen blit - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - glVertexPointer(2, GL_FLOAT, 0, vert); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); - - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } - - unbindDeferredShader(gDeferredSoftenProgram); - } - - { //render sky - LLGLDisable blend(GL_BLEND); - LLGLDisable stencil(GL_STENCIL_TEST); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - gPipeline.pushRenderTypeMask(); - - gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_CLOUDS, - LLPipeline::RENDER_TYPE_WL_SKY, - LLPipeline::END_RENDER_TYPES); - - - renderGeomPostDeferred(*LLViewerCamera::getInstance()); - gPipeline.popRenderTypeMask(); - } - - BOOL render_local = gSavedSettings.getBOOL("RenderLocalLights"); - - if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) - { - mDeferredLight[1].flush(); - mDeferredLight[2].bindTarget(); - mDeferredLight[2].clear(GL_COLOR_BUFFER_BIT); - } - - if (render_local) - { - gGL.setSceneBlendType(LLRender::BT_ADD); - std::list fullscreen_lights; - LLDrawable::drawable_list_t spot_lights; - LLDrawable::drawable_list_t fullscreen_spot_lights; - - for (U32 i = 0; i < 2; i++) - { - mTargetShadowSpotLight[i] = NULL; - } - - std::list light_colors; - - LLVertexBuffer::unbind(); - - F32 v[24]; - glVertexPointer(3, GL_FLOAT, 0, v); - - { - bindDeferredShader(gDeferredLightProgram); - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter) - { - LLDrawable* drawablep = *iter; - - LLVOVolume* volume = drawablep->getVOVolume(); - if (!volume) - { - continue; - } - - if (volume->isAttachment()) - { - if (!sRenderAttachedLights) - { - continue; - } - } - - - LLVector4a center; - center.load3(drawablep->getPositionAgent().mV); - const F32* c = center.getF32ptr(); - F32 s = volume->getLightRadius()*1.5f; - - LLColor3 col = volume->getLightColor(); - col *= volume->getLightIntensity(); - - if (col.magVecSquared() < 0.001f) - { - continue; - } - - if (s <= 0.001f) - { - continue; - } - - LLVector4a sa; - sa.splat(s); - if (camera->AABBInFrustumNoFarClip(center, sa) == 0) - { - continue; - } - - sVisibleLightCount++; - - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); - - //vertex positions are encoded so the 3 bits of their vertex index - //correspond to their axis facing, with bit position 3,2,1 matching - //axis facing x,y,z, bit set meaning positive facing, bit clear - //meaning negative facing - v[0] = c[0]-s; v[1] = c[1]-s; v[2] = c[2]-s; // 0 - 0000 - v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001 - v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010 - v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011 - - v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100 - v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101 - v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110 - v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111 - - if (camera->getOrigin().mV[0] > c[0] + s + 0.2f || - camera->getOrigin().mV[0] < c[0] - s - 0.2f || - camera->getOrigin().mV[1] > c[1] + s + 0.2f || - camera->getOrigin().mV[1] < c[1] - s - 0.2f || - camera->getOrigin().mV[2] > c[2] + s + 0.2f || - camera->getOrigin().mV[2] < c[2] - s - 0.2f) - { //draw box if camera is outside box - if (render_local) - { - if (volume->isLightSpotlight()) - { - drawablep->getVOVolume()->updateSpotLightPriority(); - spot_lights.push_back(drawablep); - continue; - } - - LLFastTimer ftm(FTM_LOCAL_LIGHTS); - glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); - glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f); - glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, - GL_UNSIGNED_BYTE, get_box_fan_indices_ptr(camera, center)); - stop_glerror(); - } - } - else - { - if (volume->isLightSpotlight()) - { - drawablep->getVOVolume()->updateSpotLightPriority(); - fullscreen_spot_lights.push_back(drawablep); - continue; - } - - fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s)); - light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f)); - } - } - unbindDeferredShader(gDeferredLightProgram); - } - - if (!spot_lights.empty()) - { - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - bindDeferredShader(gDeferredSpotLightProgram); - - gDeferredSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); - - for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter) - { - LLFastTimer ftm(FTM_PROJECTORS); - LLDrawable* drawablep = *iter; - - LLVOVolume* volume = drawablep->getVOVolume(); - - LLVector4a center; - center.load3(drawablep->getPositionAgent().mV); - const F32* c = center.getF32ptr(); - F32 s = volume->getLightRadius()*1.5f; - - sVisibleLightCount++; - - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); - - setupSpotLight(gDeferredSpotLightProgram, drawablep); - - LLColor3 col = volume->getLightColor(); - col *= volume->getLightIntensity(); - - //vertex positions are encoded so the 3 bits of their vertex index - //correspond to their axis facing, with bit position 3,2,1 matching - //axis facing x,y,z, bit set meaning positive facing, bit clear - //meaning negative facing - v[0] = c[0]-s; v[1] = c[1]-s; v[2] = c[2]-s; // 0 - 0000 - v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001 - v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010 - v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011 - - v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100 - v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101 - v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110 - v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111 - - glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); - glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f); - glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, - GL_UNSIGNED_BYTE, get_box_fan_indices_ptr(camera, center)); - } - gDeferredSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); - unbindDeferredShader(gDeferredSpotLightProgram); - } - - { - bindDeferredShader(gDeferredMultiLightProgram); - - LLGLDepthTest depth(GL_FALSE); - - //full screen blit - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - U32 count = 0; - - const U32 max_count = 8; - LLVector4 light[max_count]; - LLVector4 col[max_count]; - - glVertexPointer(2, GL_FLOAT, 0, vert); - - F32 far_z = 0.f; - - while (!fullscreen_lights.empty()) - { - LLFastTimer ftm(FTM_FULLSCREEN_LIGHTS); - light[count] = fullscreen_lights.front(); - fullscreen_lights.pop_front(); - col[count] = light_colors.front(); - light_colors.pop_front(); - - far_z = llmin(light[count].mV[2]-sqrtf(light[count].mV[3]), far_z); - - count++; - if (count == max_count || fullscreen_lights.empty()) - { - gDeferredMultiLightProgram.uniform1i("light_count", count); - gDeferredMultiLightProgram.uniform4fv("light", count, (GLfloat*) light); - gDeferredMultiLightProgram.uniform4fv("light_col", count, (GLfloat*) col); - gDeferredMultiLightProgram.uniform1f("far_z", far_z); - far_z = 0.f; - count = 0; - glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); - } - } - - unbindDeferredShader(gDeferredMultiLightProgram); - - bindDeferredShader(gDeferredMultiSpotLightProgram); - - gDeferredMultiSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); - - for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter) - { - LLFastTimer ftm(FTM_PROJECTORS); - LLDrawable* drawablep = *iter; - - LLVOVolume* volume = drawablep->getVOVolume(); - - LLVector3 center = drawablep->getPositionAgent(); - F32* c = center.mV; - F32 s = volume->getLightRadius()*1.5f; - - sVisibleLightCount++; - - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); - - setupSpotLight(gDeferredMultiSpotLightProgram, drawablep); - - LLColor3 col = volume->getLightColor(); - col *= volume->getLightIntensity(); - - glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); - glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); - } - - gDeferredMultiSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); - unbindDeferredShader(gDeferredMultiSpotLightProgram); - - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } - } - - gGL.setColorMask(true, true); - - if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) - { - mDeferredLight[2].flush(); - - mScreen.bindTarget(); - mScreen.clear(GL_COLOR_BUFFER_BIT); - - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - { //mix various light maps (local, sun, gi) - LLFastTimer ftm(FTM_POST); - LLGLDisable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); - LLGLDepthTest depth(GL_FALSE); - LLGLDisable stencil(GL_STENCIL_TEST); - - bindDeferredShader(gDeferredPostProgram, 0, &mGIMapPost[0]); - - gDeferredPostProgram.bind(); - - LLVertexBuffer::unbind(); - - glVertexPointer(2, GL_FLOAT, 0, vert); - glColor3f(1,1,1); - - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - glDrawArrays(GL_TRIANGLES, 0, 3); - - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - unbindDeferredShader(gDeferredPostProgram); - } - } - } - - { //render non-deferred geometry (alpha, fullbright, glow) - LLGLDisable blend(GL_BLEND); - LLGLDisable stencil(GL_STENCIL_TEST); - - pushRenderTypeMask(); - andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA, - LLPipeline::RENDER_TYPE_FULLBRIGHT, - LLPipeline::RENDER_TYPE_VOLUME, - LLPipeline::RENDER_TYPE_GLOW, - LLPipeline::RENDER_TYPE_BUMP, - LLPipeline::RENDER_TYPE_PASS_SIMPLE, - LLPipeline::RENDER_TYPE_PASS_ALPHA, - LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, - LLPipeline::RENDER_TYPE_PASS_BUMP, - LLPipeline::RENDER_TYPE_PASS_POST_BUMP, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, - LLPipeline::RENDER_TYPE_PASS_GLOW, - LLPipeline::RENDER_TYPE_PASS_GRASS, - LLPipeline::RENDER_TYPE_PASS_SHINY, - LLPipeline::RENDER_TYPE_PASS_INVISIBLE, - LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY, - LLPipeline::RENDER_TYPE_AVATAR, - END_RENDER_TYPES); - - renderGeomPostDeferred(*LLViewerCamera::getInstance()); - popRenderTypeMask(); - } - - { - //render highlights, etc. - renderHighlights(); - mHighlightFaces.clear(); - - renderDebug(); - - LLVertexBuffer::unbind(); - - if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - // Render debugging beacons. - gObjectList.renderObjectBeacons(); - LLHUDObject::renderAll(); - gObjectList.resetObjectBeacons(); - } - } - - mScreen.flush(); - -} - -void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) -{ - //construct frustum - LLVOVolume* volume = drawablep->getVOVolume(); - LLVector3 params = volume->getSpotLightParams(); - - F32 fov = params.mV[0]; - F32 focus = params.mV[1]; - - LLVector3 pos = drawablep->getPositionAgent(); - LLQuaternion quat = volume->getRenderRotation(); - LLVector3 scale = volume->getScale(); - - //get near clip plane - LLVector3 at_axis(0,0,-scale.mV[2]*0.5f); - at_axis *= quat; - - LLVector3 np = pos+at_axis; - at_axis.normVec(); - - //get origin that has given fov for plane np, at_axis, and given scale - F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f); - - LLVector3 origin = np - at_axis*dist; - - //matrix from volume space to agent space - LLMatrix4 light_mat(quat, LLVector4(origin,1.f)); - - glh::matrix4f light_to_agent((F32*) light_mat.mMatrix); - glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent; - - glh::matrix4f screen_to_light = light_to_screen.inverse(); - - F32 s = volume->getLightRadius()*1.5f; - F32 near_clip = dist; - F32 width = scale.mV[VX]; - F32 height = scale.mV[VY]; - F32 far_clip = s+dist-scale.mV[VZ]; - - F32 fovy = fov * RAD_TO_DEG; - F32 aspect = width/height; - - glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, - 0.f, 0.5f, 0.f, 0.5f, - 0.f, 0.f, 0.5f, 0.5f, - 0.f, 0.f, 0.f, 1.f); - - glh::vec3f p1(0, 0, -(near_clip+0.01f)); - glh::vec3f p2(0, 0, -(near_clip+1.f)); - - glh::vec3f screen_origin(0, 0, 0); - - light_to_screen.mult_matrix_vec(p1); - light_to_screen.mult_matrix_vec(p2); - light_to_screen.mult_matrix_vec(screen_origin); - - glh::vec3f n = p2-p1; - n.normalize(); - - F32 proj_range = far_clip - near_clip; - glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip); - screen_to_light = trans * light_proj * screen_to_light; - shader.uniformMatrix4fv("proj_mat", 1, FALSE, screen_to_light.m); - shader.uniform1f("proj_near", near_clip); - shader.uniform3fv("proj_p", 1, p1.v); - shader.uniform3fv("proj_n", 1, n.v); - shader.uniform3fv("proj_origin", 1, screen_origin.v); - shader.uniform1f("proj_range", proj_range); - shader.uniform1f("proj_ambiance", params.mV[2]); - S32 s_idx = -1; - - for (U32 i = 0; i < 2; i++) - { - if (mShadowSpotLight[i] == drawablep) - { - s_idx = i; - } - } - - shader.uniform1i("proj_shadow_idx", s_idx); - - if (s_idx >= 0) - { - shader.uniform1f("shadow_fade", 1.f-mSpotLightFade[s_idx]); - } - else - { - shader.uniform1f("shadow_fade", 1.f); - } - - { - LLDrawable* potential = drawablep; - //determine if this is a good light for casting shadows - F32 m_pri = volume->getSpotLightPriority(); - - for (U32 i = 0; i < 2; i++) - { - F32 pri = 0.f; - - if (mTargetShadowSpotLight[i].notNull()) - { - pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority(); - } - - if (m_pri > pri) - { - LLDrawable* temp = mTargetShadowSpotLight[i]; - mTargetShadowSpotLight[i] = potential; - potential = temp; - m_pri = pri; - } - } - } - - LLViewerTexture* img = volume->getLightTexture(); - - S32 channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); - - if (channel > -1 && img) - { - gGL.getTexUnit(channel)->bind(img); - - F32 lod_range = logf(img->getWidth())/logf(2.f); - - shader.uniform1f("proj_focus", focus); - shader.uniform1f("proj_lod", lod_range); - shader.uniform1f("proj_ambient_lod", llclamp((proj_range-focus)/proj_range*lod_range, 0.f, 1.f)); - } -} - -void LLPipeline::unbindDeferredShader(LLGLSLShader &shader) -{ - stop_glerror(); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE); - shader.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIP); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_BLOOM); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS); - - for (U32 i = 0; i < 4; i++) - { - if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE) > -1) - { - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); - } - } - - for (U32 i = 4; i < 6; i++) - { - if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i) > -1) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); - } - } - - shader.disableTexture(LLViewerShaderMgr::DEFERRED_NOISE); - shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC); - - S32 channel = shader.disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - if (channel > -1) - { - LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; - if (cube_map) - { - cube_map->disable(); - } - } - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(0)->activate(); - shader.unbind(); - - LLGLState::checkTextureChannels(); -} - -inline float sgn(float a) -{ - if (a > 0.0F) return (1.0F); - if (a < 0.0F) return (-1.0F); - return (0.0F); -} - -void LLPipeline::generateWaterReflection(LLCamera& camera_in) -{ - if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate) - { - BOOL skip_avatar_update = FALSE; - if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK) - { - skip_avatar_update = TRUE; - } - - if (!skip_avatar_update) - { - gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON); - } - LLVertexBuffer::unbind(); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - - LLCamera camera = camera_in; - camera.setFar(camera.getFar()*0.87654321f); - LLPipeline::sReflectionRender = TRUE; - - gPipeline.pushRenderTypeMask(); - - glh::matrix4f projection = glh_get_current_projection(); - glh::matrix4f mat; - - stop_glerror(); - LLPlane plane; - - F32 height = gAgent.getRegion()->getWaterHeight(); - F32 to_clip = fabsf(camera.getOrigin().mV[2]-height); - F32 pad = -to_clip*0.05f; //amount to "pad" clip plane by - - //plane params - LLVector3 pnorm; - F32 pd; - - S32 water_clip = 0; - if (!LLViewerCamera::getInstance()->cameraUnderWater()) - { //camera is above water, clip plane points up - pnorm.setVec(0,0,1); - pd = -height; - plane.setVec(pnorm, pd); - water_clip = -1; - } - else - { //camera is below water, clip plane points down - pnorm = LLVector3(0,0,-1); - pd = height; - plane.setVec(pnorm, pd); - water_clip = 1; - } - - if (!LLViewerCamera::getInstance()->cameraUnderWater()) - { //generate planar reflection map - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glClearColor(0,0,0,0); - mWaterRef.bindTarget(); - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER0; - gGL.setColorMask(true, true); - mWaterRef.clear(); - gGL.setColorMask(true, false); - - mWaterRef.getViewport(gGLViewport); - - stop_glerror(); - - glPushMatrix(); - - mat.set_scale(glh::vec3f(1,1,-1)); - mat.set_translate(glh::vec3f(0,0,height*2.f)); - - glh::matrix4f current = glh_get_current_modelview(); - - mat = current * mat; - - glh_set_current_modelview(mat); - glLoadMatrixf(mat.m); - - LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE); - - glh::matrix4f inv_mat = mat.inverse(); - - glh::vec3f origin(0,0,0); - inv_mat.mult_matrix_vec(origin); - - camera.setOrigin(origin.v); - - glCullFace(GL_FRONT); - - static LLCullResult ref_result; - - if (LLDrawPoolWater::sNeedsDistortionUpdate) - { - //initial sky pass (no user clip plane) - { //mask out everything but the sky - gPipeline.pushRenderTypeMask(); - gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_WL_SKY, - LLPipeline::END_RENDER_TYPES); - - static LLCullResult result; - updateCull(camera, result); - stateSort(camera, result); - - andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_CLOUDS, - LLPipeline::RENDER_TYPE_WL_SKY, - LLPipeline::END_RENDER_TYPES); - - //bad pop here - renderGeom(camera, TRUE); - - gPipeline.popRenderTypeMask(); - } - - gPipeline.pushRenderTypeMask(); - - clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER, - LLPipeline::RENDER_TYPE_VOIDWATER, - LLPipeline::RENDER_TYPE_GROUND, - LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_CLOUDS, - LLPipeline::END_RENDER_TYPES); - - S32 detail = gSavedSettings.getS32("RenderReflectionDetail"); - if (detail > 0) - { //mask out selected geometry based on reflection detail - if (detail < 4) - { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES); - if (detail < 3) - { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); - if (detail < 2) - { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES); - } - } - } - - LLGLUserClipPlane clip_plane(plane, mat, projection); - LLGLDisable cull(GL_CULL_FACE); - updateCull(camera, ref_result, 1); - stateSort(camera, ref_result); - } - - if (LLDrawPoolWater::sNeedsDistortionUpdate) - { - if (gSavedSettings.getS32("RenderReflectionDetail") > 0) - { - gPipeline.grabReferences(ref_result); - LLGLUserClipPlane clip_plane(plane, mat, projection); - renderGeom(camera); - } - } - - gPipeline.popRenderTypeMask(); - } - glCullFace(GL_BACK); - glPopMatrix(); - mWaterRef.flush(); - glh_set_current_modelview(current); - } - - camera.setOrigin(camera_in.getOrigin()); - //render distortion map - static BOOL last_update = TRUE; - if (last_update) - { - camera.setFar(camera_in.getFar()); - clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER, - LLPipeline::RENDER_TYPE_VOIDWATER, - LLPipeline::RENDER_TYPE_GROUND, - END_RENDER_TYPES); - stop_glerror(); - - LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? FALSE : TRUE; - - if (LLPipeline::sUnderWaterRender) - { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_GROUND, - LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_CLOUDS, - LLPipeline::RENDER_TYPE_WL_SKY, - END_RENDER_TYPES); - } - LLViewerCamera::updateFrustumPlanes(camera); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLColor4& col = LLDrawPoolWater::sWaterFogColor; - glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); - mWaterDis.bindTarget(); - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1; - mWaterDis.getViewport(gGLViewport); - - if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate) - { - //clip out geometry on the same side of water as the camera - mat = glh_get_current_modelview(); - LLGLUserClipPlane clip_plane(LLPlane(-pnorm, -(pd+pad)), mat, projection); - static LLCullResult result; - updateCull(camera, result, water_clip); - stateSort(camera, result); - - gGL.setColorMask(true, true); - mWaterDis.clear(); - gGL.setColorMask(true, false); - - renderGeom(camera); - } - - LLPipeline::sUnderWaterRender = FALSE; - mWaterDis.flush(); - } - last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate; - - LLRenderTarget::unbindTarget(); - - LLPipeline::sReflectionRender = FALSE; - - if (!LLRenderTarget::sUseFBO) - { - glClear(GL_DEPTH_BUFFER_BIT); - } - glClearColor(0.f, 0.f, 0.f, 0.f); - gViewerWindow->setup3DViewport(); - gPipeline.popRenderTypeMask(); - LLDrawPoolWater::sNeedsReflectionUpdate = FALSE; - LLDrawPoolWater::sNeedsDistortionUpdate = FALSE; - LLPlane npnorm(-pnorm, -pd); - LLViewerCamera::getInstance()->setUserClipPlane(npnorm); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - - if (!skip_avatar_update) - { - gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode()); - } - - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; - } -} - -glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up) -{ - glh::matrix4f ret; - - LLVector3 dirN; - LLVector3 upN; - LLVector3 lftN; - - lftN = dir % up; - lftN.normVec(); - - upN = lftN % dir; - upN.normVec(); - - dirN = dir; - dirN.normVec(); - - ret.m[ 0] = lftN[0]; - ret.m[ 1] = upN[0]; - ret.m[ 2] = -dirN[0]; - ret.m[ 3] = 0.f; - - ret.m[ 4] = lftN[1]; - ret.m[ 5] = upN[1]; - ret.m[ 6] = -dirN[1]; - ret.m[ 7] = 0.f; - - ret.m[ 8] = lftN[2]; - ret.m[ 9] = upN[2]; - ret.m[10] = -dirN[2]; - ret.m[11] = 0.f; - - ret.m[12] = -(lftN*pos); - ret.m[13] = -(upN*pos); - ret.m[14] = dirN*pos; - ret.m[15] = 1.f; - - return ret; -} - -glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max) -{ - glh::matrix4f ret; - ret.m[ 0] = 2/(max[0]-min[0]); - ret.m[ 4] = 0; - ret.m[ 8] = 0; - ret.m[12] = -(max[0]+min[0])/(max[0]-min[0]); - - ret.m[ 1] = 0; - ret.m[ 5] = 2/(max[1]-min[1]); - ret.m[ 9] = 0; - ret.m[13] = -(max[1]+min[1])/(max[1]-min[1]); - - ret.m[ 2] = 0; - ret.m[ 6] = 0; - ret.m[10] = 2/(max[2]-min[2]); - ret.m[14] = -(max[2]+min[2])/(max[2]-min[2]); - - ret.m[ 3] = 0; - ret.m[ 7] = 0; - ret.m[11] = 0; - ret.m[15] = 1; - - return ret; -} - -static LLFastTimer::DeclareTimer FTM_SHADOW_RENDER("Render Shadows"); -static LLFastTimer::DeclareTimer FTM_SHADOW_ALPHA("Alpha Shadow"); -static LLFastTimer::DeclareTimer FTM_SHADOW_SIMPLE("Simple Shadow"); - -void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion) -{ - LLFastTimer t(FTM_SHADOW_RENDER); - - //clip out geometry on the same side of water as the camera - S32 occlude = LLPipeline::sUseOcclusion; - if (!use_occlusion) - { - LLPipeline::sUseOcclusion = 0; - } - LLPipeline::sShadowRender = TRUE; - - U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY, LLRenderPass::PASS_BUMP, LLRenderPass::PASS_FULLBRIGHT_SHINY }; - LLGLEnable cull(GL_CULL_FACE); - - if (use_shader) - { - gDeferredShadowProgram.bind(); - } - - updateCull(shadow_cam, result); - stateSort(shadow_cam, result); - - //generate shadow map - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadMatrixf(proj.m); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadMatrixd(gGLModelView); - - stop_glerror(); - gGLLastMatrix = NULL; - - { - //LLGLDepthTest depth(GL_TRUE); - //glClear(GL_DEPTH_BUFFER_BIT); - } - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - glColor4f(1,1,1,1); - - stop_glerror(); - - gGL.setColorMask(false, false); - - //glCullFace(GL_FRONT); - - LLVertexBuffer::unbind(); - - { - LLFastTimer ftm(FTM_SHADOW_SIMPLE); - LLGLDisable test(GL_ALPHA_TEST); - gGL.getTexUnit(0)->disable(); - for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i) - { - renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE); - } - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - } - - if (use_shader) - { - gDeferredShadowProgram.unbind(); - renderGeomShadow(shadow_cam); - gDeferredShadowProgram.bind(); - } - else - { - renderGeomShadow(shadow_cam); - } - - { - LLFastTimer ftm(FTM_SHADOW_ALPHA); - LLGLEnable test(GL_ALPHA_TEST); - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.6f); - renderObjects(LLRenderPass::PASS_ALPHA_SHADOW, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR, TRUE); - glColor4f(1,1,1,1); - renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE); - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); - } - - //glCullFace(GL_BACK); - - gGLLastMatrix = NULL; - glLoadMatrixd(gGLModelView); - doOcclusion(shadow_cam); - - if (use_shader) - { - gDeferredShadowProgram.unbind(); - } - - gGL.setColorMask(true, true); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - gGLLastMatrix = NULL; - - LLPipeline::sUseOcclusion = occlude; - LLPipeline::sShadowRender = FALSE; -} - -static LLFastTimer::DeclareTimer FTM_VISIBLE_CLOUD("Visible Cloud"); -BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector& fp, LLVector3 light_dir) -{ - LLFastTimer t(FTM_VISIBLE_CLOUD); - //get point cloud of intersection of frust and min, max - - if (getVisibleExtents(camera, min, max)) - { - return FALSE; - } - - //get set of planes on bounding box - LLPlane bp[] = { - LLPlane(min, LLVector3(-1,0,0)), - LLPlane(min, LLVector3(0,-1,0)), - LLPlane(min, LLVector3(0,0,-1)), - LLPlane(max, LLVector3(1,0,0)), - LLPlane(max, LLVector3(0,1,0)), - LLPlane(max, LLVector3(0,0,1))}; - - //potential points - std::vector pp; - - //add corners of AABB - pp.push_back(LLVector3(min.mV[0], min.mV[1], min.mV[2])); - pp.push_back(LLVector3(max.mV[0], min.mV[1], min.mV[2])); - pp.push_back(LLVector3(min.mV[0], max.mV[1], min.mV[2])); - pp.push_back(LLVector3(max.mV[0], max.mV[1], min.mV[2])); - pp.push_back(LLVector3(min.mV[0], min.mV[1], max.mV[2])); - pp.push_back(LLVector3(max.mV[0], min.mV[1], max.mV[2])); - pp.push_back(LLVector3(min.mV[0], max.mV[1], max.mV[2])); - pp.push_back(LLVector3(max.mV[0], max.mV[1], max.mV[2])); - - //add corners of camera frustum - for (U32 i = 0; i < 8; i++) - { - pp.push_back(camera.mAgentFrustum[i]); - } - - - //bounding box line segments - U32 bs[] = - { - 0,1, - 1,3, - 3,2, - 2,0, - - 4,5, - 5,7, - 7,6, - 6,4, - - 0,4, - 1,5, - 3,7, - 2,6 - }; - - for (U32 i = 0; i < 12; i++) - { //for each line segment in bounding box - for (U32 j = 0; j < 6; j++) - { //for each plane in camera frustum - const LLPlane& cp = camera.getAgentPlane(j); - const LLVector3& v1 = pp[bs[i*2+0]]; - const LLVector3& v2 = pp[bs[i*2+1]]; - LLVector3 n; - cp.getVector3(n); - - LLVector3 line = v1-v2; - - F32 d1 = line*n; - F32 d2 = -cp.dist(v2); - - F32 t = d2/d1; - - if (t > 0.f && t < 1.f) - { - LLVector3 intersect = v2+line*t; - pp.push_back(intersect); - } - } - } - - //camera frustum line segments - const U32 fs[] = - { - 0,1, - 1,2, - 2,3, - 3,0, - - 4,5, - 5,6, - 6,7, - 7,4, - - 0,4, - 1,5, - 2,6, - 3,7 - }; - - LLVector3 center = (max+min)*0.5f; - LLVector3 size = (max-min)*0.5f; - - for (U32 i = 0; i < 12; i++) - { - for (U32 j = 0; j < 6; ++j) - { - const LLVector3& v1 = pp[fs[i*2+0]+8]; - const LLVector3& v2 = pp[fs[i*2+1]+8]; - const LLPlane& cp = bp[j]; - LLVector3 n; - cp.getVector3(n); - - LLVector3 line = v1-v2; - - F32 d1 = line*n; - F32 d2 = -cp.dist(v2); - - F32 t = d2/d1; - - if (t > 0.f && t < 1.f) - { - LLVector3 intersect = v2+line*t; - pp.push_back(intersect); - } - } - } - - LLVector3 ext[] = { min-LLVector3(0.05f,0.05f,0.05f), - max+LLVector3(0.05f,0.05f,0.05f) }; - - for (U32 i = 0; i < pp.size(); ++i) - { - bool found = true; - - const F32* p = pp[i].mV; - - for (U32 j = 0; j < 3; ++j) - { - if (p[j] < ext[0].mV[j] || - p[j] > ext[1].mV[j]) - { - found = false; - break; - } - } - - for (U32 j = 0; j < 6; ++j) - { - const LLPlane& cp = camera.getAgentPlane(j); - F32 dist = cp.dist(pp[i]); - if (dist > 0.05f) //point is above some plane, not contained - { - found = false; - break; - } - } - - if (found) - { - fp.push_back(pp[i]); - } - } - - if (fp.empty()) - { - return FALSE; - } - - return TRUE; -} - -void LLPipeline::generateGI(LLCamera& camera, LLVector3& lightDir, std::vector& vpc) -{ - if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) < 3) - { - return; - } - - LLVector3 up; - - //LLGLEnable depth_clamp(GL_DEPTH_CLAMP_NV); - - if (lightDir.mV[2] > 0.5f) - { - up = LLVector3(1,0,0); - } - else - { - up = LLVector3(0, 0, 1); - } - - - F32 gi_range = gSavedSettings.getF32("RenderGIRange"); - - U32 res = mGIMap.getWidth(); - - F32 atten = llmax(gSavedSettings.getF32("RenderGIAttenuation"), 0.001f); - - //set radius to range at which distance attenuation of incoming photons is near 0 - - F32 lrad = sqrtf(1.f/(atten*0.01f)); - - F32 lrange = lrad+gi_range*0.5f; - - LLVector3 pad(lrange,lrange,lrange); - - glh::matrix4f view = look(LLVector3(128.f,128.f,128.f), lightDir, up); - - LLVector3 cp = camera.getOrigin()+camera.getAtAxis()*(gi_range*0.5f); - - glh::vec3f scp(cp.mV); - view.mult_matrix_vec(scp); - cp.setVec(scp.v); - - F32 pix_width = lrange/(res*0.5f); - - //move cp to the nearest pix_width - for (U32 i = 0; i < 3; i++) - { - cp.mV[i] = llround(cp.mV[i], pix_width); - } - - LLVector3 min = cp-pad; - LLVector3 max = cp+pad; - - //set mGIRange to range in tc space[0,1] that covers texture block of intersecting lights around a point - mGIRange.mV[0] = (max.mV[0]-min.mV[0])/res; - mGIRange.mV[1] = (max.mV[1]-min.mV[1])/res; - mGILightRadius = lrad/lrange*0.5f; - - glh::matrix4f proj = gl_ortho(min.mV[0], max.mV[0], - min.mV[1], max.mV[1], - -max.mV[2], -min.mV[2]); - - LLCamera sun_cam = camera; - - glh::matrix4f eye_view = glh_get_current_modelview(); - - //get eye space to camera space matrix - mGIMatrix = view*eye_view.inverse(); - mGINormalMatrix = mGIMatrix.inverse().transpose(); - mGIInvProj = proj.inverse(); - mGIMatrixProj = proj*mGIMatrix; - - //translate and scale to [0,1] - glh::matrix4f trans(.5f, 0.f, 0.f, .5f, - 0.f, 0.5f, 0.f, 0.5f, - 0.f, 0.f, 0.5f, 0.5f, - 0.f, 0.f, 0.f, 1.f); - - mGIMatrixProj = trans*mGIMatrixProj; - - glh_set_current_modelview(view); - glh_set_current_projection(proj); - - LLViewerCamera::updateFrustumPlanes(sun_cam, TRUE, FALSE, TRUE); - - sun_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR); - static LLCullResult result; - - pushRenderTypeMask(); - - andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE, - LLPipeline::RENDER_TYPE_FULLBRIGHT, - LLPipeline::RENDER_TYPE_BUMP, - LLPipeline::RENDER_TYPE_VOLUME, - LLPipeline::RENDER_TYPE_TREE, - LLPipeline::RENDER_TYPE_TERRAIN, - LLPipeline::RENDER_TYPE_WATER, - LLPipeline::RENDER_TYPE_VOIDWATER, - LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW, - LLPipeline::RENDER_TYPE_AVATAR, - LLPipeline::RENDER_TYPE_PASS_SIMPLE, - LLPipeline::RENDER_TYPE_PASS_BUMP, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, - LLPipeline::RENDER_TYPE_PASS_SHINY, - END_RENDER_TYPES); - - - - S32 occlude = LLPipeline::sUseOcclusion; - //LLPipeline::sUseOcclusion = 0; - LLPipeline::sShadowRender = TRUE; - - //only render large objects into GI map - sMinRenderSize = gSavedSettings.getF32("RenderGIMinRenderSize"); - - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_GI_SOURCE; - mGIMap.bindTarget(); - - F64 last_modelview[16]; - F64 last_projection[16]; - for (U32 i = 0; i < 16; i++) - { - last_modelview[i] = gGLLastModelView[i]; - last_projection[i] = gGLLastProjection[i]; - gGLLastModelView[i] = mGIModelview.m[i]; - gGLLastProjection[i] = mGIProjection.m[i]; - } - - sun_cam.setOrigin(0.f, 0.f, 0.f); - updateCull(sun_cam, result); - stateSort(sun_cam, result); - - for (U32 i = 0; i < 16; i++) - { - gGLLastModelView[i] = last_modelview[i]; - gGLLastProjection[i] = last_projection[i]; - } - - mGIProjection = proj; - mGIModelview = view; - - LLGLEnable cull(GL_CULL_FACE); - - //generate GI map - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadMatrixf(proj.m); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadMatrixf(view.m); - - stop_glerror(); - gGLLastMatrix = NULL; - - mGIMap.clear(); - - { - //LLGLEnable enable(GL_DEPTH_CLAMP_NV); - renderGeomDeferred(camera); - } - - mGIMap.flush(); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - gGLLastMatrix = NULL; - - LLPipeline::sUseOcclusion = occlude; - LLPipeline::sShadowRender = FALSE; - sMinRenderSize = 0.f; - - popRenderTypeMask(); - -} - -void LLPipeline::renderHighlight(const LLViewerObject* obj, F32 fade) -{ - if (obj && obj->getVolume()) - { - for (LLViewerObject::child_list_t::const_iterator iter = obj->getChildren().begin(); iter != obj->getChildren().end(); ++iter) - { - renderHighlight(*iter, fade); - } - - LLDrawable* drawable = obj->mDrawable; - if (drawable) - { - for (S32 i = 0; i < drawable->getNumFaces(); ++i) - { - LLFace* face = drawable->getFace(i); - if (face) - { - face->renderSelected(LLViewerTexture::sNullImagep, LLColor4(1,1,1,fade)); - } - } - } - } -} - -void LLPipeline::generateHighlight(LLCamera& camera) -{ - //render highlighted object as white into offscreen render target - if (mHighlightObject.notNull()) - { - mHighlightSet.insert(HighlightItem(mHighlightObject)); - } - - if (!mHighlightSet.empty()) - { - F32 transition = gFrameIntervalSeconds/gSavedSettings.getF32("RenderHighlightFadeTime"); - - LLGLDisable test(GL_ALPHA_TEST); - LLGLDepthTest depth(GL_FALSE); - mHighlight.bindTarget(); - disableLights(); - gGL.setColorMask(true, true); - mHighlight.clear(); - - gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); - for (std::set::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ) - { - std::set::iterator cur_iter = iter++; - - if (cur_iter->mItem.isNull()) - { - mHighlightSet.erase(cur_iter); - continue; - } - - if (cur_iter->mItem == mHighlightObject) - { - cur_iter->incrFade(transition); - } - else - { - cur_iter->incrFade(-transition); - if (cur_iter->mFade <= 0.f) - { - mHighlightSet.erase(cur_iter); - continue; - } - } - - renderHighlight(cur_iter->mItem->getVObj(), cur_iter->mFade); - } - - mHighlight.flush(); - gGL.setColorMask(true, false); - gViewerWindow->setup3DViewport(); - } -} - - -void LLPipeline::generateSunShadow(LLCamera& camera) -{ - if (!sRenderDeferred || gSavedSettings.getS32("RenderShadowDetail") <= 0) - { - return; - } - - F64 last_modelview[16]; - F64 last_projection[16]; - for (U32 i = 0; i < 16; i++) - { //store last_modelview of world camera - last_modelview[i] = gGLLastModelView[i]; - last_projection[i] = gGLLastProjection[i]; - } - - pushRenderTypeMask(); - andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE, - LLPipeline::RENDER_TYPE_ALPHA, - LLPipeline::RENDER_TYPE_GRASS, - LLPipeline::RENDER_TYPE_FULLBRIGHT, - LLPipeline::RENDER_TYPE_BUMP, - LLPipeline::RENDER_TYPE_VOLUME, - LLPipeline::RENDER_TYPE_AVATAR, - LLPipeline::RENDER_TYPE_TREE, - LLPipeline::RENDER_TYPE_TERRAIN, - LLPipeline::RENDER_TYPE_WATER, - LLPipeline::RENDER_TYPE_VOIDWATER, - LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW, - LLPipeline::RENDER_TYPE_PASS_SIMPLE, - LLPipeline::RENDER_TYPE_PASS_BUMP, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, - LLPipeline::RENDER_TYPE_PASS_SHINY, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, - END_RENDER_TYPES); - - gGL.setColorMask(false, false); - - //get sun view matrix - - //store current projection/modelview matrix - glh::matrix4f saved_proj = glh_get_current_projection(); - glh::matrix4f saved_view = glh_get_current_modelview(); - glh::matrix4f inv_view = saved_view.inverse(); - - glh::matrix4f view[6]; - glh::matrix4f proj[6]; - - //clip contains parallel split distances for 3 splits - LLVector3 clip = gSavedSettings.getVector3("RenderShadowClipPlanes"); - - //F32 slope_threshold = gSavedSettings.getF32("RenderShadowSlopeThreshold"); - - //far clip on last split is minimum of camera view distance and 128 - mSunClipPlanes = LLVector4(clip, clip.mV[2] * clip.mV[2]/clip.mV[1]); - - clip = gSavedSettings.getVector3("RenderShadowOrthoClipPlanes"); - mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]); - - //currently used for amount to extrude frusta corners for constructing shadow frusta - LLVector3 n = gSavedSettings.getVector3("RenderShadowNearDist"); - //F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] }; - - //put together a universal "near clip" plane for shadow frusta - LLPlane shadow_near_clip; - { - LLVector3 p = gAgent.getPositionAgent(); - p += mSunDir * gSavedSettings.getF32("RenderFarClip")*2.f; - shadow_near_clip.setVec(p, mSunDir); - } - - LLVector3 lightDir = -mSunDir; - lightDir.normVec(); - - glh::vec3f light_dir(lightDir.mV); - - //create light space camera matrix - - LLVector3 at = lightDir; - - LLVector3 up = camera.getAtAxis(); - - if (fabsf(up*lightDir) > 0.75f) - { - up = camera.getUpAxis(); - } - - /*LLVector3 left = up%at; - up = at%left;*/ - - up.normVec(); - at.normVec(); - - - LLCamera main_camera = camera; - - F32 near_clip = 0.f; - { - //get visible point cloud - std::vector fp; - - main_camera.calcAgentFrustumPlanes(main_camera.mAgentFrustum); - - LLVector3 min,max; - getVisiblePointCloud(main_camera,min,max,fp); - - if (fp.empty()) - { - if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA)) - { - mShadowCamera[0] = main_camera; - mShadowExtents[0][0] = min; - mShadowExtents[0][1] = max; - - mShadowFrustPoints[0].clear(); - mShadowFrustPoints[1].clear(); - mShadowFrustPoints[2].clear(); - mShadowFrustPoints[3].clear(); - } - popRenderTypeMask(); - return; - } - - generateGI(camera, lightDir, fp); - - //get good split distances for frustum - for (U32 i = 0; i < fp.size(); ++i) - { - glh::vec3f v(fp[i].mV); - saved_view.mult_matrix_vec(v); - fp[i].setVec(v.v); - } - - min = fp[0]; - max = fp[0]; - - //get camera space bounding box - for (U32 i = 1; i < fp.size(); ++i) - { - update_min_max(min, max, fp[i]); - } - - near_clip = -max.mV[2]; - F32 far_clip = -min.mV[2]*2.f; - - far_clip = llmin(far_clip, 128.f); - far_clip = llmin(far_clip, camera.getFar()); - - F32 range = far_clip-near_clip; - - LLVector3 split_exp = gSavedSettings.getVector3("RenderShadowSplitExponent"); - - F32 da = 1.f-llmax( fabsf(lightDir*up), fabsf(lightDir*camera.getLeftAxis()) ); - - da = powf(da, split_exp.mV[2]); - - - F32 sxp = split_exp.mV[1] + (split_exp.mV[0]-split_exp.mV[1])*da; - - - for (U32 i = 0; i < 4; ++i) - { - F32 x = (F32)(i+1)/4.f; - x = powf(x, sxp); - mSunClipPlanes.mV[i] = near_clip+range*x; - } - } - - // convenience array of 4 near clip plane distances - F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] }; - - for (S32 j = 0; j < 4; j++) - { - if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA)) - { - mShadowFrustPoints[j].clear(); - } - - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+j; - - //restore render matrices - glh_set_current_modelview(saved_view); - glh_set_current_projection(saved_proj); - - LLVector3 eye = camera.getOrigin(); - - //camera used for shadow cull/render - LLCamera shadow_cam; - - //create world space camera frustum for this split - shadow_cam = camera; - shadow_cam.setFar(16.f); - - LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); - - LLVector3* frust = shadow_cam.mAgentFrustum; - - LLVector3 pn = shadow_cam.getAtAxis(); - - LLVector3 min, max; - - //construct 8 corners of split frustum section - for (U32 i = 0; i < 4; i++) - { - LLVector3 delta = frust[i+4]-eye; - delta += (frust[i+4]-frust[(i+2)%4+4])*0.05f; - delta.normVec(); - F32 dp = delta*pn; - frust[i] = eye + (delta*dist[j]*0.95f)/dp; - frust[i+4] = eye + (delta*dist[j+1]*1.05f)/dp; - } - - shadow_cam.calcAgentFrustumPlanes(frust); - shadow_cam.mFrustumCornerDist = 0.f; - - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - mShadowCamera[j] = shadow_cam; - } - - std::vector fp; - - if (!gPipeline.getVisiblePointCloud(shadow_cam, min, max, fp, lightDir)) - { - //no possible shadow receivers - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - mShadowExtents[j][0] = LLVector3(); - mShadowExtents[j][1] = LLVector3(); - mShadowCamera[j+4] = shadow_cam; - } - - mShadow[j].bindTarget(); - { - LLGLDepthTest depth(GL_TRUE); - mShadow[j].clear(); - } - mShadow[j].flush(); - - mShadowError.mV[j] = 0.f; - mShadowFOV.mV[j] = 0.f; - - continue; - } - - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - mShadowExtents[j][0] = min; - mShadowExtents[j][1] = max; - mShadowFrustPoints[j] = fp; - } - - - //find a good origin for shadow projection - LLVector3 origin; - - //get a temporary view projection - view[j] = look(camera.getOrigin(), lightDir, -up); - - std::vector wpf; - - for (U32 i = 0; i < fp.size(); i++) - { - glh::vec3f p = glh::vec3f(fp[i].mV); - view[j].mult_matrix_vec(p); - wpf.push_back(LLVector3(p.v)); - } - - min = wpf[0]; - max = wpf[0]; - - for (U32 i = 0; i < fp.size(); ++i) - { //get AABB in camera space - update_min_max(min, max, wpf[i]); - } - - // Construct a perspective transform with perspective along y-axis that contains - // points in wpf - //Known: - // - far clip plane - // - near clip plane - // - points in frustum - //Find: - // - origin - - //get some "interesting" points of reference - LLVector3 center = (min+max)*0.5f; - LLVector3 size = (max-min)*0.5f; - LLVector3 near_center = center; - near_center.mV[1] += size.mV[1]*2.f; - - - //put all points in wpf in quadrant 0, reletive to center of min/max - //get the best fit line using least squares - F32 bfm = 0.f; - F32 bfb = 0.f; - - for (U32 i = 0; i < wpf.size(); ++i) - { - wpf[i] -= center; - wpf[i].mV[0] = fabsf(wpf[i].mV[0]); - wpf[i].mV[2] = fabsf(wpf[i].mV[2]); - } - - if (!wpf.empty()) - { - F32 sx = 0.f; - F32 sx2 = 0.f; - F32 sy = 0.f; - F32 sxy = 0.f; - - for (U32 i = 0; i < wpf.size(); ++i) - { - sx += wpf[i].mV[0]; - sx2 += wpf[i].mV[0]*wpf[i].mV[0]; - sy += wpf[i].mV[1]; - sxy += wpf[i].mV[0]*wpf[i].mV[1]; - } - - bfm = (sy*sx-wpf.size()*sxy)/(sx*sx-wpf.size()*sx2); - bfb = (sx*sxy-sy*sx2)/(sx*sx-bfm*sx2); - } - - { - // best fit line is y=bfm*x+bfb - - //find point that is furthest to the right of line - F32 off_x = -1.f; - LLVector3 lp; - - for (U32 i = 0; i < wpf.size(); ++i) - { - //y = bfm*x+bfb - //x = (y-bfb)/bfm - F32 lx = (wpf[i].mV[1]-bfb)/bfm; - - lx = wpf[i].mV[0]-lx; - - if (off_x < lx) - { - off_x = lx; - lp = wpf[i]; - } - } - - //get line with slope bfm through lp - // bfb = y-bfm*x - bfb = lp.mV[1]-bfm*lp.mV[0]; - - //calculate error - mShadowError.mV[j] = 0.f; - - for (U32 i = 0; i < wpf.size(); ++i) - { - F32 lx = (wpf[i].mV[1]-bfb)/bfm; - mShadowError.mV[j] += fabsf(wpf[i].mV[0]-lx); - } - - mShadowError.mV[j] /= wpf.size(); - mShadowError.mV[j] /= size.mV[0]; - - if (mShadowError.mV[j] > gSavedSettings.getF32("RenderShadowErrorCutoff")) - { //just use ortho projection - mShadowFOV.mV[j] = -1.f; - origin.clearVec(); - proj[j] = gl_ortho(min.mV[0], max.mV[0], - min.mV[1], max.mV[1], - -max.mV[2], -min.mV[2]); - } - else - { - //origin is where line x = 0; - origin.setVec(0,bfb,0); - - F32 fovz = 1.f; - F32 fovx = 1.f; - - LLVector3 zp; - LLVector3 xp; - - for (U32 i = 0; i < wpf.size(); ++i) - { - LLVector3 atz = wpf[i]-origin; - atz.mV[0] = 0.f; - atz.normVec(); - if (fovz > -atz.mV[1]) - { - zp = wpf[i]; - fovz = -atz.mV[1]; - } - - LLVector3 atx = wpf[i]-origin; - atx.mV[2] = 0.f; - atx.normVec(); - if (fovx > -atx.mV[1]) - { - fovx = -atx.mV[1]; - xp = wpf[i]; - } - } - - fovx = acos(fovx); - fovz = acos(fovz); - - F32 cutoff = llmin(gSavedSettings.getF32("RenderShadowFOVCutoff"), 1.4f); - - mShadowFOV.mV[j] = fovx; - - if (fovx < cutoff && fovz > cutoff) - { - //x is a good fit, but z is too big, move away from zp enough so that fovz matches cutoff - F32 d = zp.mV[2]/tan(cutoff); - F32 ny = zp.mV[1] + fabsf(d); - - origin.mV[1] = ny; - - fovz = 1.f; - fovx = 1.f; - - for (U32 i = 0; i < wpf.size(); ++i) - { - LLVector3 atz = wpf[i]-origin; - atz.mV[0] = 0.f; - atz.normVec(); - fovz = llmin(fovz, -atz.mV[1]); - - LLVector3 atx = wpf[i]-origin; - atx.mV[2] = 0.f; - atx.normVec(); - fovx = llmin(fovx, -atx.mV[1]); - } - - fovx = acos(fovx); - fovz = acos(fovz); - - if (fovx > cutoff || llround(fovz, 0.01f) > cutoff) - { - // llerrs << "WTF?" << llendl; - } - - mShadowFOV.mV[j] = cutoff; - } - - - origin += center; - - F32 ynear = -(max.mV[1]-origin.mV[1]); - F32 yfar = -(min.mV[1]-origin.mV[1]); - - if (ynear < 0.1f) //keep a sensible near clip plane - { - F32 diff = 0.1f-ynear; - origin.mV[1] += diff; - ynear += diff; - yfar += diff; - } - - if (fovx > cutoff) - { //just use ortho projection - origin.clearVec(); - mShadowError.mV[j] = -1.f; - proj[j] = gl_ortho(min.mV[0], max.mV[0], - min.mV[1], max.mV[1], - -max.mV[2], -min.mV[2]); - } - else - { - //get perspective projection - view[j] = view[j].inverse(); - - glh::vec3f origin_agent(origin.mV); - - //translate view to origin - view[j].mult_matrix_vec(origin_agent); - - eye = LLVector3(origin_agent.v); - - if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - mShadowFrustOrigin[j] = eye; - } - - view[j] = look(LLVector3(origin_agent.v), lightDir, -up); - - F32 fx = 1.f/tanf(fovx); - F32 fz = 1.f/tanf(fovz); - - proj[j] = glh::matrix4f(-fx, 0, 0, 0, - 0, (yfar+ynear)/(ynear-yfar), 0, (2.f*yfar*ynear)/(ynear-yfar), - 0, 0, -fz, 0, - 0, -1.f, 0, 0); - } - } - } - - shadow_cam.setFar(128.f); - shadow_cam.setOriginAndLookAt(eye, up, center); - - shadow_cam.setOrigin(0,0,0); - - glh_set_current_modelview(view[j]); - glh_set_current_projection(proj[j]); - - LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); - - //shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR); - shadow_cam.getAgentPlane(LLCamera::AGENT_PLANE_NEAR).set(shadow_near_clip); - - //translate and scale to from [-1, 1] to [0, 1] - glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, - 0.f, 0.5f, 0.f, 0.5f, - 0.f, 0.f, 0.5f, 0.5f, - 0.f, 0.f, 0.f, 1.f); - - glh_set_current_modelview(view[j]); - glh_set_current_projection(proj[j]); - - for (U32 i = 0; i < 16; i++) - { - gGLLastModelView[i] = mShadowModelview[j].m[i]; - gGLLastProjection[i] = mShadowProjection[j].m[i]; - } - - mShadowModelview[j] = view[j]; - mShadowProjection[j] = proj[j]; - - - mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view; - - stop_glerror(); - - mShadow[j].bindTarget(); - mShadow[j].getViewport(gGLViewport); - mShadow[j].clear(); - - { - static LLCullResult result[4]; - - //LLGLEnable enable(GL_DEPTH_CLAMP_NV); - renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE); - } - - mShadow[j].flush(); - - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); - mShadowCamera[j+4] = shadow_cam; - } - } - - - //hack to disable projector shadows - bool gen_shadow = gSavedSettings.getS32("RenderShadowDetail") > 1; - - if (gen_shadow) - { - F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f); - - //update shadow targets - for (U32 i = 0; i < 2; i++) - { //for each current shadow - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i; - - if (mShadowSpotLight[i].notNull() && - (mShadowSpotLight[i] == mTargetShadowSpotLight[0] || - mShadowSpotLight[i] == mTargetShadowSpotLight[1])) - { //keep this spotlight - mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f); - } - else - { //fade out this light - mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f); - - if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull()) - { //faded out, grab one of the pending spots (whichever one isn't already taken) - if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2]) - { - mShadowSpotLight[i] = mTargetShadowSpotLight[0]; - } - else - { - mShadowSpotLight[i] = mTargetShadowSpotLight[1]; - } - } - } - } - - for (S32 i = 0; i < 2; i++) - { - glh_set_current_modelview(saved_view); - glh_set_current_projection(saved_proj); - - if (mShadowSpotLight[i].isNull()) - { - continue; - } - - LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume(); - - if (!volume) - { - mShadowSpotLight[i] = NULL; - continue; - } - - LLDrawable* drawable = mShadowSpotLight[i]; - - LLVector3 params = volume->getSpotLightParams(); - F32 fov = params.mV[0]; - - //get agent->light space matrix (modelview) - LLVector3 center = drawable->getPositionAgent(); - LLQuaternion quat = volume->getRenderRotation(); - - //get near clip plane - LLVector3 scale = volume->getScale(); - LLVector3 at_axis(0,0,-scale.mV[2]*0.5f); - at_axis *= quat; - - LLVector3 np = center+at_axis; - at_axis.normVec(); - - //get origin that has given fov for plane np, at_axis, and given scale - F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f); - - LLVector3 origin = np - at_axis*dist; - - LLMatrix4 mat(quat, LLVector4(origin, 1.f)); - - view[i+4] = glh::matrix4f((F32*) mat.mMatrix); - - view[i+4] = view[i+4].inverse(); - - //get perspective matrix - F32 near_clip = dist+0.01f; - F32 width = scale.mV[VX]; - F32 height = scale.mV[VY]; - F32 far_clip = dist+volume->getLightRadius()*1.5f; - - F32 fovy = fov * RAD_TO_DEG; - F32 aspect = width/height; - - proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip); - - //translate and scale to from [-1, 1] to [0, 1] - glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, - 0.f, 0.5f, 0.f, 0.5f, - 0.f, 0.f, 0.5f, 0.5f, - 0.f, 0.f, 0.f, 1.f); - - glh_set_current_modelview(view[i+4]); - glh_set_current_projection(proj[i+4]); - - mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view; - - for (U32 j = 0; j < 16; j++) - { - gGLLastModelView[j] = mShadowModelview[i+4].m[j]; - gGLLastProjection[j] = mShadowProjection[i+4].m[j]; - } - - mShadowModelview[i+4] = view[i+4]; - mShadowProjection[i+4] = proj[i+4]; - - LLCamera shadow_cam = camera; - shadow_cam.setFar(far_clip); - shadow_cam.setOrigin(origin); - - LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); - - stop_glerror(); - - mShadow[i+4].bindTarget(); - mShadow[i+4].getViewport(gGLViewport); - mShadow[i+4].clear(); - - static LLCullResult result[2]; - - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4; - - renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE); - - mShadow[i+4].flush(); - } - } - - if (!gSavedSettings.getBOOL("CameraOffset")) - { - glh_set_current_modelview(saved_view); - glh_set_current_projection(saved_proj); - } - else - { - glh_set_current_modelview(view[1]); - glh_set_current_projection(proj[1]); - glLoadMatrixf(view[1].m); - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(proj[1].m); - glMatrixMode(GL_MODELVIEW); - } - gGL.setColorMask(true, false); - - for (U32 i = 0; i < 16; i++) - { - gGLLastModelView[i] = last_modelview[i]; - gGLLastProjection[i] = last_projection[i]; - } - - popRenderTypeMask(); -} - -void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture) -{ - for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) - { - LLSpatialGroup* group = *i; - if (!group->isDead() && - (!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && - gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) && - group->mDrawMap.find(type) != group->mDrawMap.end()) - { - pass->renderGroup(group,type,mask,texture); - } - } -} - -void LLPipeline::generateImpostor(LLVOAvatar* avatar) -{ - LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - - static LLCullResult result; - result.clear(); - grabReferences(result); - - if (!avatar || !avatar->mDrawable) - { - return; - } - - assertInitialized(); - - BOOL muted = LLMuteList::getInstance()->isMuted(avatar->getID()); - - pushRenderTypeMask(); - - if (muted) - { - andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); - } - else - { - andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, - LLPipeline::RENDER_TYPE_AVATAR, - LLPipeline::RENDER_TYPE_BUMP, - LLPipeline::RENDER_TYPE_GRASS, - LLPipeline::RENDER_TYPE_SIMPLE, - LLPipeline::RENDER_TYPE_FULLBRIGHT, - LLPipeline::RENDER_TYPE_ALPHA, - LLPipeline::RENDER_TYPE_INVISIBLE, - LLPipeline::RENDER_TYPE_PASS_SIMPLE, - LLPipeline::RENDER_TYPE_PASS_ALPHA, - LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, - LLPipeline::RENDER_TYPE_PASS_SHINY, - LLPipeline::RENDER_TYPE_PASS_INVISIBLE, - LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY, - END_RENDER_TYPES); - } - - S32 occlusion = sUseOcclusion; - sUseOcclusion = 0; - sReflectionRender = sRenderDeferred ? FALSE : TRUE; - sShadowRender = TRUE; - sImpostorRender = TRUE; - - LLViewerCamera* viewer_camera = LLViewerCamera::getInstance(); - markVisible(avatar->mDrawable, *viewer_camera); - LLVOAvatar::sUseImpostors = FALSE; - - LLVOAvatar::attachment_map_t::iterator iter; - for (iter = avatar->mAttachmentPoints.begin(); - iter != avatar->mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment *attachment = iter->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - if (LLViewerObject* attached_object = (*attachment_iter)) - { - markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); - } - } - } - - stateSort(*LLViewerCamera::getInstance(), result); - - const LLVector4a* ext = avatar->mDrawable->getSpatialExtents(); - LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset()); - - LLCamera camera = *viewer_camera; - - camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis()); - - LLVector2 tdim; - - - LLVector4a half_height; - half_height.setSub(ext[1], ext[0]); - half_height.mul(0.5f); - - LLVector4a left; - left.load3(camera.getLeftAxis().mV); - left.mul(left); - left.normalize3fast(); - - LLVector4a up; - up.load3(camera.getUpAxis().mV); - up.mul(up); - up.normalize3fast(); - - tdim.mV[0] = fabsf(half_height.dot3(left).getF32()); - tdim.mV[1] = fabsf(half_height.dot3(up).getF32()); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - - F32 distance = (pos-camera.getOrigin()).length(); - F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG; - F32 aspect = tdim.mV[0]/tdim.mV[1]; - glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f); - glh_set_current_projection(persp); - glLoadMatrixf(persp.m); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glh::matrix4f mat; - camera.getOpenGLTransform(mat.m); - - mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat; - - glLoadMatrixf(mat.m); - glh_set_current_modelview(mat); - - glClearColor(0.0f,0.0f,0.0f,0.0f); - gGL.setColorMask(true, true); - - // get the number of pixels per angle - F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView()); - - //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing) - U32 resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512); - U32 resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512); - - if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() || - resY != avatar->mImpostor.getHeight()) - { - avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE); - - if (LLPipeline::sRenderDeferred) - { - addDeferredAttachments(avatar->mImpostor); - } - - gGL.getTexUnit(0)->bind(&avatar->mImpostor); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } - - avatar->mImpostor.bindTarget(); - - if (LLPipeline::sRenderDeferred) - { - avatar->mImpostor.clear(); - renderGeomDeferred(camera); - renderGeomPostDeferred(camera); - } - else - { - LLGLEnable scissor(GL_SCISSOR_TEST); - glScissor(0, 0, resX, resY); - avatar->mImpostor.clear(); - renderGeom(camera); - } - - { //create alpha mask based on depth buffer (grey out if muted) - if (LLPipeline::sRenderDeferred) - { - GLuint buff = GL_COLOR_ATTACHMENT0; - glDrawBuffersARB(1, &buff); - } - - LLGLDisable blend(GL_BLEND); - - if (muted) - { - gGL.setColorMask(true, true); - } - else - { - gGL.setColorMask(false, true); - } - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); - - gGL.flush(); - - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - static const F32 clip_plane = 0.99999f; - - gGL.color4ub(64,64,64,255); - gGL.begin(LLRender::QUADS); - gGL.vertex3f(-1, -1, clip_plane); - gGL.vertex3f(1, -1, clip_plane); - gGL.vertex3f(1, 1, clip_plane); - gGL.vertex3f(-1, 1, clip_plane); - gGL.end(); - gGL.flush(); - - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } - - avatar->mImpostor.flush(); - - avatar->setImpostorDim(tdim); - - LLVOAvatar::sUseImpostors = TRUE; - sUseOcclusion = occlusion; - sReflectionRender = FALSE; - sImpostorRender = FALSE; - sShadowRender = FALSE; - popRenderTypeMask(); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - avatar->mNeedsImpostorUpdate = FALSE; - avatar->cacheImpostorValues(); - - LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); -} - -BOOL LLPipeline::hasRenderBatches(const U32 type) const -{ - return sCull->getRenderMapSize(type) > 0; -} - -LLCullResult::drawinfo_list_t::iterator LLPipeline::beginRenderMap(U32 type) -{ - return sCull->beginRenderMap(type); -} - -LLCullResult::drawinfo_list_t::iterator LLPipeline::endRenderMap(U32 type) -{ - return sCull->endRenderMap(type); -} - -LLCullResult::sg_list_t::iterator LLPipeline::beginAlphaGroups() -{ - return sCull->beginAlphaGroups(); -} - -LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups() -{ - return sCull->endAlphaGroups(); -} - -BOOL LLPipeline::hasRenderType(const U32 type) const -{ - // STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render" - // We then need to test that value here and return FALSE to prevent attachment to render (in mouselook for instance) - // TODO: reintroduce RENDER_TYPE_NONE in LLRenderTypeMask and initialize its mRenderTypeEnabled[RENDER_TYPE_NONE] to FALSE explicitely - return (type == 0 ? FALSE : mRenderTypeEnabled[type]); -} - -void LLPipeline::setRenderTypeMask(U32 type, ...) -{ - va_list args; - - va_start(args, type); - while (type < END_RENDER_TYPES) - { - mRenderTypeEnabled[type] = TRUE; - type = va_arg(args, U32); - } - va_end(args); - - if (type > END_RENDER_TYPES) - { - llerrs << "Invalid render type." << llendl; - } -} - -BOOL LLPipeline::hasAnyRenderType(U32 type, ...) const -{ - va_list args; - - va_start(args, type); - while (type < END_RENDER_TYPES) - { - if (mRenderTypeEnabled[type]) - { - return TRUE; - } - type = va_arg(args, U32); - } - va_end(args); - - if (type > END_RENDER_TYPES) - { - llerrs << "Invalid render type." << llendl; - } - - return FALSE; -} - -void LLPipeline::pushRenderTypeMask() -{ - std::string cur_mask; - cur_mask.assign((const char*) mRenderTypeEnabled, sizeof(mRenderTypeEnabled)); - mRenderTypeEnableStack.push(cur_mask); -} - -void LLPipeline::popRenderTypeMask() -{ - if (mRenderTypeEnableStack.empty()) - { - llerrs << "Depleted render type stack." << llendl; - } - - memcpy(mRenderTypeEnabled, mRenderTypeEnableStack.top().data(), sizeof(mRenderTypeEnabled)); - mRenderTypeEnableStack.pop(); -} - -void LLPipeline::andRenderTypeMask(U32 type, ...) -{ - va_list args; - - BOOL tmp[NUM_RENDER_TYPES]; - for (U32 i = 0; i < NUM_RENDER_TYPES; ++i) - { - tmp[i] = FALSE; - } - - va_start(args, type); - while (type < END_RENDER_TYPES) - { - if (mRenderTypeEnabled[type]) - { - tmp[type] = TRUE; - } - - type = va_arg(args, U32); - } - va_end(args); - - if (type > END_RENDER_TYPES) - { - llerrs << "Invalid render type." << llendl; - } - - for (U32 i = 0; i < LLPipeline::NUM_RENDER_TYPES; ++i) - { - mRenderTypeEnabled[i] = tmp[i]; - } - -} - -void LLPipeline::clearRenderTypeMask(U32 type, ...) -{ - va_list args; - - va_start(args, type); - while (type < END_RENDER_TYPES) - { - mRenderTypeEnabled[type] = FALSE; - - type = va_arg(args, U32); - } - va_end(args); - - if (type > END_RENDER_TYPES) - { - llerrs << "Invalid render type." << llendl; - } -} - - +/** + * @file pipeline.cpp + * @brief Rendering pipeline. + * + * $LicenseInfo:firstyear=2005&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 "llviewerprecompiledheaders.h" + +#include "pipeline.h" + +// library includes +#include "llaudioengine.h" // For debugging. +#include "imageids.h" +#include "llerror.h" +#include "llviewercontrol.h" +#include "llfasttimer.h" +#include "llfontgl.h" +#include "llmemtype.h" +#include "llnamevalue.h" +#include "llpointer.h" +#include "llprimitive.h" +#include "llvolume.h" +#include "material_codes.h" +#include "timing.h" +#include "v3color.h" +#include "llui.h" +#include "llglheaders.h" +#include "llrender.h" +#include "llwindow.h" // swapBuffers() + +// newview includes +#include "llagent.h" +#include "llagentcamera.h" +#include "lldrawable.h" +#include "lldrawpoolalpha.h" +#include "lldrawpoolavatar.h" +#include "lldrawpoolground.h" +#include "lldrawpoolbump.h" +#include "lldrawpooltree.h" +#include "lldrawpoolwater.h" +#include "llface.h" +#include "llfeaturemanager.h" +#include "llfloatertelehub.h" +#include "llfloaterreg.h" +#include "llgldbg.h" +#include "llhudmanager.h" +#include "llhudnametag.h" +#include "llhudtext.h" +#include "lllightconstants.h" +#include "llmeshrepository.h" +#include "llresmgr.h" +#include "llselectmgr.h" +#include "llsky.h" +#include "lltracker.h" +#include "lltool.h" +#include "lltoolmgr.h" +#include "llviewercamera.h" +#include "llviewertexturelist.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" // for audio debugging. +#include "llviewerwindow.h" // For getSpinAxis +#include "llvoavatarself.h" +#include "llvoground.h" +#include "llvosky.h" +#include "llvotree.h" +#include "llvovolume.h" +#include "llvosurfacepatch.h" +#include "llvowater.h" +#include "llvotree.h" +#include "llvopartgroup.h" +#include "llworld.h" +#include "llcubemap.h" +#include "llviewershadermgr.h" +#include "llviewerstats.h" +#include "llviewerjoystick.h" +#include "llviewerdisplay.h" +#include "llwlparammanager.h" +#include "llwaterparammanager.h" +#include "llspatialpartition.h" +#include "llmutelist.h" +#include "lltoolpie.h" +#include "llcurl.h" + + +void check_stack_depth(S32 stack_depth) +{ + if (gDebugGL || gDebugSession) + { + GLint depth; + glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth); + if (depth != stack_depth) + { + if (gDebugSession) + { + ll_fail("GL matrix stack corrupted."); + } + else + { + llerrs << "GL matrix stack corrupted!" << llendl; + } + } + } +} + +#ifdef _DEBUG +// Debug indices is disabled for now for debug performance - djs 4/24/02 +//#define DEBUG_INDICES +#else +//#define DEBUG_INDICES +#endif + +const F32 BACKLIGHT_DAY_MAGNITUDE_AVATAR = 0.2f; +const F32 BACKLIGHT_NIGHT_MAGNITUDE_AVATAR = 0.1f; +const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f; +const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f; +const S32 MAX_OFFSCREEN_GEOMETRY_CHANGES_PER_FRAME = 10; +const U32 REFLECTION_MAP_RES = 128; + +// Max number of occluders to search for. JC +const S32 MAX_OCCLUDER_COUNT = 2; + +extern S32 gBoxFrame; +//extern BOOL gHideSelectedObjects; +extern BOOL gDisplaySwapBuffers; +extern BOOL gDebugGL; + +// hack counter for rendering a fixed number of frames after toggling +// fullscreen to work around DEV-5361 +static S32 sDelayedVBOEnable = 0; + +BOOL gAvatarBacklight = FALSE; + +BOOL gDebugPipeline = FALSE; +LLPipeline gPipeline; +const LLMatrix4* gGLLastMatrix = NULL; + +LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry"); +LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass"); +LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible"); +LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion"); +LLFastTimer::DeclareTimer FTM_RENDER_SHINY("Shiny"); +LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE("Simple"); +LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN("Terrain"); +LLFastTimer::DeclareTimer FTM_RENDER_TREES("Trees"); +LLFastTimer::DeclareTimer FTM_RENDER_UI("UI"); +LLFastTimer::DeclareTimer FTM_RENDER_WATER("Water"); +LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky"); +LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects"); +LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars"); +LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump"); +LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright"); +LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow"); +LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update"); +LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool"); +LLFastTimer::DeclareTimer FTM_POOLS("Pools"); +LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO"); +LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State"); +LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline"); +LLFastTimer::DeclareTimer FTM_CLIENT_COPY("Client Copy"); +LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading"); + + +static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables"); +static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort"); + +//---------------------------------------- +std::string gPoolNames[] = +{ + // Correspond to LLDrawpool enum render type + "NONE", + "POOL_SIMPLE", + "POOL_TERRAIN", + "POOL_BUMP", + "POOL_TREE", + "POOL_SKY", + "POOL_WL_SKY", + "POOL_GROUND", + "POOL_INVISIBLE", + "POOL_AVATAR", + "POOL_WATER", + "POOL_GRASS", + "POOL_FULLBRIGHT", + "POOL_GLOW", + "POOL_ALPHA", +}; + +void drawBox(const LLVector3& c, const LLVector3& r); +void drawBoxOutline(const LLVector3& pos, const LLVector3& size); + +U32 nhpo2(U32 v) +{ + U32 r = 1; + while (r < v) { + r *= 2; + } + return r; +} + +glh::matrix4f glh_copy_matrix(GLdouble* src) +{ + glh::matrix4f ret; + for (U32 i = 0; i < 16; i++) + { + ret.m[i] = (F32) src[i]; + } + return ret; +} + +glh::matrix4f glh_get_current_modelview() +{ + return glh_copy_matrix(gGLModelView); +} + +glh::matrix4f glh_get_current_projection() +{ + return glh_copy_matrix(gGLProjection); +} + +void glh_copy_matrix(const glh::matrix4f& src, GLdouble* dst) +{ + for (U32 i = 0; i < 16; i++) + { + dst[i] = src.m[i]; + } +} + +void glh_set_current_modelview(const glh::matrix4f& mat) +{ + glh_copy_matrix(mat, gGLModelView); +} + +void glh_set_current_projection(glh::matrix4f& mat) +{ + glh_copy_matrix(mat, gGLProjection); +} + +glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar) +{ + glh::matrix4f ret( + 2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left), + 0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom), + 0.f, 0.f, -2.f/(zfar-znear), -(zfar+znear)/(zfar-znear), + 0.f, 0.f, 0.f, 1.f); + + return ret; +} + +void display_update_camera(); +//---------------------------------------- + +S32 LLPipeline::sCompiles = 0; + +BOOL LLPipeline::sPickAvatar = TRUE; +BOOL LLPipeline::sDynamicLOD = TRUE; +BOOL LLPipeline::sShowHUDAttachments = TRUE; +BOOL LLPipeline::sRenderPhysicalBeacons = TRUE; +BOOL LLPipeline::sRenderScriptedBeacons = FALSE; +BOOL LLPipeline::sRenderScriptedTouchBeacons = TRUE; +BOOL LLPipeline::sRenderParticleBeacons = FALSE; +BOOL LLPipeline::sRenderSoundBeacons = FALSE; +BOOL LLPipeline::sRenderBeacons = FALSE; +BOOL LLPipeline::sRenderHighlight = TRUE; +BOOL LLPipeline::sForceOldBakedUpload = FALSE; +S32 LLPipeline::sUseOcclusion = 0; +BOOL LLPipeline::sDelayVBUpdate = TRUE; +BOOL LLPipeline::sAutoMaskAlphaDeferred = TRUE; +BOOL LLPipeline::sAutoMaskAlphaNonDeferred = FALSE; +BOOL LLPipeline::sDisableShaders = FALSE; +BOOL LLPipeline::sRenderBump = TRUE; +BOOL LLPipeline::sBakeSunlight = FALSE; +BOOL LLPipeline::sNoAlpha = FALSE; +BOOL LLPipeline::sUseTriStrips = TRUE; +BOOL LLPipeline::sUseFarClip = TRUE; +BOOL LLPipeline::sShadowRender = FALSE; +BOOL LLPipeline::sWaterReflections = FALSE; +BOOL LLPipeline::sRenderGlow = FALSE; +BOOL LLPipeline::sReflectionRender = FALSE; +BOOL LLPipeline::sImpostorRender = FALSE; +BOOL LLPipeline::sUnderWaterRender = FALSE; +BOOL LLPipeline::sTextureBindTest = FALSE; +BOOL LLPipeline::sRenderFrameTest = FALSE; +BOOL LLPipeline::sRenderAttachedLights = TRUE; +BOOL LLPipeline::sRenderAttachedParticles = TRUE; +BOOL LLPipeline::sRenderDeferred = FALSE; +S32 LLPipeline::sVisibleLightCount = 0; +F32 LLPipeline::sMinRenderSize = 0.f; + + +static LLCullResult* sCull = NULL; + +static const U32 gl_cube_face[] = +{ + GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, +}; + +void validate_framebuffer_object(); + + +void addDeferredAttachments(LLRenderTarget& target) +{ + target.addColorAttachment(GL_RGBA); //specular + target.addColorAttachment(GL_RGBA); //normal+z +} + +LLPipeline::LLPipeline() : + mBackfaceCull(FALSE), + mBatchCount(0), + mMatrixOpCount(0), + mTextureMatrixOps(0), + mMaxBatchSize(0), + mMinBatchSize(0), + mMeanBatchSize(0), + mTrianglesDrawn(0), + mNumVisibleNodes(0), + mVerticesRelit(0), + mLightingChanges(0), + mGeometryChanges(0), + mNumVisibleFaces(0), + + mInitialized(FALSE), + mVertexShadersEnabled(FALSE), + mVertexShadersLoaded(0), + mRenderDebugFeatureMask(0), + mRenderDebugMask(0), + mOldRenderDebugMask(0), + mGroupQ1Locked(false), + mGroupQ2Locked(false), + mLastRebuildPool(NULL), + mAlphaPool(NULL), + mSkyPool(NULL), + mTerrainPool(NULL), + mWaterPool(NULL), + mGroundPool(NULL), + mSimplePool(NULL), + mFullbrightPool(NULL), + mInvisiblePool(NULL), + mGlowPool(NULL), + mBumpPool(NULL), + mWLSkyPool(NULL), + mLightMask(0), + mLightMovingMask(0), + mLightingDetail(0), + mScreenWidth(0), + mScreenHeight(0) +{ + mNoiseMap = 0; + mTrueNoiseMap = 0; + mLightFunc = 0; +} + +void LLPipeline::init() +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_INIT); + + sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD"); + sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); + sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips"); + LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO"); + LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw"); + sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); + sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); + + mInitialized = TRUE; + + stop_glerror(); + + //create render pass pools + getPool(LLDrawPool::POOL_ALPHA); + getPool(LLDrawPool::POOL_SIMPLE); + getPool(LLDrawPool::POOL_GRASS); + getPool(LLDrawPool::POOL_FULLBRIGHT); + getPool(LLDrawPool::POOL_INVISIBLE); + getPool(LLDrawPool::POOL_BUMP); + getPool(LLDrawPool::POOL_GLOW); + + LLViewerStats::getInstance()->mTrianglesDrawnStat.reset(); + resetFrameStats(); + + for (U32 i = 0; i < NUM_RENDER_TYPES; ++i) + { + mRenderTypeEnabled[i] = TRUE; //all rendering types start enabled + } + + mRenderDebugFeatureMask = 0xffffffff; // All debugging features on + mRenderDebugMask = 0; // All debug starts off + + // Don't turn on ground when this is set + // Mac Books with intel 950s need this + if(!gSavedSettings.getBOOL("RenderGround")) + { + toggleRenderType(RENDER_TYPE_GROUND); + } + + // make sure RenderPerformanceTest persists (hackity hack hack) + // disables non-object rendering (UI, sky, water, etc) + if (gSavedSettings.getBOOL("RenderPerformanceTest")) + { + gSavedSettings.setBOOL("RenderPerformanceTest", FALSE); + gSavedSettings.setBOOL("RenderPerformanceTest", TRUE); + } + + mOldRenderDebugMask = mRenderDebugMask; + + mBackfaceCull = TRUE; + + stop_glerror(); + + // Enable features + + LLViewerShaderMgr::instance()->setShaders(); + + stop_glerror(); + + for (U32 i = 0; i < 2; ++i) + { + mSpotLightFade[i] = 1.f; + } + + setLightingDetail(-1); +} + +LLPipeline::~LLPipeline() +{ + +} + +void LLPipeline::cleanup() +{ + assertInitialized(); + + mGroupQ1.clear() ; + mGroupQ2.clear() ; + + for(pool_set_t::iterator iter = mPools.begin(); + iter != mPools.end(); ) + { + pool_set_t::iterator curiter = iter++; + LLDrawPool* poolp = *curiter; + if (poolp->isFacePool()) + { + LLFacePool* face_pool = (LLFacePool*) poolp; + if (face_pool->mReferences.empty()) + { + mPools.erase(curiter); + removeFromQuickLookup( poolp ); + delete poolp; + } + } + else + { + mPools.erase(curiter); + removeFromQuickLookup( poolp ); + delete poolp; + } + } + + if (!mTerrainPools.empty()) + { + llwarns << "Terrain Pools not cleaned up" << llendl; + } + if (!mTreePools.empty()) + { + llwarns << "Tree Pools not cleaned up" << llendl; + } + + delete mAlphaPool; + mAlphaPool = NULL; + delete mSkyPool; + mSkyPool = NULL; + delete mTerrainPool; + mTerrainPool = NULL; + delete mWaterPool; + mWaterPool = NULL; + delete mGroundPool; + mGroundPool = NULL; + delete mSimplePool; + mSimplePool = NULL; + delete mFullbrightPool; + mFullbrightPool = NULL; + delete mInvisiblePool; + mInvisiblePool = NULL; + delete mGlowPool; + mGlowPool = NULL; + delete mBumpPool; + mBumpPool = NULL; + // don't delete wl sky pool it was handled above in the for loop + //delete mWLSkyPool; + mWLSkyPool = NULL; + + releaseGLBuffers(); + + mFaceSelectImagep = NULL; + + mMovedBridge.clear(); + + mInitialized = FALSE; +} + +//============================================================================ + +void LLPipeline::destroyGL() +{ + stop_glerror(); + unloadShaders(); + mHighlightFaces.clear(); + + resetDrawOrders(); + + resetVertexBuffers(); + + releaseGLBuffers(); + + if (LLVertexBuffer::sEnableVBOs) + { + // render 30 frames after switching to work around DEV-5361 + sDelayedVBOEnable = 30; + LLVertexBuffer::sEnableVBOs = FALSE; + } +} + +static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture"); + +void LLPipeline::resizeScreenTexture() +{ + LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE); + if (gPipeline.canUseVertexShaders() && assertInitialized()) + { + GLuint resX = gViewerWindow->getWorldViewWidthRaw(); + GLuint resY = gViewerWindow->getWorldViewHeightRaw(); + + allocateScreenBuffer(resX,resY); + } +} + +void LLPipeline::allocatePhysicsBuffer() +{ + GLuint resX = gViewerWindow->getWorldViewWidthRaw(); + GLuint resY = gViewerWindow->getWorldViewHeightRaw(); + + if (mPhysicsDisplay.getWidth() != resX || mPhysicsDisplay.getHeight() != resY) + { + mPhysicsDisplay.allocate(resX, resY, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + if (mSampleBuffer.getWidth() == mPhysicsDisplay.getWidth() && + mSampleBuffer.getHeight() == mPhysicsDisplay.getHeight()) + { + mPhysicsDisplay.setSampleBuffer(&mSampleBuffer); + } + } +} + +void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY) +{ + // remember these dimensions + mScreenWidth = resX; + mScreenHeight = resY; + + //never use more than 4 samples for render targets + U32 samples = llmin(gSavedSettings.getU32("RenderFSAASamples"), (U32) 4); + if (gGLManager.mIsATI) + { //disable multisampling of render targets where ATI is involved + samples = 0; + } + + U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor"); + + if (res_mod > 1 && res_mod < resX && res_mod < resY) + { + resX /= res_mod; + resY /= res_mod; + } + + if (gSavedSettings.getBOOL("RenderUIBuffer")) + { + mUIScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + } + + if (LLPipeline::sRenderDeferred) + { + S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail"); + BOOL ssao = gSavedSettings.getBOOL("RenderDeferredSSAO"); + bool gi = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED); + + //allocate deferred rendering color buffers + mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + addDeferredAttachments(mDeferredScreen); + + mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + mEdgeMap.allocate(resX, resY, GL_ALPHA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + + if (shadow_detail > 0 || ssao) + { //only need mDeferredLight[0] for shadows OR ssao + mDeferredLight[0].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE); + } + else + { + mDeferredLight[0].release(); + } + + if (ssao) + { //only need mDeferredLight[1] for ssao + mDeferredLight[1].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE); + } + else + { + mDeferredLight[1].release(); + } + + if (gi) + { //only need mDeferredLight[2] and mGIMapPost for gi + mDeferredLight[2].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE); + for (U32 i = 0; i < 2; i++) + { + mGIMapPost[i].allocate(resX,resY, GL_RGB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE); + } + } + else + { + mDeferredLight[2].release(); + + for (U32 i = 0; i < 2; i++) + { + mGIMapPost[i].release(); + } + } + + F32 scale = gSavedSettings.getF32("RenderShadowResolutionScale"); + + //HACK: make alpha masking work on ATI depth shadows (work around for ATI driver bug) + U32 shadow_fmt = gGLManager.mIsATI ? GL_ALPHA : 0; + + if (shadow_detail > 0) + { //allocate 4 sun shadow maps + for (U32 i = 0; i < 4; i++) + { + mShadow[i].allocate(U32(resX*scale),U32(resY*scale), shadow_fmt, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE); + } + } + else + { + for (U32 i = 0; i < 4; i++) + { + mShadow[i].release(); + } + } + + U32 width = nhpo2(U32(resX*scale))/2; + U32 height = width; + + if (shadow_detail > 1) + { //allocate two spot shadow maps + for (U32 i = 4; i < 6; i++) + { + mShadow[i].allocate(width, height, shadow_fmt, TRUE, FALSE); + } + } + else + { + for (U32 i = 4; i < 6; i++) + { + mShadow[i].release(); + } + } + + width = nhpo2(resX)/2; + height = nhpo2(resY)/2; + mLuminanceMap.allocate(width,height, GL_RGBA, FALSE, FALSE); + } + else + { + for (U32 i = 0; i < 3; i++) + { + mDeferredLight[i].release(); + } + for (U32 i = 0; i < 2; i++) + { + mGIMapPost[i].release(); + } + for (U32 i = 0; i < 6; i++) + { + mShadow[i].release(); + } + mScreen.release(); + mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first + mDeferredDepth.release(); + mEdgeMap.release(); + mLuminanceMap.release(); + + mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + } + + if (LLRenderTarget::sUseFBO && samples > 1) + { + mSampleBuffer.allocate(resX,resY,GL_RGBA,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples); + if (LLPipeline::sRenderDeferred) + { + addDeferredAttachments(mSampleBuffer); + mDeferredScreen.setSampleBuffer(&mSampleBuffer); + mEdgeMap.setSampleBuffer(&mSampleBuffer); + } + + mScreen.setSampleBuffer(&mSampleBuffer); + + stop_glerror(); + } + else + { + mSampleBuffer.release(); + } + + if (LLPipeline::sRenderDeferred) + { //share depth buffer between deferred targets + mDeferredScreen.shareDepthBuffer(mScreen); + for (U32 i = 0; i < 3; i++) + { //share stencil buffer with screen space lightmap to stencil out sky + if (mDeferredLight[i].getTexture(0)) + { + mDeferredScreen.shareDepthBuffer(mDeferredLight[i]); + } + } + } + + gGL.getTexUnit(0)->disable(); + + stop_glerror(); + +} + +//static +void LLPipeline::updateRenderDeferred() +{ + BOOL deferred = ((gSavedSettings.getBOOL("RenderDeferred") && + LLRenderTarget::sUseFBO && + LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && + gSavedSettings.getBOOL("VertexShaderEnable") && + gSavedSettings.getBOOL("RenderAvatarVP") && + gSavedSettings.getBOOL("WindLightUseAtmosShaders")) ? TRUE : FALSE) && + !gUseWireframe; + + sRenderDeferred = deferred; + if (deferred) + { //must render glow when rendering deferred since post effect pass is needed to present any lighting at all + sRenderGlow = TRUE; + } +} + +void LLPipeline::releaseGLBuffers() +{ + assertInitialized(); + + if (mNoiseMap) + { + LLImageGL::deleteTextures(1, &mNoiseMap); + mNoiseMap = 0; + } + + if (mTrueNoiseMap) + { + LLImageGL::deleteTextures(1, &mTrueNoiseMap); + mTrueNoiseMap = 0; + } + + if (mLightFunc) + { + LLImageGL::deleteTextures(1, &mLightFunc); + mLightFunc = 0; + } + + mWaterRef.release(); + mWaterDis.release(); + mScreen.release(); + mPhysicsDisplay.release(); + mUIScreen.release(); + mSampleBuffer.release(); + mDeferredScreen.release(); + mDeferredDepth.release(); + for (U32 i = 0; i < 3; i++) + { + mDeferredLight[i].release(); + } + + mEdgeMap.release(); + mGIMap.release(); + mGIMapPost[0].release(); + mGIMapPost[1].release(); + mHighlight.release(); + mLuminanceMap.release(); + + for (U32 i = 0; i < 6; i++) + { + mShadow[i].release(); + } + + for (U32 i = 0; i < 3; i++) + { + mGlow[i].release(); + } + + LLVOAvatar::resetImpostors(); +} + +void LLPipeline::createGLBuffers() +{ + LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS); + assertInitialized(); + + updateRenderDeferred(); + + if (LLPipeline::sWaterReflections) + { //water reflection texture + U32 res = (U32) gSavedSettings.getS32("RenderWaterRefResolution"); + + mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE); + mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE); + } + + mHighlight.allocate(256,256,GL_RGBA, FALSE, FALSE); + + stop_glerror(); + + GLuint resX = gViewerWindow->getWorldViewWidthRaw(); + GLuint resY = gViewerWindow->getWorldViewHeightRaw(); + + if (LLPipeline::sRenderGlow) + { //screen space glow buffers + const U32 glow_res = llmax(1, + llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow"))); + + for (U32 i = 0; i < 3; i++) + { + mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE,FALSE); + } + + allocateScreenBuffer(resX,resY); + mScreenWidth = 0; + mScreenHeight = 0; + } + + if (sRenderDeferred) + { + if (!mNoiseMap) + { + const U32 noiseRes = 128; + LLVector3 noise[noiseRes*noiseRes]; + + F32 scaler = gSavedSettings.getF32("RenderDeferredNoise")/100.f; + for (U32 i = 0; i < noiseRes*noiseRes; ++i) + { + noise[i] = LLVector3(ll_frand()-0.5f, ll_frand()-0.5f, 0.f); + noise[i].normVec(); + noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f; + } + + LLImageGL::generateTextures(1, &mNoiseMap); + + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap); + LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + if (!mTrueNoiseMap) + { + const U32 noiseRes = 128; + F32 noise[noiseRes*noiseRes*3]; + for (U32 i = 0; i < noiseRes*noiseRes*3; i++) + { + noise[i] = ll_frand()*2.0-1.0; + } + + LLImageGL::generateTextures(1, &mTrueNoiseMap); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap); + LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + if (!mLightFunc) + { + U32 lightResX = gSavedSettings.getU32("RenderSpecularResX"); + U32 lightResY = gSavedSettings.getU32("RenderSpecularResY"); + U8* lg = new U8[lightResX*lightResY]; + + for (U32 y = 0; y < lightResY; ++y) + { + for (U32 x = 0; x < lightResX; ++x) + { + //spec func + F32 sa = (F32) x/(lightResX-1); + F32 spec = (F32) y/(lightResY-1); + //lg[y*lightResX+x] = (U8) (powf(sa, 128.f*spec*spec)*255); + + //F32 sp = acosf(sa)/(1.f-spec); + + sa = powf(sa, gSavedSettings.getF32("RenderSpecularExponent")); + F32 a = acosf(sa*0.25f+0.75f); + F32 m = llmax(0.5f-spec*0.5f, 0.001f); + F32 t2 = tanf(a)/m; + t2 *= t2; + + F32 c4a = (3.f+4.f*cosf(2.f*a)+cosf(4.f*a))/8.f; + F32 bd = 1.f/(4.f*m*m*c4a)*powf(F_E, -t2); + + lg[y*lightResX+x] = (U8) (llclamp(bd, 0.f, 1.f)*255); + } + } + + LLImageGL::generateTextures(1, &mLightFunc); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); + LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_ALPHA, lightResX, lightResY, GL_ALPHA, GL_UNSIGNED_BYTE, lg); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR); + + delete [] lg; + } + + if (gSavedSettings.getBOOL("RenderDeferredGI")) + { + mGIMap.allocate(512,512,GL_RGBA, TRUE, FALSE); + addDeferredAttachments(mGIMap); + } + } +} + +void LLPipeline::restoreGL() +{ + LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_RESTORE_GL); + assertInitialized(); + + if (mVertexShadersEnabled) + { + LLViewerShaderMgr::instance()->setShaders(); + } + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + part->restoreGL(); + } + } + } +} + + +BOOL LLPipeline::canUseVertexShaders() +{ + if (sDisableShaders || + !gGLManager.mHasVertexShader || + !gGLManager.mHasFragmentShader || + !LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") || + (assertInitialized() && mVertexShadersLoaded != 1) ) + { + return FALSE; + } + else + { + return TRUE; + } +} + +BOOL LLPipeline::canUseWindLightShaders() const +{ + return (!LLPipeline::sDisableShaders && + gWLSkyProgram.mProgramObject != 0 && + LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1); +} + +BOOL LLPipeline::canUseWindLightShadersOnObjects() const +{ + return (canUseWindLightShaders() + && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0); +} + +BOOL LLPipeline::canUseAntiAliasing() const +{ + return TRUE; +} + +void LLPipeline::unloadShaders() +{ + LLMemType mt_us(LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS); + LLViewerShaderMgr::instance()->unloadShaders(); + + mVertexShadersLoaded = 0; +} + +void LLPipeline::assertInitializedDoError() +{ + llerrs << "LLPipeline used when uninitialized." << llendl; +} + +//============================================================================ + +void LLPipeline::enableShadows(const BOOL enable_shadows) +{ + //should probably do something here to wrangle shadows.... +} + +S32 LLPipeline::getMaxLightingDetail() const +{ + /*if (mVertexShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS) + { + return 3; + } + else*/ + { + return 1; + } +} + +S32 LLPipeline::setLightingDetail(S32 level) +{ + LLMemType mt_ld(LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL); + + if (level < 0) + { + if (gSavedSettings.getBOOL("RenderLocalLights")) + { + level = 1; + } + else + { + level = 0; + } + } + level = llclamp(level, 0, getMaxLightingDetail()); + mLightingDetail = level; + + return mLightingDetail; +} + +class LLOctreeDirtyTexture : public LLOctreeTraveler +{ +public: + const std::set& mTextures; + + LLOctreeDirtyTexture(const std::set& textures) : mTextures(textures) { } + + virtual void visit(const LLOctreeNode* node) + { + LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); + + if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->getData().empty()) + { + for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) + { + for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) + { + LLDrawInfo* params = *j; + LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params->mTexture); + if (tex && mTextures.find(tex) != mTextures.end()) + { + group->setState(LLSpatialGroup::GEOM_DIRTY); + } + } + } + } + + for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i) + { + LLSpatialBridge* bridge = *i; + traverse(bridge->mOctree); + } + } +}; + +// Called when a texture changes # of channels (causes faces to move to alpha pool) +void LLPipeline::dirtyPoolObjectTextures(const std::set& textures) +{ + assertInitialized(); + + // *TODO: This is inefficient and causes frame spikes; need a better way to do this + // Most of the time is spent in dirty.traverse. + + for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) + { + LLDrawPool *poolp = *iter; + if (poolp->isFacePool()) + { + ((LLFacePool*) poolp)->dirtyTextures(textures); + } + } + + LLOctreeDirtyTexture dirty(textures); + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + dirty.traverse(part->mOctree); + } + } + } +} + +LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0) +{ + assertInitialized(); + + LLDrawPool *poolp = NULL; + switch( type ) + { + case LLDrawPool::POOL_SIMPLE: + poolp = mSimplePool; + break; + + case LLDrawPool::POOL_GRASS: + poolp = mGrassPool; + break; + + case LLDrawPool::POOL_FULLBRIGHT: + poolp = mFullbrightPool; + break; + + case LLDrawPool::POOL_INVISIBLE: + poolp = mInvisiblePool; + break; + + case LLDrawPool::POOL_GLOW: + poolp = mGlowPool; + break; + + case LLDrawPool::POOL_TREE: + poolp = get_if_there(mTreePools, (uintptr_t)tex0, (LLDrawPool*)0 ); + break; + + case LLDrawPool::POOL_TERRAIN: + poolp = get_if_there(mTerrainPools, (uintptr_t)tex0, (LLDrawPool*)0 ); + break; + + case LLDrawPool::POOL_BUMP: + poolp = mBumpPool; + break; + + case LLDrawPool::POOL_ALPHA: + poolp = mAlphaPool; + break; + + case LLDrawPool::POOL_AVATAR: + break; // Do nothing + + case LLDrawPool::POOL_SKY: + poolp = mSkyPool; + break; + + case LLDrawPool::POOL_WATER: + poolp = mWaterPool; + break; + + case LLDrawPool::POOL_GROUND: + poolp = mGroundPool; + break; + + case LLDrawPool::POOL_WL_SKY: + poolp = mWLSkyPool; + break; + + default: + llassert(0); + llerrs << "Invalid Pool Type in LLPipeline::findPool() type=" << type << llendl; + break; + } + + return poolp; +} + + +LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerTexture *tex0) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLDrawPool *poolp = findPool(type, tex0); + if (poolp) + { + return poolp; + } + + LLDrawPool *new_poolp = LLDrawPool::createPool(type, tex0); + addPool( new_poolp ); + + return new_poolp; +} + + +// static +LLDrawPool* LLPipeline::getPoolFromTE(const LLTextureEntry* te, LLViewerTexture* imagep) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE); + U32 type = getPoolTypeFromTE(te, imagep); + return gPipeline.getPool(type, imagep); +} + +//static +U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* imagep) +{ + LLMemType mt_gpt(LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE); + + if (!te || !imagep) + { + return 0; + } + + bool alpha = te->getColor().mV[3] < 0.999f; + if (imagep) + { + alpha = alpha || (imagep->getComponents() == 4 && imagep->getType() != LLViewerTexture::MEDIA_TEXTURE) || (imagep->getComponents() == 2); + } + + if (alpha) + { + return LLDrawPool::POOL_ALPHA; + } + else if ((te->getBumpmap() || te->getShiny())) + { + return LLDrawPool::POOL_BUMP; + } + else + { + return LLDrawPool::POOL_SIMPLE; + } +} + + +void LLPipeline::addPool(LLDrawPool *new_poolp) +{ + LLMemType mt_a(LLMemType::MTYPE_PIPELINE_ADD_POOL); + assertInitialized(); + mPools.insert(new_poolp); + addToQuickLookup( new_poolp ); +} + +void LLPipeline::allocDrawable(LLViewerObject *vobj) +{ + LLMemType mt_ad(LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE); + LLDrawable *drawable = new LLDrawable(); + vobj->mDrawable = drawable; + + drawable->mVObjp = vobj; + + //encompass completely sheared objects by taking + //the most extreme point possible (<1,1,0.5>) + drawable->setRadius(LLVector3(1,1,0.5f).scaleVec(vobj->getScale()).length()); + if (vobj->isOrphaned()) + { + drawable->setState(LLDrawable::FORCE_INVISIBLE); + } + drawable->updateXform(TRUE); +} + + +static LLFastTimer::DeclareTimer FTM_UNLINK("Unlink"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_MOVE_LIST("Movelist"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_LIGHT_SET("Light Set"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set"); + +void LLPipeline::unlinkDrawable(LLDrawable *drawable) +{ + LLFastTimer t(FTM_UNLINK); + + assertInitialized(); + + LLPointer drawablep = drawable; // make sure this doesn't get deleted before we are done + + // Based on flags, remove the drawable from the queues that it's on. + if (drawablep->isState(LLDrawable::ON_MOVE_LIST)) + { + LLFastTimer t(FTM_REMOVE_FROM_MOVE_LIST); + LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep); + if (iter != mMovedList.end()) + { + mMovedList.erase(iter); + } + } + + if (drawablep->getSpatialGroup()) + { + LLFastTimer t(FTM_REMOVE_FROM_SPATIAL_PARTITION); + if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup())) + { +#ifdef LL_RELEASE_FOR_DOWNLOAD + llwarns << "Couldn't remove object from spatial group!" << llendl; +#else + llerrs << "Couldn't remove object from spatial group!" << llendl; +#endif + } + } + + { + LLFastTimer t(FTM_REMOVE_FROM_LIGHT_SET); + mLights.erase(drawablep); + + for (light_set_t::iterator iter = mNearbyLights.begin(); + iter != mNearbyLights.end(); iter++) + { + if (iter->drawable == drawablep) + { + mNearbyLights.erase(iter); + break; + } + } + } + + { + LLFastTimer t(FTM_REMOVE_FROM_HIGHLIGHT_SET); + HighlightItem item(drawablep); + mHighlightSet.erase(item); + + if (mHighlightObject == drawablep) + { + mHighlightObject = NULL; + } + } + + for (U32 i = 0; i < 2; ++i) + { + if (mShadowSpotLight[i] == drawablep) + { + mShadowSpotLight[i] = NULL; + } + + if (mTargetShadowSpotLight[i] == drawablep) + { + mTargetShadowSpotLight[i] = NULL; + } + } + + +} + +U32 LLPipeline::addObject(LLViewerObject *vobj) +{ + LLMemType mt_ao(LLMemType::MTYPE_PIPELINE_ADD_OBJECT); + if (gNoRender) + { + return 0; + } + + if (gSavedSettings.getBOOL("RenderDelayCreation")) + { + mCreateQ.push_back(vobj); + } + else + { + createObject(vobj); + } + + return 1; +} + +void LLPipeline::createObjects(F32 max_dtime) +{ + LLFastTimer ftm(FTM_GEO_UPDATE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS); + + LLTimer update_timer; + + while (!mCreateQ.empty() && update_timer.getElapsedTimeF32() < max_dtime) + { + LLViewerObject* vobj = mCreateQ.front(); + if (!vobj->isDead()) + { + createObject(vobj); + } + mCreateQ.pop_front(); + } + + //for (LLViewerObject::vobj_list_t::iterator iter = mCreateQ.begin(); iter != mCreateQ.end(); ++iter) + //{ + // createObject(*iter); + //} + + //mCreateQ.clear(); +} + +void LLPipeline::createObject(LLViewerObject* vobj) +{ + LLDrawable* drawablep = vobj->mDrawable; + + if (!drawablep) + { + drawablep = vobj->createDrawable(this); + } + else + { + llerrs << "Redundant drawable creation!" << llendl; + } + + llassert(drawablep); + + if (vobj->getParent()) + { + vobj->setDrawableParent(((LLViewerObject*)vobj->getParent())->mDrawable); // LLPipeline::addObject 1 + } + else + { + vobj->setDrawableParent(NULL); // LLPipeline::addObject 2 + } + + markRebuild(drawablep, LLDrawable::REBUILD_ALL, TRUE); + + if (drawablep->getVOVolume() && gSavedSettings.getBOOL("RenderAnimateRes")) + { + // fun animated res + drawablep->updateXform(TRUE); + drawablep->clearState(LLDrawable::MOVE_UNDAMPED); + drawablep->setScale(LLVector3(0,0,0)); + drawablep->makeActive(); + } +} + + +void LLPipeline::resetFrameStats() +{ + assertInitialized(); + + LLViewerStats::getInstance()->mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f); + + if (mBatchCount > 0) + { + mMeanBatchSize = gPipeline.mTrianglesDrawn/gPipeline.mBatchCount; + } + mTrianglesDrawn = 0; + sCompiles = 0; + mVerticesRelit = 0; + mLightingChanges = 0; + mGeometryChanges = 0; + mNumVisibleFaces = 0; + + if (mOldRenderDebugMask != mRenderDebugMask) + { + gObjectList.clearDebugText(); + mOldRenderDebugMask = mRenderDebugMask; + } + +} + +//external functions for asynchronous updating +void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep) +{ + if (gSavedSettings.getBOOL("FreezeTime")) + { + return; + } + if (!drawablep) + { + llerrs << "updateMove called with NULL drawablep" << llendl; + return; + } + if (drawablep->isState(LLDrawable::EARLY_MOVE)) + { + return; + } + + assertInitialized(); + + // update drawable now + drawablep->clearState(LLDrawable::MOVE_UNDAMPED); // force to DAMPED + drawablep->updateMove(); // returns done + drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame + // Put on move list so that EARLY_MOVE gets cleared + if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) + { + mMovedList.push_back(drawablep); + drawablep->setState(LLDrawable::ON_MOVE_LIST); + } +} + +void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep) +{ + if (gSavedSettings.getBOOL("FreezeTime")) + { + return; + } + if (!drawablep) + { + llerrs << "updateMove called with NULL drawablep" << llendl; + return; + } + if (drawablep->isState(LLDrawable::EARLY_MOVE)) + { + return; + } + + assertInitialized(); + + // update drawable now + drawablep->setState(LLDrawable::MOVE_UNDAMPED); // force to UNDAMPED + drawablep->updateMove(); + drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame + // Put on move list so that EARLY_MOVE gets cleared + if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) + { + mMovedList.push_back(drawablep); + drawablep->setState(LLDrawable::ON_MOVE_LIST); + } +} + +void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list) +{ + for (LLDrawable::drawable_vector_t::iterator iter = moved_list.begin(); + iter != moved_list.end(); ) + { + LLDrawable::drawable_vector_t::iterator curiter = iter++; + LLDrawable *drawablep = *curiter; + BOOL done = TRUE; + if (!drawablep->isDead() && (!drawablep->isState(LLDrawable::EARLY_MOVE))) + { + done = drawablep->updateMove(); + } + drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED); + if (done) + { + drawablep->clearState(LLDrawable::ON_MOVE_LIST); + iter = moved_list.erase(curiter); + } + } +} + +static LLFastTimer::DeclareTimer FTM_OCTREE_BALANCE("Balance Octree"); +static LLFastTimer::DeclareTimer FTM_UPDATE_MOVE("Update Move"); + +void LLPipeline::updateMove() +{ + LLFastTimer t(FTM_UPDATE_MOVE); + LLMemType mt_um(LLMemType::MTYPE_PIPELINE_UPDATE_MOVE); + + if (gSavedSettings.getBOOL("FreezeTime")) + { + return; + } + + assertInitialized(); + + { + static LLFastTimer::DeclareTimer ftm("Retexture"); + LLFastTimer t(ftm); + + for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin(); + iter != mRetexturedList.end(); ++iter) + { + LLDrawable* drawablep = *iter; + if (drawablep && !drawablep->isDead()) + { + drawablep->updateTexture(); + } + } + mRetexturedList.clear(); + } + + { + static LLFastTimer::DeclareTimer ftm("Moved List"); + LLFastTimer t(ftm); + updateMovedList(mMovedList); + } + + //balance octrees + { + LLFastTimer ot(FTM_OCTREE_BALANCE); + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + part->mOctree->balance(); + } + } + } + } +} + +///////////////////////////////////////////////////////////////////////////// +// Culling and occlusion testing +///////////////////////////////////////////////////////////////////////////// + +//static +F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera) +{ + LLVector3 lookAt = center - camera.getOrigin(); + F32 dist = lookAt.length(); + + //ramp down distance for nearby objects + //shrink dist by dist/16. + if (dist < 16.f) + { + dist /= 16.f; + dist *= dist; + dist *= 16.f; + } + + //get area of circle around node + F32 app_angle = atanf(size.length()/dist); + F32 radius = app_angle*LLDrawable::sCurPixelAngle; + return radius*radius * F_PI; +} + +//static +F32 LLPipeline::calcPixelArea(const LLVector4a& center, const LLVector4a& size, LLCamera &camera) +{ + LLVector4a origin; + origin.load3(camera.getOrigin().mV); + + LLVector4a lookAt; + lookAt.setSub(center, origin); + F32 dist = lookAt.getLength3().getF32(); + + //ramp down distance for nearby objects + //shrink dist by dist/16. + if (dist < 16.f) + { + dist /= 16.f; + dist *= dist; + dist *= 16.f; + } + + //get area of circle around node + F32 app_angle = atanf(size.getLength3().getF32()/dist); + F32 radius = app_angle*LLDrawable::sCurPixelAngle; + return radius*radius * F_PI; +} + +void LLPipeline::grabReferences(LLCullResult& result) +{ + sCull = &result; +} + +void LLPipeline::clearReferences() +{ + sCull = NULL; +} + +void check_references(LLSpatialGroup* group, LLDrawable* drawable) +{ + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + { + if (drawable == *i) + { + llerrs << "LLDrawable deleted while actively reference by LLPipeline." << llendl; + } + } +} + +void check_references(LLDrawable* drawable, LLFace* face) +{ + for (S32 i = 0; i < drawable->getNumFaces(); ++i) + { + if (drawable->getFace(i) == face) + { + llerrs << "LLFace deleted while actively referenced by LLPipeline." << llendl; + } + } +} + +void check_references(LLSpatialGroup* group, LLFace* face) +{ + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + { + LLDrawable* drawable = *i; + check_references(drawable, face); + } +} + +void LLPipeline::checkReferences(LLFace* face) +{ +#if 0 + if (sCull) + { + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, face); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, face); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, face); + } + + for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) + { + LLDrawable* drawable = *iter; + check_references(drawable, face); + } + } +#endif +} + +void LLPipeline::checkReferences(LLDrawable* drawable) +{ +#if 0 + if (sCull) + { + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, drawable); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, drawable); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, drawable); + } + + for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) + { + if (drawable == *iter) + { + llerrs << "LLDrawable deleted while actively referenced by LLPipeline." << llendl; + } + } + } +#endif +} + +void check_references(LLSpatialGroup* group, LLDrawInfo* draw_info) +{ + for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) + { + LLSpatialGroup::drawmap_elem_t& draw_vec = i->second; + for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j) + { + LLDrawInfo* params = *j; + if (params == draw_info) + { + llerrs << "LLDrawInfo deleted while actively referenced by LLPipeline." << llendl; + } + } + } +} + + +void LLPipeline::checkReferences(LLDrawInfo* draw_info) +{ +#if 0 + if (sCull) + { + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, draw_info); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, draw_info); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, draw_info); + } + } +#endif +} + +void LLPipeline::checkReferences(LLSpatialGroup* group) +{ +#if 0 + if (sCull) + { + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + if (group == *iter) + { + llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; + } + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + { + if (group == *iter) + { + llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; + } + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + { + if (group == *iter) + { + llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; + } + } + } +#endif +} + + +BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera) +{ + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + if (hasRenderType(part->mDrawableType)) + { + if (part->visibleObjectsInFrustum(camera)) + { + return TRUE; + } + } + } + } + } + + return FALSE; +} + +BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& max) +{ + const F32 X = 65536.f; + + min = LLVector3(X,X,X); + max = LLVector3(-X,-X,-X); + + U32 saved_camera_id = LLViewerCamera::sCurCameraID; + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + + BOOL res = TRUE; + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + if (hasRenderType(part->mDrawableType)) + { + if (!part->getVisibleExtents(camera, min, max)) + { + res = FALSE; + } + } + } + } + } + + LLViewerCamera::sCurCameraID = saved_camera_id; + + return res; +} + +static LLFastTimer::DeclareTimer FTM_CULL("Object Culling"); + +void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip) +{ + LLFastTimer t(FTM_CULL); + LLMemType mt_uc(LLMemType::MTYPE_PIPELINE_UPDATE_CULL); + + grabReferences(result); + + sCull->clear(); + + BOOL to_texture = LLPipeline::sUseOcclusion > 1 && + !hasRenderType(LLPipeline::RENDER_TYPE_HUD) && + LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && + gPipeline.canUseVertexShaders() && + sRenderGlow; + + if (to_texture) + { + mScreen.bindTarget(); + } + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadMatrixd(gGLLastProjection); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + gGLLastMatrix = NULL; + glLoadMatrixd(gGLLastModelView); + + + LLVertexBuffer::unbind(); + LLGLDisable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + if (sUseOcclusion > 1) + { + gGL.setColorMask(false, false); + } + + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + if (water_clip != 0) + { + LLPlane plane(LLVector3(0,0, (F32) -water_clip), (F32) water_clip*region->getWaterHeight()); + camera.setUserClipPlane(plane); + } + else + { + camera.disableUserClipPlane(); + } + + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + if (hasRenderType(part->mDrawableType)) + { + part->cull(camera); + } + } + } + } + + camera.disableUserClipPlane(); + + if (hasRenderType(LLPipeline::RENDER_TYPE_SKY) && + gSky.mVOSkyp.notNull() && + gSky.mVOSkyp->mDrawable.notNull()) + { + gSky.mVOSkyp->mDrawable->setVisible(camera); + sCull->pushDrawable(gSky.mVOSkyp->mDrawable); + gSky.updateCull(); + stop_glerror(); + } + + if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) && + !gPipeline.canUseWindLightShaders() && + gSky.mVOGroundp.notNull() && + gSky.mVOGroundp->mDrawable.notNull() && + !LLPipeline::sWaterReflections) + { + gSky.mVOGroundp->mDrawable->setVisible(camera); + sCull->pushDrawable(gSky.mVOGroundp->mDrawable); + } + + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + if (sUseOcclusion > 1) + { + gGL.setColorMask(true, false); + } + + if (to_texture) + { + mScreen.flush(); + } +} + +void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera) +{ + if (group->getData().empty()) + { + return; + } + + group->setVisible(); + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + { + group->updateDistance(camera); + } + + const F32 MINIMUM_PIXEL_AREA = 16.f; + + if (group->mPixelArea < MINIMUM_PIXEL_AREA) + { + return; + } + + if (sMinRenderSize > 0.f && + llmax(llmax(group->mBounds[1][0], group->mBounds[1][1]), group->mBounds[1][2]) < sMinRenderSize) + { + return; + } + + assertInitialized(); + + if (!group->mSpatialPartition->mRenderByGroup) + { //render by drawable + sCull->pushDrawableGroup(group); + } + else + { //render by group + sCull->pushVisibleGroup(group); + } + + mNumVisibleNodes++; +} + +void LLPipeline::markOccluder(LLSpatialGroup* group) +{ + if (sUseOcclusion > 1 && group && !group->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION)) + { + LLSpatialGroup* parent = group->getParent(); + + if (!parent || !parent->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { //only mark top most occluders as active occlusion + sCull->pushOcclusionGroup(group); + group->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION); + + if (parent && + !parent->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION) && + parent->getElementCount() == 0 && + parent->needsUpdate()) + { + sCull->pushOcclusionGroup(group); + parent->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION); + } + } + } +} + +void LLPipeline::doOcclusion(LLCamera& camera) +{ + if (LLPipeline::sUseOcclusion > 1 && sCull->hasOcclusionGroups()) + { + LLVertexBuffer::unbind(); + + if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION)) + { + gGL.setColorMask(true, false, false, false); + } + else + { + gGL.setColorMask(false, false); + } + LLGLDisable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + + LLGLDisable cull(GL_CULL_FACE); + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + group->doOcclusion(&camera); + group->clearOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION); + } + + gGL.setColorMask(true, false); + } +} + +BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority) +{ + BOOL update_complete = drawablep->updateGeometry(priority); + if (update_complete && assertInitialized()) + { + drawablep->setState(LLDrawable::BUILT); + mGeometryChanges++; + } + return update_complete; +} + +void LLPipeline::updateGL() +{ + while (!LLGLUpdate::sGLQ.empty()) + { + LLGLUpdate* glu = LLGLUpdate::sGLQ.front(); + glu->updateGL(); + glu->mInQ = FALSE; + LLGLUpdate::sGLQ.pop_front(); + } +} + +void LLPipeline::rebuildPriorityGroups() +{ + LLTimer update_timer; + LLMemType mt(LLMemType::MTYPE_PIPELINE); + + assertInitialized(); + + gMeshRepo.notifyLoadedMeshes(); + + mGroupQ1Locked = true; + // Iterate through all drawables on the priority build queue, + for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ1.begin(); + iter != mGroupQ1.end(); ++iter) + { + LLSpatialGroup* group = *iter; + group->rebuildGeom(); + group->clearState(LLSpatialGroup::IN_BUILD_Q1); + } + + mGroupQ1.clear(); + mGroupQ1Locked = false; + +} + +void LLPipeline::rebuildGroups() +{ + if (mGroupQ2.empty()) + { + return; + } + + mGroupQ2Locked = true; + // Iterate through some drawables on the non-priority build queue + S32 size = (S32) mGroupQ2.size(); + S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size); + + S32 count = 0; + + std::sort(mGroupQ2.begin(), mGroupQ2.end(), LLSpatialGroup::CompareUpdateUrgency()); + + LLSpatialGroup::sg_vector_t::iterator iter; + LLSpatialGroup::sg_vector_t::iterator last_iter = mGroupQ2.begin(); + + for (iter = mGroupQ2.begin(); + iter != mGroupQ2.end() && count <= min_count; ++iter) + { + LLSpatialGroup* group = *iter; + last_iter = iter; + + if (!group->isDead()) + { + group->rebuildGeom(); + + if (group->mSpatialPartition->mRenderByGroup) + { + count++; + } + } + + group->clearState(LLSpatialGroup::IN_BUILD_Q2); + } + + mGroupQ2.erase(mGroupQ2.begin(), ++last_iter); + + mGroupQ2Locked = false; + + updateMovedList(mMovedBridge); +} + +void LLPipeline::updateGeom(F32 max_dtime) +{ + LLTimer update_timer; + LLMemType mt(LLMemType::MTYPE_PIPELINE_UPDATE_GEOM); + LLPointer drawablep; + + LLFastTimer t(FTM_GEO_UPDATE); + + assertInitialized(); + + if (sDelayedVBOEnable > 0) + { + if (--sDelayedVBOEnable <= 0) + { + resetVertexBuffers(); + LLVertexBuffer::sEnableVBOs = TRUE; + } + } + + // notify various object types to reset internal cost metrics, etc. + // for now, only LLVOVolume does this to throttle LOD changes + LLVOVolume::preUpdateGeom(); + + // Iterate through all drawables on the priority build queue, + for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin(); + iter != mBuildQ1.end();) + { + LLDrawable::drawable_list_t::iterator curiter = iter++; + LLDrawable* drawablep = *curiter; + if (drawablep && !drawablep->isDead()) + { + if (drawablep->isState(LLDrawable::IN_REBUILD_Q2)) + { + drawablep->clearState(LLDrawable::IN_REBUILD_Q2); + LLDrawable::drawable_list_t::iterator find = std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep); + if (find != mBuildQ2.end()) + { + mBuildQ2.erase(find); + } + } + + if (updateDrawableGeom(drawablep, TRUE)) + { + drawablep->clearState(LLDrawable::IN_REBUILD_Q1); + mBuildQ1.erase(curiter); + } + } + else + { + mBuildQ1.erase(curiter); + } + } + + // Iterate through some drawables on the non-priority build queue + S32 min_count = 16; + S32 size = (S32) mBuildQ2.size(); + if (size > 1024) + { + min_count = llclamp((S32) (size * (F32) size/4096), 16, size); + } + + S32 count = 0; + + max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, max_dtime); + LLSpatialGroup* last_group = NULL; + LLSpatialBridge* last_bridge = NULL; + + for (LLDrawable::drawable_list_t::iterator iter = mBuildQ2.begin(); + iter != mBuildQ2.end(); ) + { + LLDrawable::drawable_list_t::iterator curiter = iter++; + LLDrawable* drawablep = *curiter; + + LLSpatialBridge* bridge = drawablep->isRoot() ? drawablep->getSpatialBridge() : + drawablep->getParent()->getSpatialBridge(); + + if (drawablep->getSpatialGroup() != last_group && + (!last_bridge || bridge != last_bridge) && + (update_timer.getElapsedTimeF32() >= max_dtime) && count > min_count) + { + break; + } + + //make sure updates don't stop in the middle of a spatial group + //to avoid thrashing (objects are enqueued by group) + last_group = drawablep->getSpatialGroup(); + last_bridge = bridge; + + BOOL update_complete = TRUE; + if (!drawablep->isDead()) + { + update_complete = updateDrawableGeom(drawablep, FALSE); + count++; + } + if (update_complete) + { + drawablep->clearState(LLDrawable::IN_REBUILD_Q2); + mBuildQ2.erase(curiter); + } + } + + updateMovedList(mMovedBridge); +} + +void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_VISIBLE); + + if(drawablep && !drawablep->isDead()) + { + if (drawablep->isSpatialBridge()) + { + const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable; + llassert(root); // trying to catch a bad assumption + if (root && // // this test may not be needed, see above + root->getVObj()->isAttachment()) + { + LLDrawable* rootparent = root->getParent(); + if (rootparent) // this IS sometimes NULL + { + LLViewerObject *vobj = rootparent->getVObj(); + llassert(vobj); // trying to catch a bad assumption + if (vobj) // this test may not be needed, see above + { + const LLVOAvatar* av = vobj->asAvatar(); + if (av && av->isImpostor()) + { + return; + } + } + } + } + sCull->pushBridge((LLSpatialBridge*) drawablep); + } + else + { + sCull->pushDrawable(drawablep); + } + + drawablep->setVisible(camera); + } +} + +void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion) +{ + LLMemType mt_mm(LLMemType::MTYPE_PIPELINE_MARK_MOVED); + + if (!drawablep) + { + //llerrs << "Sending null drawable to moved list!" << llendl; + return; + } + + if (drawablep->isDead()) + { + llwarns << "Marking NULL or dead drawable moved!" << llendl; + return; + } + + if (drawablep->getParent()) + { + //ensure that parent drawables are moved first + markMoved(drawablep->getParent(), damped_motion); + } + + assertInitialized(); + + if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) + { + if (drawablep->isSpatialBridge()) + { + mMovedBridge.push_back(drawablep); + } + else + { + mMovedList.push_back(drawablep); + } + drawablep->setState(LLDrawable::ON_MOVE_LIST); + } + if (damped_motion == FALSE) + { + drawablep->setState(LLDrawable::MOVE_UNDAMPED); // UNDAMPED trumps DAMPED + } + else if (drawablep->isState(LLDrawable::MOVE_UNDAMPED)) + { + drawablep->clearState(LLDrawable::MOVE_UNDAMPED); + } +} + +void LLPipeline::markShift(LLDrawable *drawablep) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_SHIFT); + + if (!drawablep || drawablep->isDead()) + { + return; + } + + assertInitialized(); + + if (!drawablep->isState(LLDrawable::ON_SHIFT_LIST)) + { + drawablep->getVObj()->setChanged(LLXform::SHIFTED | LLXform::SILHOUETTE); + if (drawablep->getParent()) + { + markShift(drawablep->getParent()); + } + mShiftList.push_back(drawablep); + drawablep->setState(LLDrawable::ON_SHIFT_LIST); + } +} + +void LLPipeline::shiftObjects(const LLVector3 &offset) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS); + + assertInitialized(); + + glClear(GL_DEPTH_BUFFER_BIT); + gDepthDirty = TRUE; + + LLVector4a offseta; + offseta.load3(offset.mV); + + for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin(); + iter != mShiftList.end(); iter++) + { + LLDrawable *drawablep = *iter; + if (drawablep->isDead()) + { + continue; + } + drawablep->shiftPos(offseta); + drawablep->clearState(LLDrawable::ON_SHIFT_LIST); + } + mShiftList.resize(0); + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + part->shift(offseta); + } + } + } + + LLHUDText::shiftAll(offset); + LLHUDNameTag::shiftAll(offset); + display_update_camera(); +} + +void LLPipeline::markTextured(LLDrawable *drawablep) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_TEXTURED); + + if (drawablep && !drawablep->isDead() && assertInitialized()) + { + mRetexturedList.insert(drawablep); + } +} + +void LLPipeline::markGLRebuild(LLGLUpdate* glu) +{ + if (glu && !glu->mInQ) + { + LLGLUpdate::sGLQ.push_back(glu); + glu->mInQ = TRUE; + } +} + +void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE); + + if (group && !group->isDead() && group->mSpatialPartition) + { + if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD) + { + priority = TRUE; + } + + if (priority) + { + if (!group->isState(LLSpatialGroup::IN_BUILD_Q1)) + { + llassert_always(!mGroupQ1Locked); + + mGroupQ1.push_back(group); + group->setState(LLSpatialGroup::IN_BUILD_Q1); + + if (group->isState(LLSpatialGroup::IN_BUILD_Q2)) + { + LLSpatialGroup::sg_vector_t::iterator iter = std::find(mGroupQ2.begin(), mGroupQ2.end(), group); + if (iter != mGroupQ2.end()) + { + mGroupQ2.erase(iter); + } + group->clearState(LLSpatialGroup::IN_BUILD_Q2); + } + } + } + else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1)) + { + llassert_always(!mGroupQ2Locked); + mGroupQ2.push_back(group); + group->setState(LLSpatialGroup::IN_BUILD_Q2); + + } + } +} + +void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag, BOOL priority) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD); + + if (drawablep && !drawablep->isDead() && assertInitialized()) + { + if (!drawablep->isState(LLDrawable::BUILT)) + { + priority = TRUE; + } + if (priority) + { + if (!drawablep->isState(LLDrawable::IN_REBUILD_Q1)) + { + mBuildQ1.push_back(drawablep); + drawablep->setState(LLDrawable::IN_REBUILD_Q1); // mark drawable as being in priority queue + } + } + else if (!drawablep->isState(LLDrawable::IN_REBUILD_Q2)) + { + mBuildQ2.push_back(drawablep); + drawablep->setState(LLDrawable::IN_REBUILD_Q2); // need flag here because it is just a list + } + if (flag & (LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION)) + { + drawablep->getVObj()->setChanged(LLXform::SILHOUETTE); + } + drawablep->setState(flag); + } +} + +static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order"); + +void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) +{ + if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_GROUND, + LLPipeline::RENDER_TYPE_TERRAIN, + LLPipeline::RENDER_TYPE_TREE, + LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_VOIDWATER, + LLPipeline::RENDER_TYPE_WATER, + LLPipeline::END_RENDER_TYPES)) + { + //clear faces from face pools + LLFastTimer t(FTM_RESET_DRAWORDER); + gPipeline.resetDrawOrders(); + } + + LLFastTimer ftm(FTM_STATESORT); + LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); + + //LLVertexBuffer::unbind(); + + grabReferences(result); + for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + group->checkOcclusion(); + if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { + markOccluder(group); + } + else + { + group->setVisible(); + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + { + markVisible(*i, camera); + } + } + } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + { + LLSpatialGroup* last_group = NULL; + for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) + { + LLCullResult::bridge_list_t::iterator cur_iter = i; + LLSpatialBridge* bridge = *cur_iter; + LLSpatialGroup* group = bridge->getSpatialGroup(); + + if (last_group == NULL) + { + last_group = group; + } + + if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { + stateSort(bridge, camera); + } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && + last_group != group && last_group->changeLOD()) + { + last_group->mLastUpdateDistance = last_group->mDistance; + } + + last_group = group; + } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && + last_group && last_group->changeLOD()) + { + last_group->mLastUpdateDistance = last_group->mDistance; + } + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + group->checkOcclusion(); + if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { + markOccluder(group); + } + else + { + group->setVisible(); + stateSort(group, camera); + } + } + + { + LLFastTimer ftm(FTM_STATESORT_DRAWABLE); + for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); + iter != sCull->endVisibleList(); ++iter) + { + LLDrawable *drawablep = *iter; + if (!drawablep->isDead()) + { + stateSort(drawablep, camera); + } + } + } + { + LLFastTimer ftm(FTM_CLIENT_COPY); + LLVertexBuffer::clientCopy(); + } + + postSort(camera); +} + +void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); + if (group->changeLOD()) + { + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + { + LLDrawable* drawablep = *i; + stateSort(drawablep, camera); + } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + { //avoid redundant stateSort calls + group->mLastUpdateDistance = group->mDistance; + } + } + +} + +void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); + if (bridge->getSpatialGroup()->changeLOD()) + { + bool force_update = false; + bridge->updateDistance(camera, force_update); + } +} + +void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); + + if (!drawablep + || drawablep->isDead() + || !hasRenderType(drawablep->getRenderType())) + { + return; + } + + if (LLSelectMgr::getInstance()->mHideSelectedObjects) + { + if (drawablep->getVObj().notNull() && + drawablep->getVObj()->isSelected()) + { + return; + } + } + + if (drawablep->isAvatar()) + { //don't draw avatars beyond render distance or if we don't have a spatial group. + if ((drawablep->getSpatialGroup() == NULL) || + (drawablep->getSpatialGroup()->mDistance > LLVOAvatar::sRenderDistance)) + { + return; + } + + LLVOAvatar* avatarp = (LLVOAvatar*) drawablep->getVObj().get(); + if (!avatarp->isVisible()) + { + return; + } + } + + assertInitialized(); + + if (hasRenderType(drawablep->mRenderType)) + { + if (!drawablep->isState(LLDrawable::INVISIBLE|LLDrawable::FORCE_INVISIBLE)) + { + drawablep->setVisible(camera, NULL, FALSE); + } + else if (drawablep->isState(LLDrawable::CLEAR_INVISIBLE)) + { + // clear invisible flag here to avoid single frame glitch + drawablep->clearState(LLDrawable::FORCE_INVISIBLE|LLDrawable::CLEAR_INVISIBLE); + } + } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + { + if (drawablep->isVisible()) + { + if (!drawablep->isActive()) + { + bool force_update = false; + drawablep->updateDistance(camera, force_update); + } + else if (drawablep->isAvatar()) + { + bool force_update = false; + drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility() + } + } + } + + if (!drawablep->getVOVolume()) + { + for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin(); + iter != drawablep->mFaces.end(); iter++) + { + LLFace* facep = *iter; + + if (facep->hasGeometry()) + { + if (facep->getPool()) + { + facep->getPool()->enqueue(facep); + } + else + { + break; + } + } + } + } + + + mNumVisibleFaces += drawablep->getNumFaces(); +} + + +void forAllDrawables(LLCullResult::sg_list_t::iterator begin, + LLCullResult::sg_list_t::iterator end, + void (*func)(LLDrawable*)) +{ + for (LLCullResult::sg_list_t::iterator i = begin; i != end; ++i) + { + for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j) + { + func(*j); + } + } +} + +void LLPipeline::forAllVisibleDrawables(void (*func)(LLDrawable*)) +{ + forAllDrawables(sCull->beginDrawableGroups(), sCull->endDrawableGroups(), func); + forAllDrawables(sCull->beginVisibleGroups(), sCull->endVisibleGroups(), func); +} + +//function for creating scripted beacons +void renderScriptedBeacons(LLDrawable* drawablep) +{ + LLViewerObject *vobj = drawablep->getVObj(); + if (vobj + && !vobj->isAvatar() + && !vobj->getParent() + && vobj->flagScripted()) + { + if (gPipeline.sRenderBeacons) + { + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); + } + + if (gPipeline.sRenderHighlight) + { + S32 face_id; + S32 count = drawablep->getNumFaces(); + for (face_id = 0; face_id < count; face_id++) + { + gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + } + } + } +} + +void renderScriptedTouchBeacons(LLDrawable* drawablep) +{ + LLViewerObject *vobj = drawablep->getVObj(); + if (vobj + && !vobj->isAvatar() + && !vobj->getParent() + && vobj->flagScripted() + && vobj->flagHandleTouch()) + { + if (gPipeline.sRenderBeacons) + { + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); + } + + if (gPipeline.sRenderHighlight) + { + S32 face_id; + S32 count = drawablep->getNumFaces(); + for (face_id = 0; face_id < count; face_id++) + { + gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + } + } + } +} + +void renderPhysicalBeacons(LLDrawable* drawablep) +{ + LLViewerObject *vobj = drawablep->getVObj(); + if (vobj + && !vobj->isAvatar() + //&& !vobj->getParent() + && vobj->usePhysics()) + { + if (gPipeline.sRenderBeacons) + { + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); + } + + if (gPipeline.sRenderHighlight) + { + S32 face_id; + S32 count = drawablep->getNumFaces(); + for (face_id = 0; face_id < count; face_id++) + { + gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + } + } + } +} + +void renderParticleBeacons(LLDrawable* drawablep) +{ + // Look for attachments, objects, etc. + LLViewerObject *vobj = drawablep->getVObj(); + if (vobj + && vobj->isParticleSource()) + { + if (gPipeline.sRenderBeacons) + { + LLColor4 light_blue(0.5f, 0.5f, 1.f, 0.5f); + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); + } + + if (gPipeline.sRenderHighlight) + { + S32 face_id; + S32 count = drawablep->getNumFaces(); + for (face_id = 0; face_id < count; face_id++) + { + gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + } + } + } +} + +void renderSoundHighlights(LLDrawable* drawablep) +{ + // Look for attachments, objects, etc. + LLViewerObject *vobj = drawablep->getVObj(); + if (vobj && vobj->isAudioSource()) + { + if (gPipeline.sRenderHighlight) + { + S32 face_id; + S32 count = drawablep->getNumFaces(); + for (face_id = 0; face_id < count; face_id++) + { + gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + } + } + } +} + +void LLPipeline::postSort(LLCamera& camera) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_POST_SORT); + LLFastTimer ftm(FTM_STATESORT_POSTSORT); + + assertInitialized(); + + llpushcallstacks ; + //rebuild drawable geometry + for (LLCullResult::sg_list_t::iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i) + { + LLSpatialGroup* group = *i; + if (!sUseOcclusion || + !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { + group->rebuildGeom(); + } + } + llpushcallstacks ; + //rebuild groups + sCull->assertDrawMapsEmpty(); + + rebuildPriorityGroups(); + llpushcallstacks ; + + const S32 bin_count = 1024*8; + + static LLCullResult::drawinfo_list_t alpha_bins[bin_count]; + static U32 bin_size[bin_count]; + + //clear one bin per frame to avoid memory bloat + static S32 clear_idx = 0; + clear_idx = (1+clear_idx)%bin_count; + alpha_bins[clear_idx].clear(); + + for (U32 j = 0; j < bin_count; j++) + { + bin_size[j] = 0; + } + + //build render map + for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) + { + LLSpatialGroup* group = *i; + if (sUseOcclusion && + group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { + continue; + } + + if (group->isState(LLSpatialGroup::NEW_DRAWINFO) && group->isState(LLSpatialGroup::GEOM_DIRTY)) + { //no way this group is going to be drawable without a rebuild + group->rebuildGeom(); + } + + for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j) + { + LLSpatialGroup::drawmap_elem_t& src_vec = j->second; + if (!hasRenderType(j->first)) + { + continue; + } + + for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k) + { + if (sMinRenderSize > 0.f) + { + LLVector4a bounds; + bounds.setSub((*k)->mExtents[1],(*k)->mExtents[0]); + + if (llmax(llmax(bounds[0], bounds[1]), bounds[2]) > sMinRenderSize) + { + sCull->pushDrawInfo(j->first, *k); + } + } + else + { + sCull->pushDrawInfo(j->first, *k); + } + } + } + + if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA)) + { + LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA); + + if (alpha != group->mDrawMap.end()) + { //store alpha groups for sorting + LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + { + if (bridge) + { + LLCamera trans_camera = bridge->transformCamera(camera); + group->updateDistance(trans_camera); + } + else + { + group->updateDistance(camera); + } + } + + if (hasRenderType(LLDrawPool::POOL_ALPHA)) + { + sCull->pushAlphaGroup(group); + } + } + } + } + + if (!sShadowRender) + { + //sort by texture or bump map + for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; ++i) + { + if (i == LLRenderPass::PASS_BUMP) + { + std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareBump()); + } + else + { + std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareTexturePtrMatrix()); + } + } + + std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater()); + } + llpushcallstacks ; + // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus + if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender) + { + if (sRenderScriptedTouchBeacons) + { + // Only show the beacon on the root object. + forAllVisibleDrawables(renderScriptedTouchBeacons); + } + else + if (sRenderScriptedBeacons) + { + // Only show the beacon on the root object. + forAllVisibleDrawables(renderScriptedBeacons); + } + + if (sRenderPhysicalBeacons) + { + // Only show the beacon on the root object. + forAllVisibleDrawables(renderPhysicalBeacons); + } + + if (sRenderParticleBeacons) + { + forAllVisibleDrawables(renderParticleBeacons); + } + + // If god mode, also show audio cues + if (sRenderSoundBeacons && gAudiop) + { + // Walk all sound sources and render out beacons for them. Note, this isn't done in the ForAllVisibleDrawables function, because some are not visible. + LLAudioEngine::source_map::iterator iter; + for (iter = gAudiop->mAllSources.begin(); iter != gAudiop->mAllSources.end(); ++iter) + { + LLAudioSource *sourcep = iter->second; + + LLVector3d pos_global = sourcep->getPositionGlobal(); + LLVector3 pos = gAgent.getPosAgentFromGlobal(pos_global); + if (gPipeline.sRenderBeacons) + { + //pos += LLVector3(0.f, 0.f, 0.2f); + gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); + } + } + // now deal with highlights for all those seeable sound sources + forAllVisibleDrawables(renderSoundHighlights); + } + } + llpushcallstacks ; + // If managing your telehub, draw beacons at telehub and currently selected spawnpoint. + if (LLFloaterTelehub::renderBeacons()) + { + LLFloaterTelehub::addBeacons(); + } + + if (!sShadowRender) + { + mSelectedFaces.clear(); + + // Draw face highlights for selected faces. + if (LLSelectMgr::getInstance()->getTEMode()) + { + struct f : public LLSelectedTEFunctor + { + virtual bool apply(LLViewerObject* object, S32 te) + { + if (object->mDrawable) + { + gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te)); + } + return true; + } + } func; + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func); + } + } + + //LLSpatialGroup::sNoDelete = FALSE; + llpushcallstacks ; +} + + +void render_hud_elements() +{ + LLMemType mt_rhe(LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS); + LLFastTimer t(FTM_RENDER_UI); + gPipeline.disableLights(); + + LLGLDisable fog(GL_FOG); + LLGLSUIDefault gls_ui; + + LLGLEnable stencil(GL_STENCIL_TEST); + glStencilFunc(GL_ALWAYS, 255, 0xFFFFFFFF); + glStencilMask(0xFFFFFFFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + gGL.color4f(1,1,1,1); + if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); + gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD version in render_ui_3d() + + // Draw the tracking overlays + LLTracker::render3D(); + + // Show the property lines + LLWorld::getInstance()->renderPropertyLines(); + LLViewerParcelMgr::getInstance()->render(); + LLViewerParcelMgr::getInstance()->renderParcelCollision(); + + // Render name tags. + LLHUDObject::renderAll(); + } + else if (gForceRenderLandFence) + { + // This is only set when not rendering the UI, for parcel snapshots + LLViewerParcelMgr::getInstance()->render(); + } + else if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + LLHUDText::renderAllHUD(); + } + gGL.flush(); +} + +void LLPipeline::renderHighlights() +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_HL); + + assertInitialized(); + + // Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD) + // Render highlighted faces. + LLGLSPipelineAlpha gls_pipeline_alpha; + LLColor4 color(1.f, 1.f, 1.f, 0.5f); + LLGLEnable color_mat(GL_COLOR_MATERIAL); + disableLights(); + + if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && !mHighlightSet.empty()) + { //draw blurry highlight image over screen + LLGLEnable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + LLGLDisable test(GL_ALPHA_TEST); + + LLGLEnable stencil(GL_STENCIL_TEST); + gGL.flush(); + glStencilMask(0xFFFFFFFF); + glClearStencil(1); + glClear(GL_STENCIL_BUFFER_BIT); + + glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + + gGL.setColorMask(false, false); + for (std::set::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter) + { + renderHighlight(iter->mItem->getVObj(), 1.f); + } + gGL.setColorMask(true, false); + + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF); + + //gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); + + gGL.pushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + gGL.pushMatrix(); + glLoadIdentity(); + + gGL.getTexUnit(0)->bind(&mHighlight); + + LLVector2 tc1; + LLVector2 tc2; + + tc1.setVec(0,0); + tc2.setVec(2,2); + + gGL.begin(LLRender::TRIANGLES); + + F32 scale = gSavedSettings.getF32("RenderHighlightBrightness"); + LLColor4 color = gSavedSettings.getColor4("RenderHighlightColor"); + F32 thickness = gSavedSettings.getF32("RenderHighlightThickness"); + + for (S32 pass = 0; pass < 2; ++pass) + { + if (pass == 0) + { + gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); + } + else + { + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + + for (S32 i = 0; i < 8; ++i) + { + for (S32 j = 0; j < 8; ++j) + { + LLVector2 tc(i-4+0.5f, j-4+0.5f); + + F32 dist = 1.f-(tc.length()/sqrtf(32.f)); + dist *= scale/64.f; + + tc *= thickness; + tc.mV[0] = (tc.mV[0])/mHighlight.getWidth(); + tc.mV[1] = (tc.mV[1])/mHighlight.getHeight(); + + gGL.color4f(color.mV[0], + color.mV[1], + color.mV[2], + color.mV[3]*dist); + + gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc2.mV[1]); + gGL.vertex2f(-1,3); + + gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc1.mV[1]); + gGL.vertex2f(-1,-1); + + gGL.texCoord2f(tc.mV[0]+tc2.mV[0], tc.mV[1]+tc1.mV[1]); + gGL.vertex2f(3,-1); + } + } + } + + gGL.end(); + + gGL.popMatrix(); + glMatrixMode(GL_MODELVIEW); + gGL.popMatrix(); + + //gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + + if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) + { + gHighlightProgram.bind(); + gHighlightProgram.vertexAttrib4f(LLViewerShaderMgr::MATERIAL_COLOR,1,1,1,0.5f); + } + + if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED)) + { + // Make sure the selection image gets downloaded and decoded + if (!mFaceSelectImagep) + { + mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT); + } + mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA); + + U32 count = mSelectedFaces.size(); + for (U32 i = 0; i < count; i++) + { + LLFace *facep = mSelectedFaces[i]; + if (!facep || facep->getDrawable()->isDead()) + { + llerrs << "Bad face on selection" << llendl; + return; + } + + facep->renderSelected(mFaceSelectImagep, color); + } + } + + if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED)) + { + // Paint 'em red! + color.setVec(1.f, 0.f, 0.f, 0.5f); + if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) + { + gHighlightProgram.vertexAttrib4f(LLViewerShaderMgr::MATERIAL_COLOR,1,0,0,0.5f); + } + int count = mHighlightFaces.size(); + for (S32 i = 0; i < count; i++) + { + LLFace* facep = mHighlightFaces[i]; + facep->renderSelected(LLViewerTexture::sNullImagep, color); + } + } + + // Contains a list of the faces of objects that are physical or + // have touch-handlers. + mHighlightFaces.clear(); + + if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0) + { + gHighlightProgram.unbind(); + } +} + +//debug use +U32 LLPipeline::sCurRenderPoolType = 0 ; + +void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_GEOM); + LLFastTimer t(FTM_RENDER_GEOMETRY); + + assertInitialized(); + + F64 saved_modelview[16]; + F64 saved_projection[16]; + + //HACK: preserve/restore matrices around HUD render + if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + for (U32 i = 0; i < 16; i++) + { + saved_modelview[i] = gGLModelView[i]; + saved_projection[i] = gGLProjection[i]; + } + } + + S32 stack_depth = 0; + + if (gDebugGL) + { + glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &stack_depth); + } + + /////////////////////////////////////////// + // + // Sync and verify GL state + // + // + + stop_glerror(); + + LLVertexBuffer::unbind(); + + // Do verification of GL state + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + if (mRenderDebugMask & RENDER_DEBUG_VERIFY) + { + if (!verify()) + { + llerrs << "Pipeline verification failed!" << llendl; + } + } + + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:ForceVBO"); + + // Initialize lots of GL state to "safe" values + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + + LLGLSPipeline gls_pipeline; + LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); + + LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2); + + // Toggle backface culling for debugging + LLGLEnable cull_face(mBackfaceCull ? GL_CULL_FACE : 0); + // Set fog + BOOL use_fog = hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG); + LLGLEnable fog_enable(use_fog && + !gPipeline.canUseWindLightShadersOnObjects() ? GL_FOG : 0); + gSky.updateFog(camera.getFar()); + if (!use_fog) + { + sUnderWaterRender = FALSE; + } + + gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sDefaultImagep); + LLViewerFetchedTexture::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP); + + ////////////////////////////////////////////// + // + // Actually render all of the geometry + // + // + stop_glerror(); + + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPools"); + + for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) + { + LLDrawPool *poolp = *iter; + if (hasRenderType(poolp->getType())) + { + poolp->prerender(); + } + } + + { + LLFastTimer t(FTM_POOLS); + + // HACK: don't calculate local lights if we're rendering the HUD! + // Removing this check will cause bad flickering when there are + // HUD elements being rendered AND the user is in flycam mode -nyx + if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + calcNearbyLights(camera); + setupHWLights(NULL); + } + + BOOL occlude = sUseOcclusion > 1; + U32 cur_type = 0; + + pool_set_t::iterator iter1 = mPools.begin(); + while ( iter1 != mPools.end() ) + { + LLDrawPool *poolp = *iter1; + + cur_type = poolp->getType(); + + //debug use + sCurRenderPoolType = cur_type ; + + if (occlude && cur_type >= LLDrawPool::POOL_GRASS) + { + occlude = FALSE; + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + doOcclusion(camera); + } + + pool_set_t::iterator iter2 = iter1; + if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0) + { + LLFastTimer t(FTM_POOLRENDER); + + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + + for( S32 i = 0; i < poolp->getNumPasses(); i++ ) + { + LLVertexBuffer::unbind(); + poolp->beginRenderPass(i); + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + + p->render(i); + } + poolp->endRenderPass(i); + LLVertexBuffer::unbind(); + if (gDebugGL) + { + check_stack_depth(stack_depth); + std::string msg = llformat("%s pass %d", gPoolNames[cur_type].c_str(), i); + LLGLState::checkStates(msg); + LLGLState::checkTextureChannels(msg); + LLGLState::checkClientArrays(msg); + } + } + } + else + { + // Skip all pools of this type + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + } + } + iter1 = iter2; + stop_glerror(); + } + + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd"); + + LLVertexBuffer::unbind(); + + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + + if (occlude) + { + occlude = FALSE; + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + doOcclusion(camera); + } + } + + LLVertexBuffer::unbind(); + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + + + + stop_glerror(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderHighlights"); + + if (!sReflectionRender) + { + renderHighlights(); + } + + // Contains a list of the faces of objects that are physical or + // have touch-handlers. + mHighlightFaces.clear(); + + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDebug"); + + renderDebug(); + + LLVertexBuffer::unbind(); + + if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred) + { + if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + // Render debugging beacons. + gObjectList.renderObjectBeacons(); + gObjectList.resetObjectBeacons(); + } + else + { + // Make sure particle effects disappear + LLHUDObject::renderAllForTimer(); + } + } + else + { + // Make sure particle effects disappear + LLHUDObject::renderAllForTimer(); + } + + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomEnd"); + + //HACK: preserve/restore matrices around HUD render + if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + for (U32 i = 0; i < 16; i++) + { + gGLModelView[i] = saved_modelview[i]; + gGLProjection[i] = saved_projection[i]; + } + } + + LLVertexBuffer::unbind(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); +} + +void LLPipeline::renderGeomDeferred(LLCamera& camera) +{ + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred"); + + LLMemType mt_rgd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED); + LLFastTimer t(FTM_RENDER_GEOMETRY); + + LLFastTimer t2(FTM_POOLS); + + LLGLEnable cull(GL_CULL_FACE); + + LLGLEnable stencil(GL_STENCIL_TEST); + glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF); + stop_glerror(); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + stop_glerror(); + + for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) + { + LLDrawPool *poolp = *iter; + if (hasRenderType(poolp->getType())) + { + poolp->prerender(); + } + } + + LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); + + LLVertexBuffer::unbind(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + + U32 cur_type = 0; + + gGL.setColorMask(true, true); + + pool_set_t::iterator iter1 = mPools.begin(); + + while ( iter1 != mPools.end() ) + { + LLDrawPool *poolp = *iter1; + + cur_type = poolp->getType(); + + pool_set_t::iterator iter2 = iter1; + if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0) + { + LLFastTimer t(FTM_POOLRENDER); + + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + + for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ ) + { + LLVertexBuffer::unbind(); + poolp->beginDeferredPass(i); + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + + p->renderDeferred(i); + } + poolp->endDeferredPass(i); + LLVertexBuffer::unbind(); + + if (gDebugGL || gDebugPipeline) + { + GLint depth; + glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth); + if (depth > 3) + { + llerrs << "GL matrix stack corrupted!" << llendl; + } + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + } + } + } + else + { + // Skip all pools of this type + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + } + } + iter1 = iter2; + stop_glerror(); + } + + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + + gGL.setColorMask(true, false); +} + +void LLPipeline::renderGeomPostDeferred(LLCamera& camera) +{ + LLMemType mt_rgpd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF); + LLFastTimer t(FTM_POOLS); + U32 cur_type = 0; + + LLGLEnable cull(GL_CULL_FACE); + + LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); + + calcNearbyLights(camera); + setupHWLights(NULL); + + gGL.setColorMask(true, false); + + pool_set_t::iterator iter1 = mPools.begin(); + BOOL occlude = LLPipeline::sUseOcclusion > 1; + + while ( iter1 != mPools.end() ) + { + LLDrawPool *poolp = *iter1; + + cur_type = poolp->getType(); + + if (occlude && cur_type >= LLDrawPool::POOL_GRASS) + { + occlude = FALSE; + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + doOcclusion(camera); + gGL.setColorMask(true, false); + } + + pool_set_t::iterator iter2 = iter1; + if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0) + { + LLFastTimer t(FTM_POOLRENDER); + + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + + for( S32 i = 0; i < poolp->getNumPostDeferredPasses(); i++ ) + { + LLVertexBuffer::unbind(); + poolp->beginPostDeferredPass(i); + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + + p->renderPostDeferred(i); + } + poolp->endPostDeferredPass(i); + LLVertexBuffer::unbind(); + + if (gDebugGL || gDebugPipeline) + { + GLint depth; + glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth); + if (depth > 3) + { + llerrs << "GL matrix stack corrupted!" << llendl; + } + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + } + } + } + else + { + // Skip all pools of this type + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + } + } + iter1 = iter2; + stop_glerror(); + } + + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + + if (occlude) + { + occlude = FALSE; + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + doOcclusion(camera); + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + } +} + +void LLPipeline::renderGeomShadow(LLCamera& camera) +{ + LLMemType mt_rgs(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW); + U32 cur_type = 0; + + LLGLEnable cull(GL_CULL_FACE); + + LLVertexBuffer::unbind(); + + pool_set_t::iterator iter1 = mPools.begin(); + + while ( iter1 != mPools.end() ) + { + LLDrawPool *poolp = *iter1; + + cur_type = poolp->getType(); + + pool_set_t::iterator iter2 = iter1; + if (hasRenderType(poolp->getType()) && poolp->getNumShadowPasses() > 0) + { + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + + for( S32 i = 0; i < poolp->getNumShadowPasses(); i++ ) + { + LLVertexBuffer::unbind(); + poolp->beginShadowPass(i); + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + + p->renderShadow(i); + } + poolp->endShadowPass(i); + LLVertexBuffer::unbind(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + } + } + else + { + // Skip all pools of this type + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + } + } + iter1 = iter2; + stop_glerror(); + } + + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); +} + + +void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type) +{ + assertInitialized(); + S32 count = 0; + if (render_type == LLRender::TRIANGLE_STRIP) + { + count = index_count-2; + } + else + { + count = index_count/3; + } + + mTrianglesDrawn += count; + mBatchCount++; + mMaxBatchSize = llmax(mMaxBatchSize, count); + mMinBatchSize = llmin(mMinBatchSize, count); + + if (LLPipeline::sRenderFrameTest) + { + gViewerWindow->getWindow()->swapBuffers(); + ms_sleep(16); + } +} + +void LLPipeline::renderPhysicsDisplay() +{ + if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)) + { + return; + } + + allocatePhysicsBuffer(); + + gGL.flush(); + mPhysicsDisplay.bindTarget(); + glClearColor(0,0,0,1); + gGL.setColorMask(true, true); + mPhysicsDisplay.clear(); + glClearColor(0,0,0,0); + + gGL.setColorMask(true, false); + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + if (hasRenderType(part->mDrawableType)) + { + part->renderPhysicsShapes(); + } + } + } + } + + for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) + { + LLSpatialBridge* bridge = *i; + if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) + { + glPushMatrix(); + glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); + bridge->renderPhysicsShapes(); + glPopMatrix(); + } + } + + + gGL.flush(); + mPhysicsDisplay.flush(); +} + + +void LLPipeline::renderDebug() +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE); + + assertInitialized(); + + gGL.color4f(1,1,1,1); + + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + gGL.setColorMask(true, false); + + // Debug stuff. + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + if (hasRenderType(part->mDrawableType)) + { + part->renderDebug(); + } + } + } + } + + for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) + { + LLSpatialBridge* bridge = *i; + if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) + { + glPushMatrix(); + glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); + bridge->renderDebug(); + glPopMatrix(); + } + } + + if (gSavedSettings.getBOOL("DebugShowUploadCost")) + { + std::set textures; + std::set sculpts; + std::set meshes; + + BOOL selected = TRUE; + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + selected = FALSE; + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + LLSpatialGroup::OctreeNode* node = group->mOctreeNode; + for (LLSpatialGroup::OctreeNode::element_iter elem = node->getData().begin(); elem != node->getData().end(); ++elem) + { + LLDrawable* drawable = *elem; + LLVOVolume* volume = drawable->getVOVolume(); + if (volume && volume->isSelected() == selected) + { + for (U32 i = 0; i < volume->getNumTEs(); ++i) + { + LLTextureEntry* te = volume->getTE(i); + textures.insert(te->getID()); + } + + if (volume->isSculpted()) + { + LLUUID sculpt_id = volume->getVolume()->getParams().getSculptID(); + if (volume->isMesh()) + { + meshes.insert(sculpt_id); + } + else + { + sculpts.insert(sculpt_id); + } + } + } + } + } + + gPipeline.mDebugTextureUploadCost = textures.size() * 10; + gPipeline.mDebugSculptUploadCost = sculpts.size()*10; + + U32 mesh_cost = 0; + + for (std::set::iterator iter = meshes.begin(); iter != meshes.end(); ++iter) + { + mesh_cost += gMeshRepo.getResourceCost(*iter)*10; + } + + gPipeline.mDebugMeshUploadCost = mesh_cost; + } + + if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + { + LLVertexBuffer::unbind(); + + LLGLEnable blend(GL_BLEND); + LLGLDepthTest depth(TRUE, FALSE); + LLGLDisable cull(GL_CULL_FACE); + + gGL.color4f(1,1,1,1); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + F32 a = 0.1f; + + F32 col[] = + { + 1,0,0,a, + 0,1,0,a, + 0,0,1,a, + 1,0,1,a, + + 1,1,0,a, + 0,1,1,a, + 1,1,1,a, + 1,0,1,a, + }; + + for (U32 i = 0; i < 8; i++) + { + LLVector3* frust = mShadowCamera[i].mAgentFrustum; + + if (i > 3) + { //render shadow frusta as volumes + if (mShadowFrustPoints[i-4].empty()) + { + continue; + } + + gGL.color4fv(col+(i-4)*4); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); + gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV); + gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV); + gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV); + gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); + gGL.end(); + + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3fv(frust[0].mV); + gGL.vertex3fv(frust[1].mV); + gGL.vertex3fv(frust[3].mV); + gGL.vertex3fv(frust[2].mV); + gGL.end(); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3fv(frust[4].mV); + gGL.vertex3fv(frust[5].mV); + gGL.vertex3fv(frust[7].mV); + gGL.vertex3fv(frust[6].mV); + gGL.end(); + } + + + if (i < 4) + { + + //if (i == 0 || !mShadowFrustPoints[i].empty()) + { + //render visible point cloud + gGL.flush(); + glPointSize(8.f); + gGL.begin(LLRender::POINTS); + + F32* c = col+i*4; + gGL.color3fv(c); + + for (U32 j = 0; j < mShadowFrustPoints[i].size(); ++j) + { + gGL.vertex3fv(mShadowFrustPoints[i][j].mV); + + } + gGL.end(); + + gGL.flush(); + glPointSize(1.f); + + LLVector3* ext = mShadowExtents[i]; + LLVector3 pos = (ext[0]+ext[1])*0.5f; + LLVector3 size = (ext[1]-ext[0])*0.5f; + drawBoxOutline(pos, size); + + //render camera frustum splits as outlines + gGL.begin(LLRender::LINES); + gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV); + gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV); + gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV); + gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV); + gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV); + gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV); + gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV); + gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV); + gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); + gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV); + gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV); + gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV); + gGL.end(); + } + } + + /*gGL.flush(); + glLineWidth(16-i*2); + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++) + { + LLSpatialPartition* part = region->getSpatialPartition(j); + if (part) + { + if (hasRenderType(part->mDrawableType)) + { + part->renderIntersectingBBoxes(&mShadowCamera[i]); + } + } + } + } + gGL.flush(); + glLineWidth(1.f);*/ + } + } + + if (mRenderDebugMask & RENDER_DEBUG_COMPOSITION) + { + // Debug composition layers + F32 x, y; + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + if (gAgent.getRegion()) + { + gGL.begin(LLRender::POINTS); + // Draw the composition layer for the region that I'm in. + for (x = 0; x <= 260; x++) + { + for (y = 0; y <= 260; y++) + { + if ((x > 255) || (y > 255)) + { + gGL.color4f(1.f, 0.f, 0.f, 1.f); + } + else + { + gGL.color4f(0.f, 0.f, 1.f, 1.f); + } + F32 z = gAgent.getRegion()->getCompositionXY((S32)x, (S32)y); + z *= 5.f; + z += 50.f; + gGL.vertex3f(x, y, z); + } + } + gGL.end(); + } + } + + if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_BUILD_QUEUE) + { + U32 count = 0; + U32 size = mGroupQ2.size(); + LLColor4 col; + + LLVertexBuffer::unbind(); + LLGLEnable blend(GL_BLEND); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); + + gGL.pushMatrix(); + glLoadMatrixd(gGLModelView); + gGLLastMatrix = NULL; + + for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ2.begin(); iter != mGroupQ2.end(); ++iter) + { + LLSpatialGroup* group = *iter; + if (group->isDead()) + { + continue; + } + + LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); + + if (bridge && (!bridge->mDrawable || bridge->mDrawable->isDead())) + { + continue; + } + + if (bridge) + { + gGL.pushMatrix(); + glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); + } + + F32 alpha = llclamp((F32) (size-count)/size, 0.f, 1.f); + + + LLVector2 c(1.f-alpha, alpha); + c.normVec(); + + + ++count; + col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.5f); + group->drawObjectBox(col); + + if (bridge) + { + gGL.popMatrix(); + } + } + + gGL.popMatrix(); + } + + gGL.flush(); + + gPipeline.renderPhysicsDisplay(); +} + +void LLPipeline::rebuildPools() +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_REBUILD_POOLS); + + assertInitialized(); + + S32 max_count = mPools.size(); + pool_set_t::iterator iter1 = mPools.upper_bound(mLastRebuildPool); + while(max_count > 0 && mPools.size() > 0) // && num_rebuilds < MAX_REBUILDS) + { + if (iter1 == mPools.end()) + { + iter1 = mPools.begin(); + } + LLDrawPool* poolp = *iter1; + + if (poolp->isDead()) + { + mPools.erase(iter1++); + removeFromQuickLookup( poolp ); + if (poolp == mLastRebuildPool) + { + mLastRebuildPool = NULL; + } + delete poolp; + } + else + { + mLastRebuildPool = poolp; + iter1++; + } + max_count--; + } + + if (isAgentAvatarValid()) + { + gAgentAvatarp->rebuildHUD(); + } +} + +void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP); + + assertInitialized(); + + switch( new_poolp->getType() ) + { + case LLDrawPool::POOL_SIMPLE: + if (mSimplePool) + { + llassert(0); + llwarns << "Ignoring duplicate simple pool." << llendl; + } + else + { + mSimplePool = (LLRenderPass*) new_poolp; + } + break; + + case LLDrawPool::POOL_GRASS: + if (mGrassPool) + { + llassert(0); + llwarns << "Ignoring duplicate grass pool." << llendl; + } + else + { + mGrassPool = (LLRenderPass*) new_poolp; + } + break; + + case LLDrawPool::POOL_FULLBRIGHT: + if (mFullbrightPool) + { + llassert(0); + llwarns << "Ignoring duplicate simple pool." << llendl; + } + else + { + mFullbrightPool = (LLRenderPass*) new_poolp; + } + break; + + case LLDrawPool::POOL_INVISIBLE: + if (mInvisiblePool) + { + llassert(0); + llwarns << "Ignoring duplicate simple pool." << llendl; + } + else + { + mInvisiblePool = (LLRenderPass*) new_poolp; + } + break; + + case LLDrawPool::POOL_GLOW: + if (mGlowPool) + { + llassert(0); + llwarns << "Ignoring duplicate glow pool." << llendl; + } + else + { + mGlowPool = (LLRenderPass*) new_poolp; + } + break; + + case LLDrawPool::POOL_TREE: + mTreePools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ; + break; + + case LLDrawPool::POOL_TERRAIN: + mTerrainPools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ; + break; + + case LLDrawPool::POOL_BUMP: + if (mBumpPool) + { + llassert(0); + llwarns << "Ignoring duplicate bump pool." << llendl; + } + else + { + mBumpPool = new_poolp; + } + break; + + case LLDrawPool::POOL_ALPHA: + if( mAlphaPool ) + { + llassert(0); + llwarns << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << llendl; + } + else + { + mAlphaPool = new_poolp; + } + break; + + case LLDrawPool::POOL_AVATAR: + break; // Do nothing + + case LLDrawPool::POOL_SKY: + if( mSkyPool ) + { + llassert(0); + llwarns << "LLPipeline::addPool(): Ignoring duplicate Sky pool" << llendl; + } + else + { + mSkyPool = new_poolp; + } + break; + + case LLDrawPool::POOL_WATER: + if( mWaterPool ) + { + llassert(0); + llwarns << "LLPipeline::addPool(): Ignoring duplicate Water pool" << llendl; + } + else + { + mWaterPool = new_poolp; + } + break; + + case LLDrawPool::POOL_GROUND: + if( mGroundPool ) + { + llassert(0); + llwarns << "LLPipeline::addPool(): Ignoring duplicate Ground Pool" << llendl; + } + else + { + mGroundPool = new_poolp; + } + break; + + case LLDrawPool::POOL_WL_SKY: + if( mWLSkyPool ) + { + llassert(0); + llwarns << "LLPipeline::addPool(): Ignoring duplicate WLSky Pool" << llendl; + } + else + { + mWLSkyPool = new_poolp; + } + break; + + default: + llassert(0); + llwarns << "Invalid Pool Type in LLPipeline::addPool()" << llendl; + break; + } +} + +void LLPipeline::removePool( LLDrawPool* poolp ) +{ + assertInitialized(); + removeFromQuickLookup(poolp); + mPools.erase(poolp); + delete poolp; +} + +void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) +{ + assertInitialized(); + LLMemType mt(LLMemType::MTYPE_PIPELINE); + switch( poolp->getType() ) + { + case LLDrawPool::POOL_SIMPLE: + llassert(mSimplePool == poolp); + mSimplePool = NULL; + break; + + case LLDrawPool::POOL_GRASS: + llassert(mGrassPool == poolp); + mGrassPool = NULL; + break; + + case LLDrawPool::POOL_FULLBRIGHT: + llassert(mFullbrightPool == poolp); + mFullbrightPool = NULL; + break; + + case LLDrawPool::POOL_INVISIBLE: + llassert(mInvisiblePool == poolp); + mInvisiblePool = NULL; + break; + + case LLDrawPool::POOL_WL_SKY: + llassert(mWLSkyPool == poolp); + mWLSkyPool = NULL; + break; + + case LLDrawPool::POOL_GLOW: + llassert(mGlowPool == poolp); + mGlowPool = NULL; + break; + + case LLDrawPool::POOL_TREE: + #ifdef _DEBUG + { + BOOL found = mTreePools.erase( (uintptr_t)poolp->getTexture() ); + llassert( found ); + } + #else + mTreePools.erase( (uintptr_t)poolp->getTexture() ); + #endif + break; + + case LLDrawPool::POOL_TERRAIN: + #ifdef _DEBUG + { + BOOL found = mTerrainPools.erase( (uintptr_t)poolp->getTexture() ); + llassert( found ); + } + #else + mTerrainPools.erase( (uintptr_t)poolp->getTexture() ); + #endif + break; + + case LLDrawPool::POOL_BUMP: + llassert( poolp == mBumpPool ); + mBumpPool = NULL; + break; + + case LLDrawPool::POOL_ALPHA: + llassert( poolp == mAlphaPool ); + mAlphaPool = NULL; + break; + + case LLDrawPool::POOL_AVATAR: + break; // Do nothing + + case LLDrawPool::POOL_SKY: + llassert( poolp == mSkyPool ); + mSkyPool = NULL; + break; + + case LLDrawPool::POOL_WATER: + llassert( poolp == mWaterPool ); + mWaterPool = NULL; + break; + + case LLDrawPool::POOL_GROUND: + llassert( poolp == mGroundPool ); + mGroundPool = NULL; + break; + + default: + llassert(0); + llwarns << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << llendl; + break; + } +} + +void LLPipeline::resetDrawOrders() +{ + assertInitialized(); + // Iterate through all of the draw pools and rebuild them. + for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) + { + LLDrawPool *poolp = *iter; + poolp->resetDrawOrders(); + } +} + +//============================================================================ +// Once-per-frame setup of hardware lights, +// including sun/moon, avatar backlight, and up to 6 local lights + +void LLPipeline::setupAvatarLights(BOOL for_edit) +{ + assertInitialized(); + + if (for_edit) + { + LLColor4 diffuse(1.f, 1.f, 1.f, 0.f); + LLVector4 light_pos_cam(-8.f, 0.25f, 10.f, 0.f); // w==0 => directional light + LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview(); + LLMatrix4 camera_rot(camera_mat.getMat3()); + camera_rot.invert(); + LLVector4 light_pos = light_pos_cam * camera_rot; + + light_pos.normalize(); + + LLLightState* light = gGL.getLight(1); + + mHWLightColors[1] = diffuse; + + light->setDiffuse(diffuse); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + light->setPosition(light_pos); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + } + else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini) + { + LLVector3 opposite_pos = -1.f * mSunDir; + LLVector3 orthog_light_pos = mSunDir % LLVector3::z_axis; + LLVector4 backlight_pos = LLVector4(lerp(opposite_pos, orthog_light_pos, 0.3f), 0.0f); + backlight_pos.normalize(); + + LLColor4 light_diffuse = mSunDiffuse; + LLColor4 backlight_diffuse(1.f - light_diffuse.mV[VRED], 1.f - light_diffuse.mV[VGREEN], 1.f - light_diffuse.mV[VBLUE], 1.f); + F32 max_component = 0.001f; + for (S32 i = 0; i < 3; i++) + { + if (backlight_diffuse.mV[i] > max_component) + { + max_component = backlight_diffuse.mV[i]; + } + } + F32 backlight_mag; + if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS) + { + backlight_mag = BACKLIGHT_DAY_MAGNITUDE_OBJECT; + } + else + { + backlight_mag = BACKLIGHT_NIGHT_MAGNITUDE_OBJECT; + } + backlight_diffuse *= backlight_mag / max_component; + + mHWLightColors[1] = backlight_diffuse; + + LLLightState* light = gGL.getLight(1); + + light->setPosition(backlight_pos); + light->setDiffuse(backlight_diffuse); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + } + else + { + LLLightState* light = gGL.getLight(1); + + mHWLightColors[1] = LLColor4::black; + + light->setDiffuse(LLColor4::black); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + } +} + +static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_dist) +{ + F32 inten = light->getLightIntensity(); + if (inten < .001f) + { + return max_dist; + } + F32 radius = light->getLightRadius(); + BOOL selected = light->isSelected(); + LLVector3 dpos = light->getRenderPosition() - cam_pos; + F32 dist2 = dpos.lengthSquared(); + if (!selected && dist2 > (max_dist + radius)*(max_dist + radius)) + { + return max_dist; + } + F32 dist = (F32) sqrt(dist2); + dist *= 1.f / inten; + dist -= radius; + if (selected) + { + dist -= 10000.f; // selected lights get highest priority + } + if (light->mDrawable.notNull() && light->mDrawable->isState(LLDrawable::ACTIVE)) + { + // moving lights get a little higher priority (too much causes artifacts) + dist -= light->getLightRadius()*0.25f; + } + return dist; +} + +void LLPipeline::calcNearbyLights(LLCamera& camera) +{ + assertInitialized(); + + if (LLPipeline::sReflectionRender) + { + return; + } + + if (mLightingDetail >= 1) + { + // mNearbyLight (and all light_set_t's) are sorted such that + // begin() == the closest light and rbegin() == the farthest light + const S32 MAX_LOCAL_LIGHTS = 6; +// LLVector3 cam_pos = gAgent.getCameraPositionAgent(); + LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ? + camera.getOrigin() : + gAgent.getPositionAgent(); + + F32 max_dist = LIGHT_MAX_RADIUS * 4.f; // ignore enitrely lights > 4 * max light rad + + // UPDATE THE EXISTING NEARBY LIGHTS + light_set_t cur_nearby_lights; + for (light_set_t::iterator iter = mNearbyLights.begin(); + iter != mNearbyLights.end(); iter++) + { + const Light* light = &(*iter); + LLDrawable* drawable = light->drawable; + LLVOVolume* volight = drawable->getVOVolume(); + if (!volight || !drawable->isState(LLDrawable::LIGHT)) + { + drawable->clearState(LLDrawable::NEARBY_LIGHT); + continue; + } + if (light->fade <= -LIGHT_FADE_TIME) + { + drawable->clearState(LLDrawable::NEARBY_LIGHT); + continue; + } + if (!sRenderAttachedLights && volight && volight->isAttachment()) + { + drawable->clearState(LLDrawable::NEARBY_LIGHT); + continue; + } + + F32 dist = calc_light_dist(volight, cam_pos, max_dist); + cur_nearby_lights.insert(Light(drawable, dist, light->fade)); + } + mNearbyLights = cur_nearby_lights; + + // FIND NEW LIGHTS THAT ARE IN RANGE + light_set_t new_nearby_lights; + for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); + iter != mLights.end(); ++iter) + { + LLDrawable* drawable = *iter; + LLVOVolume* light = drawable->getVOVolume(); + if (!light || drawable->isState(LLDrawable::NEARBY_LIGHT)) + { + continue; + } + if (light->isHUDAttachment()) + { + continue; // no lighting from HUD objects + } + F32 dist = calc_light_dist(light, cam_pos, max_dist); + if (dist >= max_dist) + { + continue; + } + if (!sRenderAttachedLights && light && light->isAttachment()) + { + continue; + } + new_nearby_lights.insert(Light(drawable, dist, 0.f)); + if (new_nearby_lights.size() > (U32)MAX_LOCAL_LIGHTS) + { + new_nearby_lights.erase(--new_nearby_lights.end()); + const Light& last = *new_nearby_lights.rbegin(); + max_dist = last.dist; + } + } + + // INSERT ANY NEW LIGHTS + for (light_set_t::iterator iter = new_nearby_lights.begin(); + iter != new_nearby_lights.end(); iter++) + { + const Light* light = &(*iter); + if (mNearbyLights.size() < (U32)MAX_LOCAL_LIGHTS) + { + mNearbyLights.insert(*light); + ((LLDrawable*) light->drawable)->setState(LLDrawable::NEARBY_LIGHT); + } + else + { + // crazy cast so that we can overwrite the fade value + // even though gcc enforces sets as const + // (fade value doesn't affect sort so this is safe) + Light* farthest_light = ((Light*) (&(*(mNearbyLights.rbegin())))); + if (light->dist < farthest_light->dist) + { + if (farthest_light->fade >= 0.f) + { + farthest_light->fade = -gFrameIntervalSeconds; + } + } + else + { + break; // none of the other lights are closer + } + } + } + + } +} + +void LLPipeline::setupHWLights(LLDrawPool* pool) +{ + assertInitialized(); + + // Ambient + LLColor4 ambient = gSky.getTotalAmbientColor(); + glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV); + + // Light 0 = Sun or Moon (All objects) + { + if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS) + { + mSunDir.setVec(gSky.getSunDirection()); + mSunDiffuse.setVec(gSky.getSunDiffuseColor()); + } + else + { + mSunDir.setVec(gSky.getMoonDirection()); + mSunDiffuse.setVec(gSky.getMoonDiffuseColor()); + } + + F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]); + if (max_color > 1.f) + { + mSunDiffuse *= 1.f/max_color; + } + mSunDiffuse.clamp(); + + LLVector4 light_pos(mSunDir, 0.0f); + LLColor4 light_diffuse = mSunDiffuse; + mHWLightColors[0] = light_diffuse; + + LLLightState* light = gGL.getLight(0); + light->setPosition(light_pos); + light->setDiffuse(light_diffuse); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + } + + // Light 1 = Backlight (for avatars) + // (set by enableLightsAvatar) + + S32 cur_light = 2; + + // Nearby lights = LIGHT 2-7 + + mLightMovingMask = 0; + + if (mLightingDetail >= 1) + { + for (light_set_t::iterator iter = mNearbyLights.begin(); + iter != mNearbyLights.end(); ++iter) + { + LLDrawable* drawable = iter->drawable; + LLVOVolume* light = drawable->getVOVolume(); + if (!light) + { + continue; + } + if (drawable->isState(LLDrawable::ACTIVE)) + { + mLightMovingMask |= (1<getLightColor(); + light_color.mV[3] = 0.0f; + + F32 fade = iter->fade; + if (fade < LIGHT_FADE_TIME) + { + // fade in/out light + if (fade >= 0.f) + { + fade = fade / LIGHT_FADE_TIME; + ((Light*) (&(*iter)))->fade += gFrameIntervalSeconds; + } + else + { + fade = 1.f + fade / LIGHT_FADE_TIME; + ((Light*) (&(*iter)))->fade -= gFrameIntervalSeconds; + } + fade = llclamp(fade,0.f,1.f); + light_color *= fade; + } + + LLVector3 light_pos(light->getRenderPosition()); + LLVector4 light_pos_gl(light_pos, 1.0f); + + F32 light_radius = llmax(light->getLightRadius(), 0.001f); + + F32 x = (3.f * (1.f + light->getLightFalloff())); // why this magic? probably trying to match a historic behavior. + float linatten = x / (light_radius); // % of brightness at radius + + mHWLightColors[cur_light] = light_color; + LLLightState* light_state = gGL.getLight(cur_light); + + light_state->setPosition(light_pos_gl); + light_state->setDiffuse(light_color); + light_state->setAmbient(LLColor4::black); + light_state->setConstantAttenuation(0.f); + light_state->setLinearAttenuation(linatten); + light_state->setQuadraticAttenuation(0.f); + + if (light->isLightSpotlight() // directional (spot-)light + && (LLPipeline::sRenderDeferred || gSavedSettings.getBOOL("RenderSpotLightsInNondeferred"))) // these are only rendered as GL spotlights if we're in deferred rendering mode *or* the setting forces them on + { + LLVector3 spotparams = light->getSpotLightParams(); + LLQuaternion quat = light->getRenderRotation(); + LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction + at_axis *= quat; + + light_state->setSpotDirection(at_axis); + light_state->setSpotCutoff(90.f); + light_state->setSpotExponent(2.f); + + light_state->setSpecular(LLColor4::black); + } + else // omnidirectional (point) light + { + light_state->setSpotExponent(0.f); + light_state->setSpotCutoff(180.f); + + // we use specular.w = 1.0 as a cheap hack for the shaders to know that this is omnidirectional rather than a spotlight + const LLColor4 specular(0.f, 0.f, 0.f, 1.f); + light_state->setSpecular(specular); + } + cur_light++; + if (cur_light >= 8) + { + break; // safety + } + } + } + for ( ; cur_light < 8 ; cur_light++) + { + mHWLightColors[cur_light] = LLColor4::black; + LLLightState* light = gGL.getLight(cur_light); + + light->setDiffuse(LLColor4::black); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + } + if (gAgentAvatarp && + gAgentAvatarp->mSpecialRenderMode == 3) + { + LLColor4 light_color = LLColor4::white; + light_color.mV[3] = 0.0f; + + LLVector3 light_pos(LLViewerCamera::getInstance()->getOrigin()); + LLVector4 light_pos_gl(light_pos, 1.0f); + + F32 light_radius = 16.f; + + F32 x = 3.f; + float linatten = x / (light_radius); // % of brightness at radius + + mHWLightColors[2] = light_color; + LLLightState* light = gGL.getLight(2); + + light->setPosition(light_pos_gl); + light->setDiffuse(light_color); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + light->setQuadraticAttenuation(0.f); + light->setConstantAttenuation(0.f); + light->setLinearAttenuation(linatten); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + } + + // Init GL state + glDisable(GL_LIGHTING); + for (S32 i = 0; i < 8; ++i) + { + gGL.getLight(i)->disable(); + } + mLightMask = 0; +} + +void LLPipeline::enableLights(U32 mask) +{ + assertInitialized(); + + if (mLightingDetail == 0) + { + mask &= 0xf003; // sun and backlight only (and fullbright bit) + } + if (mLightMask != mask) + { + stop_glerror(); + if (!mLightMask) + { + glEnable(GL_LIGHTING); + } + if (mask) + { + stop_glerror(); + for (S32 i=0; i<8; i++) + { + LLLightState* light = gGL.getLight(i); + if (mask & (1<enable(); + light->setDiffuse(mHWLightColors[i]); + } + else + { + light->disable(); + light->setDiffuse(LLColor4::black); + } + } + stop_glerror(); + } + else + { + glDisable(GL_LIGHTING); + } + stop_glerror(); + mLightMask = mask; + LLColor4 ambient = gSky.getTotalAmbientColor(); + glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV); + stop_glerror(); + } +} + +void LLPipeline::enableLightsStatic() +{ + assertInitialized(); + U32 mask = 0x01; // Sun + if (mLightingDetail >= 2) + { + mask |= mLightMovingMask; // Hardware moving lights + } + else + { + mask |= 0xff & (~2); // Hardware local lights + } + enableLights(mask); +} + +void LLPipeline::enableLightsDynamic() +{ + assertInitialized(); + U32 mask = 0xff & (~2); // Local lights + enableLights(mask); + + if (isAgentAvatarValid() && getLightingDetail() <= 0) + { + if (gAgentAvatarp->mSpecialRenderMode == 0) // normal + { + gPipeline.enableLightsAvatar(); + } + else if (gAgentAvatarp->mSpecialRenderMode >= 1) // anim preview + { + gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f)); + } + } +} + +void LLPipeline::enableLightsAvatar() +{ + U32 mask = 0xff; // All lights + setupAvatarLights(FALSE); + enableLights(mask); +} + +void LLPipeline::enableLightsPreview() +{ + disableLights(); + + glEnable(GL_LIGHTING); + LLColor4 ambient = gSavedSettings.getColor4("PreviewAmbientColor"); + glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV); + + + LLColor4 diffuse0 = gSavedSettings.getColor4("PreviewDiffuse0"); + LLColor4 specular0 = gSavedSettings.getColor4("PreviewSpecular0"); + LLColor4 diffuse1 = gSavedSettings.getColor4("PreviewDiffuse1"); + LLColor4 specular1 = gSavedSettings.getColor4("PreviewSpecular1"); + LLColor4 diffuse2 = gSavedSettings.getColor4("PreviewDiffuse2"); + LLColor4 specular2 = gSavedSettings.getColor4("PreviewSpecular2"); + + LLVector3 dir0 = gSavedSettings.getVector3("PreviewDirection0"); + LLVector3 dir1 = gSavedSettings.getVector3("PreviewDirection1"); + LLVector3 dir2 = gSavedSettings.getVector3("PreviewDirection2"); + + dir0.normVec(); + dir1.normVec(); + dir2.normVec(); + + LLVector4 light_pos(dir0, 0.0f); + + LLLightState* light = gGL.getLight(0); + + light->enable(); + light->setPosition(light_pos); + light->setDiffuse(diffuse0); + light->setAmbient(LLColor4::black); + light->setSpecular(specular0); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + + light_pos = LLVector4(dir1, 0.f); + + light = gGL.getLight(1); + light->enable(); + light->setPosition(light_pos); + light->setDiffuse(diffuse1); + light->setAmbient(LLColor4::black); + light->setSpecular(specular1); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + + light_pos = LLVector4(dir2, 0.f); + light = gGL.getLight(2); + light->enable(); + light->setPosition(light_pos); + light->setDiffuse(diffuse2); + light->setAmbient(LLColor4::black); + light->setSpecular(specular2); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); +} + + +void LLPipeline::enableLightsAvatarEdit(const LLColor4& color) +{ + U32 mask = 0x2002; // Avatar backlight only, set ambient + setupAvatarLights(TRUE); + enableLights(mask); + + glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV); +} + +void LLPipeline::enableLightsFullbright(const LLColor4& color) +{ + assertInitialized(); + U32 mask = 0x1000; // Non-0 mask, set ambient + enableLights(mask); + + glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV); +} + +void LLPipeline::disableLights() +{ + enableLights(0); // no lighting (full bright) +} + +//============================================================================ + +class LLMenuItemGL; +class LLInvFVBridge; +struct cat_folder_pair; +class LLVOBranch; +class LLVOLeaf; + +void LLPipeline::findReferences(LLDrawable *drawablep) +{ + assertInitialized(); + if (mLights.find(drawablep) != mLights.end()) + { + llinfos << "In mLights" << llendl; + } + if (std::find(mMovedList.begin(), mMovedList.end(), drawablep) != mMovedList.end()) + { + llinfos << "In mMovedList" << llendl; + } + if (std::find(mShiftList.begin(), mShiftList.end(), drawablep) != mShiftList.end()) + { + llinfos << "In mShiftList" << llendl; + } + if (mRetexturedList.find(drawablep) != mRetexturedList.end()) + { + llinfos << "In mRetexturedList" << llendl; + } + + if (std::find(mBuildQ1.begin(), mBuildQ1.end(), drawablep) != mBuildQ1.end()) + { + llinfos << "In mBuildQ1" << llendl; + } + if (std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep) != mBuildQ2.end()) + { + llinfos << "In mBuildQ2" << llendl; + } + + S32 count; + + count = gObjectList.findReferences(drawablep); + if (count) + { + llinfos << "In other drawables: " << count << " references" << llendl; + } +} + +BOOL LLPipeline::verify() +{ + BOOL ok = assertInitialized(); + if (ok) + { + for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) + { + LLDrawPool *poolp = *iter; + if (!poolp->verify()) + { + ok = FALSE; + } + } + } + + if (!ok) + { + llwarns << "Pipeline verify failed!" << llendl; + } + return ok; +} + +////////////////////////////// +// +// Collision detection +// +// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * A method to compute a ray-AABB intersection. + * Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990 + * Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500) + * Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only) + * + * Hence this version is faster as well as more robust than the original one. + * + * Should work provided: + * 1) the integer representation of 0.0f is 0x00000000 + * 2) the sign bit of the float is the most significant one + * + * Report bugs: p.terdiman@codercorner.com + * + * \param aabb [in] the axis-aligned bounding box + * \param origin [in] ray origin + * \param dir [in] ray direction + * \param coord [out] impact coordinates + * \return true if ray intersects AABB + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//#define RAYAABB_EPSILON 0.00001f +#define IR(x) ((U32&)x) + +bool LLRayAABB(const LLVector3 ¢er, const LLVector3 &size, const LLVector3& origin, const LLVector3& dir, LLVector3 &coord, F32 epsilon) +{ + BOOL Inside = TRUE; + LLVector3 MinB = center - size; + LLVector3 MaxB = center + size; + LLVector3 MaxT; + MaxT.mV[VX]=MaxT.mV[VY]=MaxT.mV[VZ]=-1.0f; + + // Find candidate planes. + for(U32 i=0;i<3;i++) + { + if(origin.mV[i] < MinB.mV[i]) + { + coord.mV[i] = MinB.mV[i]; + Inside = FALSE; + + // Calculate T distances to candidate planes + if(IR(dir.mV[i])) MaxT.mV[i] = (MinB.mV[i] - origin.mV[i]) / dir.mV[i]; + } + else if(origin.mV[i] > MaxB.mV[i]) + { + coord.mV[i] = MaxB.mV[i]; + Inside = FALSE; + + // Calculate T distances to candidate planes + if(IR(dir.mV[i])) MaxT.mV[i] = (MaxB.mV[i] - origin.mV[i]) / dir.mV[i]; + } + } + + // Ray origin inside bounding box + if(Inside) + { + coord = origin; + return true; + } + + // Get largest of the maxT's for final choice of intersection + U32 WhichPlane = 0; + if(MaxT.mV[1] > MaxT.mV[WhichPlane]) WhichPlane = 1; + if(MaxT.mV[2] > MaxT.mV[WhichPlane]) WhichPlane = 2; + + // Check final candidate actually inside box + if(IR(MaxT.mV[WhichPlane])&0x80000000) return false; + + for(U32 i=0;i<3;i++) + { + if(i!=WhichPlane) + { + coord.mV[i] = origin.mV[i] + MaxT.mV[WhichPlane] * dir.mV[i]; + if (epsilon > 0) + { + if(coord.mV[i] < MinB.mV[i] - epsilon || coord.mV[i] > MaxB.mV[i] + epsilon) return false; + } + else + { + if(coord.mV[i] < MinB.mV[i] || coord.mV[i] > MaxB.mV[i]) return false; + } + } + } + return true; // ray hits box +} + +////////////////////////////// +// +// Macros, functions, and inline methods from other classes +// +// + +void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light) +{ + if (drawablep && assertInitialized()) + { + if (is_light) + { + mLights.insert(drawablep); + drawablep->setState(LLDrawable::LIGHT); + } + else + { + drawablep->clearState(LLDrawable::LIGHT); + mLights.erase(drawablep); + } + } +} + +//static +void LLPipeline::toggleRenderType(U32 type) +{ + gPipeline.mRenderTypeEnabled[type] = !gPipeline.mRenderTypeEnabled[type]; + if (type == LLPipeline::RENDER_TYPE_WATER) + { + gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER] = !gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER]; + } +} + +//static +void LLPipeline::toggleRenderTypeControl(void* data) +{ + U32 type = (U32)(intptr_t)data; + U32 bit = (1<inBuildMode() ? FALSE : TRUE; + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + + for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++) + { + if ((j == LLViewerRegion::PARTITION_VOLUME) || + (j == LLViewerRegion::PARTITION_BRIDGE) || + (j == LLViewerRegion::PARTITION_TERRAIN) || + (j == LLViewerRegion::PARTITION_TREE) || + (j == LLViewerRegion::PARTITION_GRASS)) // only check these partitions for now + { + LLSpatialPartition* part = region->getSpatialPartition(j); + if (part && hasRenderType(part->mDrawableType)) + { + LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal); + if (hit) + { + drawable = hit; + local_end = position; + } + } + } + } + } + + if (!sPickAvatar) + { + //save hit info in case we need to restore + //due to attachment override + LLVector3 local_normal; + LLVector3 local_binormal; + LLVector2 local_texcoord; + S32 local_face_hit = -1; + + if (face_hit) + { + local_face_hit = *face_hit; + } + if (tex_coord) + { + local_texcoord = *tex_coord; + } + if (bi_normal) + { + local_binormal = *bi_normal; + } + if (normal) + { + local_normal = *normal; + } + + const F32 ATTACHMENT_OVERRIDE_DIST = 0.1f; + + //check against avatars + sPickAvatar = TRUE; + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + + LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE); + if (part && hasRenderType(part->mDrawableType)) + { + LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal); + if (hit) + { + if (!drawable || + !drawable->getVObj()->isAttachment() || + (position-local_end).magVec() > ATTACHMENT_OVERRIDE_DIST) + { //avatar overrides if previously hit drawable is not an attachment or + //attachment is far enough away from detected intersection + drawable = hit; + local_end = position; + } + else + { //prioritize attachments over avatars + position = local_end; + + if (face_hit) + { + *face_hit = local_face_hit; + } + if (tex_coord) + { + *tex_coord = local_texcoord; + } + if (bi_normal) + { + *bi_normal = local_binormal; + } + if (normal) + { + *normal = local_normal; + } + } + } + } + } + } + + //check all avatar nametags (silly, isn't it?) + for (std::vector< LLCharacter* >::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); + ++iter) + { + LLVOAvatar* av = (LLVOAvatar*) *iter; + if (av->mNameText.notNull() + && av->mNameText->lineSegmentIntersect(start, local_end, position)) + { + drawable = av->mDrawable; + local_end = position; + } + } + + if (intersection) + { + *intersection = position; + } + + return drawable ? drawable->getVObj().get() : NULL; +} + +LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end, + BOOL pick_transparent, + S32* face_hit, + LLVector3* intersection, // return the intersection point + LLVector2* tex_coord, // return the texture coordinates of the intersection point + LLVector3* normal, // return the surface normal at the intersection point + LLVector3* bi_normal // return the surface bi-normal at the intersection point + ) +{ + LLDrawable* drawable = NULL; + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + + BOOL toggle = FALSE; + if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + toggleRenderType(LLPipeline::RENDER_TYPE_HUD); + toggle = TRUE; + } + + LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_HUD); + if (part) + { + LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal); + if (hit) + { + drawable = hit; + } + } + + if (toggle) + { + toggleRenderType(LLPipeline::RENDER_TYPE_HUD); + } + } + return drawable ? drawable->getVObj().get() : NULL; +} + +LLSpatialPartition* LLPipeline::getSpatialPartition(LLViewerObject* vobj) +{ + if (vobj) + { + LLViewerRegion* region = vobj->getRegion(); + if (region) + { + return region->getSpatialPartition(vobj->getPartitionType()); + } + } + return NULL; +} + + +void LLPipeline::resetVertexBuffers(LLDrawable* drawable) +{ + if (!drawable || drawable->isDead()) + { + return; + } + + for (S32 i = 0; i < drawable->getNumFaces(); i++) + { + LLFace* facep = drawable->getFace(i); + facep->mVertexBuffer = NULL; + facep->mLastVertexBuffer = NULL; + } +} + +void LLPipeline::resetVertexBuffers() +{ + sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); + sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips"); + LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO"); + LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw"); + LLVertexBuffer::sEnableVBOs = gSavedSettings.getBOOL("RenderVBOEnable"); + sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight"); + sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha"); + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + part->resetVertexBuffers(); + } + } + } + + resetDrawOrders(); + + gSky.resetVertexBuffers(); + + if (LLVertexBuffer::sGLCount > 0) + { + LLVertexBuffer::cleanupClass(); + } + + //delete all name pool caches + LLGLNamePool::cleanupPools(); + + if (LLVertexBuffer::sGLCount > 0) + { + llwarns << "VBO wipe failed." << llendl; + } + + if (!LLVertexBuffer::sStreamIBOPool.mNameList.empty() || + !LLVertexBuffer::sStreamVBOPool.mNameList.empty() || + !LLVertexBuffer::sDynamicIBOPool.mNameList.empty() || + !LLVertexBuffer::sDynamicVBOPool.mNameList.empty()) + { + llwarns << "VBO name pool cleanup failed." << llendl; + } + + LLVertexBuffer::unbind(); + + LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind"); +} + +void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture) +{ + LLMemType mt_ro(LLMemType::MTYPE_PIPELINE_RENDER_OBJECTS); + assertInitialized(); + glLoadMatrixd(gGLModelView); + gGLLastMatrix = NULL; + mSimplePool->pushBatches(type, mask); + glLoadMatrixd(gGLModelView); + gGLLastMatrix = NULL; +} + +void apply_cube_face_rotation(U32 face) +{ + switch (face) + { + case 0: + glRotatef(90.f, 0, 1, 0); + glRotatef(180.f, 1, 0, 0); + break; + case 2: + glRotatef(-90.f, 1, 0, 0); + break; + case 4: + glRotatef(180.f, 0, 1, 0); + glRotatef(180.f, 0, 0, 1); + break; + case 1: + glRotatef(-90.f, 0, 1, 0); + glRotatef(180.f, 1, 0, 0); + break; + case 3: + glRotatef(90, 1, 0, 0); + break; + case 5: + glRotatef(180, 0, 0, 1); + break; + } +} + +void validate_framebuffer_object() +{ + GLenum status; + status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT); + switch(status) + { + case GL_FRAMEBUFFER_COMPLETE: + //framebuffer OK, no error. + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + // frame buffer not OK: probably means unsupported depth buffer format + llerrs << "Framebuffer Incomplete Missing Attachment." << llendl; + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + // frame buffer not OK: probably means unsupported depth buffer format + llerrs << "Framebuffer Incomplete Attachment." << llendl; + break; + case GL_FRAMEBUFFER_UNSUPPORTED: + /* choose different formats */ + llerrs << "Framebuffer unsupported." << llendl; + break; + default: + llerrs << "Unknown framebuffer status." << llendl; + break; + } +} + +void LLPipeline::bindScreenToTexture() +{ + +} + +static LLFastTimer::DeclareTimer FTM_RENDER_BLOOM("Bloom"); + +void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) +{ + LLMemType mt_ru(LLMemType::MTYPE_PIPELINE_RENDER_BLOOM); + if (!(gPipeline.canUseVertexShaders() && + sRenderGlow)) + { + return; + } + + LLVertexBuffer::unbind(); + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + + assertInitialized(); + + if (gUseWireframe) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + + U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor"); + + LLVector2 tc1(0,0); + LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2, + (F32) gViewerWindow->getWorldViewHeightRaw()*2); + + if (res_mod > 1) + { + tc2 /= (F32) res_mod; + } + + LLFastTimer ftm(FTM_RENDER_BLOOM); + gGL.color4f(1,1,1,1); + LLGLDepthTest depth(GL_FALSE); + LLGLDisable blend(GL_BLEND); + LLGLDisable cull(GL_CULL_FACE); + + enableLightsFullbright(LLColor4(1,1,1,1)); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + LLGLDisable test(GL_ALPHA_TEST); + + gGL.setColorMask(true, true); + glClearColor(0,0,0,0); + + /*if (for_snapshot) + { + gGL.getTexUnit(0)->bind(&mGlow[1]); + { + //LLGLEnable stencil(GL_STENCIL_TEST); + //glStencilFunc(GL_NOTEQUAL, 255, 0xFFFFFFFF); + //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + //LLGLDisable blend(GL_BLEND); + + // If the snapshot is constructed from tiles, calculate which + // tile we're in. + + //from LLViewerCamera::setPerpsective + if (zoom_factor > 1.f) + { + int pos_y = subfield / llceil(zoom_factor); + int pos_x = subfield - (pos_y*llceil(zoom_factor)); + F32 size = 1.f/zoom_factor; + + tc1.set(pos_x*size, pos_y*size); + tc2 = tc1 + LLVector2(size,size); + } + else + { + tc2.set(1,1); + } + + LLGLEnable blend(GL_BLEND); + gGL.setSceneBlendType(LLRender::BT_ADD); + + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.color4f(1,1,1,1); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1,-1); + + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1,1); + + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(1,-1); + + gGL.texCoord2f(tc2.mV[0], tc2.mV[1]); + gGL.vertex2f(1,1); + + gGL.end(); + + gGL.flush(); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + + gGL.flush(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + return; + }*/ + + { + { + LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); + mGlow[2].bindTarget(); + mGlow[2].clear(); + } + + gGlowExtractProgram.bind(); + F32 minLum = llmax(gSavedSettings.getF32("RenderGlowMinLuminance"), 0.0f); + F32 maxAlpha = gSavedSettings.getF32("RenderGlowMaxExtractAlpha"); + F32 warmthAmount = gSavedSettings.getF32("RenderGlowWarmthAmount"); + LLVector3 lumWeights = gSavedSettings.getVector3("RenderGlowLumWeights"); + LLVector3 warmthWeights = gSavedSettings.getVector3("RenderGlowWarmthWeights"); + gGlowExtractProgram.uniform1f("minLuminance", minLum); + gGlowExtractProgram.uniform1f("maxExtractAlpha", maxAlpha); + gGlowExtractProgram.uniform3f("lumWeights", lumWeights.mV[0], lumWeights.mV[1], lumWeights.mV[2]); + gGlowExtractProgram.uniform3f("warmthWeights", warmthWeights.mV[0], warmthWeights.mV[1], warmthWeights.mV[2]); + gGlowExtractProgram.uniform1f("warmthAmount", warmthAmount); + LLGLEnable blend_on(GL_BLEND); + LLGLEnable test(GL_ALPHA_TEST); + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->disable(); + gGL.getTexUnit(0)->enable(LLTexUnit::TT_RECT_TEXTURE); + gGL.getTexUnit(0)->bind(&mScreen); + + gGL.color4f(1,1,1,1); + gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1,-1); + + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1,3); + + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3,-1); + + gGL.end(); + + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); + + mGlow[2].flush(); + } + + tc1.setVec(0,0); + tc2.setVec(2,2); + + // power of two between 1 and 1024 + U32 glowResPow = gSavedSettings.getS32("RenderGlowResolutionPow"); + const U32 glow_res = llmax(1, + llmin(1024, 1 << glowResPow)); + + S32 kernel = gSavedSettings.getS32("RenderGlowIterations")*2; + F32 delta = gSavedSettings.getF32("RenderGlowWidth") / glow_res; + // Use half the glow width if we have the res set to less than 9 so that it looks + // almost the same in either case. + if (glowResPow < 9) + { + delta *= 0.5f; + } + F32 strength = gSavedSettings.getF32("RenderGlowStrength"); + + gGlowProgram.bind(); + gGlowProgram.uniform1f("glowStrength", strength); + + for (S32 i = 0; i < kernel; i++) + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + { + LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); + mGlow[i%2].bindTarget(); + mGlow[i%2].clear(); + } + + if (i == 0) + { + gGL.getTexUnit(0)->bind(&mGlow[2]); + } + else + { + gGL.getTexUnit(0)->bind(&mGlow[(i-1)%2]); + } + + if (i%2 == 0) + { + gGlowProgram.uniform2f("glowDelta", delta, 0); + } + else + { + gGlowProgram.uniform2f("glowDelta", 0, delta); + } + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1,-1); + + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1,3); + + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3,-1); + + gGL.end(); + + mGlow[i%2].flush(); + } + + gGlowProgram.unbind(); + + if (LLRenderTarget::sUseFBO) + { + LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; + gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; + gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); + gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); + glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); + + tc2.setVec((F32) gViewerWindow->getWorldViewWidthRaw(), + (F32) gViewerWindow->getWorldViewHeightRaw()); + + gGL.flush(); + + LLVertexBuffer::unbind(); + + if (LLPipeline::sRenderDeferred) + { + LLGLSLShader* shader = &gDeferredPostProgram; + if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) + { + shader = &gDeferredGIFinalProgram; + } + + LLGLDisable blend(GL_BLEND); + bindDeferredShader(*shader); + + //depth of field focal plane calculations + + F32 subject_distance = 16.f; + if (LLViewerJoystick::getInstance()->getOverrideCamera()) + { + //flycam mode, use mouse cursor as focus point + LLVector3 eye = LLViewerCamera::getInstance()->getOrigin(); + subject_distance = (eye-gDebugRaycastIntersection).magVec(); + } + else + { + LLViewerObject* obj = gAgentCamera.getFocusObject(); + if (obj) + { + LLVector3 focus = LLVector3(gAgentCamera.getFocusGlobal()-gAgent.getRegion()->getOriginGlobal()); + LLVector3 eye = LLViewerCamera::getInstance()->getOrigin(); + subject_distance = (focus-eye).magVec(); + } + } + + //convert to mm + subject_distance *= 1000.f; + F32 fnumber = gSavedSettings.getF32("CameraFNumber"); + const F32 default_focal_length = gSavedSettings.getF32("CameraFocalLength"); + + F32 fov = LLViewerCamera::getInstance()->getView(); + + const F32 default_fov = gSavedSettings.getF32("CameraFieldOfView") * F_PI/180.f; + //const F32 default_aspect_ratio = gSavedSettings.getF32("CameraAspectRatio"); + + //F32 aspect_ratio = (F32) mScreen.getWidth()/(F32)mScreen.getHeight(); + + F32 dv = 2.f*default_focal_length * tanf(default_fov/2.f); + //F32 dh = 2.f*default_focal_length * tanf(default_fov*default_aspect_ratio/2.f); + + F32 focal_length = dv/(2*tanf(fov/2.f)); + + //F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle); + + // from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f)) + // where N = fnumber + // s2 = dot distance + // s1 = subject distance + // f = focal length + // + + F32 blur_constant = focal_length*focal_length/(fnumber*(subject_distance-focal_length)); + blur_constant /= 1000.f; //convert to meters for shader + F32 magnification = focal_length/(subject_distance-focal_length); + + shader->uniform1f("focal_distance", -subject_distance/1000.f); + shader->uniform1f("blur_constant", blur_constant); + shader->uniform1f("tan_pixel_angle", tanf(1.f/LLDrawable::sCurPixelAngle)); + shader->uniform1f("magnification", magnification); + + S32 channel = shader->enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + mScreen.bindTexture(0, channel); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + //channel = shader->enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE); + //if (channel > -1) + //{ + //gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + //} + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1,-1); + + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1,3); + + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3,-1); + + gGL.end(); + + unbindDeferredShader(*shader); + } + else + { + if (res_mod > 1) + { + tc2 /= (F32) res_mod; + } + + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; + LLPointer buff = new LLVertexBuffer(mask, 0); + buff->allocateBuffer(3,0,TRUE); + + LLStrider v; + LLStrider uv1; + LLStrider uv2; + + buff->getVertexStrider(v); + buff->getTexCoord0Strider(uv1); + buff->getTexCoord1Strider(uv2); + + uv1[0] = LLVector2(0, 0); + uv1[1] = LLVector2(0, 2); + uv1[2] = LLVector2(2, 0); + + uv2[0] = LLVector2(0, 0); + uv2[1] = LLVector2(0, tc2.mV[1]*2.f); + uv2[2] = LLVector2(tc2.mV[0]*2.f, 0); + + v[0] = LLVector3(-1,-1,0); + v[1] = LLVector3(-1,3,0); + v[2] = LLVector3(3,-1,0); + + buff->setBuffer(0); + + LLGLDisable blend(GL_BLEND); + + //tex unit 0 + gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR); + + gGL.getTexUnit(0)->bind(&mGlow[1]); + gGL.getTexUnit(1)->activate(); + gGL.getTexUnit(1)->enable(LLTexUnit::TT_RECT_TEXTURE); + + + //tex unit 1 + gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR); + + gGL.getTexUnit(1)->bind(&mScreen); + gGL.getTexUnit(1)->activate(); + + LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); + + buff->setBuffer(mask); + buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3); + + gGL.getTexUnit(1)->disable(); + gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT); + + gGL.getTexUnit(0)->activate(); + gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); + } + + if (LLRenderTarget::sUseFBO) + { //copy depth buffer from mScreen to framebuffer + LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(), + 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } + + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)) + { + LLVector2 tc1(0,0); + LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2, + (F32) gViewerWindow->getWorldViewHeightRaw()*2); + + LLGLEnable blend(GL_BLEND); + gGL.color4f(1,1,1,0.75f); + + gGL.getTexUnit(0)->bind(&mPhysicsDisplay); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1,-1); + + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1,3); + + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3,-1); + + gGL.end(); + gGL.flush(); + } + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + LLVertexBuffer::unbind(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + +} + +static LLFastTimer::DeclareTimer FTM_BIND_DEFERRED("Bind Deferred"); + +void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, LLRenderTarget* gi_source, LLRenderTarget* last_gi_post, U32 noise_map) +{ + LLFastTimer t(FTM_BIND_DEFERRED); + + if (noise_map == 0xFFFFFFFF) + { + noise_map = mNoiseMap; + } + + LLGLState::checkTextureChannels(); + + shader.bind(); + S32 channel = 0; + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + mDeferredScreen.bindTexture(0,channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + mDeferredScreen.bindTexture(1, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + mDeferredScreen.bindTexture(2, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + if (gi_source) + { + BOOL has_gi = FALSE; + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE); + if (channel > -1) + { + has_gi = TRUE; + gi_source->bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR); + if (channel > -1) + { + has_gi = TRUE; + gi_source->bindTexture(1, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL); + if (channel > -1) + { + has_gi = TRUE; + gi_source->bindTexture(2, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS); + if (channel > -1) + { + has_gi = TRUE; + gi_source->bindTexture(1, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS); + if (channel > -1) + { + has_gi = TRUE; + gi_source->bindTexture(3, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE); + if (channel > -1) + { + has_gi = TRUE; + last_gi_post->bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL); + if (channel > -1) + { + has_gi = TRUE; + last_gi_post->bindTexture(2, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS); + if (channel > -1) + { + has_gi = TRUE; + last_gi_post->bindTexture(1, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS); + if (channel > -1) + { + has_gi = TRUE; + last_gi_post->bindTexture(3, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH); + if (channel > -1) + { + has_gi = TRUE; + gGL.getTexUnit(channel)->bind(gi_source, TRUE); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + stop_glerror(); + + glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA); + + stop_glerror(); + } + + if (has_gi) + { + F32 range_x = llmin(mGIRange.mV[0], 1.f); + F32 range_y = llmin(mGIRange.mV[1], 1.f); + + LLVector2 scale(range_x,range_y); + + LLVector2 kern[25]; + + for (S32 i = 0; i < 5; ++i) + { + for (S32 j = 0; j < 5; ++j) + { + S32 idx = i*5+j; + kern[idx].mV[0] = (i-2)*0.5f; + kern[idx].mV[1] = (j-2)*0.5f; + kern[idx].scaleVec(scale); + } + } + + shader.uniform2fv("gi_kern", 25, (F32*) kern); + shader.uniformMatrix4fv("gi_mat", 1, FALSE, mGIMatrix.m); + shader.uniformMatrix4fv("gi_mat_proj", 1, FALSE, mGIMatrixProj.m); + shader.uniformMatrix4fv("gi_inv_proj", 1, FALSE, mGIInvProj.m); + shader.uniformMatrix4fv("gi_norm_mat", 1, FALSE, mGINormalMatrix.m); + } + } + + /*channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + mDeferredScreen.bindTexture(3, channel); + }*/ + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + stop_glerror(); + + glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA); + + stop_glerror(); + + glh::matrix4f projection = glh_get_current_projection(); + glh::matrix4f inv_proj = projection.inverse(); + + shader.uniformMatrix4fv("inv_proj", 1, FALSE, inv_proj.m); + shader.uniform4f("viewport", (F32) gGLViewport[0], + (F32) gGLViewport[1], + (F32) gGLViewport[2], + (F32) gGLViewport[3]); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NOISE); + if (channel > -1) + { + gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, noise_map); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC); + if (channel > -1) + { + gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); + } + + stop_glerror(); + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + mDeferredLight[light_index].bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE); + if (channel > -1) + { + gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_BLOOM); + if (channel > -1) + { + mGlow[1].bindTexture(0, channel); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + gi_source->bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + mEdgeMap.bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + mDeferredLight[1].bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + mDeferredLight[2].bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + + stop_glerror(); + + for (U32 i = 0; i < 4; i++) + { + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE); + stop_glerror(); + if (channel > -1) + { + stop_glerror(); + gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + stop_glerror(); + + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + stop_glerror(); + } + } + + for (U32 i = 4; i < 6; i++) + { + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i); + stop_glerror(); + if (channel > -1) + { + stop_glerror(); + gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + stop_glerror(); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + stop_glerror(); + } + } + + stop_glerror(); + + F32 mat[16*6]; + for (U32 i = 0; i < 16; i++) + { + mat[i] = mSunShadowMatrix[0].m[i]; + mat[i+16] = mSunShadowMatrix[1].m[i]; + mat[i+32] = mSunShadowMatrix[2].m[i]; + mat[i+48] = mSunShadowMatrix[3].m[i]; + mat[i+64] = mSunShadowMatrix[4].m[i]; + mat[i+80] = mSunShadowMatrix[5].m[i]; + } + + shader.uniformMatrix4fv("shadow_matrix[0]", 6, FALSE, mat); + shader.uniformMatrix4fv("shadow_matrix", 6, FALSE, mat); + + stop_glerror(); + + channel = shader.enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); + if (channel > -1) + { + LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; + if (cube_map) + { + cube_map->enable(channel); + cube_map->bind(); + F64* m = gGLModelView; + + + F32 mat[] = { m[0], m[1], m[2], + m[4], m[5], m[6], + m[8], m[9], m[10] }; + + shader.uniform3fv("env_mat[0]", 3, mat); + shader.uniform3fv("env_mat", 3, mat); + } + } + + shader.uniform4fv("shadow_clip", 1, mSunClipPlanes.mV); + shader.uniform1f("sun_wash", gSavedSettings.getF32("RenderDeferredSunWash")); + shader.uniform1f("shadow_noise", gSavedSettings.getF32("RenderShadowNoise")); + shader.uniform1f("blur_size", gSavedSettings.getF32("RenderShadowBlurSize")); + + shader.uniform1f("ssao_radius", gSavedSettings.getF32("RenderSSAOScale")); + shader.uniform1f("ssao_max_radius", gSavedSettings.getU32("RenderSSAOMaxScale")); + + F32 ssao_factor = gSavedSettings.getF32("RenderSSAOFactor"); + shader.uniform1f("ssao_factor", ssao_factor); + shader.uniform1f("ssao_factor_inv", 1.0/ssao_factor); + + LLVector3 ssao_effect = gSavedSettings.getVector3("RenderSSAOEffect"); + F32 matrix_diag = (ssao_effect[0] + 2.0*ssao_effect[1])/3.0; + F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1])/3.0; + // This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by + // value factor, and scales remainder by saturation factor + F32 ssao_effect_mat[] = { matrix_diag, matrix_nondiag, matrix_nondiag, + matrix_nondiag, matrix_diag, matrix_nondiag, + matrix_nondiag, matrix_nondiag, matrix_diag}; + shader.uniformMatrix3fv("ssao_effect_mat", 1, GL_FALSE, ssao_effect_mat); + + F32 shadow_offset_error = 1.f + gSavedSettings.getF32("RenderShadowOffsetError") * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]); + F32 shadow_bias_error = 1.f + gSavedSettings.getF32("RenderShadowBiasError") * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]); + + shader.uniform2f("screen_res", mDeferredScreen.getWidth(), mDeferredScreen.getHeight()); + shader.uniform1f("near_clip", LLViewerCamera::getInstance()->getNear()*2.f); + shader.uniform1f ("shadow_offset", gSavedSettings.getF32("RenderShadowOffset")*shadow_offset_error); + shader.uniform1f("shadow_bias", gSavedSettings.getF32("RenderShadowBias")*shadow_bias_error); + shader.uniform1f ("spot_shadow_offset", gSavedSettings.getF32("RenderSpotShadowOffset")); + shader.uniform1f("spot_shadow_bias", gSavedSettings.getF32("RenderSpotShadowBias")); + + shader.uniform1f("lum_scale", gSavedSettings.getF32("RenderLuminanceScale")); + shader.uniform1f("sun_lum_scale", gSavedSettings.getF32("RenderSunLuminanceScale")); + shader.uniform1f("sun_lum_offset", gSavedSettings.getF32("RenderSunLuminanceOffset")); + shader.uniform1f("lum_lod", gSavedSettings.getF32("RenderLuminanceDetail")); + shader.uniform1f("gi_range", gSavedSettings.getF32("RenderGIRange")); + shader.uniform1f("gi_brightness", gSavedSettings.getF32("RenderGIBrightness")); + shader.uniform1f("gi_luminance", gSavedSettings.getF32("RenderGILuminance")); + shader.uniform1f("gi_edge_weight", gSavedSettings.getF32("RenderGIBlurEdgeWeight")); + shader.uniform1f("gi_blur_brightness", gSavedSettings.getF32("RenderGIBlurBrightness")); + shader.uniform1f("gi_sample_width", mGILightRadius); + shader.uniform1f("gi_noise", gSavedSettings.getF32("RenderGINoise")); + shader.uniform1f("gi_attenuation", gSavedSettings.getF32("RenderGIAttenuation")); + shader.uniform1f("gi_ambiance", gSavedSettings.getF32("RenderGIAmbiance")); + shader.uniform2f("shadow_res", mShadow[0].getWidth(), mShadow[0].getHeight()); + shader.uniform2f("proj_shadow_res", mShadow[4].getWidth(), mShadow[4].getHeight()); + shader.uniform1f("depth_cutoff", gSavedSettings.getF32("RenderEdgeDepthCutoff")); + shader.uniform1f("norm_cutoff", gSavedSettings.getF32("RenderEdgeNormCutoff")); + + + if (shader.getUniformLocation("norm_mat") >= 0) + { + glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose(); + shader.uniformMatrix4fv("norm_mat", 1, FALSE, norm_mat.m); + } +} + +static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace"); +static LLFastTimer::DeclareTimer FTM_GI_GATHER("Gather"); +static LLFastTimer::DeclareTimer FTM_SUN_SHADOW("Shadow Map"); +static LLFastTimer::DeclareTimer FTM_SOFTEN_SHADOW("Shadow Soften"); +static LLFastTimer::DeclareTimer FTM_EDGE_DETECTION("Find Edges"); +static LLFastTimer::DeclareTimer FTM_LOCAL_LIGHTS("Local Lights"); +static LLFastTimer::DeclareTimer FTM_ATMOSPHERICS("Atmospherics"); +static LLFastTimer::DeclareTimer FTM_FULLSCREEN_LIGHTS("Fullscreen Lights"); +static LLFastTimer::DeclareTimer FTM_PROJECTORS("Projectors"); +static LLFastTimer::DeclareTimer FTM_POST("Post"); + + +void LLPipeline::renderDeferredLighting() +{ + if (!sCull) + { + return; + } + + { + LLFastTimer ftm(FTM_RENDER_DEFERRED); + + LLViewerCamera* camera = LLViewerCamera::getInstance(); + { + LLGLDepthTest depth(GL_TRUE); + mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), + 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } + + LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0); + + if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); + } + + //ati doesn't seem to love actually using the stencil buffer on FBO's + LLGLEnable stencil(GL_STENCIL_TEST); + glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + gGL.setColorMask(true, true); + + //draw a cube around every light + LLVertexBuffer::unbind(); + + LLGLEnable cull(GL_CULL_FACE); + LLGLEnable blend(GL_BLEND); + + glh::matrix4f mat = glh_copy_matrix(gGLModelView); + + F32 vert[] = + { + -1,1, + -1,-3, + 3,1, + }; + glVertexPointer(2, GL_FLOAT, 0, vert); + glColor3f(1,1,1); + + { + setupHWLights(NULL); //to set mSunDir; + LLVector4 dir(mSunDir, 0.f); + glh::vec4f tc(dir.mV); + mat.mult_matrix_vec(tc); + glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], 0); + } + + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + if (gSavedSettings.getBOOL("RenderDeferredSSAO") || gSavedSettings.getS32("RenderShadowDetail") > 0) + { + mDeferredLight[0].bindTarget(); + { //paint shadow/SSAO light map (direct lighting lightmap) + LLFastTimer ftm(FTM_SUN_SHADOW); + bindDeferredShader(gDeferredSunProgram, 0); + + glClearColor(1,1,1,1); + mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT); + glClearColor(0,0,0,0); + + glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); + + const U32 slice = 32; + F32 offset[slice*3]; + for (U32 i = 0; i < 4; i++) + { + for (U32 j = 0; j < 8; j++) + { + glh::vec3f v; + v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i); + v.normalize(); + inv_trans.mult_matrix_vec(v); + v.normalize(); + offset[(i*8+j)*3+0] = v.v[0]; + offset[(i*8+j)*3+1] = v.v[2]; + offset[(i*8+j)*3+2] = v.v[1]; + } + } + + gDeferredSunProgram.uniform3fv("offset", slice, offset); + gDeferredSunProgram.uniform2f("screenRes", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight()); + + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + stop_glerror(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + stop_glerror(); + } + + unbindDeferredShader(gDeferredSunProgram); + } + mDeferredLight[0].flush(); + } + + { //global illumination specific block (still experimental) + if (gSavedSettings.getBOOL("RenderDeferredBlurLight") && + gSavedSettings.getBOOL("RenderDeferredGI")) + { + LLFastTimer ftm(FTM_EDGE_DETECTION); + //generate edge map + LLGLDisable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + LLGLDepthTest depth(GL_FALSE); + LLGLDisable stencil(GL_STENCIL_TEST); + + { + gDeferredEdgeProgram.bind(); + mEdgeMap.bindTarget(); + bindDeferredShader(gDeferredEdgeProgram); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + unbindDeferredShader(gDeferredEdgeProgram); + mEdgeMap.flush(); + } + } + + if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) + { + { //get luminance map from previous frame's light map + LLGLEnable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + LLGLDepthTest depth(GL_FALSE); + LLGLDisable stencil(GL_STENCIL_TEST); + + //static F32 fade = 1.f; + + { + gGL.setSceneBlendType(LLRender::BT_ALPHA); + gLuminanceGatherProgram.bind(); + gLuminanceGatherProgram.uniform2f("screen_res", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight()); + mLuminanceMap.bindTarget(); + bindDeferredShader(gLuminanceGatherProgram); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + unbindDeferredShader(gLuminanceGatherProgram); + mLuminanceMap.flush(); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR); + glGenerateMipmap(GL_TEXTURE_2D); + } + } + + { //paint noisy GI map (bounce lighting lightmap) + LLFastTimer ftm(FTM_GI_TRACE); + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_FALSE); + LLGLDisable test(GL_ALPHA_TEST); + + mGIMapPost[0].bindTarget(); + + bindDeferredShader(gDeferredGIProgram, 0, &mGIMap, 0, mTrueNoiseMap); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + unbindDeferredShader(gDeferredGIProgram); + mGIMapPost[0].flush(); + } + + U32 pass_count = 0; + if (gSavedSettings.getBOOL("RenderDeferredBlurLight")) + { + pass_count = llclamp(gSavedSettings.getU32("RenderGIBlurPasses"), (U32) 1, (U32) 128); + } + + for (U32 i = 0; i < pass_count; ++i) + { //gather/soften indirect lighting map + LLFastTimer ftm(FTM_GI_GATHER); + bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[0], NULL, mTrueNoiseMap); + F32 blur_size = gSavedSettings.getF32("RenderGIBlurSize")/((F32) i * gSavedSettings.getF32("RenderGIBlurIncrement")+1.f); + gDeferredPostGIProgram.uniform2f("delta", 1.f, 0.f); + gDeferredPostGIProgram.uniform1f("kern_scale", blur_size); + gDeferredPostGIProgram.uniform1f("gi_blur_brightness", gSavedSettings.getF32("RenderGIBlurBrightness")); + + mGIMapPost[1].bindTarget(); + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_FALSE); + stop_glerror(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + stop_glerror(); + } + + mGIMapPost[1].flush(); + unbindDeferredShader(gDeferredPostGIProgram); + bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[1], NULL, mTrueNoiseMap); + mGIMapPost[0].bindTarget(); + + gDeferredPostGIProgram.uniform2f("delta", 0.f, 1.f); + + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_FALSE); + stop_glerror(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + stop_glerror(); + } + mGIMapPost[0].flush(); + unbindDeferredShader(gDeferredPostGIProgram); + } + } + } + + if (gSavedSettings.getBOOL("RenderDeferredSSAO")) + { //soften direct lighting lightmap + LLFastTimer ftm(FTM_SOFTEN_SHADOW); + //blur lightmap + mDeferredLight[1].bindTarget(); + + glClearColor(1,1,1,1); + mDeferredLight[1].clear(GL_COLOR_BUFFER_BIT); + glClearColor(0,0,0,0); + + bindDeferredShader(gDeferredBlurLightProgram); + + LLVector3 go = gSavedSettings.getVector3("RenderShadowGaussian"); + const U32 kern_length = 4; + F32 blur_size = gSavedSettings.getF32("RenderShadowBlurSize"); + F32 dist_factor = gSavedSettings.getF32("RenderShadowBlurDistFactor"); + + // sample symmetrically with the middle sample falling exactly on 0.0 + F32 x = 0.f; + + LLVector3 gauss[32]; // xweight, yweight, offset + + for (U32 i = 0; i < kern_length; i++) + { + gauss[i].mV[0] = llgaussian(x, go.mV[0]); + gauss[i].mV[1] = llgaussian(x, go.mV[1]); + gauss[i].mV[2] = x; + x += 1.f; + } + + gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f); + gDeferredBlurLightProgram.uniform1f("dist_factor", dist_factor); + gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV); + gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f)); + + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + stop_glerror(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + stop_glerror(); + } + + mDeferredLight[1].flush(); + unbindDeferredShader(gDeferredBlurLightProgram); + + bindDeferredShader(gDeferredBlurLightProgram, 1); + mDeferredLight[0].bindTarget(); + + gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f); + + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + stop_glerror(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + stop_glerror(); + } + mDeferredLight[0].flush(); + unbindDeferredShader(gDeferredBlurLightProgram); + } + + stop_glerror(); + glPopMatrix(); + stop_glerror(); + glMatrixMode(GL_MODELVIEW); + stop_glerror(); + glPopMatrix(); + stop_glerror(); + + //copy depth and stencil from deferred screen + //mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), + // 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); + + if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) + { + mDeferredLight[1].bindTarget(); + // clear color buffer here (GI) - zeroing alpha (glow) is important or it will accumulate against sky + glClearColor(0,0,0,0); + mScreen.clear(GL_COLOR_BUFFER_BIT); + } + else + { + mScreen.bindTarget(); + // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky + glClearColor(0,0,0,0); + mScreen.clear(GL_COLOR_BUFFER_BIT); + } + + if (gSavedSettings.getBOOL("RenderDeferredAtmospheric")) + { //apply sunlight contribution + LLFastTimer ftm(FTM_ATMOSPHERICS); + bindDeferredShader(gDeferredSoftenProgram, 0, &mGIMapPost[0]); + { + LLGLDepthTest depth(GL_FALSE); + LLGLDisable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + + //full screen blit + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glVertexPointer(2, GL_FLOAT, 0, vert); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + } + + unbindDeferredShader(gDeferredSoftenProgram); + } + + { //render sky + LLGLDisable blend(GL_BLEND); + LLGLDisable stencil(GL_STENCIL_TEST); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + gPipeline.pushRenderTypeMask(); + + gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_CLOUDS, + LLPipeline::RENDER_TYPE_WL_SKY, + LLPipeline::END_RENDER_TYPES); + + + renderGeomPostDeferred(*LLViewerCamera::getInstance()); + gPipeline.popRenderTypeMask(); + } + + BOOL render_local = gSavedSettings.getBOOL("RenderLocalLights"); + + if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) + { + mDeferredLight[1].flush(); + mDeferredLight[2].bindTarget(); + mDeferredLight[2].clear(GL_COLOR_BUFFER_BIT); + } + + if (render_local) + { + gGL.setSceneBlendType(LLRender::BT_ADD); + std::list fullscreen_lights; + LLDrawable::drawable_list_t spot_lights; + LLDrawable::drawable_list_t fullscreen_spot_lights; + + for (U32 i = 0; i < 2; i++) + { + mTargetShadowSpotLight[i] = NULL; + } + + std::list light_colors; + + LLVertexBuffer::unbind(); + + F32 v[24]; + glVertexPointer(3, GL_FLOAT, 0, v); + + { + bindDeferredShader(gDeferredLightProgram); + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter) + { + LLDrawable* drawablep = *iter; + + LLVOVolume* volume = drawablep->getVOVolume(); + if (!volume) + { + continue; + } + + if (volume->isAttachment()) + { + if (!sRenderAttachedLights) + { + continue; + } + } + + + LLVector4a center; + center.load3(drawablep->getPositionAgent().mV); + const F32* c = center.getF32ptr(); + F32 s = volume->getLightRadius()*1.5f; + + LLColor3 col = volume->getLightColor(); + col *= volume->getLightIntensity(); + + if (col.magVecSquared() < 0.001f) + { + continue; + } + + if (s <= 0.001f) + { + continue; + } + + LLVector4a sa; + sa.splat(s); + if (camera->AABBInFrustumNoFarClip(center, sa) == 0) + { + continue; + } + + sVisibleLightCount++; + + glh::vec3f tc(c); + mat.mult_matrix_vec(tc); + + //vertex positions are encoded so the 3 bits of their vertex index + //correspond to their axis facing, with bit position 3,2,1 matching + //axis facing x,y,z, bit set meaning positive facing, bit clear + //meaning negative facing + v[0] = c[0]-s; v[1] = c[1]-s; v[2] = c[2]-s; // 0 - 0000 + v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001 + v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010 + v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011 + + v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100 + v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101 + v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110 + v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111 + + if (camera->getOrigin().mV[0] > c[0] + s + 0.2f || + camera->getOrigin().mV[0] < c[0] - s - 0.2f || + camera->getOrigin().mV[1] > c[1] + s + 0.2f || + camera->getOrigin().mV[1] < c[1] - s - 0.2f || + camera->getOrigin().mV[2] > c[2] + s + 0.2f || + camera->getOrigin().mV[2] < c[2] - s - 0.2f) + { //draw box if camera is outside box + if (render_local) + { + if (volume->isLightSpotlight()) + { + drawablep->getVOVolume()->updateSpotLightPriority(); + spot_lights.push_back(drawablep); + continue; + } + + LLFastTimer ftm(FTM_LOCAL_LIGHTS); + glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); + glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f); + glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, + GL_UNSIGNED_BYTE, get_box_fan_indices_ptr(camera, center)); + stop_glerror(); + } + } + else + { + if (volume->isLightSpotlight()) + { + drawablep->getVOVolume()->updateSpotLightPriority(); + fullscreen_spot_lights.push_back(drawablep); + continue; + } + + fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s)); + light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f)); + } + } + unbindDeferredShader(gDeferredLightProgram); + } + + if (!spot_lights.empty()) + { + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + bindDeferredShader(gDeferredSpotLightProgram); + + gDeferredSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); + + for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter) + { + LLFastTimer ftm(FTM_PROJECTORS); + LLDrawable* drawablep = *iter; + + LLVOVolume* volume = drawablep->getVOVolume(); + + LLVector4a center; + center.load3(drawablep->getPositionAgent().mV); + const F32* c = center.getF32ptr(); + F32 s = volume->getLightRadius()*1.5f; + + sVisibleLightCount++; + + glh::vec3f tc(c); + mat.mult_matrix_vec(tc); + + setupSpotLight(gDeferredSpotLightProgram, drawablep); + + LLColor3 col = volume->getLightColor(); + col *= volume->getLightIntensity(); + + //vertex positions are encoded so the 3 bits of their vertex index + //correspond to their axis facing, with bit position 3,2,1 matching + //axis facing x,y,z, bit set meaning positive facing, bit clear + //meaning negative facing + v[0] = c[0]-s; v[1] = c[1]-s; v[2] = c[2]-s; // 0 - 0000 + v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001 + v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010 + v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011 + + v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100 + v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101 + v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110 + v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111 + + glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); + glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f); + glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, + GL_UNSIGNED_BYTE, get_box_fan_indices_ptr(camera, center)); + } + gDeferredSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); + unbindDeferredShader(gDeferredSpotLightProgram); + } + + { + bindDeferredShader(gDeferredMultiLightProgram); + + LLGLDepthTest depth(GL_FALSE); + + //full screen blit + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + U32 count = 0; + + const U32 max_count = 8; + LLVector4 light[max_count]; + LLVector4 col[max_count]; + + glVertexPointer(2, GL_FLOAT, 0, vert); + + F32 far_z = 0.f; + + while (!fullscreen_lights.empty()) + { + LLFastTimer ftm(FTM_FULLSCREEN_LIGHTS); + light[count] = fullscreen_lights.front(); + fullscreen_lights.pop_front(); + col[count] = light_colors.front(); + light_colors.pop_front(); + + far_z = llmin(light[count].mV[2]-sqrtf(light[count].mV[3]), far_z); + + count++; + if (count == max_count || fullscreen_lights.empty()) + { + gDeferredMultiLightProgram.uniform1i("light_count", count); + gDeferredMultiLightProgram.uniform4fv("light", count, (GLfloat*) light); + gDeferredMultiLightProgram.uniform4fv("light_col", count, (GLfloat*) col); + gDeferredMultiLightProgram.uniform1f("far_z", far_z); + far_z = 0.f; + count = 0; + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + } + } + + unbindDeferredShader(gDeferredMultiLightProgram); + + bindDeferredShader(gDeferredMultiSpotLightProgram); + + gDeferredMultiSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); + + for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter) + { + LLFastTimer ftm(FTM_PROJECTORS); + LLDrawable* drawablep = *iter; + + LLVOVolume* volume = drawablep->getVOVolume(); + + LLVector3 center = drawablep->getPositionAgent(); + F32* c = center.mV; + F32 s = volume->getLightRadius()*1.5f; + + sVisibleLightCount++; + + glh::vec3f tc(c); + mat.mult_matrix_vec(tc); + + setupSpotLight(gDeferredMultiSpotLightProgram, drawablep); + + LLColor3 col = volume->getLightColor(); + col *= volume->getLightIntensity(); + + glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); + glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + } + + gDeferredMultiSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); + unbindDeferredShader(gDeferredMultiSpotLightProgram); + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + } + } + + gGL.setColorMask(true, true); + + if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) + { + mDeferredLight[2].flush(); + + mScreen.bindTarget(); + mScreen.clear(GL_COLOR_BUFFER_BIT); + + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + { //mix various light maps (local, sun, gi) + LLFastTimer ftm(FTM_POST); + LLGLDisable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + LLGLDepthTest depth(GL_FALSE); + LLGLDisable stencil(GL_STENCIL_TEST); + + bindDeferredShader(gDeferredPostProgram, 0, &mGIMapPost[0]); + + gDeferredPostProgram.bind(); + + LLVertexBuffer::unbind(); + + glVertexPointer(2, GL_FLOAT, 0, vert); + glColor3f(1,1,1); + + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + unbindDeferredShader(gDeferredPostProgram); + } + } + } + + { //render non-deferred geometry (alpha, fullbright, glow) + LLGLDisable blend(GL_BLEND); + LLGLDisable stencil(GL_STENCIL_TEST); + + pushRenderTypeMask(); + andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA, + LLPipeline::RENDER_TYPE_FULLBRIGHT, + LLPipeline::RENDER_TYPE_VOLUME, + LLPipeline::RENDER_TYPE_GLOW, + LLPipeline::RENDER_TYPE_BUMP, + LLPipeline::RENDER_TYPE_PASS_SIMPLE, + LLPipeline::RENDER_TYPE_PASS_ALPHA, + LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, + LLPipeline::RENDER_TYPE_PASS_BUMP, + LLPipeline::RENDER_TYPE_PASS_POST_BUMP, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, + LLPipeline::RENDER_TYPE_PASS_GLOW, + LLPipeline::RENDER_TYPE_PASS_GRASS, + LLPipeline::RENDER_TYPE_PASS_SHINY, + LLPipeline::RENDER_TYPE_PASS_INVISIBLE, + LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY, + LLPipeline::RENDER_TYPE_AVATAR, + END_RENDER_TYPES); + + renderGeomPostDeferred(*LLViewerCamera::getInstance()); + popRenderTypeMask(); + } + + { + //render highlights, etc. + renderHighlights(); + mHighlightFaces.clear(); + + renderDebug(); + + LLVertexBuffer::unbind(); + + if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + // Render debugging beacons. + gObjectList.renderObjectBeacons(); + LLHUDObject::renderAll(); + gObjectList.resetObjectBeacons(); + } + } + + mScreen.flush(); + +} + +void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) +{ + //construct frustum + LLVOVolume* volume = drawablep->getVOVolume(); + LLVector3 params = volume->getSpotLightParams(); + + F32 fov = params.mV[0]; + F32 focus = params.mV[1]; + + LLVector3 pos = drawablep->getPositionAgent(); + LLQuaternion quat = volume->getRenderRotation(); + LLVector3 scale = volume->getScale(); + + //get near clip plane + LLVector3 at_axis(0,0,-scale.mV[2]*0.5f); + at_axis *= quat; + + LLVector3 np = pos+at_axis; + at_axis.normVec(); + + //get origin that has given fov for plane np, at_axis, and given scale + F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f); + + LLVector3 origin = np - at_axis*dist; + + //matrix from volume space to agent space + LLMatrix4 light_mat(quat, LLVector4(origin,1.f)); + + glh::matrix4f light_to_agent((F32*) light_mat.mMatrix); + glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent; + + glh::matrix4f screen_to_light = light_to_screen.inverse(); + + F32 s = volume->getLightRadius()*1.5f; + F32 near_clip = dist; + F32 width = scale.mV[VX]; + F32 height = scale.mV[VY]; + F32 far_clip = s+dist-scale.mV[VZ]; + + F32 fovy = fov * RAD_TO_DEG; + F32 aspect = width/height; + + glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, + 0.f, 0.5f, 0.f, 0.5f, + 0.f, 0.f, 0.5f, 0.5f, + 0.f, 0.f, 0.f, 1.f); + + glh::vec3f p1(0, 0, -(near_clip+0.01f)); + glh::vec3f p2(0, 0, -(near_clip+1.f)); + + glh::vec3f screen_origin(0, 0, 0); + + light_to_screen.mult_matrix_vec(p1); + light_to_screen.mult_matrix_vec(p2); + light_to_screen.mult_matrix_vec(screen_origin); + + glh::vec3f n = p2-p1; + n.normalize(); + + F32 proj_range = far_clip - near_clip; + glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip); + screen_to_light = trans * light_proj * screen_to_light; + shader.uniformMatrix4fv("proj_mat", 1, FALSE, screen_to_light.m); + shader.uniform1f("proj_near", near_clip); + shader.uniform3fv("proj_p", 1, p1.v); + shader.uniform3fv("proj_n", 1, n.v); + shader.uniform3fv("proj_origin", 1, screen_origin.v); + shader.uniform1f("proj_range", proj_range); + shader.uniform1f("proj_ambiance", params.mV[2]); + S32 s_idx = -1; + + for (U32 i = 0; i < 2; i++) + { + if (mShadowSpotLight[i] == drawablep) + { + s_idx = i; + } + } + + shader.uniform1i("proj_shadow_idx", s_idx); + + if (s_idx >= 0) + { + shader.uniform1f("shadow_fade", 1.f-mSpotLightFade[s_idx]); + } + else + { + shader.uniform1f("shadow_fade", 1.f); + } + + { + LLDrawable* potential = drawablep; + //determine if this is a good light for casting shadows + F32 m_pri = volume->getSpotLightPriority(); + + for (U32 i = 0; i < 2; i++) + { + F32 pri = 0.f; + + if (mTargetShadowSpotLight[i].notNull()) + { + pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority(); + } + + if (m_pri > pri) + { + LLDrawable* temp = mTargetShadowSpotLight[i]; + mTargetShadowSpotLight[i] = potential; + potential = temp; + m_pri = pri; + } + } + } + + LLViewerTexture* img = volume->getLightTexture(); + + S32 channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); + + if (channel > -1 && img) + { + gGL.getTexUnit(channel)->bind(img); + + F32 lod_range = logf(img->getWidth())/logf(2.f); + + shader.uniform1f("proj_focus", focus); + shader.uniform1f("proj_lod", lod_range); + shader.uniform1f("proj_ambient_lod", llclamp((proj_range-focus)/proj_range*lod_range, 0.f, 1.f)); + } +} + +void LLPipeline::unbindDeferredShader(LLGLSLShader &shader) +{ + stop_glerror(); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE); + shader.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIP); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_BLOOM); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS); + + for (U32 i = 0; i < 4; i++) + { + if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE) > -1) + { + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + } + } + + for (U32 i = 4; i < 6; i++) + { + if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i) > -1) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + } + } + + shader.disableTexture(LLViewerShaderMgr::DEFERRED_NOISE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC); + + S32 channel = shader.disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); + if (channel > -1) + { + LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; + if (cube_map) + { + cube_map->disable(); + } + } + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->activate(); + shader.unbind(); + + LLGLState::checkTextureChannels(); +} + +inline float sgn(float a) +{ + if (a > 0.0F) return (1.0F); + if (a < 0.0F) return (-1.0F); + return (0.0F); +} + +void LLPipeline::generateWaterReflection(LLCamera& camera_in) +{ + if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate) + { + BOOL skip_avatar_update = FALSE; + if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK) + { + skip_avatar_update = TRUE; + } + + if (!skip_avatar_update) + { + gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON); + } + LLVertexBuffer::unbind(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + + LLCamera camera = camera_in; + camera.setFar(camera.getFar()*0.87654321f); + LLPipeline::sReflectionRender = TRUE; + + gPipeline.pushRenderTypeMask(); + + glh::matrix4f projection = glh_get_current_projection(); + glh::matrix4f mat; + + stop_glerror(); + LLPlane plane; + + F32 height = gAgent.getRegion()->getWaterHeight(); + F32 to_clip = fabsf(camera.getOrigin().mV[2]-height); + F32 pad = -to_clip*0.05f; //amount to "pad" clip plane by + + //plane params + LLVector3 pnorm; + F32 pd; + + S32 water_clip = 0; + if (!LLViewerCamera::getInstance()->cameraUnderWater()) + { //camera is above water, clip plane points up + pnorm.setVec(0,0,1); + pd = -height; + plane.setVec(pnorm, pd); + water_clip = -1; + } + else + { //camera is below water, clip plane points down + pnorm = LLVector3(0,0,-1); + pd = height; + plane.setVec(pnorm, pd); + water_clip = 1; + } + + if (!LLViewerCamera::getInstance()->cameraUnderWater()) + { //generate planar reflection map + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + glClearColor(0,0,0,0); + mWaterRef.bindTarget(); + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER0; + gGL.setColorMask(true, true); + mWaterRef.clear(); + gGL.setColorMask(true, false); + + mWaterRef.getViewport(gGLViewport); + + stop_glerror(); + + glPushMatrix(); + + mat.set_scale(glh::vec3f(1,1,-1)); + mat.set_translate(glh::vec3f(0,0,height*2.f)); + + glh::matrix4f current = glh_get_current_modelview(); + + mat = current * mat; + + glh_set_current_modelview(mat); + glLoadMatrixf(mat.m); + + LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE); + + glh::matrix4f inv_mat = mat.inverse(); + + glh::vec3f origin(0,0,0); + inv_mat.mult_matrix_vec(origin); + + camera.setOrigin(origin.v); + + glCullFace(GL_FRONT); + + static LLCullResult ref_result; + + if (LLDrawPoolWater::sNeedsDistortionUpdate) + { + //initial sky pass (no user clip plane) + { //mask out everything but the sky + gPipeline.pushRenderTypeMask(); + gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_WL_SKY, + LLPipeline::END_RENDER_TYPES); + + static LLCullResult result; + updateCull(camera, result); + stateSort(camera, result); + + andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_CLOUDS, + LLPipeline::RENDER_TYPE_WL_SKY, + LLPipeline::END_RENDER_TYPES); + + //bad pop here + renderGeom(camera, TRUE); + + gPipeline.popRenderTypeMask(); + } + + gPipeline.pushRenderTypeMask(); + + clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER, + LLPipeline::RENDER_TYPE_VOIDWATER, + LLPipeline::RENDER_TYPE_GROUND, + LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_CLOUDS, + LLPipeline::END_RENDER_TYPES); + + S32 detail = gSavedSettings.getS32("RenderReflectionDetail"); + if (detail > 0) + { //mask out selected geometry based on reflection detail + if (detail < 4) + { + clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES); + if (detail < 3) + { + clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); + if (detail < 2) + { + clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES); + } + } + } + + LLGLUserClipPlane clip_plane(plane, mat, projection); + LLGLDisable cull(GL_CULL_FACE); + updateCull(camera, ref_result, 1); + stateSort(camera, ref_result); + } + + if (LLDrawPoolWater::sNeedsDistortionUpdate) + { + if (gSavedSettings.getS32("RenderReflectionDetail") > 0) + { + gPipeline.grabReferences(ref_result); + LLGLUserClipPlane clip_plane(plane, mat, projection); + renderGeom(camera); + } + } + + gPipeline.popRenderTypeMask(); + } + glCullFace(GL_BACK); + glPopMatrix(); + mWaterRef.flush(); + glh_set_current_modelview(current); + } + + camera.setOrigin(camera_in.getOrigin()); + //render distortion map + static BOOL last_update = TRUE; + if (last_update) + { + camera.setFar(camera_in.getFar()); + clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER, + LLPipeline::RENDER_TYPE_VOIDWATER, + LLPipeline::RENDER_TYPE_GROUND, + END_RENDER_TYPES); + stop_glerror(); + + LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? FALSE : TRUE; + + if (LLPipeline::sUnderWaterRender) + { + clearRenderTypeMask(LLPipeline::RENDER_TYPE_GROUND, + LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_CLOUDS, + LLPipeline::RENDER_TYPE_WL_SKY, + END_RENDER_TYPES); + } + LLViewerCamera::updateFrustumPlanes(camera); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLColor4& col = LLDrawPoolWater::sWaterFogColor; + glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); + mWaterDis.bindTarget(); + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1; + mWaterDis.getViewport(gGLViewport); + + if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate) + { + //clip out geometry on the same side of water as the camera + mat = glh_get_current_modelview(); + LLGLUserClipPlane clip_plane(LLPlane(-pnorm, -(pd+pad)), mat, projection); + static LLCullResult result; + updateCull(camera, result, water_clip); + stateSort(camera, result); + + gGL.setColorMask(true, true); + mWaterDis.clear(); + gGL.setColorMask(true, false); + + renderGeom(camera); + } + + LLPipeline::sUnderWaterRender = FALSE; + mWaterDis.flush(); + } + last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate; + + LLRenderTarget::unbindTarget(); + + LLPipeline::sReflectionRender = FALSE; + + if (!LLRenderTarget::sUseFBO) + { + glClear(GL_DEPTH_BUFFER_BIT); + } + glClearColor(0.f, 0.f, 0.f, 0.f); + gViewerWindow->setup3DViewport(); + gPipeline.popRenderTypeMask(); + LLDrawPoolWater::sNeedsReflectionUpdate = FALSE; + LLDrawPoolWater::sNeedsDistortionUpdate = FALSE; + LLPlane npnorm(-pnorm, -pd); + LLViewerCamera::getInstance()->setUserClipPlane(npnorm); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + + if (!skip_avatar_update) + { + gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode()); + } + + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + } +} + +glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up) +{ + glh::matrix4f ret; + + LLVector3 dirN; + LLVector3 upN; + LLVector3 lftN; + + lftN = dir % up; + lftN.normVec(); + + upN = lftN % dir; + upN.normVec(); + + dirN = dir; + dirN.normVec(); + + ret.m[ 0] = lftN[0]; + ret.m[ 1] = upN[0]; + ret.m[ 2] = -dirN[0]; + ret.m[ 3] = 0.f; + + ret.m[ 4] = lftN[1]; + ret.m[ 5] = upN[1]; + ret.m[ 6] = -dirN[1]; + ret.m[ 7] = 0.f; + + ret.m[ 8] = lftN[2]; + ret.m[ 9] = upN[2]; + ret.m[10] = -dirN[2]; + ret.m[11] = 0.f; + + ret.m[12] = -(lftN*pos); + ret.m[13] = -(upN*pos); + ret.m[14] = dirN*pos; + ret.m[15] = 1.f; + + return ret; +} + +glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max) +{ + glh::matrix4f ret; + ret.m[ 0] = 2/(max[0]-min[0]); + ret.m[ 4] = 0; + ret.m[ 8] = 0; + ret.m[12] = -(max[0]+min[0])/(max[0]-min[0]); + + ret.m[ 1] = 0; + ret.m[ 5] = 2/(max[1]-min[1]); + ret.m[ 9] = 0; + ret.m[13] = -(max[1]+min[1])/(max[1]-min[1]); + + ret.m[ 2] = 0; + ret.m[ 6] = 0; + ret.m[10] = 2/(max[2]-min[2]); + ret.m[14] = -(max[2]+min[2])/(max[2]-min[2]); + + ret.m[ 3] = 0; + ret.m[ 7] = 0; + ret.m[11] = 0; + ret.m[15] = 1; + + return ret; +} + +static LLFastTimer::DeclareTimer FTM_SHADOW_RENDER("Render Shadows"); +static LLFastTimer::DeclareTimer FTM_SHADOW_ALPHA("Alpha Shadow"); +static LLFastTimer::DeclareTimer FTM_SHADOW_SIMPLE("Simple Shadow"); + +void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion) +{ + LLFastTimer t(FTM_SHADOW_RENDER); + + //clip out geometry on the same side of water as the camera + S32 occlude = LLPipeline::sUseOcclusion; + if (!use_occlusion) + { + LLPipeline::sUseOcclusion = 0; + } + LLPipeline::sShadowRender = TRUE; + + U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY, LLRenderPass::PASS_BUMP, LLRenderPass::PASS_FULLBRIGHT_SHINY }; + LLGLEnable cull(GL_CULL_FACE); + + if (use_shader) + { + gDeferredShadowProgram.bind(); + } + + updateCull(shadow_cam, result); + stateSort(shadow_cam, result); + + //generate shadow map + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadMatrixf(proj.m); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadMatrixd(gGLModelView); + + stop_glerror(); + gGLLastMatrix = NULL; + + { + //LLGLDepthTest depth(GL_TRUE); + //glClear(GL_DEPTH_BUFFER_BIT); + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + glColor4f(1,1,1,1); + + stop_glerror(); + + gGL.setColorMask(false, false); + + //glCullFace(GL_FRONT); + + LLVertexBuffer::unbind(); + + { + LLFastTimer ftm(FTM_SHADOW_SIMPLE); + LLGLDisable test(GL_ALPHA_TEST); + gGL.getTexUnit(0)->disable(); + for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i) + { + renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE); + } + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); + } + + if (use_shader) + { + gDeferredShadowProgram.unbind(); + renderGeomShadow(shadow_cam); + gDeferredShadowProgram.bind(); + } + else + { + renderGeomShadow(shadow_cam); + } + + { + LLFastTimer ftm(FTM_SHADOW_ALPHA); + LLGLEnable test(GL_ALPHA_TEST); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.6f); + renderObjects(LLRenderPass::PASS_ALPHA_SHADOW, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR, TRUE); + glColor4f(1,1,1,1); + renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE); + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + } + + //glCullFace(GL_BACK); + + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + doOcclusion(shadow_cam); + + if (use_shader) + { + gDeferredShadowProgram.unbind(); + } + + gGL.setColorMask(true, true); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + gGLLastMatrix = NULL; + + LLPipeline::sUseOcclusion = occlude; + LLPipeline::sShadowRender = FALSE; +} + +static LLFastTimer::DeclareTimer FTM_VISIBLE_CLOUD("Visible Cloud"); +BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector& fp, LLVector3 light_dir) +{ + LLFastTimer t(FTM_VISIBLE_CLOUD); + //get point cloud of intersection of frust and min, max + + if (getVisibleExtents(camera, min, max)) + { + return FALSE; + } + + //get set of planes on bounding box + LLPlane bp[] = { + LLPlane(min, LLVector3(-1,0,0)), + LLPlane(min, LLVector3(0,-1,0)), + LLPlane(min, LLVector3(0,0,-1)), + LLPlane(max, LLVector3(1,0,0)), + LLPlane(max, LLVector3(0,1,0)), + LLPlane(max, LLVector3(0,0,1))}; + + //potential points + std::vector pp; + + //add corners of AABB + pp.push_back(LLVector3(min.mV[0], min.mV[1], min.mV[2])); + pp.push_back(LLVector3(max.mV[0], min.mV[1], min.mV[2])); + pp.push_back(LLVector3(min.mV[0], max.mV[1], min.mV[2])); + pp.push_back(LLVector3(max.mV[0], max.mV[1], min.mV[2])); + pp.push_back(LLVector3(min.mV[0], min.mV[1], max.mV[2])); + pp.push_back(LLVector3(max.mV[0], min.mV[1], max.mV[2])); + pp.push_back(LLVector3(min.mV[0], max.mV[1], max.mV[2])); + pp.push_back(LLVector3(max.mV[0], max.mV[1], max.mV[2])); + + //add corners of camera frustum + for (U32 i = 0; i < 8; i++) + { + pp.push_back(camera.mAgentFrustum[i]); + } + + + //bounding box line segments + U32 bs[] = + { + 0,1, + 1,3, + 3,2, + 2,0, + + 4,5, + 5,7, + 7,6, + 6,4, + + 0,4, + 1,5, + 3,7, + 2,6 + }; + + for (U32 i = 0; i < 12; i++) + { //for each line segment in bounding box + for (U32 j = 0; j < 6; j++) + { //for each plane in camera frustum + const LLPlane& cp = camera.getAgentPlane(j); + const LLVector3& v1 = pp[bs[i*2+0]]; + const LLVector3& v2 = pp[bs[i*2+1]]; + LLVector3 n; + cp.getVector3(n); + + LLVector3 line = v1-v2; + + F32 d1 = line*n; + F32 d2 = -cp.dist(v2); + + F32 t = d2/d1; + + if (t > 0.f && t < 1.f) + { + LLVector3 intersect = v2+line*t; + pp.push_back(intersect); + } + } + } + + //camera frustum line segments + const U32 fs[] = + { + 0,1, + 1,2, + 2,3, + 3,0, + + 4,5, + 5,6, + 6,7, + 7,4, + + 0,4, + 1,5, + 2,6, + 3,7 + }; + + LLVector3 center = (max+min)*0.5f; + LLVector3 size = (max-min)*0.5f; + + for (U32 i = 0; i < 12; i++) + { + for (U32 j = 0; j < 6; ++j) + { + const LLVector3& v1 = pp[fs[i*2+0]+8]; + const LLVector3& v2 = pp[fs[i*2+1]+8]; + const LLPlane& cp = bp[j]; + LLVector3 n; + cp.getVector3(n); + + LLVector3 line = v1-v2; + + F32 d1 = line*n; + F32 d2 = -cp.dist(v2); + + F32 t = d2/d1; + + if (t > 0.f && t < 1.f) + { + LLVector3 intersect = v2+line*t; + pp.push_back(intersect); + } + } + } + + LLVector3 ext[] = { min-LLVector3(0.05f,0.05f,0.05f), + max+LLVector3(0.05f,0.05f,0.05f) }; + + for (U32 i = 0; i < pp.size(); ++i) + { + bool found = true; + + const F32* p = pp[i].mV; + + for (U32 j = 0; j < 3; ++j) + { + if (p[j] < ext[0].mV[j] || + p[j] > ext[1].mV[j]) + { + found = false; + break; + } + } + + for (U32 j = 0; j < 6; ++j) + { + const LLPlane& cp = camera.getAgentPlane(j); + F32 dist = cp.dist(pp[i]); + if (dist > 0.05f) //point is above some plane, not contained + { + found = false; + break; + } + } + + if (found) + { + fp.push_back(pp[i]); + } + } + + if (fp.empty()) + { + return FALSE; + } + + return TRUE; +} + +void LLPipeline::generateGI(LLCamera& camera, LLVector3& lightDir, std::vector& vpc) +{ + if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) < 3) + { + return; + } + + LLVector3 up; + + //LLGLEnable depth_clamp(GL_DEPTH_CLAMP_NV); + + if (lightDir.mV[2] > 0.5f) + { + up = LLVector3(1,0,0); + } + else + { + up = LLVector3(0, 0, 1); + } + + + F32 gi_range = gSavedSettings.getF32("RenderGIRange"); + + U32 res = mGIMap.getWidth(); + + F32 atten = llmax(gSavedSettings.getF32("RenderGIAttenuation"), 0.001f); + + //set radius to range at which distance attenuation of incoming photons is near 0 + + F32 lrad = sqrtf(1.f/(atten*0.01f)); + + F32 lrange = lrad+gi_range*0.5f; + + LLVector3 pad(lrange,lrange,lrange); + + glh::matrix4f view = look(LLVector3(128.f,128.f,128.f), lightDir, up); + + LLVector3 cp = camera.getOrigin()+camera.getAtAxis()*(gi_range*0.5f); + + glh::vec3f scp(cp.mV); + view.mult_matrix_vec(scp); + cp.setVec(scp.v); + + F32 pix_width = lrange/(res*0.5f); + + //move cp to the nearest pix_width + for (U32 i = 0; i < 3; i++) + { + cp.mV[i] = llround(cp.mV[i], pix_width); + } + + LLVector3 min = cp-pad; + LLVector3 max = cp+pad; + + //set mGIRange to range in tc space[0,1] that covers texture block of intersecting lights around a point + mGIRange.mV[0] = (max.mV[0]-min.mV[0])/res; + mGIRange.mV[1] = (max.mV[1]-min.mV[1])/res; + mGILightRadius = lrad/lrange*0.5f; + + glh::matrix4f proj = gl_ortho(min.mV[0], max.mV[0], + min.mV[1], max.mV[1], + -max.mV[2], -min.mV[2]); + + LLCamera sun_cam = camera; + + glh::matrix4f eye_view = glh_get_current_modelview(); + + //get eye space to camera space matrix + mGIMatrix = view*eye_view.inverse(); + mGINormalMatrix = mGIMatrix.inverse().transpose(); + mGIInvProj = proj.inverse(); + mGIMatrixProj = proj*mGIMatrix; + + //translate and scale to [0,1] + glh::matrix4f trans(.5f, 0.f, 0.f, .5f, + 0.f, 0.5f, 0.f, 0.5f, + 0.f, 0.f, 0.5f, 0.5f, + 0.f, 0.f, 0.f, 1.f); + + mGIMatrixProj = trans*mGIMatrixProj; + + glh_set_current_modelview(view); + glh_set_current_projection(proj); + + LLViewerCamera::updateFrustumPlanes(sun_cam, TRUE, FALSE, TRUE); + + sun_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR); + static LLCullResult result; + + pushRenderTypeMask(); + + andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE, + LLPipeline::RENDER_TYPE_FULLBRIGHT, + LLPipeline::RENDER_TYPE_BUMP, + LLPipeline::RENDER_TYPE_VOLUME, + LLPipeline::RENDER_TYPE_TREE, + LLPipeline::RENDER_TYPE_TERRAIN, + LLPipeline::RENDER_TYPE_WATER, + LLPipeline::RENDER_TYPE_VOIDWATER, + LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW, + LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_PASS_SIMPLE, + LLPipeline::RENDER_TYPE_PASS_BUMP, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, + LLPipeline::RENDER_TYPE_PASS_SHINY, + END_RENDER_TYPES); + + + + S32 occlude = LLPipeline::sUseOcclusion; + //LLPipeline::sUseOcclusion = 0; + LLPipeline::sShadowRender = TRUE; + + //only render large objects into GI map + sMinRenderSize = gSavedSettings.getF32("RenderGIMinRenderSize"); + + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_GI_SOURCE; + mGIMap.bindTarget(); + + F64 last_modelview[16]; + F64 last_projection[16]; + for (U32 i = 0; i < 16; i++) + { + last_modelview[i] = gGLLastModelView[i]; + last_projection[i] = gGLLastProjection[i]; + gGLLastModelView[i] = mGIModelview.m[i]; + gGLLastProjection[i] = mGIProjection.m[i]; + } + + sun_cam.setOrigin(0.f, 0.f, 0.f); + updateCull(sun_cam, result); + stateSort(sun_cam, result); + + for (U32 i = 0; i < 16; i++) + { + gGLLastModelView[i] = last_modelview[i]; + gGLLastProjection[i] = last_projection[i]; + } + + mGIProjection = proj; + mGIModelview = view; + + LLGLEnable cull(GL_CULL_FACE); + + //generate GI map + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadMatrixf(proj.m); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadMatrixf(view.m); + + stop_glerror(); + gGLLastMatrix = NULL; + + mGIMap.clear(); + + { + //LLGLEnable enable(GL_DEPTH_CLAMP_NV); + renderGeomDeferred(camera); + } + + mGIMap.flush(); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + gGLLastMatrix = NULL; + + LLPipeline::sUseOcclusion = occlude; + LLPipeline::sShadowRender = FALSE; + sMinRenderSize = 0.f; + + popRenderTypeMask(); + +} + +void LLPipeline::renderHighlight(const LLViewerObject* obj, F32 fade) +{ + if (obj && obj->getVolume()) + { + for (LLViewerObject::child_list_t::const_iterator iter = obj->getChildren().begin(); iter != obj->getChildren().end(); ++iter) + { + renderHighlight(*iter, fade); + } + + LLDrawable* drawable = obj->mDrawable; + if (drawable) + { + for (S32 i = 0; i < drawable->getNumFaces(); ++i) + { + LLFace* face = drawable->getFace(i); + if (face) + { + face->renderSelected(LLViewerTexture::sNullImagep, LLColor4(1,1,1,fade)); + } + } + } + } +} + +void LLPipeline::generateHighlight(LLCamera& camera) +{ + //render highlighted object as white into offscreen render target + if (mHighlightObject.notNull()) + { + mHighlightSet.insert(HighlightItem(mHighlightObject)); + } + + if (!mHighlightSet.empty()) + { + F32 transition = gFrameIntervalSeconds/gSavedSettings.getF32("RenderHighlightFadeTime"); + + LLGLDisable test(GL_ALPHA_TEST); + LLGLDepthTest depth(GL_FALSE); + mHighlight.bindTarget(); + disableLights(); + gGL.setColorMask(true, true); + mHighlight.clear(); + + gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); + for (std::set::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ) + { + std::set::iterator cur_iter = iter++; + + if (cur_iter->mItem.isNull()) + { + mHighlightSet.erase(cur_iter); + continue; + } + + if (cur_iter->mItem == mHighlightObject) + { + cur_iter->incrFade(transition); + } + else + { + cur_iter->incrFade(-transition); + if (cur_iter->mFade <= 0.f) + { + mHighlightSet.erase(cur_iter); + continue; + } + } + + renderHighlight(cur_iter->mItem->getVObj(), cur_iter->mFade); + } + + mHighlight.flush(); + gGL.setColorMask(true, false); + gViewerWindow->setup3DViewport(); + } +} + + +void LLPipeline::generateSunShadow(LLCamera& camera) +{ + if (!sRenderDeferred || gSavedSettings.getS32("RenderShadowDetail") <= 0) + { + return; + } + + F64 last_modelview[16]; + F64 last_projection[16]; + for (U32 i = 0; i < 16; i++) + { //store last_modelview of world camera + last_modelview[i] = gGLLastModelView[i]; + last_projection[i] = gGLLastProjection[i]; + } + + pushRenderTypeMask(); + andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE, + LLPipeline::RENDER_TYPE_ALPHA, + LLPipeline::RENDER_TYPE_GRASS, + LLPipeline::RENDER_TYPE_FULLBRIGHT, + LLPipeline::RENDER_TYPE_BUMP, + LLPipeline::RENDER_TYPE_VOLUME, + LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_TREE, + LLPipeline::RENDER_TYPE_TERRAIN, + LLPipeline::RENDER_TYPE_WATER, + LLPipeline::RENDER_TYPE_VOIDWATER, + LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW, + LLPipeline::RENDER_TYPE_PASS_SIMPLE, + LLPipeline::RENDER_TYPE_PASS_BUMP, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, + LLPipeline::RENDER_TYPE_PASS_SHINY, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, + END_RENDER_TYPES); + + gGL.setColorMask(false, false); + + //get sun view matrix + + //store current projection/modelview matrix + glh::matrix4f saved_proj = glh_get_current_projection(); + glh::matrix4f saved_view = glh_get_current_modelview(); + glh::matrix4f inv_view = saved_view.inverse(); + + glh::matrix4f view[6]; + glh::matrix4f proj[6]; + + //clip contains parallel split distances for 3 splits + LLVector3 clip = gSavedSettings.getVector3("RenderShadowClipPlanes"); + + //F32 slope_threshold = gSavedSettings.getF32("RenderShadowSlopeThreshold"); + + //far clip on last split is minimum of camera view distance and 128 + mSunClipPlanes = LLVector4(clip, clip.mV[2] * clip.mV[2]/clip.mV[1]); + + clip = gSavedSettings.getVector3("RenderShadowOrthoClipPlanes"); + mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]); + + //currently used for amount to extrude frusta corners for constructing shadow frusta + LLVector3 n = gSavedSettings.getVector3("RenderShadowNearDist"); + //F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] }; + + //put together a universal "near clip" plane for shadow frusta + LLPlane shadow_near_clip; + { + LLVector3 p = gAgent.getPositionAgent(); + p += mSunDir * gSavedSettings.getF32("RenderFarClip")*2.f; + shadow_near_clip.setVec(p, mSunDir); + } + + LLVector3 lightDir = -mSunDir; + lightDir.normVec(); + + glh::vec3f light_dir(lightDir.mV); + + //create light space camera matrix + + LLVector3 at = lightDir; + + LLVector3 up = camera.getAtAxis(); + + if (fabsf(up*lightDir) > 0.75f) + { + up = camera.getUpAxis(); + } + + /*LLVector3 left = up%at; + up = at%left;*/ + + up.normVec(); + at.normVec(); + + + LLCamera main_camera = camera; + + F32 near_clip = 0.f; + { + //get visible point cloud + std::vector fp; + + main_camera.calcAgentFrustumPlanes(main_camera.mAgentFrustum); + + LLVector3 min,max; + getVisiblePointCloud(main_camera,min,max,fp); + + if (fp.empty()) + { + if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowCamera[0] = main_camera; + mShadowExtents[0][0] = min; + mShadowExtents[0][1] = max; + + mShadowFrustPoints[0].clear(); + mShadowFrustPoints[1].clear(); + mShadowFrustPoints[2].clear(); + mShadowFrustPoints[3].clear(); + } + popRenderTypeMask(); + return; + } + + generateGI(camera, lightDir, fp); + + //get good split distances for frustum + for (U32 i = 0; i < fp.size(); ++i) + { + glh::vec3f v(fp[i].mV); + saved_view.mult_matrix_vec(v); + fp[i].setVec(v.v); + } + + min = fp[0]; + max = fp[0]; + + //get camera space bounding box + for (U32 i = 1; i < fp.size(); ++i) + { + update_min_max(min, max, fp[i]); + } + + near_clip = -max.mV[2]; + F32 far_clip = -min.mV[2]*2.f; + + far_clip = llmin(far_clip, 128.f); + far_clip = llmin(far_clip, camera.getFar()); + + F32 range = far_clip-near_clip; + + LLVector3 split_exp = gSavedSettings.getVector3("RenderShadowSplitExponent"); + + F32 da = 1.f-llmax( fabsf(lightDir*up), fabsf(lightDir*camera.getLeftAxis()) ); + + da = powf(da, split_exp.mV[2]); + + + F32 sxp = split_exp.mV[1] + (split_exp.mV[0]-split_exp.mV[1])*da; + + + for (U32 i = 0; i < 4; ++i) + { + F32 x = (F32)(i+1)/4.f; + x = powf(x, sxp); + mSunClipPlanes.mV[i] = near_clip+range*x; + } + } + + // convenience array of 4 near clip plane distances + F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] }; + + for (S32 j = 0; j < 4; j++) + { + if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowFrustPoints[j].clear(); + } + + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+j; + + //restore render matrices + glh_set_current_modelview(saved_view); + glh_set_current_projection(saved_proj); + + LLVector3 eye = camera.getOrigin(); + + //camera used for shadow cull/render + LLCamera shadow_cam; + + //create world space camera frustum for this split + shadow_cam = camera; + shadow_cam.setFar(16.f); + + LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); + + LLVector3* frust = shadow_cam.mAgentFrustum; + + LLVector3 pn = shadow_cam.getAtAxis(); + + LLVector3 min, max; + + //construct 8 corners of split frustum section + for (U32 i = 0; i < 4; i++) + { + LLVector3 delta = frust[i+4]-eye; + delta += (frust[i+4]-frust[(i+2)%4+4])*0.05f; + delta.normVec(); + F32 dp = delta*pn; + frust[i] = eye + (delta*dist[j]*0.95f)/dp; + frust[i+4] = eye + (delta*dist[j+1]*1.05f)/dp; + } + + shadow_cam.calcAgentFrustumPlanes(frust); + shadow_cam.mFrustumCornerDist = 0.f; + + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowCamera[j] = shadow_cam; + } + + std::vector fp; + + if (!gPipeline.getVisiblePointCloud(shadow_cam, min, max, fp, lightDir)) + { + //no possible shadow receivers + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowExtents[j][0] = LLVector3(); + mShadowExtents[j][1] = LLVector3(); + mShadowCamera[j+4] = shadow_cam; + } + + mShadow[j].bindTarget(); + { + LLGLDepthTest depth(GL_TRUE); + mShadow[j].clear(); + } + mShadow[j].flush(); + + mShadowError.mV[j] = 0.f; + mShadowFOV.mV[j] = 0.f; + + continue; + } + + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowExtents[j][0] = min; + mShadowExtents[j][1] = max; + mShadowFrustPoints[j] = fp; + } + + + //find a good origin for shadow projection + LLVector3 origin; + + //get a temporary view projection + view[j] = look(camera.getOrigin(), lightDir, -up); + + std::vector wpf; + + for (U32 i = 0; i < fp.size(); i++) + { + glh::vec3f p = glh::vec3f(fp[i].mV); + view[j].mult_matrix_vec(p); + wpf.push_back(LLVector3(p.v)); + } + + min = wpf[0]; + max = wpf[0]; + + for (U32 i = 0; i < fp.size(); ++i) + { //get AABB in camera space + update_min_max(min, max, wpf[i]); + } + + // Construct a perspective transform with perspective along y-axis that contains + // points in wpf + //Known: + // - far clip plane + // - near clip plane + // - points in frustum + //Find: + // - origin + + //get some "interesting" points of reference + LLVector3 center = (min+max)*0.5f; + LLVector3 size = (max-min)*0.5f; + LLVector3 near_center = center; + near_center.mV[1] += size.mV[1]*2.f; + + + //put all points in wpf in quadrant 0, reletive to center of min/max + //get the best fit line using least squares + F32 bfm = 0.f; + F32 bfb = 0.f; + + for (U32 i = 0; i < wpf.size(); ++i) + { + wpf[i] -= center; + wpf[i].mV[0] = fabsf(wpf[i].mV[0]); + wpf[i].mV[2] = fabsf(wpf[i].mV[2]); + } + + if (!wpf.empty()) + { + F32 sx = 0.f; + F32 sx2 = 0.f; + F32 sy = 0.f; + F32 sxy = 0.f; + + for (U32 i = 0; i < wpf.size(); ++i) + { + sx += wpf[i].mV[0]; + sx2 += wpf[i].mV[0]*wpf[i].mV[0]; + sy += wpf[i].mV[1]; + sxy += wpf[i].mV[0]*wpf[i].mV[1]; + } + + bfm = (sy*sx-wpf.size()*sxy)/(sx*sx-wpf.size()*sx2); + bfb = (sx*sxy-sy*sx2)/(sx*sx-bfm*sx2); + } + + { + // best fit line is y=bfm*x+bfb + + //find point that is furthest to the right of line + F32 off_x = -1.f; + LLVector3 lp; + + for (U32 i = 0; i < wpf.size(); ++i) + { + //y = bfm*x+bfb + //x = (y-bfb)/bfm + F32 lx = (wpf[i].mV[1]-bfb)/bfm; + + lx = wpf[i].mV[0]-lx; + + if (off_x < lx) + { + off_x = lx; + lp = wpf[i]; + } + } + + //get line with slope bfm through lp + // bfb = y-bfm*x + bfb = lp.mV[1]-bfm*lp.mV[0]; + + //calculate error + mShadowError.mV[j] = 0.f; + + for (U32 i = 0; i < wpf.size(); ++i) + { + F32 lx = (wpf[i].mV[1]-bfb)/bfm; + mShadowError.mV[j] += fabsf(wpf[i].mV[0]-lx); + } + + mShadowError.mV[j] /= wpf.size(); + mShadowError.mV[j] /= size.mV[0]; + + if (mShadowError.mV[j] > gSavedSettings.getF32("RenderShadowErrorCutoff")) + { //just use ortho projection + mShadowFOV.mV[j] = -1.f; + origin.clearVec(); + proj[j] = gl_ortho(min.mV[0], max.mV[0], + min.mV[1], max.mV[1], + -max.mV[2], -min.mV[2]); + } + else + { + //origin is where line x = 0; + origin.setVec(0,bfb,0); + + F32 fovz = 1.f; + F32 fovx = 1.f; + + LLVector3 zp; + LLVector3 xp; + + for (U32 i = 0; i < wpf.size(); ++i) + { + LLVector3 atz = wpf[i]-origin; + atz.mV[0] = 0.f; + atz.normVec(); + if (fovz > -atz.mV[1]) + { + zp = wpf[i]; + fovz = -atz.mV[1]; + } + + LLVector3 atx = wpf[i]-origin; + atx.mV[2] = 0.f; + atx.normVec(); + if (fovx > -atx.mV[1]) + { + fovx = -atx.mV[1]; + xp = wpf[i]; + } + } + + fovx = acos(fovx); + fovz = acos(fovz); + + F32 cutoff = llmin(gSavedSettings.getF32("RenderShadowFOVCutoff"), 1.4f); + + mShadowFOV.mV[j] = fovx; + + if (fovx < cutoff && fovz > cutoff) + { + //x is a good fit, but z is too big, move away from zp enough so that fovz matches cutoff + F32 d = zp.mV[2]/tan(cutoff); + F32 ny = zp.mV[1] + fabsf(d); + + origin.mV[1] = ny; + + fovz = 1.f; + fovx = 1.f; + + for (U32 i = 0; i < wpf.size(); ++i) + { + LLVector3 atz = wpf[i]-origin; + atz.mV[0] = 0.f; + atz.normVec(); + fovz = llmin(fovz, -atz.mV[1]); + + LLVector3 atx = wpf[i]-origin; + atx.mV[2] = 0.f; + atx.normVec(); + fovx = llmin(fovx, -atx.mV[1]); + } + + fovx = acos(fovx); + fovz = acos(fovz); + + if (fovx > cutoff || llround(fovz, 0.01f) > cutoff) + { + // llerrs << "WTF?" << llendl; + } + + mShadowFOV.mV[j] = cutoff; + } + + + origin += center; + + F32 ynear = -(max.mV[1]-origin.mV[1]); + F32 yfar = -(min.mV[1]-origin.mV[1]); + + if (ynear < 0.1f) //keep a sensible near clip plane + { + F32 diff = 0.1f-ynear; + origin.mV[1] += diff; + ynear += diff; + yfar += diff; + } + + if (fovx > cutoff) + { //just use ortho projection + origin.clearVec(); + mShadowError.mV[j] = -1.f; + proj[j] = gl_ortho(min.mV[0], max.mV[0], + min.mV[1], max.mV[1], + -max.mV[2], -min.mV[2]); + } + else + { + //get perspective projection + view[j] = view[j].inverse(); + + glh::vec3f origin_agent(origin.mV); + + //translate view to origin + view[j].mult_matrix_vec(origin_agent); + + eye = LLVector3(origin_agent.v); + + if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowFrustOrigin[j] = eye; + } + + view[j] = look(LLVector3(origin_agent.v), lightDir, -up); + + F32 fx = 1.f/tanf(fovx); + F32 fz = 1.f/tanf(fovz); + + proj[j] = glh::matrix4f(-fx, 0, 0, 0, + 0, (yfar+ynear)/(ynear-yfar), 0, (2.f*yfar*ynear)/(ynear-yfar), + 0, 0, -fz, 0, + 0, -1.f, 0, 0); + } + } + } + + shadow_cam.setFar(128.f); + shadow_cam.setOriginAndLookAt(eye, up, center); + + shadow_cam.setOrigin(0,0,0); + + glh_set_current_modelview(view[j]); + glh_set_current_projection(proj[j]); + + LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); + + //shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR); + shadow_cam.getAgentPlane(LLCamera::AGENT_PLANE_NEAR).set(shadow_near_clip); + + //translate and scale to from [-1, 1] to [0, 1] + glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, + 0.f, 0.5f, 0.f, 0.5f, + 0.f, 0.f, 0.5f, 0.5f, + 0.f, 0.f, 0.f, 1.f); + + glh_set_current_modelview(view[j]); + glh_set_current_projection(proj[j]); + + for (U32 i = 0; i < 16; i++) + { + gGLLastModelView[i] = mShadowModelview[j].m[i]; + gGLLastProjection[i] = mShadowProjection[j].m[i]; + } + + mShadowModelview[j] = view[j]; + mShadowProjection[j] = proj[j]; + + + mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view; + + stop_glerror(); + + mShadow[j].bindTarget(); + mShadow[j].getViewport(gGLViewport); + mShadow[j].clear(); + + { + static LLCullResult result[4]; + + //LLGLEnable enable(GL_DEPTH_CLAMP_NV); + renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE); + } + + mShadow[j].flush(); + + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + { + LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); + mShadowCamera[j+4] = shadow_cam; + } + } + + + //hack to disable projector shadows + bool gen_shadow = gSavedSettings.getS32("RenderShadowDetail") > 1; + + if (gen_shadow) + { + F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f); + + //update shadow targets + for (U32 i = 0; i < 2; i++) + { //for each current shadow + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i; + + if (mShadowSpotLight[i].notNull() && + (mShadowSpotLight[i] == mTargetShadowSpotLight[0] || + mShadowSpotLight[i] == mTargetShadowSpotLight[1])) + { //keep this spotlight + mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f); + } + else + { //fade out this light + mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f); + + if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull()) + { //faded out, grab one of the pending spots (whichever one isn't already taken) + if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2]) + { + mShadowSpotLight[i] = mTargetShadowSpotLight[0]; + } + else + { + mShadowSpotLight[i] = mTargetShadowSpotLight[1]; + } + } + } + } + + for (S32 i = 0; i < 2; i++) + { + glh_set_current_modelview(saved_view); + glh_set_current_projection(saved_proj); + + if (mShadowSpotLight[i].isNull()) + { + continue; + } + + LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume(); + + if (!volume) + { + mShadowSpotLight[i] = NULL; + continue; + } + + LLDrawable* drawable = mShadowSpotLight[i]; + + LLVector3 params = volume->getSpotLightParams(); + F32 fov = params.mV[0]; + + //get agent->light space matrix (modelview) + LLVector3 center = drawable->getPositionAgent(); + LLQuaternion quat = volume->getRenderRotation(); + + //get near clip plane + LLVector3 scale = volume->getScale(); + LLVector3 at_axis(0,0,-scale.mV[2]*0.5f); + at_axis *= quat; + + LLVector3 np = center+at_axis; + at_axis.normVec(); + + //get origin that has given fov for plane np, at_axis, and given scale + F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f); + + LLVector3 origin = np - at_axis*dist; + + LLMatrix4 mat(quat, LLVector4(origin, 1.f)); + + view[i+4] = glh::matrix4f((F32*) mat.mMatrix); + + view[i+4] = view[i+4].inverse(); + + //get perspective matrix + F32 near_clip = dist+0.01f; + F32 width = scale.mV[VX]; + F32 height = scale.mV[VY]; + F32 far_clip = dist+volume->getLightRadius()*1.5f; + + F32 fovy = fov * RAD_TO_DEG; + F32 aspect = width/height; + + proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip); + + //translate and scale to from [-1, 1] to [0, 1] + glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, + 0.f, 0.5f, 0.f, 0.5f, + 0.f, 0.f, 0.5f, 0.5f, + 0.f, 0.f, 0.f, 1.f); + + glh_set_current_modelview(view[i+4]); + glh_set_current_projection(proj[i+4]); + + mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view; + + for (U32 j = 0; j < 16; j++) + { + gGLLastModelView[j] = mShadowModelview[i+4].m[j]; + gGLLastProjection[j] = mShadowProjection[i+4].m[j]; + } + + mShadowModelview[i+4] = view[i+4]; + mShadowProjection[i+4] = proj[i+4]; + + LLCamera shadow_cam = camera; + shadow_cam.setFar(far_clip); + shadow_cam.setOrigin(origin); + + LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); + + stop_glerror(); + + mShadow[i+4].bindTarget(); + mShadow[i+4].getViewport(gGLViewport); + mShadow[i+4].clear(); + + static LLCullResult result[2]; + + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4; + + renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE); + + mShadow[i+4].flush(); + } + } + + if (!gSavedSettings.getBOOL("CameraOffset")) + { + glh_set_current_modelview(saved_view); + glh_set_current_projection(saved_proj); + } + else + { + glh_set_current_modelview(view[1]); + glh_set_current_projection(proj[1]); + glLoadMatrixf(view[1].m); + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(proj[1].m); + glMatrixMode(GL_MODELVIEW); + } + gGL.setColorMask(true, false); + + for (U32 i = 0; i < 16; i++) + { + gGLLastModelView[i] = last_modelview[i]; + gGLLastProjection[i] = last_projection[i]; + } + + popRenderTypeMask(); +} + +void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture) +{ + for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) + { + LLSpatialGroup* group = *i; + if (!group->isDead() && + (!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && + gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) && + group->mDrawMap.find(type) != group->mDrawMap.end()) + { + pass->renderGroup(group,type,mask,texture); + } + } +} + +void LLPipeline::generateImpostor(LLVOAvatar* avatar) +{ + LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR); + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + + static LLCullResult result; + result.clear(); + grabReferences(result); + + if (!avatar || !avatar->mDrawable) + { + return; + } + + assertInitialized(); + + BOOL muted = LLMuteList::getInstance()->isMuted(avatar->getID()); + + pushRenderTypeMask(); + + if (muted) + { + andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); + } + else + { + andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, + LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_BUMP, + LLPipeline::RENDER_TYPE_GRASS, + LLPipeline::RENDER_TYPE_SIMPLE, + LLPipeline::RENDER_TYPE_FULLBRIGHT, + LLPipeline::RENDER_TYPE_ALPHA, + LLPipeline::RENDER_TYPE_INVISIBLE, + LLPipeline::RENDER_TYPE_PASS_SIMPLE, + LLPipeline::RENDER_TYPE_PASS_ALPHA, + LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, + LLPipeline::RENDER_TYPE_PASS_SHINY, + LLPipeline::RENDER_TYPE_PASS_INVISIBLE, + LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY, + END_RENDER_TYPES); + } + + S32 occlusion = sUseOcclusion; + sUseOcclusion = 0; + sReflectionRender = sRenderDeferred ? FALSE : TRUE; + sShadowRender = TRUE; + sImpostorRender = TRUE; + + LLViewerCamera* viewer_camera = LLViewerCamera::getInstance(); + markVisible(avatar->mDrawable, *viewer_camera); + LLVOAvatar::sUseImpostors = FALSE; + + LLVOAvatar::attachment_map_t::iterator iter; + for (iter = avatar->mAttachmentPoints.begin(); + iter != avatar->mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment *attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + if (LLViewerObject* attached_object = (*attachment_iter)) + { + markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); + } + } + } + + stateSort(*LLViewerCamera::getInstance(), result); + + const LLVector4a* ext = avatar->mDrawable->getSpatialExtents(); + LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset()); + + LLCamera camera = *viewer_camera; + + camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis()); + + LLVector2 tdim; + + + LLVector4a half_height; + half_height.setSub(ext[1], ext[0]); + half_height.mul(0.5f); + + LLVector4a left; + left.load3(camera.getLeftAxis().mV); + left.mul(left); + left.normalize3fast(); + + LLVector4a up; + up.load3(camera.getUpAxis().mV); + up.mul(up); + up.normalize3fast(); + + tdim.mV[0] = fabsf(half_height.dot3(left).getF32()); + tdim.mV[1] = fabsf(half_height.dot3(up).getF32()); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + + F32 distance = (pos-camera.getOrigin()).length(); + F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG; + F32 aspect = tdim.mV[0]/tdim.mV[1]; + glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f); + glh_set_current_projection(persp); + glLoadMatrixf(persp.m); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glh::matrix4f mat; + camera.getOpenGLTransform(mat.m); + + mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat; + + glLoadMatrixf(mat.m); + glh_set_current_modelview(mat); + + glClearColor(0.0f,0.0f,0.0f,0.0f); + gGL.setColorMask(true, true); + + // get the number of pixels per angle + F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView()); + + //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing) + U32 resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512); + U32 resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512); + + if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() || + resY != avatar->mImpostor.getHeight()) + { + avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE); + + if (LLPipeline::sRenderDeferred) + { + addDeferredAttachments(avatar->mImpostor); + } + + gGL.getTexUnit(0)->bind(&avatar->mImpostor); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + + avatar->mImpostor.bindTarget(); + + if (LLPipeline::sRenderDeferred) + { + avatar->mImpostor.clear(); + renderGeomDeferred(camera); + renderGeomPostDeferred(camera); + } + else + { + LLGLEnable scissor(GL_SCISSOR_TEST); + glScissor(0, 0, resX, resY); + avatar->mImpostor.clear(); + renderGeom(camera); + } + + { //create alpha mask based on depth buffer (grey out if muted) + if (LLPipeline::sRenderDeferred) + { + GLuint buff = GL_COLOR_ATTACHMENT0; + glDrawBuffersARB(1, &buff); + } + + LLGLDisable blend(GL_BLEND); + + if (muted) + { + gGL.setColorMask(true, true); + } + else + { + gGL.setColorMask(false, true); + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); + + gGL.flush(); + + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + static const F32 clip_plane = 0.99999f; + + gGL.color4ub(64,64,64,255); + gGL.begin(LLRender::QUADS); + gGL.vertex3f(-1, -1, clip_plane); + gGL.vertex3f(1, -1, clip_plane); + gGL.vertex3f(1, 1, clip_plane); + gGL.vertex3f(-1, 1, clip_plane); + gGL.end(); + gGL.flush(); + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + } + + avatar->mImpostor.flush(); + + avatar->setImpostorDim(tdim); + + LLVOAvatar::sUseImpostors = TRUE; + sUseOcclusion = occlusion; + sReflectionRender = FALSE; + sImpostorRender = FALSE; + sShadowRender = FALSE; + popRenderTypeMask(); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + avatar->mNeedsImpostorUpdate = FALSE; + avatar->cacheImpostorValues(); + + LLVertexBuffer::unbind(); + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); +} + +BOOL LLPipeline::hasRenderBatches(const U32 type) const +{ + return sCull->getRenderMapSize(type) > 0; +} + +LLCullResult::drawinfo_list_t::iterator LLPipeline::beginRenderMap(U32 type) +{ + return sCull->beginRenderMap(type); +} + +LLCullResult::drawinfo_list_t::iterator LLPipeline::endRenderMap(U32 type) +{ + return sCull->endRenderMap(type); +} + +LLCullResult::sg_list_t::iterator LLPipeline::beginAlphaGroups() +{ + return sCull->beginAlphaGroups(); +} + +LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups() +{ + return sCull->endAlphaGroups(); +} + +BOOL LLPipeline::hasRenderType(const U32 type) const +{ + // STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render" + // We then need to test that value here and return FALSE to prevent attachment to render (in mouselook for instance) + // TODO: reintroduce RENDER_TYPE_NONE in LLRenderTypeMask and initialize its mRenderTypeEnabled[RENDER_TYPE_NONE] to FALSE explicitely + return (type == 0 ? FALSE : mRenderTypeEnabled[type]); +} + +void LLPipeline::setRenderTypeMask(U32 type, ...) +{ + va_list args; + + va_start(args, type); + while (type < END_RENDER_TYPES) + { + mRenderTypeEnabled[type] = TRUE; + type = va_arg(args, U32); + } + va_end(args); + + if (type > END_RENDER_TYPES) + { + llerrs << "Invalid render type." << llendl; + } +} + +BOOL LLPipeline::hasAnyRenderType(U32 type, ...) const +{ + va_list args; + + va_start(args, type); + while (type < END_RENDER_TYPES) + { + if (mRenderTypeEnabled[type]) + { + return TRUE; + } + type = va_arg(args, U32); + } + va_end(args); + + if (type > END_RENDER_TYPES) + { + llerrs << "Invalid render type." << llendl; + } + + return FALSE; +} + +void LLPipeline::pushRenderTypeMask() +{ + std::string cur_mask; + cur_mask.assign((const char*) mRenderTypeEnabled, sizeof(mRenderTypeEnabled)); + mRenderTypeEnableStack.push(cur_mask); +} + +void LLPipeline::popRenderTypeMask() +{ + if (mRenderTypeEnableStack.empty()) + { + llerrs << "Depleted render type stack." << llendl; + } + + memcpy(mRenderTypeEnabled, mRenderTypeEnableStack.top().data(), sizeof(mRenderTypeEnabled)); + mRenderTypeEnableStack.pop(); +} + +void LLPipeline::andRenderTypeMask(U32 type, ...) +{ + va_list args; + + BOOL tmp[NUM_RENDER_TYPES]; + for (U32 i = 0; i < NUM_RENDER_TYPES; ++i) + { + tmp[i] = FALSE; + } + + va_start(args, type); + while (type < END_RENDER_TYPES) + { + if (mRenderTypeEnabled[type]) + { + tmp[type] = TRUE; + } + + type = va_arg(args, U32); + } + va_end(args); + + if (type > END_RENDER_TYPES) + { + llerrs << "Invalid render type." << llendl; + } + + for (U32 i = 0; i < LLPipeline::NUM_RENDER_TYPES; ++i) + { + mRenderTypeEnabled[i] = tmp[i]; + } + +} + +void LLPipeline::clearRenderTypeMask(U32 type, ...) +{ + va_list args; + + va_start(args, type); + while (type < END_RENDER_TYPES) + { + mRenderTypeEnabled[type] = FALSE; + + type = va_arg(args, U32); + } + va_end(args); + + if (type > END_RENDER_TYPES) + { + llerrs << "Invalid render type." << llendl; + } +} + + diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 772e2ed1d1..32ac93388d 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -119,7 +119,6 @@ public: void allocatePhysicsBuffer(); void resetVertexBuffers(LLDrawable* drawable); - void setDisableVBOMapping(BOOL no_vbo_mapping); void generateImpostor(LLVOAvatar* avatar); void bindScreenToTexture(); void renderBloom(BOOL for_snapshot, F32 zoom_factor = 1.f, int subfield = 0); -- cgit v1.2.3 From 605e44a5749ad91d2a83bf23b52182fb38dc10ee Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 23 Feb 2011 15:42:54 -0600 Subject: SH-1019 Fix bad md5sum entry. --- install.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.xml b/install.xml index 06495b952d..bae3ff707b 100755 --- a/install.xml +++ b/install.xml @@ -280,7 +280,7 @@ windows md5sum - fbb784f39e82e052de462e48e167d69e + c1e79c9d3084727be35ce140db87717e url http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/colladadom-2.1-windows-20110223.tar.bz2 -- cgit v1.2.3 From 74d402e59e4fd864d28fac52927c4e6900416c70 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 23 Feb 2011 16:38:10 -0600 Subject: SH-473/CTS-248 Enable mirror and invert check boxes for meshes. --- indra/newview/llpanelobject.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 42da966b92..0300ea0c92 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1178,13 +1178,13 @@ void LLPanelObject::getState( ) if (mCtrlSculptMirror) { mCtrlSculptMirror->set(sculpt_mirror); - mCtrlSculptMirror->setEnabled(editable && (sculpt_stitching != LL_SCULPT_TYPE_MESH)); + mCtrlSculptMirror->setEnabled(editable); } if (mCtrlSculptInvert) { mCtrlSculptInvert->set(sculpt_invert); - mCtrlSculptInvert->setEnabled(editable && (!isMesh)); + mCtrlSculptInvert->setEnabled(editable); } if (mLabelSculptType) -- cgit v1.2.3 From 2d01424e25f0ecfddae753032fe18e451771476f Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 23 Feb 2011 17:02:43 -0600 Subject: SH-301 Use avatar distance and radius when calculating LoD for rigged attachments. --- indra/newview/llvovolume.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 5c1d10ba7d..161cbe6aa9 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1204,9 +1204,20 @@ BOOL LLVOVolume::calcLOD() S32 cur_detail = 0; - F32 radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length(); - F32 distance = mDrawable->mDistanceWRTCamera; //llmin(mDrawable->mDistanceWRTCamera, MAX_LOD_DISTANCE); - distance *= sDistanceFactor; + F32 radius; + F32 distance; + + if (mDrawable->isState(LLDrawable::RIGGED)) + { + LLVOAvatar* avatar = getAvatar(); + distance = avatar->mDrawable->mDistanceWRTCamera; + radius = avatar->getBinRadius(); + } + else + { + distance = mDrawable->mDistanceWRTCamera; + radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length(); + } F32 rampDist = LLVOVolume::sLODFactor * 2; -- cgit v1.2.3 From 34428b305a437256f5db170db91506e2d94440e9 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 23 Feb 2011 17:44:11 -0600 Subject: SH-301 Cleanup -- accidentally removed a multiply by sDistanceFactor --- indra/newview/llvovolume.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 161cbe6aa9..e3cc2f2589 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1219,6 +1219,8 @@ BOOL LLVOVolume::calcLOD() radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length(); } + distance *= sDistanceFactor; + F32 rampDist = LLVOVolume::sLODFactor * 2; if (distance < rampDist) -- cgit v1.2.3 From 9f537ad93fe7992bb6d652473a4ac3680320cab5 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Wed, 23 Feb 2011 16:31:32 -0800 Subject: SH-1035 Model preview background color should match spec --- indra/newview/llfloatermodelpreview.cpp | 8 ++++---- indra/newview/llfloatermodelwizard.cpp | 9 +++++---- indra/newview/skins/default/xui/en/floater_model_preview.xml | 3 +++ indra/newview/skins/default/xui/en/floater_model_wizard.xml | 10 ++++++---- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index dde470693c..7d42c842e8 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -603,13 +603,13 @@ void LLFloaterModelPreview::draw() gGL.begin( LLRender::QUADS ); { gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop-1); gGL.texCoord2f(0.f, 0.f); gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); + gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mBottom); gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); + gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mTop-1); } gGL.end(); @@ -3798,7 +3798,7 @@ BOOL LLModelPreview::render() gGL.pushMatrix(); glLoadIdentity(); - gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); + gGL.color4f(0.169f, 0.169f, 0.169f, 1.f); gl_rect_2d_simple( width, height ); diff --git a/indra/newview/llfloatermodelwizard.cpp b/indra/newview/llfloatermodelwizard.cpp index 095499e6b0..be43216b0e 100644 --- a/indra/newview/llfloatermodelwizard.cpp +++ b/indra/newview/llfloatermodelwizard.cpp @@ -485,6 +485,7 @@ BOOL LLFloaterModelWizard::postBuild() getChild("back")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickBack, this)); getChild("next")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickNext, this)); getChild("preview_lod_combo")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1)); + getChild("preview_lod_combo2")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1)); getChild("accuracy_slider")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onAccuracyPerformance, this, _2)); getChild("upload")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onUpload, this)); getChild("physics_slider")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPhysicsChanged, this)); @@ -630,17 +631,17 @@ void LLFloaterModelWizard::draw() LLRect item_rect; preview_panel->localRectToOtherView(preview_panel->getLocalRect(), &item_rect, this); - + gGL.begin( LLRender::QUADS ); { gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(item_rect.mLeft, item_rect.mTop); + gGL.vertex2i(item_rect.mLeft, item_rect.mTop-1); gGL.texCoord2f(0.f, 0.f); gGL.vertex2i(item_rect.mLeft, item_rect.mBottom); gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(item_rect.mRight, item_rect.mBottom); + gGL.vertex2i(item_rect.mRight-1, item_rect.mBottom); gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(item_rect.mRight, item_rect.mTop); + gGL.vertex2i(item_rect.mRight-1, item_rect.mTop-1); } gGL.end(); diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 201e971f4c..8a18861e1a 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -58,6 +58,9 @@ diff --git a/indra/newview/skins/default/xui/en/floater_model_wizard.xml b/indra/newview/skins/default/xui/en/floater_model_wizard.xml index 2377a9e4ef..f133d75eee 100644 --- a/indra/newview/skins/default/xui/en/floater_model_wizard.xml +++ b/indra/newview/skins/default/xui/en/floater_model_wizard.xml @@ -101,7 +101,7 @@ height="388" top_pad="0" name="choose_file_panel" - visible="false" + visible="true" width="530" left="0"> + name="preview_lod_combo2" width="90" tool_tip="LOD to view in preview render"> High @@ -414,6 +414,7 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se top_pad="5" name="preview_panel" bevel_style="none" + highlight_light_color="0.09 0.09 0.09 1" border_style="line" border="true" height="175" @@ -600,7 +601,7 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se height="388" top_delta="0" name="review_panel" - visible="true" + visible="false" width="530" left="0"> Date: Thu, 24 Feb 2011 15:01:14 -0800 Subject: SH-1045 Mesh Viewer temporarily allows object scaling larger than 10m, then moves the object --- indra/newview/llmanipscale.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index 683f455179..dcbf17e31f 100644 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -52,6 +52,7 @@ #include "llui.h" #include "llviewercamera.h" #include "llviewerobject.h" +#include "llviewerregion.h" #include "llviewerwindow.h" #include "llhudrender.h" #include "llworld.h" @@ -89,7 +90,10 @@ F32 get_default_max_prim_scale(bool is_flora) { // a bit of a hack, but if it's foilage, we don't want to use the // new larger scale which would result in giant trees and grass - if (gSavedSettings.getBOOL("MeshEnabled") && !is_flora) + if (gSavedSettings.getBOOL("MeshEnabled") && + gAgent.getRegion() && + !gAgent.getRegion()->getCapability("GetMesh").empty() && + !is_flora) { return DEFAULT_MAX_PRIM_SCALE; } -- cgit v1.2.3 From ca52b0bd712483675bb04421fb4ee6881e61a135 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Thu, 24 Feb 2011 15:02:55 -0800 Subject: SH-1040 Make both model preview drop downs functional --- indra/newview/llfloatermodelpreview.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 42c93a91a5..ef7d1425c7 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -4085,6 +4085,10 @@ void LLModelPreview::setPreviewLOD(S32 lod) mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); + // the wizard has two lod drop downs + LLComboBox* combo_box2 = mFMP->getChild("preview_lod_combo2"); + combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order + LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); -- cgit v1.2.3 From 4abb8b33fa0c3b5e5f809a783cfc62a9e02af338 Mon Sep 17 00:00:00 2001 From: prep linden Date: Mon, 28 Feb 2011 12:20:31 -0500 Subject: sh-517 Content authors can specify a pivot node (Assetpivot). --- indra/llprimitive/llmodel.cpp | 16 +++++++ indra/llprimitive/llmodel.h | 2 +- indra/newview/llfloatermodelpreview.cpp | 84 ++++++++++++++++++++++++++++++++- indra/newview/llfloatermodelpreview.h | 13 ++++- 4 files changed, 111 insertions(+), 4 deletions(-) diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 3d03209eaf..a9101378a4 100755 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -810,6 +810,22 @@ BOOL LLModel::createVolumeFacesFromFile(const std::string& file_name) return FALSE; } +void LLModel::offsetMesh( const LLVector3& pivotPoint ) +{ + LLVector4a pivot( pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ] ); + + for (std::vector::iterator faceIt = mVolumeFaces.begin(); faceIt != mVolumeFaces.end(); ) + { + std::vector:: iterator currentFaceIt = faceIt++; + LLVolumeFace& face = *currentFaceIt; + LLVector4a *pos = (LLVector4a*) face.mPositions; + + for (U32 i=0; i mMaterialList; diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index ef7d1425c7..e33ce055f6 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -174,7 +174,6 @@ std::string lod_label_name[NUM_LOD+1] = "I went off the end of the lod_label_name array. Me so smart." }; - bool validate_face(const LLVolumeFace& face) { for (U32 i = 0; i < face.mNumIndices; ++i) @@ -1675,10 +1674,42 @@ void LLModelLoader::run() processElement(scene); + handlePivotPoint( root ); + doOnIdleOneTime(boost::bind(&LLModelPreview::loadModelCallback,mPreview,mLod)); } } +void LLModelLoader::handlePivotPoint( daeElement* pRoot ) +{ + //Import an optional pivot point - a pivot point is just a node in the visual scene named "AssetPivot" + //If no assetpivot is found then the asset will use the SL default + daeElement* pScene = pRoot->getDescendant("visual_scene"); + if ( pScene ) + { + daeTArray< daeSmartRef > children = pScene->getChildren(); + S32 childCount = children.getCount(); + for (S32 i = 0; i < childCount; ++i) + { + domNode* pNode = daeSafeCast(children[i]); + if ( pNode && isNodeAPivotPoint( pNode ) ) + { + LLMatrix4 workingTransform; + daeSIDResolver nodeResolver( pNode, "./translate" ); + domTranslate* pTranslate = daeSafeCast( nodeResolver.getElement() ); + //Translation via SID was successful + //todo#extract via element as well + if ( pTranslate ) + { + extractTranslation( pTranslate, workingTransform ); + mPreview->setModelPivot( workingTransform.getTranslation() ); + mPreview->setHasPivot( true ); + } + } + } + } +} + bool LLModelLoader::doesJointArrayContainACompleteRig( const std::vector &jointListFromModel ) { std::deque :: const_iterator masterJointIt = mMasterJointList.begin(); @@ -1754,6 +1785,25 @@ bool LLModelLoader::isNodeAJoint( domNode* pNode ) return false; } +bool LLModelLoader::isNodeAPivotPoint( domNode* pNode ) +{ + bool result = false; + + if ( pNode && pNode->getName() ) + { + std::string name = pNode->getName(); + if ( name == "AssetPivot" ) + { + result = true; + } + else + { + result = false; + } + } + return result; +} + void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) { domFloat3 jointTrans = pTranslate->getValue(); @@ -2185,6 +2235,9 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mFMP = fmp; + mHasPivot = false; + mModelPivot = LLVector3( 0.0f, 0.0f, 0.0f ); + glodInit(); } @@ -2292,6 +2345,28 @@ void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost)); } +void LLModelPreview::alterModelsPivot( void ) +{ + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + if ( *iter ) + { + (*iter)->offsetMesh( mModelPivot ); + } + } + + for ( int i=0;ioffsetMesh( mModelPivot ); + } + } + } +} + void LLModelPreview::rebuildUploadData() { assert_main_thread(); @@ -2347,6 +2422,7 @@ void LLModelPreview::rebuildUploadData() LLModelInstance instance = *model_iter; LLModel* base_model = instance.mModel; + if (base_model) { base_model->mRequestedLabel = requested_name; @@ -3441,6 +3517,7 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) U32 vertex_count = 0; U32 mesh_count = 0; + LLModelLoader::model_list* model = NULL; if (lod < 0 || lod > 4) @@ -4129,6 +4206,11 @@ void LLFloaterModelPreview::onUpload(void* user_data) LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + if ( mp && mp->mModelPreview->mHasPivot ) + { + mp->mModelPreview->alterModelsPivot(); + } + mp->mModelPreview->rebuildUploadData(); gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index e1c520134b..8a01f7db2c 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -114,6 +114,9 @@ public: bool doesJointArrayContainACompleteRig( const std::vector &modelJointList ); bool checkForCompleteRig( const std::vector &jointListFromModel ); + void handlePivotPoint( daeElement* pRoot ); + bool isNodeAPivotPoint( domNode* pNode ); + void setLoadState( U32 state ) { mState = state; } U32 getLoadState( void ) { return mState; } @@ -279,7 +282,7 @@ public: void loadModelCallback(S32 lod); void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); void generateNormals(); - + void alterModelsPivot( void ); void clearMaterials(); U32 calcResourceCost(); void rebuildUploadData(); @@ -287,7 +290,10 @@ public: void updateStatusMessages(); void clearGLODGroup(); void onLODParamCommit(bool enforce_tri_limit); - + const bool getModelPivot( void ) const { return mHasPivot; } + void setHasPivot( bool val ) { mHasPivot = val; } + void setModelPivot( const LLVector3& pivot ) { mModelPivot = pivot; } + static void textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ); boost::signals2::connection setDetailsCallback( const details_signal_t::slot_type& cb ){ return mDetailsSignal.connect(cb); } @@ -347,6 +353,9 @@ public: details_signal_t mDetailsSignal; model_loaded_signal_t mModelLoadedSignal; + + LLVector3 mModelPivot; + bool mHasPivot; }; -- cgit v1.2.3 From 5eeca73940bb083e76cb73d1528e61544d3f7fd2 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 1 Mar 2011 15:22:17 -0600 Subject: SH-1072 Fix for DoF focal point being incorrect. --- indra/newview/app_settings/settings.xml | 12 ++++++++++ indra/newview/llviewerwindow.cpp | 2 +- indra/newview/llvovolume.cpp | 7 ++++++ indra/newview/pipeline.cpp | 41 ++++++++++++++++++++++----------- 4 files changed, 47 insertions(+), 15 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 71a611ba90..01610f73ed 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1323,6 +1323,18 @@ 0 + CameraFocusTransitionTime + + Comment + How many seconds it takes the camera to transition between focal distances + Persist + 1 + Type + F32 + Value + 0.5 + + CameraFNumber Comment diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 94fb0b7d31..7aa90bd76d 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -3698,7 +3698,7 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de { found = gPipeline.lineSegmentIntersectInWorld(mouse_world_start, mouse_world_end, pick_transparent, face_hit, intersection, uv, normal, binormal); - if (found) + if (found && !pick_transparent) { gDebugRaycastIntersection = *intersection; } diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index e3cc2f2589..132e50904a 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3365,8 +3365,15 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e end_face = face+1; } + bool special_cursor = specialHoverCursor(); for (S32 i = start_face; i < end_face; ++i) { + if (!special_cursor && !pick_transparent && getTE(i)->getColor().mV[3] == 0.f) + { //don't attempt to pick completely transparent faces unless + //pick_transparent is true + continue; + } + face_hit = volume->lineSegmentIntersect(v_start, v_end, i, &p, &tc, &n, &bn); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index c280805516..55d73f9808 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -6173,26 +6173,39 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) //depth of field focal plane calculations - F32 subject_distance = 16.f; - if (LLViewerJoystick::getInstance()->getOverrideCamera()) - { - //flycam mode, use mouse cursor as focus point - LLVector3 eye = LLViewerCamera::getInstance()->getOrigin(); - subject_distance = (eye-gDebugRaycastIntersection).magVec(); + static F32 current_distance = 16.f; + static F32 start_distance = 16.f; + static F32 transition_time = 1.f; + + LLVector3 eye = LLViewerCamera::getInstance()->getOrigin(); + F32 target_distance = LLViewerCamera::getInstance()->getAtAxis() * (gDebugRaycastIntersection-eye); + + if (transition_time >= 1.f && + fabsf(current_distance-target_distance)/current_distance > 0.01f) + { //large shift happened, interpolate smoothly to new target distance + llinfos << "start" << llendl; + transition_time = 0.f; + start_distance = current_distance; } - else - { - LLViewerObject* obj = gAgentCamera.getFocusObject(); - if (obj) + else if (transition_time < 1.f) + { //currently in a transition, continue interpolating + transition_time += 1.f/gSavedSettings.getF32("CameraFocusTransitionTime")*gFrameIntervalSeconds; + if (transition_time >= 1.f) { - LLVector3 focus = LLVector3(gAgentCamera.getFocusGlobal()-gAgent.getRegion()->getOriginGlobal()); - LLVector3 eye = LLViewerCamera::getInstance()->getOrigin(); - subject_distance = (focus-eye).magVec(); + llinfos << "stop" << llendl; } + transition_time = llmin(transition_time, 1.f); + + F32 t = cosf(transition_time*F_PI+F_PI)*0.5f+0.5f; + current_distance = start_distance + (target_distance-start_distance)*t; + } + else + { //small or no change, just snap to target distance + current_distance = target_distance; } //convert to mm - subject_distance *= 1000.f; + F32 subject_distance = current_distance*1000.f; F32 fnumber = gSavedSettings.getF32("CameraFNumber"); const F32 default_focal_length = gSavedSettings.getF32("CameraFocalLength"); -- cgit v1.2.3 From fcb205131ccc02b2b50e79ad274ed4ef4fec0330 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 1 Mar 2011 16:04:25 -0600 Subject: SH-1068 Disable DoF when underwater (shader doesn't have enough information to execute). --- indra/newview/pipeline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 55d73f9808..b29e32f1d8 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -6160,7 +6160,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) LLVertexBuffer::unbind(); - if (LLPipeline::sRenderDeferred) + if (LLPipeline::sRenderDeferred && !LLViewerCamera::getInstance()->cameraUnderWater()) { LLGLSLShader* shader = &gDeferredPostProgram; if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) -- cgit v1.2.3 From f24a040beb878a5d24519e2a849379f8d7b473bb Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Tue, 1 Mar 2011 14:29:46 -0800 Subject: SH-311 Physics Shape Type UI collides with torus parameters SH-309 Objects number in Edit Tools becomes obscured --- indra/newview/skins/default/xui/en/floater_tools.xml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 53cc808e70..0b241a9796 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -757,7 +757,7 @@ follows="left|top" halign="right" layout="topleft" - right="-100" + right="-120" name="linked_set_count" top="144" width="80"> @@ -772,7 +772,7 @@ halign="right" layout="topleft" top_delta="0" - right="-10" + right="-8" name="linked_set_cost" tool_tip="Cost of currently selected linked sets as [prims],[physics complexity]" width="80"> @@ -786,7 +786,7 @@ halign="right" layout="topleft" top_pad="5" - right="-100" + right="-120" name="object_count" width="80"> Objects: [COUNT] @@ -799,7 +799,7 @@ halign="right" layout="topleft" top_delta="0" - right="-10" + right="-8" name="object_cost" tool_tip="Cost of currently selected objects as [prims] / [physics complexity]" width="80"> @@ -843,7 +843,8 @@ tab_height="25" top="173" width="295"> - Physics Shape Type: Date: Thu, 3 Mar 2011 16:14:52 -0600 Subject: SH-1085 Fix for crash when unchecking "mirror." Basically got LLFace to be paranoid about who gets to touch its LLVertexBuffer members. Reviewed by Nyx. --- indra/newview/lldrawable.cpp | 15 +++- indra/newview/lldrawpoolavatar.cpp | 65 +++++---------- indra/newview/lldrawpooltree.cpp | 15 ++-- indra/newview/llface.cpp | 131 +++++++++++++++++++++++++------ indra/newview/llface.h | 23 ++++-- indra/newview/llspatialpartition.cpp | 15 ++-- indra/newview/llsprite.cpp | 9 ++- indra/newview/llviewerjointmesh.cpp | 16 ++-- indra/newview/llviewerjointmesh_sse.cpp | 2 +- indra/newview/llviewerjointmesh_sse2.cpp | 2 +- indra/newview/llvoavatar.cpp | 31 ++++---- indra/newview/llvograss.cpp | 2 +- indra/newview/llvoground.cpp | 9 ++- indra/newview/llvopartgroup.cpp | 2 +- indra/newview/llvosky.cpp | 46 ++++++----- indra/newview/llvosurfacepatch.cpp | 4 +- indra/newview/llvotree.cpp | 22 +++--- indra/newview/llvovolume.cpp | 73 +++++++++-------- indra/newview/llvowater.cpp | 12 +-- indra/newview/pipeline.cpp | 3 +- 20 files changed, 293 insertions(+), 204 deletions(-) diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index d370c72a04..fe743e7451 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -820,8 +820,7 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector) if (!volume && facep->hasGeometry()) { - facep->mVertexBuffer = NULL; - facep->mLastVertexBuffer = NULL; + facep->clearVertexBuffer(); } } @@ -935,6 +934,18 @@ void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp) { mSpatialGroupp->setState(LLSpatialGroup::GEOM_DIRTY); }*/ + + if (mSpatialGroupp != groupp && getVOVolume()) + { //NULL out vertex buffer references for volumes on spatial group change to maintain + //requirement that every face vertex buffer is either NULL or points to a vertex buffer + //contained by its drawable's spatial group + for (S32 i = 0; i < getNumFaces(); ++i) + { + LLFace* facep = getFace(i); + facep->clearVertexBuffer(); + } + } + mSpatialGroupp = groupp; } diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index b044a89af8..48e561b24b 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -99,19 +99,6 @@ S32 normal_channel = -1; S32 specular_channel = -1; S32 cube_channel = -1; -static const U32 rigged_data_mask[] = { - LLDrawPoolAvatar::RIGGED_SIMPLE_MASK, - LLDrawPoolAvatar::RIGGED_FULLBRIGHT_MASK, - LLDrawPoolAvatar::RIGGED_SHINY_MASK, - LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY_MASK, - LLDrawPoolAvatar::RIGGED_GLOW_MASK, - LLDrawPoolAvatar::RIGGED_ALPHA_MASK, - LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA_MASK, - LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP_MASK, - LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE_MASK, -}; - - static LLFastTimer::DeclareTimer FTM_SHADOW_AVATAR("Avatar Shadow"); LLDrawPoolAvatar::LLDrawPoolAvatar() : @@ -1297,17 +1284,10 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* return; } - LLVertexBuffer* buffer = face->mVertexBuffer; - - U32 data_mask = 0; - for (U32 i = 0; i < face->mRiggedIndex.size(); ++i) - { - if (face->mRiggedIndex[i] > -1) - { - data_mask |= rigged_data_mask[i]; - } - } + LLVertexBuffer* buffer = face->getVertexBuffer(); + U32 data_mask = face->getRiggedVertexBufferDataMask(); + if (!buffer || buffer->getTypeMask() != data_mask || buffer->getRequestedVerts() != vol_face.mNumVertices) @@ -1316,16 +1296,19 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face->setIndicesIndex(0); face->setSize(vol_face.mNumVertices, vol_face.mNumIndices, true); + if (sShaderLevel > 0) { - face->mVertexBuffer = new LLVertexBuffer(data_mask, GL_DYNAMIC_DRAW_ARB); + buffer = new LLVertexBuffer(data_mask, GL_DYNAMIC_DRAW_ARB); } else { - face->mVertexBuffer = new LLVertexBuffer(data_mask, GL_STREAM_DRAW_ARB); + buffer = new LLVertexBuffer(data_mask, GL_STREAM_DRAW_ARB); } - face->mVertexBuffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), true); + buffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), true); + + face->setVertexBuffer(buffer); U16 offset = 0; @@ -1341,7 +1324,6 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* LLMatrix3 mat_normal(mat3); face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true); - buffer = face->mVertexBuffer; } if (sShaderLevel <= 0 && face->mLastSkinTime < avatar->getLastSkinTime()) @@ -1480,9 +1462,9 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) stop_glerror(); - U32 data_mask = rigged_data_mask[type]; + U32 data_mask = LLFace::getRiggedDataMask(type); - LLVertexBuffer* buff = face->mVertexBuffer; + LLVertexBuffer* buff = face->getVertexBuffer(); if (buff) { @@ -1624,49 +1606,38 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type) { - if (facep->mRiggedIndex.empty()) - { - facep->mRiggedIndex.resize(LLDrawPoolAvatar::NUM_RIGGED_PASSES); - for (U32 i = 0; i < facep->mRiggedIndex.size(); ++i) - { - facep->mRiggedIndex[i] = -1; - } - } - if (type >= NUM_RIGGED_PASSES) { llerrs << "Invalid rigged face type." << llendl; } - if (facep->mRiggedIndex[type] != -1) + if (facep->getRiggedIndex(type) != -1) { llerrs << "Tried to add a rigged face that's referenced elsewhere." << llendl; } - - facep->mRiggedIndex[type] = mRiggedFace[type].size(); - facep->mDrawPoolp = this; + facep->setRiggedIndex(type, mRiggedFace[type].size()); + facep->setPool(this); mRiggedFace[type].push_back(facep); } void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep) { - - facep->mDrawPoolp = NULL; + facep->setPool(NULL); for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i) { - S32 index = facep->mRiggedIndex[i]; + S32 index = facep->getRiggedIndex(i); if (index > -1) { if (mRiggedFace[i].size() > index && mRiggedFace[i][index] == facep) { - facep->mRiggedIndex[i] = -1; + facep->setRiggedIndex(i,-1); mRiggedFace[i].erase(mRiggedFace[i].begin()+index); for (U32 j = index; j < mRiggedFace[i].size(); ++j) { //bump indexes down for faces referenced after erased face - mRiggedFace[i][j]->mRiggedIndex[i] = j; + mRiggedFace[i][j]->setRiggedIndex(i, j); } } else diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp index f1198c9a8d..195ee60a2e 100644 --- a/indra/newview/lldrawpooltree.cpp +++ b/indra/newview/lldrawpooltree.cpp @@ -107,11 +107,12 @@ void LLDrawPoolTree::render(S32 pass) iter != mDrawFace.end(); iter++) { LLFace *face = *iter; - if(face->mVertexBuffer.notNull()) + LLVertexBuffer* buff = face->getVertexBuffer(); + if(buff) { - face->mVertexBuffer->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK); - face->mVertexBuffer->drawRange(LLRender::TRIANGLES, 0, face->mVertexBuffer->getRequestedVerts()-1, face->mVertexBuffer->getRequestedIndices(), 0); - gPipeline.addTrianglesDrawn(face->mVertexBuffer->getRequestedIndices()); + buff->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK); + buff->drawRange(LLRender::TRIANGLES, 0, buff->getRequestedVerts()-1, buff->getRequestedIndices(), 0); + gPipeline.addTrianglesDrawn(buff->getRequestedIndices()); } } } @@ -200,13 +201,13 @@ void LLDrawPoolTree::renderTree(BOOL selecting) LLFace *face = *iter; LLDrawable *drawablep = face->getDrawable(); - if (drawablep->isDead() || face->mVertexBuffer.isNull()) + if (drawablep->isDead() || !face->getVertexBuffer()) { continue; } - face->mVertexBuffer->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK); - U16* indicesp = (U16*) face->mVertexBuffer->getIndicesPointer(); + face->getVertexBuffer()->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK); + U16* indicesp = (U16*) face->getVertexBuffer()->getIndicesPointer(); // Render each of the trees LLVOTree *treep = (LLVOTree *)drawablep->getVObj().get(); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 863e335f4a..10847e7067 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -250,6 +250,11 @@ void LLFace::setWorldMatrix(const LLMatrix4 &mat) llerrs << "Faces on this drawable are not independently modifiable\n" << llendl; } +void LLFace::setPool(LLFacePool* pool) +{ + mDrawPoolp = pool; +} + void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep) { LLMemType mt1(LLMemType::MTYPE_DRAWABLE); @@ -375,6 +380,8 @@ void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align) mVertexBuffer = NULL; mLastVertexBuffer = NULL; } + + llassert(verify()); } //============================================================================ @@ -579,23 +586,26 @@ void LLFace::printDebugInfo() const llinfos << "II: " << mIndicesIndex << " Count:" << mIndicesCount << llendl; llinfos << llendl; - poolp->printDebugInfo(); - - S32 pool_references = 0; - for (std::vector::iterator iter = poolp->mReferences.begin(); - iter != poolp->mReferences.end(); iter++) + if (poolp) { - LLFace *facep = *iter; - if (facep == this) + poolp->printDebugInfo(); + + S32 pool_references = 0; + for (std::vector::iterator iter = poolp->mReferences.begin(); + iter != poolp->mReferences.end(); iter++) { - llinfos << "Pool reference: " << pool_references << llendl; - pool_references++; + LLFace *facep = *iter; + if (facep == this) + { + llinfos << "Pool reference: " << pool_references << llendl; + pool_references++; + } } - } - if (pool_references != 1) - { - llinfos << "Incorrect number of pool references!" << llendl; + if (pool_references != 1) + { + llinfos << "Incorrect number of pool references!" << llendl; + } } #if 0 @@ -976,6 +986,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, bool force_rebuild) { LLFastTimer t(FTM_FACE_GET_GEOM); + llassert(verify()); const LLVolumeFace &vf = volume.getVolumeFace(f); S32 num_vertices = (S32)vf.mNumVertices; S32 num_indices = (S32) vf.mNumIndices; @@ -1842,16 +1853,7 @@ BOOL LLFace::verify(const U32* indices_array) const BOOL ok = TRUE; if( mVertexBuffer.isNull() ) - { - if( mGeomCount ) - { - // This happens before teleports as faces are torn down. - // Stop the crash in DEV-31893 with a null pointer check, - // but present this info. - // To clean up the log, the geometry could be cleared, or the - // face could otherwise be marked for no ::verify. - llinfos << "Face with no vertex buffer and " << mGeomCount << " mGeomCount" << llendl; - } + { //no vertex buffer, face is implicitly valid return TRUE; } @@ -1859,7 +1861,7 @@ BOOL LLFace::verify(const U32* indices_array) const if ((mGeomIndex + mGeomCount) > mVertexBuffer->getNumVerts()) { ok = FALSE; - llinfos << "Face not within pool range!" << llendl; + llinfos << "Face references invalid vertices!" << llendl; } S32 indices_count = (S32)getIndicesCount(); @@ -1875,6 +1877,12 @@ BOOL LLFace::verify(const U32* indices_array) const llinfos << "Face has bogus indices count" << llendl; } + if (mIndicesIndex + mIndicesCount > mVertexBuffer->getNumIndices()) + { + ok = FALSE; + llinfos << "Face references invalid indices!" << llendl; + } + #if 0 S32 geom_start = getGeomStart(); S32 geom_count = mGeomCount; @@ -2183,3 +2191,78 @@ BOOL LLFace::switchTexture() return mUsingAtlas ; } + +void LLFace::setVertexBuffer(LLVertexBuffer* buffer) +{ + mVertexBuffer = buffer; + llassert(verify()); +} + +void LLFace::clearVertexBuffer() +{ + mVertexBuffer = NULL; + mLastVertexBuffer = NULL; +} + +//static +U32 LLFace::getRiggedDataMask(U32 type) +{ + static const U32 rigged_data_mask[] = { + LLDrawPoolAvatar::RIGGED_SIMPLE_MASK, + LLDrawPoolAvatar::RIGGED_FULLBRIGHT_MASK, + LLDrawPoolAvatar::RIGGED_SHINY_MASK, + LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY_MASK, + LLDrawPoolAvatar::RIGGED_GLOW_MASK, + LLDrawPoolAvatar::RIGGED_ALPHA_MASK, + LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA_MASK, + LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP_MASK, + LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE_MASK, + }; + + llassert(type < sizeof(rigged_data_mask)/sizeof(U32)); + + return rigged_data_mask[type]; +} + +U32 LLFace::getRiggedVertexBufferDataMask() const +{ + U32 data_mask = 0; + for (U32 i = 0; i < mRiggedIndex.size(); ++i) + { + if (mRiggedIndex[i] > -1) + { + data_mask |= LLFace::getRiggedDataMask(i); + } + } + + return data_mask; +} + +S32 LLFace::getRiggedIndex(U32 type) const +{ + if (mRiggedIndex.empty()) + { + return -1; + } + + llassert(type < mRiggedIndex.size()); + + return mRiggedIndex[type]; +} + +void LLFace::setRiggedIndex(U32 type, S32 index) +{ + if (mRiggedIndex.empty()) + { + mRiggedIndex.resize(LLDrawPoolAvatar::NUM_RIGGED_PASSES); + for (U32 i = 0; i < mRiggedIndex.size(); ++i) + { + mRiggedIndex[i] = -1; + } + } + + llassert(type < mRiggedIndex.size()); + + mRiggedIndex[type] = index; +} + diff --git a/indra/newview/llface.h b/indra/newview/llface.h index cc04bf2f1c..1f69dd145e 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -131,14 +131,14 @@ public: LLDrawable* getDrawable() const { return mDrawablep; } LLViewerObject* getViewerObject() const { return mVObjp; } S32 getLOD() const { return mVObjp.notNull() ? mVObjp->getLOD() : 0; } - LLVertexBuffer* getVertexBuffer() const { return mVertexBuffer; } void setPoolType(U32 type) { mPoolType = type; } S32 getTEOffset() { return mTEOffset; } LLViewerTexture* getTexture() const; void setViewerObject(LLViewerObject* object); void setPool(LLFacePool *pool, LLViewerTexture *texturep); - + void setPool(LLFacePool* pool); + void setDrawable(LLDrawable *drawable); void setTEOffset(const S32 te_offset); @@ -218,6 +218,16 @@ public: void removeAtlas() ; BOOL switchTexture() ; + //vertex buffer tracking + void setVertexBuffer(LLVertexBuffer* buffer); + void clearVertexBuffer(); //sets mVertexBuffer and mLastVertexBuffer to NULL + LLVertexBuffer* getVertexBuffer() const { return mVertexBuffer; } + U32 getRiggedVertexBufferDataMask() const; + S32 getRiggedIndex(U32 type) const; + void setRiggedIndex(U32 type, S32 index); + + static U32 getRiggedDataMask(U32 type); + public: //aligned members LLVector4a mExtents[2]; @@ -235,8 +245,6 @@ public: LLVector2 mTexExtents[2]; F32 mDistance; - LLPointer mVertexBuffer; - LLPointer mLastVertexBuffer; F32 mLastUpdateTime; F32 mLastSkinTime; F32 mLastMoveTime; @@ -244,10 +252,9 @@ public: LLDrawInfo* mDrawInfo; private: - friend class LLGeometryManager; - friend class LLVolumeGeometryManager; - friend class LLDrawPoolAvatar; - + LLPointer mVertexBuffer; + LLPointer mLastVertexBuffer; + U32 mState; LLFacePool* mDrawPoolp; U32 mPoolType; diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 14775f0f21..5e7af6bbb3 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -1486,8 +1486,7 @@ void LLSpatialGroup::destroyGL() for (S32 j = 0; j < drawable->getNumFaces(); j++) { LLFace* facep = drawable->getFace(j); - facep->mVertexBuffer = NULL; - facep->mLastVertexBuffer = NULL; + facep->clearVertexBuffer(); } } } @@ -2433,7 +2432,9 @@ void pushVerts(LLSpatialGroup* group, U32 mask) void pushVerts(LLFace* face, U32 mask) { - LLVertexBuffer* buffer = face->mVertexBuffer; + llassert(face->verify()); + + LLVertexBuffer* buffer = face->getVertexBuffer(); if (buffer) { @@ -2580,7 +2581,7 @@ void renderOctree(LLSpatialGroup* group) for (S32 j = 0; j < drawable->getNumFaces(); j++) { LLFace* face = drawable->getFace(j); - if (face->mVertexBuffer.notNull()) + if (face->getVertexBuffer()) { if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f) { @@ -2595,10 +2596,10 @@ void renderOctree(LLSpatialGroup* group) continue; } - face->mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX); + face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX); //drawBox((face->mExtents[0] + face->mExtents[1])*0.5f, // (face->mExtents[1]-face->mExtents[0])*0.5f); - face->mVertexBuffer->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart()); + face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart()); } } @@ -3374,7 +3375,7 @@ void renderPhysicsShapes(LLSpatialGroup* group) for (S32 i = 0; i < drawable->getNumFaces(); ++i) { LLFace* face = drawable->getFace(i); - LLVertexBuffer* buff = face->mVertexBuffer; + LLVertexBuffer* buff = face->getVertexBuffer(); if (buff) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); diff --git a/indra/newview/llsprite.cpp b/indra/newview/llsprite.cpp index a69592b61c..4bde2dfcab 100644 --- a/indra/newview/llsprite.cpp +++ b/indra/newview/llsprite.cpp @@ -186,14 +186,15 @@ void LLSprite::updateFace(LLFace &face) U16 index_offset; // Setup face - if (face.mVertexBuffer.isNull()) + if (!face.getVertexBuffer()) { - face.mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer* buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, GL_STREAM_DRAW_ARB); - face.mVertexBuffer->allocateBuffer(4, 12, TRUE); + buff->allocateBuffer(4, 12, TRUE); face.setGeomIndex(0); face.setIndicesIndex(0); + face.setVertexBuffer(buff); } index_offset = face.getGeometry(verticesp,normalsp,tex_coordsp, indicesp); @@ -242,7 +243,7 @@ void LLSprite::updateFace(LLFace &face) *indicesp++ = 3 + index_offset; } - face.mVertexBuffer->setBuffer(0); + face.getVertexBuffer()->setBuffer(0); face.mCenterAgent = mPosition; } diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index aa6da5c9f3..77c8bb0329 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -511,7 +511,7 @@ int compare_int(const void *a, const void *b) U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) { if (!mValid || !mMesh || !mFace || !mVisible || - mFace->mVertexBuffer.isNull() || + !mFace->getVertexBuffer() || mMesh->getNumFaces() == 0) { return 0; @@ -582,7 +582,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) gGL.getTexUnit(diffuse_channel)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT)); } - mFace->mVertexBuffer->setBuffer(sRenderMask); + mFace->getVertexBuffer()->setBuffer(sRenderMask); U32 start = mMesh->mFaceVertexOffset; U32 end = start + mMesh->mFaceVertexCount - 1; @@ -599,14 +599,14 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) } } - mFace->mVertexBuffer->drawRange(LLRender::TRIANGLES, start, end, count, offset); + mFace->getVertexBuffer()->drawRange(LLRender::TRIANGLES, start, end, count, offset); } else { glPushMatrix(); LLMatrix4 jointToWorld = getWorldMatrix(); glMultMatrixf((GLfloat*)jointToWorld.mMatrix); - mFace->mVertexBuffer->drawRange(LLRender::TRIANGLES, start, end, count, offset); + mFace->getVertexBuffer()->drawRange(LLRender::TRIANGLES, start, end, count, offset); glPopMatrix(); } gPipeline.addTrianglesDrawn(count); @@ -661,7 +661,7 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w mFace = face; - if (mFace->mVertexBuffer.isNull()) + if (!mFace->getVertexBuffer()) { return; } @@ -693,7 +693,7 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w if (num_verts) { face->getGeometryAvatar(verticesp, normalsp, tex_coordsp, vertex_weightsp, clothing_weightsp); - face->mVertexBuffer->getIndexStrider(indicesp); + face->getVertexBuffer()->getIndexStrider(indicesp); verticesp += mMesh->mFaceVertexOffset; normalsp += mMesh->mFaceVertexOffset; @@ -758,7 +758,7 @@ void LLViewerJointMesh::updateGeometryOriginal(LLFace *mFace, LLPolyMesh *mMesh) LLStrider o_normals; //get vertex and normal striders - LLVertexBuffer* buffer = mFace->mVertexBuffer; + LLVertexBuffer* buffer = mFace->getVertexBuffer(); buffer->getVertexStrider(o_vertices, 0); buffer->getNormalStrider(o_normals, 0); @@ -869,7 +869,7 @@ void LLViewerJointMesh::updateJointGeometry() && mMesh && mFace && mMesh->hasWeights() - && mFace->mVertexBuffer.notNull() + && mFace->getVertexBuffer() && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) == 0)) { return; diff --git a/indra/newview/llviewerjointmesh_sse.cpp b/indra/newview/llviewerjointmesh_sse.cpp index e3b40f6943..400b49d046 100644 --- a/indra/newview/llviewerjointmesh_sse.cpp +++ b/indra/newview/llviewerjointmesh_sse.cpp @@ -83,7 +83,7 @@ void LLViewerJointMesh::updateGeometrySSE(LLFace *face, LLPolyMesh *mesh) LLStrider o_vertices; LLStrider o_normals; - LLVertexBuffer *buffer = face->mVertexBuffer; + LLVertexBuffer *buffer = face->getVertexBuffer(); buffer->getVertexStrider(o_vertices, mesh->mFaceVertexOffset); buffer->getNormalStrider(o_normals, mesh->mFaceVertexOffset); diff --git a/indra/newview/llviewerjointmesh_sse2.cpp b/indra/newview/llviewerjointmesh_sse2.cpp index 5871823dde..c2296dd569 100644 --- a/indra/newview/llviewerjointmesh_sse2.cpp +++ b/indra/newview/llviewerjointmesh_sse2.cpp @@ -90,7 +90,7 @@ void LLViewerJointMesh::updateGeometrySSE2(LLFace *face, LLPolyMesh *mesh) LLStrider o_vertices; LLStrider o_normals; - LLVertexBuffer *buffer = face->mVertexBuffer; + LLVertexBuffer *buffer = face->getVertexBuffer(); buffer->getVertexStrider(o_vertices, mesh->mFaceVertexOffset); buffer->getNormalStrider(o_normals, mesh->mFaceVertexOffset); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index e982df1c92..aa7349f129 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -2016,26 +2016,29 @@ void LLVOAvatar::updateMeshData() bool terse_update = false; - if(facep->mVertexBuffer.isNull()) + facep->setGeomIndex(0); + facep->setIndicesIndex(0); + + LLVertexBuffer* buff = facep->getVertexBuffer(); + if(!facep->getVertexBuffer()) { - facep->mVertexBuffer = new LLVertexBufferAvatar(); - facep->mVertexBuffer->allocateBuffer(num_vertices, num_indices, TRUE); + buff = new LLVertexBufferAvatar(); + buff->allocateBuffer(num_vertices, num_indices, TRUE); + facep->setVertexBuffer(buff); } else { - if (facep->mVertexBuffer->getRequestedIndices() == num_indices && - facep->mVertexBuffer->getRequestedVerts() == num_vertices) + if (buff->getRequestedIndices() == num_indices && + buff->getRequestedVerts() == num_vertices) { terse_update = true; } else { - facep->mVertexBuffer->resizeBuffer(num_vertices, num_indices) ; - } + buff->resizeBuffer(num_vertices, num_indices); + } } - - facep->setGeomIndex(0); - facep->setIndicesIndex(0); + // This is a hack! Avatars have their own pool, so we are detecting // the case of more than one avatar in the pool (thus > 0 instead of >= 0) @@ -2050,7 +2053,7 @@ void LLVOAvatar::updateMeshData() } stop_glerror(); - facep->mVertexBuffer->setBuffer(0); + buff->setBuffer(0); if(!f_num) { @@ -4006,7 +4009,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) LLFace* face = mDrawable->getFace(0); - bool needs_rebuild = !face || face->mVertexBuffer.isNull() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY); + bool needs_rebuild = !face || !face->getVertexBuffer() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY); if (needs_rebuild || mDirtyMesh) { //LOD changed or new mesh created, allocate new vertex buffer if needed @@ -4041,7 +4044,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) mNeedsSkin = FALSE; mLastSkinTime = gFrameTimeSeconds; - LLVertexBuffer* vb = mDrawable->getFace(0)->mVertexBuffer; + LLVertexBuffer* vb = mDrawable->getFace(0)->getVertexBuffer(); if (vb) { vb->setBuffer(0); @@ -8150,7 +8153,7 @@ BOOL LLVOAvatar::updateLOD() BOOL res = updateJointLODs(); LLFace* facep = mDrawable->getFace(0); - if (facep->mVertexBuffer.isNull()) + if (!facep->getVertexBuffer()) { dirtyMesh(2); } diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index edd41089c0..32822e1181 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -453,7 +453,7 @@ void LLVOGrass::plantBlades() face->setTexture(getTEImage(0)); face->setState(LLFace::GLOBAL); face->setSize(mNumBlades * 8, mNumBlades * 12); - face->mVertexBuffer = NULL; + face->setVertexBuffer(NULL); face->setTEOffset(0); face->mCenterLocal = mPosition + mRegionp->getOriginAgent(); diff --git a/indra/newview/llvoground.cpp b/indra/newview/llvoground.cpp index f032ae8780..ce256fdedf 100644 --- a/indra/newview/llvoground.cpp +++ b/indra/newview/llvoground.cpp @@ -97,13 +97,14 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable) drawable->addFace(poolp, NULL); face = drawable->getFace(0); - if (face->mVertexBuffer.isNull()) + if (!face->getVertexBuffer()) { face->setSize(5, 12); - face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolGround::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); - face->mVertexBuffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE); + LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolGround::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); + buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE); face->setGeomIndex(0); face->setIndicesIndex(0); + face->setVertexBuffer(buff); } index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); @@ -161,7 +162,7 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable) *(texCoordsp++) = LLVector2(0.f, 1.f); *(texCoordsp++) = LLVector2(0.5f, 0.5f); - face->mVertexBuffer->setBuffer(0); + face->getVertexBuffer()->setBuffer(0); LLPipeline::sCompiles++; return TRUE; } diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index f762f04d8e..6f354b78b1 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -463,7 +463,7 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) LLAlphaObject* object = (LLAlphaObject*) facep->getViewerObject(); facep->setGeomIndex(vertex_count); facep->setIndicesIndex(index_count); - facep->mVertexBuffer = buffer; + facep->setVertexBuffer(buffer); facep->setPoolType(LLDrawPool::POOL_ALPHA); object->getGeometry(facep->getTEOffset(), verticesp, normalsp, texcoordsp, colorsp, indicesp); diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp index 80f43e51d2..288d335e1d 100644 --- a/indra/newview/llvosky.cpp +++ b/indra/newview/llvosky.cpp @@ -1182,7 +1182,7 @@ BOOL LLVOSky::updateSky() } } - if (mDrawable.notNull() && mDrawable->getFace(0) && mDrawable->getFace(0)->mVertexBuffer.isNull()) + if (mDrawable.notNull() && mDrawable->getFace(0) && !mDrawable->getFace(0)->getVertexBuffer()) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); } @@ -1233,10 +1233,11 @@ void LLVOSky::createDummyVertexBuffer() mFace[FACE_DUMMY] = mDrawable->addFace(poolp, NULL); } - if(mFace[FACE_DUMMY]->mVertexBuffer.isNull()) + if(!mFace[FACE_DUMMY]->getVertexBuffer()) { - mFace[FACE_DUMMY]->mVertexBuffer = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB); - mFace[FACE_DUMMY]->mVertexBuffer->allocateBuffer(1, 1, TRUE); + LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB); + buff->allocateBuffer(1, 1, TRUE); + mFace[FACE_DUMMY]->setVertexBuffer(buff); } } @@ -1255,13 +1256,13 @@ void LLVOSky::updateDummyVertexBuffer() LLFastTimer t(FTM_RENDER_FAKE_VBO_UPDATE) ; - if(!mFace[FACE_DUMMY] || mFace[FACE_DUMMY]->mVertexBuffer.isNull()) + if(!mFace[FACE_DUMMY] || !mFace[FACE_DUMMY]->getVertexBuffer()) createDummyVertexBuffer() ; LLStrider vertices ; - mFace[FACE_DUMMY]->mVertexBuffer->getVertexStrider(vertices, 0); + mFace[FACE_DUMMY]->getVertexBuffer()->getVertexStrider(vertices, 0); *vertices = mCameraPosAgent ; - mFace[FACE_DUMMY]->mVertexBuffer->setBuffer(0) ; + mFace[FACE_DUMMY]->getVertexBuffer()->setBuffer(0) ; } //---------------------------------- //end of fake vertex buffer updating @@ -1304,14 +1305,15 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable) { face = mFace[FACE_SIDE0 + side]; - if (face->mVertexBuffer.isNull()) + if (!face->getVertexBuffer()) { face->setSize(4, 6); face->setGeomIndex(0); face->setIndicesIndex(0); - face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); - face->mVertexBuffer->allocateBuffer(4, 6, TRUE); - + LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); + buff->allocateBuffer(4, 6, TRUE); + face->setVertexBuffer(buff); + index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); S32 vtx = 0; @@ -1344,7 +1346,7 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable) *indicesp++ = index_offset + 3; *indicesp++ = index_offset + 2; - face->mVertexBuffer->setBuffer(0); + buff->setBuffer(0); } } @@ -1471,13 +1473,14 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons facep = mFace[f]; - if (facep->mVertexBuffer.isNull()) + if (!facep->getVertexBuffer()) { - facep->setSize(4, 6); - facep->mVertexBuffer = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); - facep->mVertexBuffer->allocateBuffer(facep->getGeomCount(), facep->getIndicesCount(), TRUE); + facep->setSize(4, 6); + LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); + buff->allocateBuffer(facep->getGeomCount(), facep->getIndicesCount(), TRUE); facep->setGeomIndex(0); facep->setIndicesIndex(0); + facep->setVertexBuffer(buff); } index_offset = facep->getGeometry(verticesp,normalsp,texCoordsp, indicesp); @@ -1506,7 +1509,7 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons *indicesp++ = index_offset + 2; *indicesp++ = index_offset + 3; - facep->mVertexBuffer->setBuffer(0); + facep->getVertexBuffer()->setBuffer(0); if (is_sun) { @@ -1875,13 +1878,14 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, LLFace *face = mFace[FACE_REFLECTION]; - if (face->mVertexBuffer.isNull() || quads*4 != face->getGeomCount()) + if (!face->getVertexBuffer() || quads*4 != face->getGeomCount()) { face->setSize(quads * 4, quads * 6); - face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); - face->mVertexBuffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE); + LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); + buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE); face->setIndicesIndex(0); face->setGeomIndex(0); + face->setVertexBuffer(buff); } LLStrider verticesp; @@ -2019,7 +2023,7 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, } } - face->mVertexBuffer->setBuffer(0); + face->getVertexBuffer()->setBuffer(0); } diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index 690530939e..dbcd4f50ca 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -890,7 +890,7 @@ void LLVOSurfacePatch::dirtyGeom() if (mDrawable) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); - mDrawable->getFace(0)->mVertexBuffer = NULL; + mDrawable->getFace(0)->setVertexBuffer(NULL); mDrawable->movePartition(); } } @@ -1119,7 +1119,7 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group) facep->setIndicesIndex(indices_index); facep->setGeomIndex(index_offset); - facep->mVertexBuffer = buffer; + facep->setVertexBuffer(buffer); LLVOSurfacePatch* patchp = (LLVOSurfacePatch*) facep->getViewerObject(); patchp->getGeometry(vertices, normals, colors, texcoords, texcoords2, indices); diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 1b5aed804f..e6f2b19e07 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -525,11 +525,11 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree. { mReferenceBuffer = NULL ; - mDrawable->getFace(0)->mVertexBuffer = NULL ; + mDrawable->getFace(0)->setVertexBuffer(NULL); return TRUE ; } - if (mReferenceBuffer.isNull() || mDrawable->getFace(0)->mVertexBuffer.isNull()) + if (mReferenceBuffer.isNull() || !mDrawable->getFace(0)->getVertexBuffer()) { const F32 SRR3 = 0.577350269f; // sqrt(1/3) const F32 SRR2 = 0.707106781f; // sqrt(1/2) @@ -863,7 +863,7 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) if (gSavedSettings.getBOOL("RenderAnimateTrees")) { - mDrawable->getFace(0)->mVertexBuffer = mReferenceBuffer; + mDrawable->getFace(0)->setVertexBuffer(mReferenceBuffer); } else { @@ -921,8 +921,9 @@ void LLVOTree::updateMesh() calcNumVerts(vert_count, index_count, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, mBranches); LLFace* facep = mDrawable->getFace(0); - facep->mVertexBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); - facep->mVertexBuffer->allocateBuffer(vert_count, index_count, TRUE); + LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); + buff->allocateBuffer(vert_count, index_count, TRUE); + facep->setVertexBuffer(buff); LLStrider vertices; LLStrider normals; @@ -930,16 +931,15 @@ void LLVOTree::updateMesh() LLStrider indices; U16 idx_offset = 0; - facep->mVertexBuffer->getVertexStrider(vertices); - facep->mVertexBuffer->getNormalStrider(normals); - facep->mVertexBuffer->getTexCoord0Strider(tex_coords); - facep->mVertexBuffer->getIndexStrider(indices); + buff->getVertexStrider(vertices); + buff->getNormalStrider(normals); + buff->getTexCoord0Strider(tex_coords); + buff->getIndexStrider(indices); genBranchPipeline(vertices, normals, tex_coords, indices, idx_offset, scale_mat, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, 1.0, mTwist, droop, mBranches, alpha); mReferenceBuffer->setBuffer(0); - facep->mVertexBuffer->setBuffer(0); - + buff->setBuffer(0); } void LLVOTree::appendMesh(LLStrider& vertices, diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 132e50904a..66263412ec 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3689,7 +3689,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, (type == LLRenderPass::PASS_INVISIBLE) || (type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT)); - if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL)) + if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_NORMAL)) { llwarns << "Non fullbright face has no normals!" << llendl; return; @@ -3723,13 +3723,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U8 glow = (U8) (facep->getTextureEntry()->getGlow() * 255); - if (facep->mVertexBuffer.isNull()) - { - llerrs << "WTF?" << llendl; - } - if (idx >= 0 && - draw_vec[idx]->mVertexBuffer == facep->mVertexBuffer && + draw_vec[idx]->mVertexBuffer == facep->getVertexBuffer() && draw_vec[idx]->mEnd == facep->getGeomIndex()-1 && (LLPipeline::sTextureBindTest || draw_vec[idx]->mTexture == tex) && #if LL_DARWIN @@ -3756,7 +3751,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 offset = facep->getIndicesStart(); U32 count = facep->getIndicesCount(); LLPointer draw_info = new LLDrawInfo(start,end,count,offset, tex, - facep->mVertexBuffer, fullbright, bump); + facep->getVertexBuffer(), fullbright, bump); draw_info->mGroup = group; draw_info->mVSize = facep->getVirtualSize(); draw_vec.push_back(draw_info); @@ -3896,16 +3891,22 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) //for each face for (S32 i = 0; i < drawablep->getNumFaces(); i++) { + LLFace* facep = drawablep->getFace(i); + + //ALWAYS null out vertex buffer on rebuild -- if the face lands in a render + // batch, it will recover its vertex buffer reference from the spatial group + facep->setVertexBuffer(NULL); + //sum up face verts and indices drawablep->updateFaceSize(i); - LLFace* facep = drawablep->getFace(i); + + if (rigged) { if (!facep->isState(LLFace::RIGGED)) - { - facep->mVertexBuffer = NULL; - facep->mLastVertexBuffer = NULL; + { //completely reset vertex buffer + facep->clearVertexBuffer(); } facep->setState(LLFace::RIGGED); @@ -4063,14 +4064,13 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0) { - facep->mVertexBuffer = NULL; - facep->mLastVertexBuffer = NULL; + facep->clearVertexBuffer(); continue; } cur_total += facep->getGeomCount(); - if (facep->hasGeometry() && facep->mPixelArea > FORCE_CULL_AREA) + if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) { const LLTextureEntry* te = facep->getTextureEntry(); LLViewerTexture* tex = facep->getTexture(); @@ -4083,7 +4083,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } } - BOOL force_simple = (facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA); + BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA); U32 type = gPipeline.getPoolTypeFromTE(te, tex); if (type != LLDrawPool::POOL_ALPHA && force_simple) { @@ -4169,8 +4169,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } else { //face has no renderable geometry - facep->mVertexBuffer = NULL; - facep->mLastVertexBuffer = NULL; + facep->clearVertexBuffer(); } } @@ -4251,7 +4250,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) for (S32 i = 0; i < drawablep->getNumFaces(); ++i) { LLFace* face = drawablep->getFace(i); - if (face && face->mVertexBuffer.notNull()) + if (face && face->getVertexBuffer()) { face->getGeometryVolume(*volume, face->getTEOffset(), vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex()); @@ -4303,9 +4302,10 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) for (S32 i = 0; i < drawablep->getNumFaces(); ++i) { LLFace* face = drawablep->getFace(i); - if (face && face->mVertexBuffer.notNull() && face->mVertexBuffer->isLocked()) + LLVertexBuffer* buff = face->getVertexBuffer(); + if (face && buff && buff->isLocked()) { - face->mVertexBuffer->setBuffer(0) ; + buff->setBuffer(0) ; } } } @@ -4375,7 +4375,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: U32 index_count = facep->getIndicesCount(); U32 geom_count = facep->getGeomCount(); - //sum up vertices needed for this texture + //sum up vertices needed for this render batch std::vector::iterator i = face_iter; ++i; @@ -4385,7 +4385,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: facep = *i; if (geom_count + facep->getGeomCount() > max_vertices) - { //cut vertex buffers on geom count too big + { //cut batches on geom count too big break; } @@ -4413,7 +4413,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: buffer->allocateBuffer(geom_count, index_count, TRUE); } else - { + { //resize pre-existing buffer if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage) { buffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask, @@ -4434,15 +4434,18 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: U16 index_offset = 0; while (face_iter < i) - { + { //update face indices for new buffer facep = *face_iter; - facep->mIndicesIndex = indices_index; - facep->mGeomIndex = index_offset; - facep->mVertexBuffer = buffer; + facep->setIndicesIndex(indices_index); + facep->setGeomIndex(index_offset); + facep->setVertexBuffer(buffer); + { + //for debugging, set last time face was updated vs moved facep->updateRebuildFlags(); + if (!LLPipeline::sDelayVBUpdate) - { + { //copy face geometry into vertex buffer LLDrawable* drawablep = facep->getDrawable(); LLVOVolume* vobj = drawablep->getVOVolume(); LLVolume* volume = vobj->getVolume(); @@ -4459,9 +4462,12 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: } index_offset += facep->getGeomCount(); - indices_index += facep->mIndicesCount; + indices_index += facep->getIndicesCount(); + + + //append face to appropriate render batch - BOOL force_simple = facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA; + BOOL force_simple = facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA; BOOL fullbright = facep->isState(LLFace::FULLBRIGHT); if ((mask & LLVertexBuffer::MAP_NORMAL) == 0) { //paranoia check to make sure GL doesn't try to read non-existant normals @@ -4628,7 +4634,7 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun //sum up face verts and indices drawablep->updateFaceSize(i); LLFace* facep = drawablep->getFace(i); - if (facep->hasGeometry() && facep->mPixelArea > FORCE_CULL_AREA) + if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) { vertex_count += facep->getGeomCount(); index_count += facep->getIndicesCount(); @@ -4638,8 +4644,7 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun } else { - facep->mVertexBuffer = NULL; - facep->mLastVertexBuffer = NULL; + facep->clearVertexBuffer(); } } } diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index 77875859e9..69ebad61ac 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -166,16 +166,18 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable) face->setSize(vertices_per_quad * num_quads, indices_per_quad * num_quads); - if (face->mVertexBuffer.isNull()) + LLVertexBuffer* buff = face->getVertexBuffer(); + if (!buff) { - face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB); - face->mVertexBuffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE); + buff = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB); + buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE); face->setIndicesIndex(0); face->setGeomIndex(0); + face->setVertexBuffer(buff); } else { - face->mVertexBuffer->resizeBuffer(face->getGeomCount(), face->getIndicesCount()); + buff->resizeBuffer(face->getGeomCount(), face->getIndicesCount()); } index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); @@ -229,7 +231,7 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable) } } - face->mVertexBuffer->setBuffer(0); + buff->setBuffer(0); mDrawable->movePartition(); LLPipeline::sCompiles++; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index b29e32f1d8..73cd60e2f5 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -5786,8 +5786,7 @@ void LLPipeline::resetVertexBuffers(LLDrawable* drawable) for (S32 i = 0; i < drawable->getNumFaces(); i++) { LLFace* facep = drawable->getFace(i); - facep->mVertexBuffer = NULL; - facep->mLastVertexBuffer = NULL; + facep->clearVertexBuffer(); } } -- cgit v1.2.3 From 24eb86c774eb545bb8e0d5153e3aa85e6d4f2094 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 3 Mar 2011 18:09:32 -0600 Subject: SH-1072 Implement new DoF focus rules (no DoF in build mode, always focus on media texture, focus on alt-zoom target if exists, focus 16m in front of camera when in followcam, focus on object under cursor in flycam). --- indra/newview/pipeline.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 73cd60e2f5..9eaf515c65 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -75,6 +75,7 @@ #include "lltool.h" #include "lltoolmgr.h" #include "llviewercamera.h" +#include "llviewermediafocus.h" #include "llviewertexturelist.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" @@ -6176,9 +6177,45 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) static F32 start_distance = 16.f; static F32 transition_time = 1.f; + LLVector3 focus_point; + + LLViewerObject* obj = LLViewerMediaFocus::getInstance()->getFocusedObject(); + if (obj && obj->mDrawable && obj->isSelected()) + { + S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace(); + if (obj && obj->mDrawable) + { + LLFace* face = obj->mDrawable->getFace(face_idx); + if (face) + { + focus_point = face->getPositionAgent(); + } + } + } + + if (focus_point.isExactlyZero()) + { + if (LLViewerJoystick::getInstance()->getOverrideCamera()) + { + focus_point = gDebugRaycastIntersection; + } + else + { + LLViewerObject* obj = gAgentCamera.getFocusObject(); + if (obj) + { + focus_point = LLVector3(gAgentCamera.getFocusGlobal()-gAgent.getRegion()->getOriginGlobal()); + } + } + } + LLVector3 eye = LLViewerCamera::getInstance()->getOrigin(); - F32 target_distance = LLViewerCamera::getInstance()->getAtAxis() * (gDebugRaycastIntersection-eye); - + F32 target_distance = 16.f; + if (!focus_point.isExactlyZero()) + { + target_distance = LLViewerCamera::getInstance()->getAtAxis() * (focus_point-eye); + } + if (transition_time >= 1.f && fabsf(current_distance-target_distance)/current_distance > 0.01f) { //large shift happened, interpolate smoothly to new target distance @@ -6206,8 +6243,13 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) //convert to mm F32 subject_distance = current_distance*1000.f; F32 fnumber = gSavedSettings.getF32("CameraFNumber"); - const F32 default_focal_length = gSavedSettings.getF32("CameraFocalLength"); - + F32 default_focal_length = gSavedSettings.getF32("CameraFocalLength"); + + if (LLToolMgr::getInstance()->inBuildMode()) + { //squish focal length when in build mode so DoF doesn't make editing objects difficult + default_focal_length = 5.f; + } + F32 fov = LLViewerCamera::getInstance()->getView(); const F32 default_fov = gSavedSettings.getF32("CameraFieldOfView") * F_PI/180.f; -- cgit v1.2.3 From 30763ec707bb65214420c230706d408420a5cb80 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 3 Mar 2011 18:31:59 -0600 Subject: Fix for DoF effect being busted on transparent surfaces. --- indra/newview/lldrawpoolalpha.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 7f1740e29f..a2a109d5ee 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -246,13 +246,25 @@ void LLDrawPoolAlpha::render(S32 pass) if (deferred_render && pass == 1) { gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.33f); + gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA); } + else + { + mColorSFactor = LLRender::BF_SOURCE_ALPHA; // } regular alpha blend + mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } + mAlphaSFactor = LLRender::BF_ZERO; // } glow suppression + mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } + gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); - mColorSFactor = LLRender::BF_SOURCE_ALPHA; // } regular alpha blend - mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } - mAlphaSFactor = LLRender::BF_ZERO; // } glow suppression - mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } - gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); + if (LLPipeline::sImpostorRender) + { + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); + } + else + { + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + } + } renderAlpha(getVertexDataMask()); @@ -321,22 +333,10 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask) BOOL light_enabled = TRUE; S32 diffuse_channel = 0; - //BOOL is_particle = FALSE; BOOL use_shaders = (LLPipeline::sUnderWaterRender && gPipeline.canUseVertexShaders()) || gPipeline.canUseWindLightShadersOnObjects(); - // check to see if it's a particle and if it's "close" - { - if (LLPipeline::sImpostorRender) - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); - } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); - } - } - + for (LLCullResult::sg_list_t::iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) { LLSpatialGroup* group = *i; -- cgit v1.2.3 From b89af09f598af21b67b14e5ff940461d9c89afb8 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 4 Mar 2011 14:25:46 -0600 Subject: SH-998 Fix for improper LoD when an object is first rezzed. --- indra/newview/lldrawable.cpp | 9 ++++++++- indra/newview/llviewermenu.cpp | 4 ++++ indra/newview/llvovolume.cpp | 11 ++++++++++- indra/newview/pipeline.cpp | 2 +- indra/newview/pipeline.h | 1 + indra/newview/skins/default/xui/en/menu_viewer.xml | 10 ++++++++++ 6 files changed, 34 insertions(+), 3 deletions(-) diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index fe743e7451..bdc12ec0e3 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -708,7 +708,14 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) LLVOVolume* volume = getVOVolume(); if (volume) { - pos.set(getPositionGroup().getF32ptr()); + if (getSpatialGroup()) + { + pos.set(getPositionGroup().getF32ptr()); + } + else + { + pos = getPositionAgent(); + } if (isState(LLDrawable::HAS_ALPHA)) { diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 37aa080228..99c7d4b8c9 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -937,6 +937,10 @@ U32 info_display_from_string(std::string info_display) { return LLPipeline::RENDER_DEBUG_FACE_AREA; } + else if ("lod info" == info_display) + { + return LLPipeline::RENDER_DEBUG_LOD_INFO; + } else if ("build queue" == info_display) { return LLPipeline::RENDER_DEBUG_BUILD_QUEUE; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 66263412ec..7601b68c5f 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1218,7 +1218,10 @@ BOOL LLVOVolume::calcLOD() distance = mDrawable->mDistanceWRTCamera; radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length(); } - + + //hold onto unmodified distance for debugging + F32 debug_distance = distance; + distance *= sDistanceFactor; F32 rampDist = LLVOVolume::sLODFactor * 2; @@ -1237,6 +1240,12 @@ BOOL LLVOVolume::calcLOD() cur_detail = computeLODDetail(llround(distance, 0.01f), llround(radius, 0.01f)); + + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO)) + { + setDebugText(llformat("%.2f:%.2f, %d", debug_distance, radius, cur_detail)); + } + if (cur_detail != mLOD) { mAppAngle = llround((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 9eaf515c65..ba597d62bf 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -2742,7 +2742,7 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) { - if (drawablep->isVisible()) + //if (drawablep->isVisible()) isVisible() check here is redundant, if it wasn't visible, it wouldn't be here { if (!drawablep->isActive()) { diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 32ac93388d..be58af947c 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -447,6 +447,7 @@ public: RENDER_DEBUG_UPDATE_TYPE = 0x0800000, RENDER_DEBUG_PHYSICS_SHAPES = 0x1000000, RENDER_DEBUG_NORMALS = 0x2000000, + RENDER_DEBUG_LOD_INFO = 0x4000000, }; public: diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 0a6be2899b..38e9165613 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2277,6 +2277,16 @@ function="Advanced.ToggleInfoDisplay" parameter="face area" /> + + + + -- cgit v1.2.3 From 8ca521070212bab3018fd22ac4eb30e09503fa3f Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 4 Mar 2011 14:35:22 -0600 Subject: Get rid of "start" "stop" spam from DoF focal point transition. --- indra/newview/pipeline.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index ba597d62bf..c1d1a69dfb 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -6219,17 +6219,12 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) if (transition_time >= 1.f && fabsf(current_distance-target_distance)/current_distance > 0.01f) { //large shift happened, interpolate smoothly to new target distance - llinfos << "start" << llendl; transition_time = 0.f; start_distance = current_distance; } else if (transition_time < 1.f) { //currently in a transition, continue interpolating transition_time += 1.f/gSavedSettings.getF32("CameraFocusTransitionTime")*gFrameIntervalSeconds; - if (transition_time >= 1.f) - { - llinfos << "stop" << llendl; - } transition_time = llmin(transition_time, 1.f); F32 t = cosf(transition_time*F_PI+F_PI)*0.5f+0.5f; -- cgit v1.2.3 From f6c7fdf6f274cfaafd7a3304c70b06d7b752aec9 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 4 Mar 2011 14:45:13 -0600 Subject: SH-971 Fix for local lights flag not getting set properly on xp and linux when adjusting graphics quality setting. --- indra/newview/featuretable_linux.txt | 7 ++++++- indra/newview/featuretable_xp.txt | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt index a1ebbda623..c7ad0df50b 100644 --- a/indra/newview/featuretable_linux.txt +++ b/indra/newview/featuretable_linux.txt @@ -1,4 +1,4 @@ -version 22 +version 23 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences // Should be combined into one table @@ -36,6 +36,7 @@ RenderFogRatio 1 4.0 RenderGamma 1 0 RenderGlowResolutionPow 1 9 RenderGround 1 1 +RenderLocalLights 1 1 RenderMaxPartCount 1 8192 RenderNightBrightness 1 1.0 RenderObjectBump 1 1 @@ -74,6 +75,7 @@ RenderAvatarVP 1 0 RenderFarClip 1 64 RenderFlexTimeFactor 1 0 RenderGlowResolutionPow 1 8 +RenderLocalLights 1 0 RenderMaxPartCount 1 0 RenderObjectBump 1 0 RenderReflectionDetail 1 0 @@ -102,6 +104,7 @@ RenderAvatarVP 1 1 RenderFarClip 1 96 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 8 +RenderLocalLights 1 1 RenderMaxPartCount 1 2048 RenderObjectBump 1 1 RenderReflectionDetail 1 0 @@ -129,6 +132,7 @@ RenderAvatarVP 1 1 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 +RenderLocalLights 1 1 RenderMaxPartCount 1 4096 RenderObjectBump 1 1 RenderReflectionDetail 1 0 @@ -156,6 +160,7 @@ RenderAvatarVP 1 1 RenderFarClip 1 256 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 +RenderLocalLights 1 1 RenderMaxPartCount 1 8192 RenderObjectBump 1 1 RenderReflectionDetail 1 4 diff --git a/indra/newview/featuretable_xp.txt b/indra/newview/featuretable_xp.txt index d87c3db111..84da74840f 100644 --- a/indra/newview/featuretable_xp.txt +++ b/indra/newview/featuretable_xp.txt @@ -36,6 +36,7 @@ RenderFogRatio 1 4.0 RenderGamma 1 0 RenderGlowResolutionPow 1 9 RenderGround 1 1 +RenderLocalLights 1 1 RenderMaxPartCount 1 8192 RenderNightBrightness 1 1.0 RenderObjectBump 1 1 @@ -75,6 +76,7 @@ RenderAvatarVP 1 0 RenderFarClip 1 64 RenderFlexTimeFactor 1 0 RenderGlowResolutionPow 1 8 +RenderLocalLights 1 0 RenderMaxPartCount 1 0 RenderObjectBump 1 0 RenderReflectionDetail 1 0 @@ -103,6 +105,7 @@ RenderAvatarVP 1 1 RenderFarClip 1 96 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 8 +RenderLocalLights 1 1 RenderMaxPartCount 1 2048 RenderObjectBump 1 1 RenderReflectionDetail 1 0 @@ -130,6 +133,7 @@ RenderAvatarVP 1 1 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 +RenderLocalLights 1 1 RenderMaxPartCount 1 4096 RenderObjectBump 1 1 RenderReflectionDetail 1 0 @@ -157,6 +161,7 @@ RenderAvatarVP 1 1 RenderFarClip 1 256 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 +RenderLocalLights 1 1 RenderMaxPartCount 1 8192 RenderObjectBump 1 1 RenderReflectionDetail 1 4 -- cgit v1.2.3 From 6a86c65e46f92f1a955d31e2d0b9d7ffcd171134 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 4 Mar 2011 15:04:46 -0600 Subject: SH-1066 Fix for bumpmaps not loading properly after enabling deferred rendering. --- indra/newview/pipeline.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index c1d1a69dfb..6af371072b 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -824,6 +824,7 @@ void LLPipeline::releaseGLBuffers() mGlow[i].release(); } + gBumpImageList.destroyGL(); LLVOAvatar::resetImpostors(); } @@ -946,6 +947,8 @@ void LLPipeline::createGLBuffers() addDeferredAttachments(mGIMap); } } + + gBumpImageList.restoreGL(); } void LLPipeline::restoreGL() -- cgit v1.2.3 From 04284652cfce57b0df3bc6b12f7568fa8da22ebb Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 4 Mar 2011 15:04:46 -0600 Subject: SH-1066 Fix for bumpmaps not loading properly after enabling deferred rendering. (transplanted from 30156869364d642a378411539bbca86068e29b77) --- indra/newview/pipeline.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index a533be675c..404e8cbdb9 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -836,6 +836,7 @@ void LLPipeline::releaseGLBuffers() mGlow[i].release(); } + gBumpImageList.destroyGL(); LLVOAvatar::resetImpostors(); } @@ -958,6 +959,8 @@ void LLPipeline::createGLBuffers() addDeferredAttachments(mGIMap); } } + + gBumpImageList.restoreGL(); } void LLPipeline::restoreGL() -- cgit v1.2.3 From 78cc3211275cad68cf4cd1a0a1d72dba9dae470d Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 4 Mar 2011 18:46:26 -0600 Subject: SH-1069 Fix for some bump maps not loading fully. --- indra/newview/lldrawpoolbump.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 0afa8b1794..38ff3083ce 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -1121,7 +1121,11 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI { bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries ); bump_image_map_t::iterator iter = entries_list.find(source_asset_id); - if (iter != entries_list.end()) // bump not cached yet + + if (iter != entries_list.end() || + iter->second.isNull() || + iter->second->getWidth() != src->getWidth() || + iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution { LLPointer dst_image = new LLImageRaw(src->getWidth(), src->getHeight(), 1); U8* dst_data = dst_image->getData(); -- cgit v1.2.3 From ec11823c77ac232d59f4b9ddcff354523b6e0f73 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 4 Mar 2011 18:46:26 -0600 Subject: SH-1069 Fix for some bump maps not loading fully. (transplanted from 1a03c3745cbbe47e5cc5dfec3a9114516865ddc0) --- indra/newview/lldrawpoolbump.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 0a642f494b..3f5cb4778e 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -1126,7 +1126,9 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI bump_image_map_t::iterator iter = entries_list.find(source_asset_id); if (iter == entries_list.end() || - iter->second.isNull()) + iter->second.isNull() || + iter->second->getWidth() != src->getWidth() || + iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution { //make sure an entry exists for this image LLPointer raw = new LLImageRaw(1,1,1); raw->clear(0x77, 0x77, 0xFF, 0xFF); -- cgit v1.2.3 From 85fb9f5c09e20ffe8ad5f4ed45fc560507ea8305 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 7 Mar 2011 17:10:10 -0600 Subject: Fix for crash when enabling Debug GL and rendering deferred impostors. --- indra/newview/lldrawpoolavatar.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 48e561b24b..2de4c93ffd 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -334,7 +334,14 @@ void LLDrawPoolAvatar::renderPostDeferred(S32 pass) 9, //rigged glow }; - render(actual_pass[pass]); + pass = actual_pass[pass]; + + if (LLPipeline::sImpostorRender) + { //HACK for impostors so actual pass ends up being proper pass + pass -= 2; + } + + render(pass); } -- cgit v1.2.3 From f0f126aa4f67264c42057ded8bd59c377a54356e Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 7 Mar 2011 17:11:22 -0600 Subject: SH-1064 Fix for crash in LLVertexBuffer::setupVertexBuffer --- indra/newview/llvovolume.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 7601b68c5f..1186d4d8d9 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4204,7 +4204,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { bump_mask |= LLVertexBuffer::MAP_BINORMAL; } - + genDrawInfo(group, simple_mask, simple_faces); genDrawInfo(group, bump_mask, bump_faces); genDrawInfo(group, fullbright_mask, fullbright_faces); @@ -4423,9 +4423,10 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: } else { //resize pre-existing buffer - if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage) + if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage || + buffer->getTypeMask() != mask) { - buffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask, + buffer = createVertexBuffer(mask, group->mBufferUsage); buffer->allocateBuffer(geom_count, index_count, TRUE); } -- cgit v1.2.3 From a9412b6d2e43175081a764493126ac716ee828d3 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 7 Mar 2011 17:28:04 -0600 Subject: SH-1085 Potential fix for crash when disabling mirror. --- indra/newview/llselectmgr.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 93c9131424..e57e38d141 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -5468,7 +5468,10 @@ void pushWireframe(LLDrawable* drawable) for (S32 i = 0; i < drawable->getNumFaces(); ++i) { LLFace* face = drawable->getFace(i); - pushVerts(face, LLVertexBuffer::MAP_VERTEX); + if (face->verify()) + { + pushVerts(face, LLVertexBuffer::MAP_VERTEX); + } } } } -- cgit v1.2.3 From 00c861f9678d21fc10a4cf481158732cf88c3805 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 8 Mar 2011 14:14:33 -0600 Subject: SH-1085 Fix for crash when disabling "mirror" and a face is selected. --- indra/newview/llface.cpp | 22 ++++++++++++++++++++-- indra/newview/llface.h | 4 ++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 10847e7067..290115417f 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -384,6 +384,24 @@ void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align) llassert(verify()); } +void LLFace::setGeomIndex(U16 idx) +{ + if (mGeomIndex != idx) + { + mGeomIndex = idx; + mVertexBuffer = NULL; + } +} + +void LLFace::setIndicesIndex(S32 idx) +{ + if (mIndicesIndex != idx) + { + mIndicesIndex = idx; + mVertexBuffer = NULL; + } +} + //============================================================================ U16 LLFace::getGeometryAvatar( @@ -1858,7 +1876,7 @@ BOOL LLFace::verify(const U32* indices_array) const } // First, check whether the face data fits within the pool's range. - if ((mGeomIndex + mGeomCount) > mVertexBuffer->getNumVerts()) + if ((mGeomIndex + mGeomCount) > mVertexBuffer->getRequestedVerts()) { ok = FALSE; llinfos << "Face references invalid vertices!" << llendl; @@ -1877,7 +1895,7 @@ BOOL LLFace::verify(const U32* indices_array) const llinfos << "Face has bogus indices count" << llendl; } - if (mIndicesIndex + mIndicesCount > mVertexBuffer->getNumIndices()) + if (mIndicesIndex + mIndicesCount > mVertexBuffer->getRequestedIndices()) { ok = FALSE; llinfos << "Face references invalid indices!" << llendl; diff --git a/indra/newview/llface.h b/indra/newview/llface.h index 1f69dd145e..b2170c4cf3 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -196,8 +196,8 @@ public: BOOL verify(const U32* indices_array = NULL) const; void printDebugInfo() const; - void setGeomIndex(U16 idx) { mGeomIndex = idx; } - void setIndicesIndex(S32 idx) { mIndicesIndex = idx; } + void setGeomIndex(U16 idx); + void setIndicesIndex(S32 idx); void setDrawInfo(LLDrawInfo* draw_info); F32 getTextureVirtualSize() ; -- cgit v1.2.3 From 94b0ce6d842a1f34bd46535a8b4db68aa397a541 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 8 Mar 2011 14:15:24 -0600 Subject: Make DoF focal point match behavior described in test plan at http://wiki.secondlife.com/wiki/Depth_of_Field_test --- indra/newview/llhudnametag.cpp | 25 ++++++++++++++++++++++--- indra/newview/pipeline.cpp | 10 ++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp index 8caf4d3d4c..82e1f2dfb5 100644 --- a/indra/newview/llhudnametag.cpp +++ b/indra/newview/llhudnametag.cpp @@ -146,24 +146,43 @@ BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector3& start, const LLVector3& mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f)); + LLVector3 position = mPositionAgent; + + if (mSourceObject) + { //get intersection of eye through mPositionAgent to plane of source object + //using this position keeps the camera from focusing on some seemingly random + //point several meters in front of the nametag + const LLVector3& p = mSourceObject->getPositionAgent(); + const LLVector3& n = LLViewerCamera::getInstance()->getAtAxis(); + const LLVector3& eye = LLViewerCamera::getInstance()->getOrigin(); + + LLVector3 ray = position-eye; + ray.normalize(); + + LLVector3 delta = p-position; + F32 dist = delta*n; + F32 dt = dist/(ray*n); + position += ray*dt; + } + // scale screen size of borders down //RN: for now, text on hud objects is never occluded LLVector3 x_pixel_vec; LLVector3 y_pixel_vec; - LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec); + LLViewerCamera::getInstance()->getPixelVectors(position, y_pixel_vec, x_pixel_vec); LLVector3 width_vec = mWidth * x_pixel_vec; LLVector3 height_vec = mHeight * y_pixel_vec; LLCoordGL screen_pos; - LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE); + LLViewerCamera::getInstance()->projectPosAgentToScreen(position, screen_pos, FALSE); LLVector2 screen_offset; screen_offset = updateScreenPos(mPositionOffset); - LLVector3 render_position = mPositionAgent + LLVector3 render_position = position + (x_pixel_vec * screen_offset.mV[VX]) + (y_pixel_vec * screen_offset.mV[VY]); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 6af371072b..c8ef75030d 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -6202,6 +6202,12 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) { focus_point = gDebugRaycastIntersection; } + else if (gAgentCamera.cameraMouselook()) + { + gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, + NULL, + &focus_point); + } else { LLViewerObject* obj = gAgentCamera.getFocusObject(); @@ -6209,6 +6215,10 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) { focus_point = LLVector3(gAgentCamera.getFocusGlobal()-gAgent.getRegion()->getOriginGlobal()); } + else + { + focus_point = gDebugRaycastIntersection; + } } } -- cgit v1.2.3 From d1a2ce75e27f34141eeb8a45ae914c453c419f1b Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 9 Mar 2011 14:18:39 -0600 Subject: SH-587 Make cancel button on physics tabs more responsive. --- indra/newview/llfloatermodelpreview.cpp | 40 +++++++++++++++------- .../skins/default/xui/en/floater_model_preview.xml | 3 ++ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index e33ce055f6..c2054bf00f 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -773,11 +773,13 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) if (stage == "Decompose") { + sInstance->setStatusMessage(sInstance->getString("decomposing")); sInstance->childSetVisible("Decompose", false); sInstance->childSetVisible("decompose_cancel", true); } else if (stage == "Simplify") { + sInstance->setStatusMessage(sInstance->getString("simplifying")); sInstance->childSetVisible("Simplify", false); sInstance->childSetVisible("simplify_cancel", true); } @@ -823,6 +825,8 @@ void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) DecompRequest* req = *iter; req->mContinue = 0; } + + sInstance->mCurRequest.clear(); } } @@ -4301,10 +4305,13 @@ void LLFloaterModelPreview::setStatusMessage(const std::string& msg) S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) { - setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); - if (LLFloaterModelPreview::sInstance) + if (mContinue) { - LLFloaterModelPreview::sInstance->setStatusMessage(mStatusMessage); + setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); + if (LLFloaterModelPreview::sInstance) + { + LLFloaterModelPreview::sInstance->setStatusMessage(mStatusMessage); + } } return mContinue; @@ -4312,20 +4319,27 @@ S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 void LLFloaterModelPreview::DecompRequest::completed() { //called from the main thread - mModel->setConvexHullDecomposition(mHull); - - if (sInstance) + if (mContinue) { - if (mContinue) + mModel->setConvexHullDecomposition(mHull); + + if (sInstance) { - if (sInstance->mModelPreview) + if (mContinue) { - sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; - sInstance->mModelPreview->mDirty = true; - LLFloaterModelPreview::sInstance->mModelPreview->refresh(); + if (sInstance->mModelPreview) + { + sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; + sInstance->mModelPreview->mDirty = true; + LLFloaterModelPreview::sInstance->mModelPreview->refresh(); + } } - } - sInstance->mCurRequest.erase(this); + sInstance->mCurRequest.erase(this); + } + } + else if (sInstance) + { + llassert(sInstance->mCurRequest.find(this) == sInstance->mCurRequest.end()); } } diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 8a18861e1a..1ebb3b3fb1 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -18,6 +18,9 @@ Level of detail has too many vertices. Missing required level of detail. All + Analyzing... + Simplifying... + Name: -- cgit v1.2.3 From 85f099a868224bead0718e964214b29dfd769ffa Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 9 Mar 2011 17:08:52 -0600 Subject: SH-1063 Fix for some rigged attachments preventing avatars from impostoring (don't let rigged attachments stretch avatar bounding box beyond avatar skeleton). --- indra/newview/llvoavatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index aa7349f129..a73bac39cf 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1428,7 +1428,7 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) if (attached_object && !attached_object->isHUDAttachment()) { LLDrawable* drawable = attached_object->mDrawable; - if (drawable) + if (drawable && !drawable->isState(LLDrawable::RIGGED)) { LLSpatialBridge* bridge = drawable->getSpatialBridge(); if (bridge) -- cgit v1.2.3 From 713366477d4f840ddf90b3095ea09b29b401c0e4 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 9 Mar 2011 17:09:35 -0600 Subject: Fix for texture state corruption when rendering impostors in a reflection map or underwater and deferred rendering is enabled. --- indra/newview/lldrawpoolavatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 2de4c93ffd..645c7ebcae 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -1137,7 +1137,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (impostor) { - if (LLPipeline::sRenderDeferred && avatarp->mImpostor.isComplete()) + if (LLPipeline::sRenderDeferred && !LLPipeline::sReflectionRender && avatarp->mImpostor.isComplete()) { if (normal_channel > -1) { -- cgit v1.2.3 From a0ddc7e80fec9e6d574e8937bae0a55799b2dc86 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 9 Mar 2011 17:10:02 -0600 Subject: Make a debug output report proper pool names. --- indra/newview/pipeline.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index c8ef75030d..eaa6ba231d 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -192,19 +192,20 @@ std::string gPoolNames[] = // Correspond to LLDrawpool enum render type "NONE", "POOL_SIMPLE", - "POOL_TERRAIN", + "POOL_GROUND", + "POOL_FULLBRIGHT", "POOL_BUMP", - "POOL_TREE", + "POOL_TERRAIN," "POOL_SKY", "POOL_WL_SKY", - "POOL_GROUND", + "POOL_TREE", + "POOL_GRASS", "POOL_INVISIBLE", "POOL_AVATAR", + "POOL_VOIDWATER", "POOL_WATER", - "POOL_GRASS", - "POOL_FULLBRIGHT", "POOL_GLOW", - "POOL_ALPHA", + "POOL_ALPHA" }; void drawBox(const LLVector3& c, const LLVector3& r); @@ -3972,6 +3973,8 @@ void LLPipeline::renderDebug() glLoadMatrixd(gGLModelView); gGL.setColorMask(true, false); + bool hud_only = hasRenderType(LLPipeline::RENDER_TYPE_HUD); + // Debug stuff. for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) @@ -3982,7 +3985,8 @@ void LLPipeline::renderDebug() LLSpatialPartition* part = region->getSpatialPartition(i); if (part) { - if (hasRenderType(part->mDrawableType)) + if ( hud_only && (part->mDrawableType == RENDER_TYPE_HUD || part->mDrawableType == RENDER_TYPE_HUD_PARTICLES) || + !hud_only && hasRenderType(part->mDrawableType) ) { part->renderDebug(); } -- cgit v1.2.3 From c2bdb9be1455b7e6414b9a7d034b3118f6a07f23 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 9 Mar 2011 18:19:12 -0600 Subject: SH-706 Make triangle limit and error threshold spinners respond to arrow clicks. --- indra/newview/llfloatermodelpreview.cpp | 10 +++++++++- indra/newview/llfloatermodelpreview.h | 2 ++ indra/newview/skins/default/xui/en/floater_model_preview.xml | 4 ++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index c2054bf00f..fabf92c3c6 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2235,6 +2235,11 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mBuildBorderMode = GLOD_BORDER_UNLOCK; mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE; + for (U32 i = 0; i < LLModel::NUM_LODS; ++i) + { + mRequestedTriangleCount[i] = 0; + } + mViewOption["show_textures"] = false; mFMP = fmp; @@ -2985,6 +2990,8 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim U32 actual_verts = 0; U32 submeshes = 0; + mRequestedTriangleCount[lod] = triangle_count; + glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); stop_gloderror(); @@ -3466,7 +3473,7 @@ void LLModelPreview::updateStatusMessages() LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); limit->setMaxValue(mMaxTriangleLimit); - limit->setValue(total_tris[mPreviewLOD]); + limit->setValue(mRequestedTriangleCount[mPreviewLOD]); if (lod_mode == 0) { @@ -3474,6 +3481,7 @@ void LLModelPreview::updateStatusMessages() threshold->setVisible(false); limit->setMaxValue(mMaxTriangleLimit); + limit->setIncrement(mMaxTriangleLimit/32); } else { diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 8a01f7db2c..ffda565fef 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -331,6 +331,8 @@ public: U32 mBuildQueueMode; U32 mBuildOperator; U32 mBuildBorderMode; + S32 mRequestedTriangleCount[LLModel::NUM_LODS]; + LLModelLoader* mModelLoader; diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 1ebb3b3fb1..ca4e4a3a2a 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -165,8 +165,8 @@ Error Threshold - - + + Build Operator: -- cgit v1.2.3 From a135831c848717cf3809a4ae47d36e57e2076c5b Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 9 Mar 2011 23:15:31 -0600 Subject: SH-632 Fix for inconsistent decimation results and off by one errors causing decimations where none are needed. --- indra/newview/llfloatermodelpreview.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index fabf92c3c6..f65fab41e7 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2787,9 +2787,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim lod_mode = GLOD_TRIANGLE_BUDGET; if (which_lod != -1) { - //SH-632 take budget as supplied limit+1 to prevent GLOD from creating a smaller - //decimation when the given decimation is possible - limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); //+1; + limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); } } else @@ -2948,13 +2946,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim { start = end = which_lod; } - else - { - //SH-632 -- incremenet triangle count to avoid removing any triangles from - //highest LoD when auto-generating LoD - triangle_count++; - } - mMaxTriangleLimit = base_triangle_count; @@ -2998,15 +2989,25 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); stop_gloderror(); - glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count); + glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); stop_gloderror(); - glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); + glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, 0); stop_gloderror(); glodAdaptGroup(mGroup); stop_gloderror(); + if (lod_mode == GLOD_TRIANGLE_BUDGET) + { //SH-632 Always adapt to 0 before adapting to actual desired amount, and always + //add 1 to desired amount to avoid decimating below desired amount + glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count+1); + stop_gloderror(); + + glodAdaptGroup(mGroup); + stop_gloderror(); + } + for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) { LLModel* base = mBaseModel[mdl_idx]; -- cgit v1.2.3 From 9044526994bb51b631a9a0cb7d6d6911a15957c6 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 10 Mar 2011 00:10:25 -0600 Subject: SH-755 Set physics shape type to convex hull on delink if physics shape type was none. --- indra/newview/llselectmgr.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 21a457c125..b139ba361e 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -3902,6 +3902,26 @@ void LLSelectMgr::sendDelink() return; } + struct f : public LLSelectedObjectFunctor + { //on delink, any modifyable object should + f() {} + + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + if (object->getPhysicsShapeType() == LLViewerObject::PHYSICS_SHAPE_NONE) + { + object->setPhysicsShapeType(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); + object->updateFlags(); + } + } + return true; + } + } sendfunc; + getSelection()->applyToObjects(&sendfunc); + + // Delink needs to send individuals so you can unlink a single object from // a linked set. sendListToRegions( -- cgit v1.2.3 From 5fd953df8fafb769d31688c47cf3f8634f858de5 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 10 Mar 2011 00:41:46 -0600 Subject: SH-874 Properly detect available video memory on ATI cards and disable vertex buffer objects when available vram is under 256MB. --- indra/llrender/llgl.cpp | 10 ++++++++++ indra/llrender/llgl.h | 1 + indra/newview/featuretable.txt | 6 +++++- indra/newview/featuretable_xp.txt | 6 +++++- indra/newview/llappviewerwin32.cpp | 6 +++++- indra/newview/llfeaturemanager.cpp | 4 ++++ indra/newview/llviewerwindow.cpp | 17 +++++++++++++++++ 7 files changed, 47 insertions(+), 3 deletions(-) diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 9354373dba..d1eb4c8be0 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -313,6 +313,7 @@ LLGLManager::LLGLManager() : mIsDisabled(FALSE), mHasMultitexture(FALSE), + mHasATIMemInfo(FALSE), mNumTextureUnits(1), mHasMipMapGeneration(FALSE), mHasCompressedTextures(FALSE), @@ -497,6 +498,14 @@ bool LLGLManager::initGL() // This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture. initExtensions(); + if (mHasATIMemInfo) + { //ask the gl how much vram is free at startup and attempt to use no more than half of that + S32 meminfo[4]; + glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); + + mVRAM = meminfo[0]/1024; + } + if (mHasMultitexture) { GLint num_tex_units; @@ -659,6 +668,7 @@ void LLGLManager::initExtensions() mHasTextureRectangle = FALSE; #else // LL_MESA_HEADLESS mHasMultitexture = glh_init_extensions("GL_ARB_multitexture"); + mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap"); mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color"); mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic"); diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index df110613e3..f4be067f2e 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -76,6 +76,7 @@ public: // Extensions used by everyone BOOL mHasMultitexture; + BOOL mHasATIMemInfo; S32 mNumTextureUnits; BOOL mHasMipMapGeneration; BOOL mHasCompressedTextures; diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index afc268d7a5..6022153020 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -1,4 +1,4 @@ -version 26 +version 27 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences // Should be combined into one table @@ -465,6 +465,10 @@ list ATI RenderUseStreamVBO 1 0 RenderAvatarVP 1 0 +// Disable vertex buffer objects by default for ATI cards with little video memory +list ATIVramLT256 +RenderVBOEnable 1 0 + /// Tweaked NVIDIA list NVIDIA_GeForce_FX_5100 diff --git a/indra/newview/featuretable_xp.txt b/indra/newview/featuretable_xp.txt index d87c3db111..6976bcf102 100644 --- a/indra/newview/featuretable_xp.txt +++ b/indra/newview/featuretable_xp.txt @@ -1,4 +1,4 @@ -version 26 +version 27 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences // Should be combined into one table @@ -458,6 +458,10 @@ list ATI RenderUseStreamVBO 1 0 RenderAvatarVP 1 0 +// Disable vertex buffer objects by default for ATI cards with little video memory +list ATIVramLT256 +RenderVBOEnable 1 0 + /// Tweaked NVIDIA list NVIDIA_GeForce_FX_5100 diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index d328567a0e..54689ea808 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -440,7 +440,11 @@ bool LLAppViewerWin32::initHardwareTest() LL_WARNS("AppInit") << " Someone took over my exception handler (post hardware probe)!" << LL_ENDL; } - gGLManager.mVRAM = gDXHardware.getVRAM(); + if (gGLManager.mVRAM == 0) + { + gGLManager.mVRAM = gDXHardware.getVRAM(); + } + LL_INFOS("AppInit") << "Detected VRAM: " << gGLManager.mVRAM << LL_ENDL; return true; diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index edfc4538a1..9f0b34becc 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -729,6 +729,10 @@ void LLFeatureManager::applyBaseMasks() { maskFeatures("ATI"); } + if (gGLManager.mHasATIMemInfo && gGLManager.mVRAM < 256) + { + maskFeatures("ATIVramLT256"); + } if (gGLManager.mATIOldDriver) { maskFeatures("ATIOldDriver"); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index d5008c12b0..1c573eab00 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -457,6 +457,23 @@ public: addText(xpos, ypos, "Shaders Disabled"); ypos += y_inc; } + + if (gGLManager.mHasATIMemInfo) + { + S32 meminfo[4]; + glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); + + addText(xpos, ypos, llformat("%.2f MB Texture Memory Free", meminfo[0]/1024.f)); + ypos += y_inc; + + if (gGLManager.mHasVertexBufferObject) + { + glGetIntegerv(GL_VBO_FREE_MEMORY_ATI, meminfo); + addText(xpos, ypos, llformat("%.2f MB VBO Memory Free", meminfo[0]/1024.f)); + ypos += y_inc; + } + } + addText(xpos, ypos, llformat("%d MB Vertex Data", LLVertexBuffer::sAllocatedBytes/(1024*1024))); ypos += y_inc; -- cgit v1.2.3 From 79664c1017175b2cdfdc4b16c5894bdfdf6e8188 Mon Sep 17 00:00:00 2001 From: prep Date: Thu, 10 Mar 2011 12:09:29 -0500 Subject: Fix for sh-1119: Alt Zooming on assets that contain a pivot point can at times cause erratic camera movement --- indra/newview/llagentcamera.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 2825c32d79..f5fd33d5e0 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -393,10 +393,12 @@ LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 origi { return original_focus_point - obj_pos; } - LLQuaternion inv_obj_rot = ~obj_rot; // get inverse of rotation - LLVector3 object_extents = object->getScale(); + LLVector3 object_extents; + const LLVector4a* oe4 = object->mDrawable->getSpatialExtents(); + object_extents.set( oe4[1][0], oe4[1][1], oe4[1][2] ); + // make sure they object extents are non-zero object_extents.clamp(0.001f, F32_MAX); -- cgit v1.2.3 From 666f06eacecdcde2b5562b20b5231fdf1172b7b2 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 10 Mar 2011 11:46:16 -0600 Subject: SH-874 Followup -- use GL_NVX_gpu_memory_info for NVIDIA chips to detect actual installed and available VRAM. --- indra/llrender/llgl.cpp | 8 ++++++++ indra/llrender/llgl.h | 1 + indra/llrender/llglheaders.h | 10 ++++++++++ indra/newview/llviewerwindow.cpp | 7 +++++++ 4 files changed, 26 insertions(+) diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index d1eb4c8be0..d5f0b81830 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -314,6 +314,7 @@ LLGLManager::LLGLManager() : mHasMultitexture(FALSE), mHasATIMemInfo(FALSE), + mHasNVXMemInfo(FALSE), mNumTextureUnits(1), mHasMipMapGeneration(FALSE), mHasCompressedTextures(FALSE), @@ -505,6 +506,12 @@ bool LLGLManager::initGL() mVRAM = meminfo[0]/1024; } + else if (mHasNVXMemInfo) + { + S32 dedicated_memory; + glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &dedicated_memory); + mVRAM = dedicated_memory/1024; + } if (mHasMultitexture) { @@ -669,6 +676,7 @@ void LLGLManager::initExtensions() #else // LL_MESA_HEADLESS mHasMultitexture = glh_init_extensions("GL_ARB_multitexture"); mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); + mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap"); mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color"); mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic"); diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index f4be067f2e..0d7ba15b12 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -77,6 +77,7 @@ public: // Extensions used by everyone BOOL mHasMultitexture; BOOL mHasATIMemInfo; + BOOL mHasNVXMemInfo; S32 mNumTextureUnits; BOOL mHasMipMapGeneration; BOOL mHasCompressedTextures; diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index 46bc282436..6e5f7110af 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -837,4 +837,14 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *); #define GL_DEPTH_CLAMP 0x864F #endif +//GL_NVX_gpu_memory_info constants +#ifndef GL_NVX_gpu_memory_info +#define GL_NVX_gpu_memory_info +#define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047 +#define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048 +#define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049 +#define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A +#define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B +#endif + #endif // LL_LLGLHEADERS_H diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 093e94add0..f665f39e9c 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -481,6 +481,13 @@ public: ypos += y_inc; } } + else if (gGLManager.mHasNVXMemInfo) + { + S32 free_memory; + glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory); + addText(xpos, ypos, llformat("%.2f MB Video Memory Free", free_memory/1024.f)); + ypos += y_inc; + } addText(xpos, ypos, llformat("%d MB Vertex Data", LLVertexBuffer::sAllocatedBytes/(1024*1024))); ypos += y_inc; -- cgit v1.2.3 From e3e12bc3df13af25f921d47852edff3254364282 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 10 Mar 2011 11:55:46 -0600 Subject: SH-874 Followup -- fix for mac build --- indra/llrender/llglheaders.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index 6e5f7110af..c48e2bb5fa 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -847,4 +847,12 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *); #define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B #endif +//GL_ATI_meminfo constants +#ifndef GL_ATI_meminfo +#define GL_ATI_meminfo +#define GL_VBO_FREE_MEMORY_ATI 0x87FB +#define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC +#define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD +#endif + #endif // LL_LLGLHEADERS_H -- cgit v1.2.3 From bcc54d496490c501bb212466ff1bc5a143b12a4f Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 11 Mar 2011 16:39:03 -0600 Subject: SH-477 Put estimated streaming cost back in the debug display -- use newfangled equation. --- indra/newview/app_settings/settings.xml | 2 +- indra/newview/llmeshrepository.cpp | 39 +++++++++++++++++++++++--------- indra/newview/llviewerwindow.cpp | 40 +++++++++++++++++++++++++++++---- indra/newview/llvovolume.cpp | 2 +- indra/newview/llvovolume.h | 2 +- 5 files changed, 68 insertions(+), 17 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 01610f73ed..d0c62817e5 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8930,7 +8930,7 @@ Type F32 Value - 0.125 + 2.0 MeshThreadCount diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index b6e3626cba..e259ee9846 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3100,9 +3100,7 @@ F32 LLMeshRepository::getStreamingCost(const LLSD& header, F32 radius) F32 dlowest = llmin(radius/0.06f, 256.f); F32 dlow = llmin(radius/0.24f, 256.f); F32 dmid = llmin(radius/1.0f, 256.f); - F32 dhigh = 0.f; - - + F32 bytes_lowest = header["lowest_lod"]["size"].asReal()/1024.f; F32 bytes_low = header["low_lod"]["size"].asReal()/1024.f; F32 bytes_mid = header["medium_lod"]["size"].asReal()/1024.f; @@ -3128,14 +3126,35 @@ F32 LLMeshRepository::getStreamingCost(const LLSD& header, F32 radius) bytes_lowest = bytes_low; } - F32 cost = 0.f; - cost += llmax(256.f-dlowest, 1.f)/32.f*bytes_lowest; - cost += llmax(dlowest-dlow, 1.f)/32.f*bytes_low; - cost += llmax(dlow-dmid, 1.f)/32.f*bytes_mid; - cost += llmax(dmid-dhigh, 1.f)/32.f*bytes_high; + F32 max_area = 65536.f; + F32 min_area = 1.f; + + F32 high_area = llmin(F_PI*dmid*dmid, max_area); + F32 mid_area = llmin(F_PI*dlow*dlow, max_area); + F32 low_area = llmin(F_PI*dlowest*dlowest, max_area); + F32 lowest_area = max_area; + + lowest_area -= low_area; + low_area -= mid_area; + mid_area -= high_area; + + high_area = llclamp(high_area, min_area, max_area); + mid_area = llclamp(mid_area, min_area, max_area); + low_area = llclamp(low_area, min_area, max_area); + lowest_area = llclamp(lowest_area, min_area, max_area); + + F32 total_area = high_area + mid_area + low_area + lowest_area; + high_area /= total_area; + mid_area /= total_area; + low_area /= total_area; + lowest_area /= total_area; + + F32 weighted_avg = bytes_high*high_area + + bytes_mid*mid_area + + bytes_low*low_area + + bytes_lowest*lowest_area; - cost *= gSavedSettings.getF32("MeshStreamingCostScaler"); - return cost; + return weighted_avg * gSavedSettings.getF32("MeshStreamingCostScaler"); } diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index f665f39e9c..5d91a0045a 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -489,6 +489,42 @@ public: ypos += y_inc; } + //show streaming cost/triangle count of known prims in current region OR selection + { + F32 cost = 0.f; + S32 count = 0; + const char* label = "Region"; + if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 0) + { //region + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + for (U32 i = 0; i < gObjectList.getNumObjects(); ++i) + { + LLViewerObject* object = gObjectList.getObject(i); + if (object && + object->getRegion() == region && + object->getVolume()) + { + cost += object->getStreamingCost(); + count += object->getTriangleCount(); + } + } + } + } + else + { + label = "Selection"; + cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectStreamingCost(); + count = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectTriangleCount(); + } + + addText(xpos,ypos, llformat("%s streaming cost: %.1f (%.1f KTris)", + label, cost, count/1000.f)); + ypos += y_inc; + + } + addText(xpos, ypos, llformat("%d MB Vertex Data", LLVertexBuffer::sAllocatedBytes/(1024*1024))); ypos += y_inc; @@ -572,10 +608,6 @@ public: ypos += y_inc; } - addText(xpos, ypos, llformat("Selection Triangle Count: %.3f Ktris ", LLSelectMgr::getInstance()->getSelection()->getSelectedObjectTriangleCount()/1000.f)); - - ypos += y_inc; - LLVertexBuffer::sBindCount = LLImageGL::sBindCount = LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount = gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 1186d4d8d9..7f373736fa 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3096,7 +3096,7 @@ F32 LLVOVolume::getStreamingCost() return 0.f; } -U32 LLVOVolume::getTriangleCount() const +U32 LLVOVolume::getTriangleCount() { U32 count = 0; LLVolume* volume = getVolume(); diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 0c12f14832..b09243055c 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -131,7 +131,7 @@ public: /*virtual*/ const LLMatrix4 getRenderMatrix() const; U32 getRenderCost(std::set &textures) const; /*virtual*/ F32 getStreamingCost(); - /*virtual*/ U32 getTriangleCount() const; + /*virtual*/ U32 getTriangleCount(); /*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, -- cgit v1.2.3 From 788f1c4f4dd05387a707c1e1348be39f469d4374 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Mon, 14 Mar 2011 13:19:58 -0400 Subject: SH-1146 FIXED Menu typo Trivial fix to menu entry for rendering types entry. --- indra/newview/llviewermenu.cpp | 2 +- indra/newview/skins/default/xui/en/menu_viewer.xml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 3323828d4f..89d533da28 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -697,7 +697,7 @@ U32 render_type_from_string(std::string render_type) { return LLPipeline::RENDER_TYPE_AVATAR; } - else if ("surfacePath" == render_type) + else if ("surfacePatch" == render_type) { return LLPipeline::RENDER_TYPE_TERRAIN; } diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 38e9165613..8655a6bf97 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -1355,15 +1355,15 @@ parameter="character" /> + parameter="surfacePatch" /> + parameter="surfacePatch" /> Date: Mon, 14 Mar 2011 15:50:33 -0400 Subject: SH-1087 Edit tools do not fit on default sized viewer window Work in progress. Cleaned up some of the XUI layout so that it's properly laid out (e.g. maintains position if the window is resized, even though we don't allow resize) This checkin should not have any visible UI change effects. --- .../newview/skins/default/xui/en/floater_tools.xml | 28 ++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 73190a05ca..ef4cf15938 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -295,22 +295,24 @@ width="100"> þ: [COUNT] - Stretch Both Sides @@ -323,6 +325,7 @@ left="143" name="checkbox stretch textures" top_pad="-6" + follows="left|top" width="134" /> @@ -791,10 +795,10 @@ type="string" length="1" height="10" - follows="left" + follows="left|top" halign="right" layout="topleft" - top_delta="0" + top_delta="0" right="-8" name="linked_set_cost" tool_tip="Cost of currently selected linked sets as [prims],[physics complexity]" @@ -818,7 +822,7 @@ text_color="LtGray_50" type="string" length="1" - follows="left" + follows="left|top" halign="right" layout="topleft" top_delta="0" @@ -1590,7 +1594,7 @@ even though the user gets a free copy. max_val="28" name="Physics Gravity" top_pad="10" - width="128" /> + width="132" /> + width="132" /> + width="132" /> + width="132" /> -- cgit v1.2.3 From bc54afb907e65ab2d73e1f040551c6191a4a7682 Mon Sep 17 00:00:00 2001 From: prep Date: Mon, 14 Mar 2011 16:17:34 -0400 Subject: WIP: manual pelvis offset for rigs that contain bone offsets --- indra/newview/llfloatermodelpreview.cpp | 18 +++++++++++++++++- indra/newview/llfloatermodelpreview.h | 1 + .../skins/default/xui/en/floater_model_preview.xml | 7 +++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index f65fab41e7..d4ba039eeb 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -310,6 +310,7 @@ BOOL LLFloaterModelPreview::postBuild() childSetCommitCallback("upload_joints", onUploadJointsCommit, this); childSetCommitCallback("import_scale", onImportScaleCommit, this); + childSetCommitCallback("pelvis_offset", onPelvisOffsetCommit, this); childSetCommitCallback("lod_file_or_limit", refresh, this); childSetCommitCallback("physics_load_radio", refresh, this); @@ -318,6 +319,9 @@ BOOL LLFloaterModelPreview::postBuild() childDisable("upload_skin"); childDisable("upload_joints"); + + childDisable("pelvis_offset"); + childDisable("ok_btn"); mViewOptionMenuButton = getChild("options_gear_btn"); @@ -456,6 +460,18 @@ void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata) fp->mModelPreview->calcResourceCost(); fp->mModelPreview->refresh(); } +//static +void LLFloaterModelPreview::onPelvisOffsetCommit( LLUICtrl*, void* userdata ) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview*)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->refresh(); +} //static void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) @@ -3742,7 +3758,7 @@ BOOL LLModelPreview::render() if (fmp) { fmp->enableViewOption("show_skin_weight"); - fmp->setViewOptionEnabled("show_joint_positions", skin_weight); + fmp->setViewOptionEnabled("show_joint_positions", skin_weight); } mFMP->childEnable("upload_skin"); } diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index ffda565fef..aac20244cc 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -183,6 +183,7 @@ protected: friend class LLPhysicsDecomp; static void onImportScaleCommit(LLUICtrl*, void*); + static void onPelvisOffsetCommit(LLUICtrl*, void*); static void onUploadJointsCommit(LLUICtrl*,void*); static void onUploadSkinCommit(LLUICtrl*,void*); diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index ca4e4a3a2a..e79dfcbc7d 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -388,6 +388,13 @@ + + + Pelvis Offset: + + + + -- cgit v1.2.3 From 16ff50719055aae202011e4b20aeae41d98493fa Mon Sep 17 00:00:00 2001 From: prep Date: Mon, 14 Mar 2011 18:02:25 -0400 Subject: WIP:Added pelvis offset to skinning info --- indra/llprimitive/llmodel.cpp | 4 ++++ indra/llprimitive/llmodel.h | 1 + indra/newview/llmeshrepository.cpp | 7 ++++++- indra/newview/llmeshrepository.h | 1 + 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index a9101378a4..eed82f924b 100755 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -57,6 +57,7 @@ const int MODEL_NAMES_LENGTH = sizeof(model_names) / sizeof(std::string); LLModel::LLModel(LLVolumeParams& params, F32 detail) : LLVolume(params, detail), mNormalizedScale(1,1,1), mNormalizedTranslation(0,0,0) + , mPelvisOffset( 0.0f ) { mDecompID = -1; } @@ -1497,6 +1498,7 @@ LLSD LLModel::writeModel( } } + if ( upload_joints && high->mAlternateBindMatrix.size() > 0 ) { for (U32 i = 0; i < high->mJointList.size(); ++i) @@ -1509,6 +1511,8 @@ LLSD LLModel::writeModel( } } } + + mdl["skin"]["pelvis_offset"] = high->mPelvisOffset; } } diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index c10ca1c11b..e9e33bdee5 100755 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -194,6 +194,7 @@ public: LLVector3 mNormalizedScale; LLVector3 mNormalizedTranslation; + float mPelvisOffset; // convex hull decomposition S32 mDecompID; convex_hull_decomposition mConvexHullDecomp; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index e259ee9846..8e869b2d5b 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1162,7 +1162,12 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat info.mAlternateBindMatrix.push_back(mat); } } - + + if (skin.has("pelvis_offset")) + { + info.mPelvisOffset = skin["pelvis_offset"].asReal(); + } + mSkinInfoQ.push(info); } diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 0fcb2213de..ccdcc03310 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -131,6 +131,7 @@ public: std::vector mAlternateBindMatrix; LLMatrix4 mBindShapeMatrix; + float mPelvisOffset; }; class LLMeshDecomposition -- cgit v1.2.3 From 01600af612df4421a7f095a67db2f135da9fe161 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Tue, 15 Mar 2011 11:40:12 -0400 Subject: Mesh-development work in progress --- .../newview/skins/default/xui/en/floater_tools.xml | 35 ++++++++++++++++++++-- .../skins/default/xui/en/panel_place_profile.xml | 2 +- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index ef4cf15938..7a328ee4da 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -2,7 +2,7 @@ None Prim Convex Hull + + + width="132" /> + + Date: Tue, 15 Mar 2011 13:04:21 -0400 Subject: Revert for accidental checkin for 88ce578d4bf9. --- .../newview/skins/default/xui/en/floater_tools.xml | 33 ++-------------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 7a328ee4da..a0a370dc12 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -2,7 +2,7 @@ None Prim Convex Hull - - - - Date: Wed, 16 Mar 2011 10:15:06 -0400 Subject: WIP:Manual pelvis offset --- indra/newview/llfloatermodelpreview.cpp | 9 ++++++--- indra/newview/llfloatermodelpreview.h | 2 ++ indra/newview/llmeshrepository.cpp | 2 +- indra/newview/llvoavatar.cpp | 12 ++++++++---- indra/newview/llvoavatar.h | 3 ++- indra/newview/llvovolume.cpp | 3 ++- 6 files changed, 21 insertions(+), 10 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index d4ba039eeb..3a7732c7b3 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -469,7 +469,7 @@ void LLFloaterModelPreview::onPelvisOffsetCommit( LLUICtrl*, void* userdata ) { return; } - + fp->mModelPreview->calcResourceCost(); fp->mModelPreview->refresh(); } @@ -2232,6 +2232,7 @@ LLColor4 LLModelLoader::getDaeColor(daeElement* element) LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) +, mPelvisZOffset( 0.0f ) { mNeedsUpdate = TRUE; mCameraDistance = 0.f; @@ -2298,13 +2299,14 @@ U32 LLModelPreview::calcResourceCost() U32 num_hulls = 0; F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f; - + mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 32.0f; + F32 streaming_cost = 0.f; F32 physics_cost = 0.f; for (U32 i = 0; i < mUploadData.size(); ++i) { LLModelInstance& instance = mUploadData[i]; - + if (accounted.find(instance.mModel) == accounted.end()) { accounted.insert(instance.mModel); @@ -3746,6 +3748,7 @@ BOOL LLModelPreview::render() { LLModelInstance& instance = *model_iter; LLModel* model = instance.mModel; + model->mPelvisOffset = mPelvisZOffset; if (!model->mSkinWeights.empty()) { has_skin_weights = true; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index aac20244cc..e3b0f7522e 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -359,6 +359,8 @@ public: LLVector3 mModelPivot; bool mHasPivot; + + float mPelvisZOffset; }; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 8e869b2d5b..93e6c3aafc 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1167,7 +1167,7 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat { info.mPelvisOffset = skin["pelvis_offset"].asReal(); } - + llinfos<<"info pelvis offset"< 0 ) { const int jointCnt = pSkinData->mJointNames.size(); + const int pelvisZOffset = pSkinData->mPelvisOffset; bool fullRig = (jointCnt>=20) ? true : false; if ( fullRig ) { @@ -3961,7 +3962,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) pJoint->storeCurrentXform( jointPos ); if ( !pAvatarVO->hasPelvisOffset() ) { - pAvatarVO->setPelvisOffset( true, jointPos ); + pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset ); //Trigger to rebuild viewer AV pelvisGotSet = true; } -- cgit v1.2.3 From 15b0509c01dbeec6854f4a0a5965e900eda06de1 Mon Sep 17 00:00:00 2001 From: prep linden Date: Wed, 16 Mar 2011 10:19:56 -0400 Subject: WIP:commented out pelvis offset log --- indra/newview/llmeshrepository.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 93e6c3aafc..93e773d33b 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1167,7 +1167,7 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat { info.mPelvisOffset = skin["pelvis_offset"].asReal(); } - llinfos<<"info pelvis offset"< Date: Wed, 16 Mar 2011 17:09:30 -0400 Subject: Fix for SH-1017. We now disallow malformed rigs to be uploaded (i.e. missing bones, improperly names bones etc...) --- indra/newview/llfloatermodelpreview.cpp | 33 ++++++++++++++++++++++++--------- indra/newview/llfloatermodelpreview.h | 4 ++++ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 3a7732c7b3..6bf9fdfb9b 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -495,7 +495,8 @@ void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) { return; } - + + fp->mModelPreview->calcResourceCost(); fp->mModelPreview->refresh(); fp->mModelPreview->resetPreviewTarget(); fp->mModelPreview->clearBuffers(); @@ -1480,8 +1481,8 @@ void LLModelLoader::run() //(which means we have all the joints that are required for an avatar versus //a skinned asset attached to a node in a file that contains an entire skeleton, //but does not use the skeleton). - - if ( !model->mJointList.empty() && doesJointArrayContainACompleteRig( model->mJointList ) ) + mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) ); + if ( !model->mJointList.empty() && mPreview->isRigValid() ) { mResetJoints = true; } @@ -2233,6 +2234,7 @@ LLColor4 LLModelLoader::getDaeColor(daeElement* element) LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) , mPelvisZOffset( 0.0f ) +, mRigValid( false ) { mNeedsUpdate = TRUE; mCameraDistance = 0.f; @@ -2293,6 +2295,16 @@ U32 LLModelPreview::calcResourceCost() } } + //Upload skin is selected BUT the joints coming in from the asset + //were malformed. + if ( mFMP && mFMP->childGetValue("upload_skin").asBoolean() ) + { + if ( !isRigValid() ) + { + mFMP->childDisable("ok_btn"); + } + } + U32 cost = 0; std::set accounted; U32 num_points = 0; @@ -2552,7 +2564,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) { mFMP->childDisable("ok_btn"); } - + if (lod == mPreviewLOD) { mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); @@ -3295,15 +3307,18 @@ void LLModelPreview::updateStatusMessages() bool errorStateFromLoader = mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; - if ( upload_ok && !errorStateFromLoader ) + bool skinAndRigOk = true; + bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); + if ( uploadingSkin && !isRigValid() ) { - mFMP->childEnable("ok_btn"); + skinAndRigOk = false; } - else + + if ( upload_ok && !errorStateFromLoader && skinAndRigOk ) { - mFMP->childDisable("ok_btn"); + mFMP->childEnable("ok_btn"); } - + //add up physics triangles etc S32 start = 0; S32 end = mModel[LLModel::LOD_PHYSICS].size(); diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index e3b0f7522e..b3053fe73a 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -294,6 +294,8 @@ public: const bool getModelPivot( void ) const { return mHasPivot; } void setHasPivot( bool val ) { mHasPivot = val; } void setModelPivot( const LLVector3& pivot ) { mModelPivot = pivot; } + const bool isRigValid( void ) const { return mRigValid; } + void setRigValid( bool rigValid ) { mRigValid = rigValid; } static void textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ); @@ -361,6 +363,8 @@ public: bool mHasPivot; float mPelvisZOffset; + + bool mRigValid; }; -- cgit v1.2.3 From 359d0494308451ce1318f0291ebbf0ba58e42f44 Mon Sep 17 00:00:00 2001 From: prep linden Date: Thu, 17 Mar 2011 17:25:52 -0400 Subject: Added support for handling an asset that contains a skeletal node which has no root node for the scene (yuck). Fix for an upload issue w/simplebot --- indra/newview/llfloatermodelpreview.cpp | 23 ++++++++++++++++++++--- indra/newview/llvoavatar.cpp | 4 +++- indra/newview/llvovolume.cpp | 4 +++- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6bf9fdfb9b..190af6deef 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1070,7 +1070,6 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev mMasterJointList.push_front("mChest"); mMasterJointList.push_front("mNeck"); mMasterJointList.push_front("mHead"); - mMasterJointList.push_front("mSkull"); mMasterJointList.push_front("mCollarLeft"); mMasterJointList.push_front("mShoulderLeft"); mMasterJointList.push_front("mElbowLeft"); @@ -1298,7 +1297,25 @@ void LLModelLoader::run() bool missingSkeletonOrScene = false; //If no skeleton, do a breadth-first search to get at specific joints - if ( !pSkeleton ) + bool rootNode = false; + bool skeletonWithNoRootNode = false; + + //Need to test for a skeleton that does not have a root node + //This occurs when your instance controller does not have an associated scene + if ( pSkeleton ) + { + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) + { + rootNode = true; + } + else + { + skeletonWithNoRootNode = true; + } + + } + if ( !pSkeleton || !rootNode ) { daeElement* pScene = root->getDescendant("visual_scene"); if ( !pScene ) @@ -1482,7 +1499,7 @@ void LLModelLoader::run() //a skinned asset attached to a node in a file that contains an entire skeleton, //but does not use the skeleton). mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) ); - if ( !model->mJointList.empty() && mPreview->isRigValid() ) + if ( !skeletonWithNoRootNode && !model->mJointList.empty() && mPreview->isRigValid() ) { mResetJoints = true; } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 5f0e4bcded..87a2c949b1 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -6032,7 +6032,9 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO ) if ( pSkinData ) { const int jointCnt = pSkinData->mJointNames.size(); - bool fullRig = ( jointCnt>=20 ) ? true : false; + //19 is a magic number derived from the master joint list + //TODO# move that joint list into the bone controller and query + bool fullRig = ( jointCnt>=19 ) ? true : false; if ( fullRig ) { const int bindCnt = pSkinData->mAlternateBindMatrix.size(); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 43d8b9d356..0e6110549e 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3942,7 +3942,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { const int jointCnt = pSkinData->mJointNames.size(); const int pelvisZOffset = pSkinData->mPelvisOffset; - bool fullRig = (jointCnt>=20) ? true : false; + //19 is a magic number derived from the master joint list + //TODO# move that joint list into the bone controller and query + bool fullRig = (jointCnt>=19) ? true : false; if ( fullRig ) { for ( int i=0; i Date: Thu, 17 Mar 2011 17:17:31 -0500 Subject: SH-587 Fix for crash when clicking cancel in model importer. --- indra/newview/llfloatermodelpreview.cpp | 928 +++++++++++++++++--------------- indra/newview/llfloatermodelpreview.h | 14 +- indra/newview/llfloatermodelwizard.cpp | 2 +- 3 files changed, 495 insertions(+), 449 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6bf9fdfb9b..eb0816adb5 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -986,7 +986,7 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl // LLModelLoader //----------------------------------------------------------------------------- LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) -: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE), mResetJoints( FALSE ) +: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE), mResetJoints( FALSE ) { mJointMap["mPelvis"] = "mPelvis"; mJointMap["mTorso"] = "mTorso"; @@ -1085,6 +1085,11 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev mMasterJointList.push_front("mHipLeft"); mMasterJointList.push_front("mKneeLeft"); mMasterJointList.push_front("mFootLeft"); + + if (mPreview) + { + mPreview->setLoadState(STARTING); + } } void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) @@ -1151,273 +1156,304 @@ void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& } void LLModelLoader::run() +{ + if (!doLoadModel()) + { + mPreview = NULL; + } + + doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); +} + +bool LLModelLoader::doLoadModel() { DAE dae; domCOLLADA* dom = dae.open(mFilename); - if (dom) + if (!dom) { - daeDatabase* db = dae.getDatabase(); - - daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); - - daeDocument* doc = dae.getDoc(mFilename); - if (!doc) - { - llwarns << "can't find internal doc" << llendl; - return; - } - - daeElement* root = doc->getDomRoot(); - if (!root) - { - llwarns << "document has no root" << llendl; - return; - } - - //get unit scale - mTransform.setIdentity(); - - domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); - - if (unit) - { - F32 meter = unit->getMeter(); - mTransform.mMatrix[0][0] = meter; - mTransform.mMatrix[1][1] = meter; - mTransform.mMatrix[2][2] = meter; - } - - //get up axis rotation - LLMatrix4 rotation; - - domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP - domAsset::domUp_axis* up_axis = - daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); - - if (up_axis) - { - up = up_axis->getValue(); - } + return false; + } + + daeDatabase* db = dae.getDatabase(); + + daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); + + daeDocument* doc = dae.getDoc(mFilename); + if (!doc) + { + llwarns << "can't find internal doc" << llendl; + return false; + } + + daeElement* root = doc->getDomRoot(); + if (!root) + { + llwarns << "document has no root" << llendl; + return false; + } + + //get unit scale + mTransform.setIdentity(); + + domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); + + if (unit) + { + F32 meter = unit->getMeter(); + mTransform.mMatrix[0][0] = meter; + mTransform.mMatrix[1][1] = meter; + mTransform.mMatrix[2][2] = meter; + } + + //get up axis rotation + LLMatrix4 rotation; + + domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP + domAsset::domUp_axis* up_axis = + daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); + + if (up_axis) + { + up = up_axis->getValue(); + } + + if (up == UPAXISTYPE_X_UP) + { + rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + } + else if (up == UPAXISTYPE_Y_UP) + { + rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); + } + + rotation *= mTransform; + mTransform = rotation; + + + for (daeInt idx = 0; idx < count; ++idx) + { //build map of domEntities to LLModel + domMesh* mesh = NULL; + db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); - if (up == UPAXISTYPE_X_UP) + if (mesh) { - rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); - } - else if (up == UPAXISTYPE_Y_UP) - { - rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); - } - - rotation *= mTransform; - mTransform = rotation; - - - for (daeInt idx = 0; idx < count; ++idx) - { //build map of domEntities to LLModel - domMesh* mesh = NULL; - db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); + LLPointer model = LLModel::loadModelFromDomMesh(mesh); - if (mesh) + if (model.notNull() && validate_model(model)) { - LLPointer model = LLModel::loadModelFromDomMesh(mesh); - - if (model.notNull() && validate_model(model)) - { - mModelList.push_back(model); - mModel[mesh] = model; - } + mModelList.push_back(model); + mModel[mesh] = model; } } + } + + count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); + for (daeInt idx = 0; idx < count; ++idx) + { //add skinned meshes as instances + domSkin* skin = NULL; + db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); - count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); - for (daeInt idx = 0; idx < count; ++idx) - { //add skinned meshes as instances - domSkin* skin = NULL; - db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); + if (skin) + { + domGeometry* geom = daeSafeCast(skin->getSource().getElement()); - if (skin) + if (geom) { - domGeometry* geom = daeSafeCast(skin->getSource().getElement()); - - if (geom) + domMesh* mesh = geom->getMesh(); + if (mesh) { - domMesh* mesh = geom->getMesh(); - if (mesh) + LLModel* model = mModel[mesh]; + if (model) { - LLModel* model = mModel[mesh]; - if (model) - { - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 normalized_transformation; - normalized_transformation.setTranslation(mesh_translation_vector); - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= normalized_transformation; - normalized_transformation = mesh_scale; + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 normalized_transformation; + normalized_transformation.setTranslation(mesh_translation_vector); + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= normalized_transformation; + normalized_transformation = mesh_scale; + + glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); + inv_mat = inv_mat.inverse(); + LLMatrix4 inverse_normalized_transformation(inv_mat.m); + + domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); + + if (bind_mat) + { //get bind shape matrix + domFloat4x4& dom_value = bind_mat->getValue(); - glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); - inv_mat = inv_mat.inverse(); - LLMatrix4 inverse_normalized_transformation(inv_mat.m); - - domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); - - if (bind_mat) - { //get bind shape matrix - domFloat4x4& dom_value = bind_mat->getValue(); - - for (int i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) { - for(int j = 0; j < 4; j++) - { - model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; - } + model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; } - - LLMatrix4 trans = normalized_transformation; - trans *= model->mBindShapeMatrix; - model->mBindShapeMatrix = trans; - } + LLMatrix4 trans = normalized_transformation; + trans *= model->mBindShapeMatrix; + model->mBindShapeMatrix = trans; - //The joint transfom map that we'll populate below - std::map jointTransforms; - jointTransforms.clear(); - - //Some collada setup for accessing the skeleton - daeElement* pElement = 0; - dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); - - //Try to get at the skeletal instance controller - domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); - bool missingSkeletonOrScene = false; - - //If no skeleton, do a breadth-first search to get at specific joints - if ( !pSkeleton ) + } + + + //The joint transfom map that we'll populate below + std::map jointTransforms; + jointTransforms.clear(); + + //Some collada setup for accessing the skeleton + daeElement* pElement = 0; + dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); + + //Try to get at the skeletal instance controller + domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); + bool missingSkeletonOrScene = false; + + //If no skeleton, do a breadth-first search to get at specific joints + if ( !pSkeleton ) + { + daeElement* pScene = root->getDescendant("visual_scene"); + if ( !pScene ) { - daeElement* pScene = root->getDescendant("visual_scene"); - if ( !pScene ) - { - llwarns<<"No visual scene - unable to parse bone offsets "< > children = pScene->getChildren(); + S32 childCount = children.getCount(); + + //Process any children that are joints + //Not all children are joints, some code be ambient lights, cameras, geometry etc.. + for (S32 i = 0; i < childCount; ++i) { - //Get the children at this level - daeTArray< daeSmartRef > children = pScene->getChildren(); - S32 childCount = children.getCount(); - - //Process any children that are joints - //Not all children are joints, some code be ambient lights, cameras, geometry etc.. - for (S32 i = 0; i < childCount; ++i) + domNode* pNode = daeSafeCast(children[i]); + if ( isNodeAJoint( pNode ) ) { - domNode* pNode = daeSafeCast(children[i]); - if ( isNodeAJoint( pNode ) ) - { - processJointNode( pNode, jointTransforms ); - } + processJointNode( pNode, jointTransforms ); } } } - else - //Has Skeleton + } + else + //Has Skeleton + { + //Get the root node of the skeleton + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) { - //Get the root node of the skeleton - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) + //Once we have the root node - start acccessing it's joint components + const int jointCnt = mJointMap.size(); + std::map :: const_iterator jointIt = mJointMap.begin(); + + //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. + for ( int i=0; i :: const_iterator jointIt = mJointMap.begin(); + //Build a joint for the resolver to work with + char str[64]={0}; + sprintf(str,"./%s",(*jointIt).second.c_str() ); + //llwarns<<"Joint "<< str <( resolver.getElement() ); + if ( pJoint ) + { + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolver( pJoint, "./translate" ); + domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); - //Setup the resolver - daeSIDResolver resolver( pSkeletonRootNode, str ); + LLMatrix4 workingTransform; - //Look for the joint - domNode* pJoint = daeSafeCast( resolver.getElement() ); - if ( pJoint ) - { - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolver( pJoint, "./translate" ); - domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); - - LLMatrix4 workingTransform; - - //Translation via SID - if ( pTranslate ) + //Translation via SID + if ( pTranslate ) + { + extractTranslation( pTranslate, workingTransform ); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); + if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) { - extractTranslation( pTranslate, workingTransform ); + llwarns<< "The found element is not a translate node" <typeID() != domTranslate::ID() ) - { - llwarns<< "The found element is not a translate node" <getJoints(); - - domInputLocal_Array& joint_input = joints->getInput_array(); + } + + //Store the joint transform w/respect to it's name. + jointTransforms[(*jointIt).second.c_str()] = workingTransform; + } + } + + //If anything failed in regards to extracting the skeleton, joints or translation id, + //mention it + if ( missingSkeletonOrScene ) + { + llwarns<< "Partial jointmap found in asset - did you mean to just have a partial map?" << llendl; + } + }//got skeleton? + } + + + domSkin::domJoints* joints = skin->getJoints(); + + domInputLocal_Array& joint_input = joints->getInput_array(); + + for (size_t i = 0; i < joint_input.getCount(); ++i) + { + domInputLocal* input = joint_input.get(i); + xsNMTOKEN semantic = input->getSemantic(); - for (size_t i = 0; i < joint_input.getCount(); ++i) - { - domInputLocal* input = joint_input.get(i); - xsNMTOKEN semantic = input->getSemantic(); + if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) + { //found joint source, fill model->mJointMap and model->mJointList + daeElement* elem = input->getSource().getElement(); - if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) - { //found joint source, fill model->mJointMap and model->mJointList - daeElement* elem = input->getSource().getElement(); + domSource* source = daeSafeCast(elem); + if (source) + { - domSource* source = daeSafeCast(elem); - if (source) + + domName_array* names_source = source->getName_array(); + + if (names_source) { + domListOfNames &names = names_source->getValue(); - - domName_array* names_source = source->getName_array(); - + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j)); + if (mJointMap.find(name) != mJointMap.end()) + { + name = mJointMap[name]; + } + model->mJointList.push_back(name); + model->mJointMap[name] = j; + } + } + else + { + domIDREF_array* names_source = source->getIDREF_array(); if (names_source) { - domListOfNames &names = names_source->getValue(); + xsIDREFS& names = names_source->getValue(); for (size_t j = 0; j < names.getCount(); ++j) { - std::string name(names.get(j)); + std::string name(names.get(j).getID()); if (mJointMap.find(name) != mJointMap.end()) { name = mJointMap[name]; @@ -1426,279 +1462,284 @@ void LLModelLoader::run() model->mJointMap[name] = j; } } - else - { - domIDREF_array* names_source = source->getIDREF_array(); - if (names_source) - { - xsIDREFS& names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j).getID()); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mJointList.push_back(name); - model->mJointMap[name] = j; - } - } - } } } - else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) - { //found inv_bind_matrix array, fill model->mInvBindMatrix - domSource* source = daeSafeCast(input->getSource().getElement()); - if (source) + } + else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) + { //found inv_bind_matrix array, fill model->mInvBindMatrix + domSource* source = daeSafeCast(input->getSource().getElement()); + if (source) + { + domFloat_array* t = source->getFloat_array(); + if (t) { - domFloat_array* t = source->getFloat_array(); - if (t) + domListOfFloats& transform = t->getValue(); + S32 count = transform.getCount()/16; + + for (S32 k = 0; k < count; ++k) { - domListOfFloats& transform = t->getValue(); - S32 count = transform.getCount()/16; + LLMatrix4 mat; - for (S32 k = 0; k < count; ++k) + for (int i = 0; i < 4; i++) { - LLMatrix4 mat; - - for (int i = 0; i < 4; i++) + for(int j = 0; j < 4; j++) { - for(int j = 0; j < 4; j++) - { - mat.mMatrix[i][j] = transform[k*16 + i + j*4]; - } + mat.mMatrix[i][j] = transform[k*16 + i + j*4]; } - - model->mInvBindMatrix.push_back(mat); } + + model->mInvBindMatrix.push_back(mat); } } } } - - //Now that we've parsed the joint array, let's determine if we have a full rig - //(which means we have all the joints that are required for an avatar versus - //a skinned asset attached to a node in a file that contains an entire skeleton, - //but does not use the skeleton). - mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) ); - if ( !model->mJointList.empty() && mPreview->isRigValid() ) - { - mResetJoints = true; - } - - if ( !missingSkeletonOrScene ) - { - //Set the joint translations on the avatar - if it's a full mapping - //The joints are reset in the dtor - if ( mResetJoints ) - { - std::map :: const_iterator masterJointIt = mJointMap.begin(); - std::map :: const_iterator masterJointItEnd = mJointMap.end(); - for (;masterJointIt!=masterJointItEnd;++masterJointIt ) + } + + //Now that we've parsed the joint array, let's determine if we have a full rig + //(which means we have all the joints that are required for an avatar versus + //a skinned asset attached to a node in a file that contains an entire skeleton, + //but does not use the skeleton). + mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) ); + if ( !model->mJointList.empty() && mPreview->isRigValid() ) + { + mResetJoints = true; + } + + if ( !missingSkeletonOrScene ) + { + //Set the joint translations on the avatar - if it's a full mapping + //The joints are reset in the dtor + if ( mResetJoints ) + { + std::map :: const_iterator masterJointIt = mJointMap.begin(); + std::map :: const_iterator masterJointItEnd = mJointMap.end(); + for (;masterJointIt!=masterJointItEnd;++masterJointIt ) + { + std::string lookingForJoint = (*masterJointIt).first.c_str(); + + if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() ) { - std::string lookingForJoint = (*masterJointIt).first.c_str(); - - if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() ) + //llinfos<<"joint "<getJoint( lookingForJoint ); + if ( pJoint ) + { + pJoint->storeCurrentXform( jointTransform.getTranslation() ); + } + else { - //llinfos<<"joint "<getJoint( lookingForJoint ); - if ( pJoint ) - { - pJoint->storeCurrentXform( jointTransform.getTranslation() ); - } - else - { - //Most likely an error in the asset. - llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; - } + //Most likely an error in the asset. + llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; } } } - } //missingSkeletonOrScene - - //We need to construct the alternate bind matrix (which contains the new joint positions) - //in the same order as they were stored in the joint buffer. The joints associated - //with the skeleton are not stored in the same order as they are in the exported joint buffer. - //This remaps the skeletal joints to be in the same order as the joints stored in the model. - std::vector :: const_iterator jointIt = model->mJointList.begin(); - const int jointCnt = model->mJointList.size(); - for ( int i=0; i :: const_iterator jointIt = model->mJointList.begin(); + const int jointCnt = model->mJointList.size(); + for ( int i=0; imInvBindMatrix[i]; - newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); - model->mAlternateBindMatrix.push_back( newInverse ); - } - else - { - llwarns<<"Possibly misnamed/missing joint [" <mInvBindMatrix[i]; + newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); + model->mAlternateBindMatrix.push_back( newInverse ); } - - //grab raw position array - - domVertices* verts = mesh->getVertices(); - if (verts) + else + { + llwarns<<"Possibly misnamed/missing joint [" <getVertices(); + if (verts) + { + domInputLocal_Array& inputs = verts->getInput_array(); + for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) { - domInputLocal_Array& inputs = verts->getInput_array(); - for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) + domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (pos_source) { - domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (pos_source) + domFloat_array* pos_array = pos_source->getFloat_array(); + if (pos_array) { - domFloat_array* pos_array = pos_source->getFloat_array(); - if (pos_array) + domListOfFloats& pos = pos_array->getValue(); + + for (size_t j = 0; j < pos.getCount(); j += 3) { - domListOfFloats& pos = pos_array->getValue(); - - for (size_t j = 0; j < pos.getCount(); j += 3) + if (pos.getCount() <= j+2) { - if (pos.getCount() <= j+2) - { - llerrs << "WTF?" << llendl; - } - - LLVector3 v(pos[j], pos[j+1], pos[j+2]); - - //transform from COLLADA space to volume space - v = v * inverse_normalized_transformation; - - model->mPosition.push_back(v); + llerrs << "WTF?" << llendl; } + + LLVector3 v(pos[j], pos[j+1], pos[j+2]); + + //transform from COLLADA space to volume space + v = v * inverse_normalized_transformation; + + model->mPosition.push_back(v); } } } } } - - //grab skin weights array - domSkin::domVertex_weights* weights = skin->getVertex_weights(); - if (weights) + } + + //grab skin weights array + domSkin::domVertex_weights* weights = skin->getVertex_weights(); + if (weights) + { + domInputLocalOffset_Array& inputs = weights->getInput_array(); + domFloat_array* vertex_weights = NULL; + for (size_t i = 0; i < inputs.getCount(); ++i) { - domInputLocalOffset_Array& inputs = weights->getInput_array(); - domFloat_array* vertex_weights = NULL; - for (size_t i = 0; i < inputs.getCount(); ++i) + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) + domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (weight_source) { - domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (weight_source) - { - vertex_weights = weight_source->getFloat_array(); - } + vertex_weights = weight_source->getFloat_array(); } } + } + + if (vertex_weights) + { + domListOfFloats& w = vertex_weights->getValue(); + domListOfUInts& vcount = weights->getVcount()->getValue(); + domListOfInts& v = weights->getV()->getValue(); - if (vertex_weights) - { - domListOfFloats& w = vertex_weights->getValue(); - domListOfUInts& vcount = weights->getVcount()->getValue(); - domListOfInts& v = weights->getV()->getValue(); + U32 c_idx = 0; + for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) + { //for each vertex + daeUInt count = vcount[vc_idx]; - U32 c_idx = 0; - for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) - { //for each vertex - daeUInt count = vcount[vc_idx]; - - //create list of weights that influence this vertex - LLModel::weight_list weight_list; - - for (daeUInt i = 0; i < count; ++i) - { //for each weight - daeInt joint_idx = v[c_idx++]; - daeInt weight_idx = v[c_idx++]; - - if (joint_idx == -1) - { - //ignore bindings to bind_shape_matrix - continue; - } - - F32 weight_value = w[weight_idx]; - - weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); - } - - //sort by joint weight - std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - - std::vector wght; - - F32 total = 0.f; + //create list of weights that influence this vertex + LLModel::weight_list weight_list; + + for (daeUInt i = 0; i < count; ++i) + { //for each weight + daeInt joint_idx = v[c_idx++]; + daeInt weight_idx = v[c_idx++]; - for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) - { //take up to 4 most significant weights - if (weight_list[i].mWeight > 0.f) - { - wght.push_back( weight_list[i] ); - total += weight_list[i].mWeight; - } + if (joint_idx == -1) + { + //ignore bindings to bind_shape_matrix + continue; } - F32 scale = 1.f/total; - if (scale != 1.f) - { //normalize weights - for (U32 i = 0; i < wght.size(); ++i) - { - wght[i].mWeight *= scale; - } - } + F32 weight_value = w[weight_idx]; - model->mSkinWeights[model->mPosition[vc_idx]] = wght; + weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); } - //add instance to scene for this model + //sort by joint weight + std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); + + std::vector wght; - LLMatrix4 transformation = mTransform; - // adjust the transformation to compensate for mesh normalization + F32 total = 0.f; - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; + for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) + { //take up to 4 most significant weights + if (weight_list[i].mWeight > 0.f) + { + wght.push_back( weight_list[i] ); + total += weight_list[i].mWeight; + } + } - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; + F32 scale = 1.f/total; + if (scale != 1.f) + { //normalize weights + for (U32 i = 0; i < wght.size(); ++i) + { + wght[i].mWeight *= scale; + } + } - std::vector materials; - materials.resize(model->getNumVolumeFaces()); - mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + model->mSkinWeights[model->mPosition[vc_idx]] = wght; } + + //add instance to scene for this model + + LLMatrix4 transformation = mTransform; + // adjust the transformation to compensate for mesh normalization + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + std::vector materials; + materials.resize(model->getNumVolumeFaces()); + mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); } } } } } } - - daeElement* scene = root->getDescendant("visual_scene"); - - if (!scene) - { - llwarns << "document has no visual_scene" << llendl; - setLoadState( ERROR_PARSING ); - return; - } - setLoadState( DONE ); + } + + daeElement* scene = root->getDescendant("visual_scene"); + + if (!scene) + { + llwarns << "document has no visual_scene" << llendl; + setLoadState( ERROR_PARSING ); + return false; + } + setLoadState( DONE ); - processElement(scene); - - handlePivotPoint( root ); - - doOnIdleOneTime(boost::bind(&LLModelPreview::loadModelCallback,mPreview,mLod)); + processElement(scene); + + handlePivotPoint( root ); + + return true; +} + +void LLModelLoader::setLoadState(U32 state) +{ + if (mPreview) + { + mPreview->setLoadState(state); + } +} + +void LLModelLoader::loadModelCallback() +{ + if (mPreview) + { + mPreview->loadModelCallback(mLod); + mPreview->mModelLoader = NULL; + } + + while (!isStopped()) + { //wait until this thread is stopped before deleting self + apr_sleep(100); } + + delete this; } void LLModelLoader::handlePivotPoint( daeElement* pRoot ) @@ -2248,6 +2289,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mDirty = false; mGenLOD = false; mLoading = false; + mLoadState = LLModelLoader::STARTING; mGroup = 0; mBuildShareTolerance = 0.f; mBuildQueueMode = GLOD_QUEUE_GREEDY; @@ -2273,10 +2315,8 @@ LLModelPreview::~LLModelPreview() { if (mModelLoader) { - delete mModelLoader; - mModelLoader = NULL; + mModelLoader->mPreview = NULL; } - //*HACK : *TODO : turn this back on when we understand why this crashes //glodShutdown(); } @@ -2289,7 +2329,7 @@ U32 LLModelPreview::calcResourceCost() if (mFMP && mModelLoader) { - if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) + if ( getLoadState() != LLModelLoader::ERROR_PARSING ) { mFMP->childEnable("ok_btn"); } @@ -2541,10 +2581,10 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) if (mModelLoader) { - delete mModelLoader; - mModelLoader = NULL; + llwarns << "Incompleted model load operation pending." << llendl; + return; } - + mLODFile[lod] = filename; if (lod == LLModel::LOD_HIGH) @@ -2560,7 +2600,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) setPreviewLOD(lod); - if ( mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ) + if ( getLoadState() == LLModelLoader::ERROR_PARSING ) { mFMP->childDisable("ok_btn"); } @@ -3305,7 +3345,7 @@ void LLModelPreview::updateStatusMessages() } } - bool errorStateFromLoader = mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; + bool errorStateFromLoader = getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; bool skinAndRigOk = true; bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index b3053fe73a..910a45f9fe 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -96,7 +96,9 @@ public: LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview); virtual void run(); - + bool doLoadModel(); + void loadModelCallback(); + void loadTextures() ; //called in the main thread. void processElement(daeElement* element); std::vector getMaterials(LLModel* model, domInstance_geometry* instance_geo); @@ -117,9 +119,8 @@ public: void handlePivotPoint( daeElement* pRoot ); bool isNodeAPivotPoint( domNode* pNode ); - void setLoadState( U32 state ) { mState = state; } - U32 getLoadState( void ) { return mState; } - + void setLoadState(U32 state); + //map of avatar joints as named in COLLADA assets to internal joint names std::map mJointMap; std::deque mMasterJointList; @@ -302,7 +303,11 @@ public: boost::signals2::connection setDetailsCallback( const details_signal_t::slot_type& cb ){ return mDetailsSignal.connect(cb); } boost::signals2::connection setModelLoadedCallback( const model_loaded_signal_t::slot_type& cb ){ return mModelLoadedSignal.connect(cb); } + void setLoadState( U32 state ) { mLoadState = state; } + U32 getLoadState() { return mLoadState; } + protected: + friend class LLModelLoader; friend class LLFloaterModelPreview; friend class LLFloaterModelWizard; friend class LLFloaterModelPreview::DecompRequest; @@ -326,6 +331,7 @@ public: U32 mResourceCost; std::string mLODFile[LLModel::NUM_LODS]; bool mLoading; + U32 mLoadState; std::map mViewOption; diff --git a/indra/newview/llfloatermodelwizard.cpp b/indra/newview/llfloatermodelwizard.cpp index be43216b0e..eafea1fe03 100644 --- a/indra/newview/llfloatermodelwizard.cpp +++ b/indra/newview/llfloatermodelwizard.cpp @@ -590,7 +590,7 @@ void LLFloaterModelWizard::refresh() { bool model_loaded = false; - if (mModelPreview && mModelPreview->mModelLoader && mModelPreview->mModelLoader->getLoadState() == LLModelLoader::DONE) + if (mModelPreview && mModelPreview->getLoadState() == LLModelLoader::DONE) { model_loaded = true; } -- cgit v1.2.3 From 9c1c791b29cb5087ebff142d4ad7a55b65be0ad0 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 17 Mar 2011 17:35:51 -0500 Subject: Merge indentation fix up. --- indra/newview/llfloatermodelpreview.cpp | 34 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 7d60258ca4..ce977b33bb 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1315,25 +1315,25 @@ bool LLModelLoader::doLoadModel() bool missingSkeletonOrScene = false; //If no skeleton, do a breadth-first search to get at specific joints - bool rootNode = false; - bool skeletonWithNoRootNode = false; - - //Need to test for a skeleton that does not have a root node - //This occurs when your instance controller does not have an associated scene - if ( pSkeleton ) + bool rootNode = false; + bool skeletonWithNoRootNode = false; + + //Need to test for a skeleton that does not have a root node + //This occurs when your instance controller does not have an associated scene + if ( pSkeleton ) + { + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) { - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) - { - rootNode = true; - } - else - { - skeletonWithNoRootNode = true; - } - + rootNode = true; } - if ( !pSkeleton || !rootNode ) + else + { + skeletonWithNoRootNode = true; + } + + } + if ( !pSkeleton || !rootNode ) { daeElement* pScene = root->getDescendant("visual_scene"); if ( !pScene ) -- cgit v1.2.3 From 2e7771d9866a5006c8423064ca30bb654b143fef Mon Sep 17 00:00:00 2001 From: Tofu Buzzard Date: Sun, 20 Mar 2011 15:20:02 +0000 Subject: subtler SSAO / better worst-case. --- indra/newview/app_settings/settings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index f56882b91e..c6317e1a1d 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7274,7 +7274,7 @@ Vector3 Value - 0.70 + 0.80 1.00 0.00 -- cgit v1.2.3 From fb862afc8b9b48ebcd3902f3324cb60c9af623d4 Mon Sep 17 00:00:00 2001 From: Tofu Buzzard Date: Sun, 20 Mar 2011 15:48:01 +0000 Subject: revert a bunch of stuff from my local repo so this can go in minimally. --- indra/llmath/llvolume.cpp | 2 +- indra/llprimitive/llmodel.cpp | 2 +- indra/llui/CMakeLists.txt | 4 ++-- indra/newview/llfloatersearch.cpp | 14 +++++++------- indra/newview/llfloatersearch.h | 2 ++ indra/newview/llmeshrepository.cpp | 8 ++++---- install.xml | 4 ++-- 7 files changed, 19 insertions(+), 17 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index dabec6390d..c4be176353 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1898,7 +1898,7 @@ BOOL LLVolume::generate() // Split is a parameter to LLProfile::generate that tesselates edges on the profile // to prevent lighting and texture interpolation errors on triangles that are // stretched due to twisting or scaling on the path. - S32 split = 0;//(S32) ((mDetail)*0.66f); + S32 split = (S32) ((mDetail)*0.66f); if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_LINE && (mParams.getPathParams().getScale().mV[0] != 1.0f || diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 2284ca0bee..eed82f924b 100755 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -66,7 +66,7 @@ LLModel::~LLModel() { if (mDecompID >= 0) { -// LLConvexDecomposition::getInstance()->deleteDecomposition(mDecompID); + LLConvexDecomposition::getInstance()->deleteDecomposition(mDecompID); } } diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 3e94a4738b..684e393cba 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -245,11 +245,11 @@ target_link_libraries(llui ) # Add tests -if (0 AND LL_TESTS) +if (LL_TESTS) include(LLAddBuildTest) SET(llui_TEST_SOURCE_FILES llurlmatch.cpp llurlentry.cpp ) LL_ADD_PROJECT_UNIT_TESTS(llui "${llui_TEST_SOURCE_FILES}") -endif (0 AND LL_TESTS) +endif (LL_TESTS) \ No newline at end of file diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index 1e321674a7..2041fac8d8 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -103,14 +103,14 @@ BOOL LLFloaterSearch::postBuild() void LLFloaterSearch::onOpen(const LLSD& key) { - if ( (key.has("category")) || ((mBrowser) && (mBrowser->getCurrentNavUrl().empty())) ) - { - // new search triggered - blank the page while loading, instead of - // temporarily showing stale results - mBrowser->navigateTo("about:blank"); + search(key); +} - search(key); - } +void LLFloaterSearch::onClose(bool app_quitting) +{ + // tear down the web view so we don't show the previous search + // result when the floater is opened next time + destroy(); } void LLFloaterSearch::handleMediaEvent(LLPluginClassMedia *self, EMediaEvent event) diff --git a/indra/newview/llfloatersearch.h b/indra/newview/llfloatersearch.h index 615c099d0d..ba4dc4c0fa 100644 --- a/indra/newview/llfloatersearch.h +++ b/indra/newview/llfloatersearch.h @@ -53,6 +53,8 @@ public: /// see search() for details on the key parameter. /*virtual*/ void onOpen(const LLSD& key); + /*virtual*/ void onClose(bool app_quitting); + /// perform a search with the specific search term. /// The key should be a map that can contain the following keys: /// - "id": specifies the text phrase to search for diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 986b8cd509..93e773d33b 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3532,7 +3532,7 @@ void LLPhysicsDecomp::run() if (!stages) { - //num_stages = decomp->getStages(&stages); + num_stages = decomp->getStages(&stages); } for (S32 i = 0; i < num_stages; i++) @@ -3554,9 +3554,9 @@ void LLPhysicsDecomp::run() S32& id = *(mCurRequest->mDecompID); if (id == -1) { - //decomp->genDecomposition(id); + decomp->genDecomposition(id); } - //decomp->bindDecomposition(id); + decomp->bindDecomposition(id); if (mCurRequest->mStage == "single_hull") { @@ -3569,7 +3569,7 @@ void LLPhysicsDecomp::run() } } - //decomp->quitThread(); + decomp->quitThread(); if (mSignal->isLocked()) { //let go of mSignal's associated mutex diff --git a/install.xml b/install.xml index 096921a823..1bc6746223 100755 --- a/install.xml +++ b/install.xml @@ -306,9 +306,9 @@ linux md5sum - a20e73f2e7d6a032ff25a5161b1b7394 + 9c9b629b62bf874d550c430ad678dc04 url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/curl-7.20.1-linux-20100527.tar.bz2 + https://s3.amazonaws.com/automated-builds-secondlife-com/hg/repo/brad_curl-autobuild/rev/216961/arch/Linux/installer/curl-7.21.1-linux-20101215.tar.bz2 linux64 -- cgit v1.2.3 From d693c4f6e2f581cd9c82d5526115a5bbd072a8c2 Mon Sep 17 00:00:00 2001 From: Tofu Buzzard Date: Sun, 20 Mar 2011 15:52:01 +0000 Subject: undo another local change. --- indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl index f4f6ee95d0..e3c15a2ab2 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl @@ -16,5 +16,5 @@ void main() vec4 col = texture2D(diffuseMap, gl_TexCoord[0].xy); gl_FragData[0] = vec4(col.rgb, col.a * 0.005); gl_FragData[1] = texture2D(specularMap, gl_TexCoord[0].xy); - gl_FragData[2] = texture2D(normalMap, gl_TexCoord[0].xy); + gl_FragData[2] = vec4(texture2D(normalMap, gl_TexCoord[0].xy).xyz, 0.0); } -- cgit v1.2.3 From 7e7ff13b49f6f806a385bd92d675123ff7db7232 Mon Sep 17 00:00:00 2001 From: Tofu Buzzard Date: Sun, 20 Mar 2011 15:58:34 +0000 Subject: Disable auto-glow again, though leave my other tweaks in place for those who might turn it on. --- indra/newview/app_settings/settings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index c6317e1a1d..f715272681 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8276,7 +8276,7 @@ Type F32 Value - 0.81 + 9999 RenderGlowResolutionPow -- cgit v1.2.3 From 0b4a0f8e234087ae4d6a614c00db9eeea3bec190 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 21 Mar 2011 10:46:42 -0500 Subject: Get rid of ugly seam at near/far focal planes. --- indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl index 7c89c01ea4..7a6b40006b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl @@ -102,7 +102,7 @@ void main() float fd = depth*0.5f; - while (sc > 1.0) + while (sc > 0.5) { dofSample(diff,w, fd, sc,sc); dofSample(diff,w, fd, -sc,sc); -- cgit v1.2.3 From bf3fb2566329a461ebf022a1a05a1fa95faff9aa Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 21 Mar 2011 10:51:28 -0500 Subject: SH-1069 Fix for bump maps not loading fully -- don't clear bump image list on toggling deferred rendering, but do make sure a loaded callback exists when bump resolution or desired number of components is lacking. Also, subtract radius of prim from distance to face for virtual size calculations (makes heavily tiled textures on largish spheres fully res when appropriate). --- indra/newview/lldrawpoolbump.cpp | 51 ++++++++++++++++++++++------------------ indra/newview/llface.cpp | 1 + indra/newview/pipeline.cpp | 3 --- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 38ff3083ce..bbce847fdc 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -646,6 +646,8 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi break; } + llassert(bump); + if (bump) { if (channel == -2) @@ -660,7 +662,7 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi return TRUE; } - + return FALSE; } @@ -1000,25 +1002,28 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText } bump_image_map_t::iterator iter = entries_list->find(src_image->getID()); - if (iter != entries_list->end()) + if (iter != entries_list->end() && iter->second.notNull()) { bump = iter->second; } else { LLPointer raw = new LLImageRaw(1,1,1); - raw->clear(0x77, 0x77, 0x77, 0xFF); + raw->clear(0x77, 0x77, 0xFF, 0xFF); (*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE); - (*entries_list)[src_image->getID()]->setExplicitFormat(GL_ALPHA8, GL_ALPHA); - - // Note: this may create an LLImageGL immediately - src_image->setBoostLevel(LLViewerTexture::BOOST_BUMP) ; - src_image->setLoadedCallback( callback_func, 0, TRUE, FALSE, new LLUUID(src_image->getID()), NULL ); bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image + } -// bump_total++; -// llinfos << "*** Creating " << (void*)bump << " " << bump_total << llendl; + if (!src_image->hasCallbacks()) + { //if image has no callbacks but resolutions don't match, trigger raw image loaded callback again + if (src_image->getWidth() != bump->getWidth() || + src_image->getHeight() != bump->getHeight() || + (LLPipeline::sRenderDeferred && bump->getComponents() != 4)) + { + src_image->setBoostLevel(LLViewerTexture::BOOST_BUMP) ; + src_image->setLoadedCallback( callback_func, 0, TRUE, FALSE, new LLUUID(src_image->getID()), NULL ); + } } } @@ -1122,10 +1127,18 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries ); bump_image_map_t::iterator iter = entries_list.find(source_asset_id); - if (iter != entries_list.end() || - iter->second.isNull() || - iter->second->getWidth() != src->getWidth() || - iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution + if (iter == entries_list.end() || + iter->second.isNull()) + { //make sure an entry exists for this image + LLPointer raw = new LLImageRaw(1,1,1); + raw->clear(0x77, 0x77, 0xFF, 0xFF); + + entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE); + iter = entries_list.find(src_vi->getID()); + } + + //if (iter->second->getWidth() != src->getWidth() || + // iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution { LLPointer dst_image = new LLImageRaw(src->getWidth(), src->getHeight(), 1); U8* dst_data = dst_image->getData(); @@ -1251,18 +1264,10 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI bump->setExplicitFormat(GL_RGBA, GL_RGBA); bump->createGLTexture(0, nrm_image); } - - + iter->second = bump; // derefs (and deletes) old image //--------------------------------------------------- } - else - { - // entry should have been added in LLBumpImageList::getImage(). - - // Not a legit assertion - the bump texture could have been flushed by the bump image manager - //llassert(0); - } } } diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 290115417f..ae455a8287 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1729,6 +1729,7 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) t.load3(camera->getOrigin().mV); lookAt.setSub(center, t); F32 dist = lookAt.getLength3().getF32(); + dist = llmax(dist-size.getLength3().getF32(), 0.f); lookAt.normalize3fast() ; //get area of circle around node diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 24486a7411..6a376554b9 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -825,7 +825,6 @@ void LLPipeline::releaseGLBuffers() mGlow[i].release(); } - gBumpImageList.destroyGL(); LLVOAvatar::resetImpostors(); } @@ -948,8 +947,6 @@ void LLPipeline::createGLBuffers() addDeferredAttachments(mGIMap); } } - - gBumpImageList.restoreGL(); } void LLPipeline::restoreGL() -- cgit v1.2.3 From a034ffd4b1af3560ae8498725bb96bd6f651ca48 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 21 Mar 2011 17:30:26 -0500 Subject: Remove unneeded assertion. --- indra/newview/lldrawpoolbump.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index bbce847fdc..0a642f494b 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -646,8 +646,6 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi break; } - llassert(bump); - if (bump) { if (channel == -2) -- cgit v1.2.3 From 51a4867ae6bcf0ec71882ba77b1c995d98834126 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 21 Mar 2011 17:31:25 -0500 Subject: SH-1168 Export upload data to disk on upload. --- indra/llmath/m4math.cpp | 50 ++++++++++++++++++++++ indra/llmath/m4math.h | 2 + indra/llprimitive/llmodel.cpp | 1 + indra/llprimitive/llmodel.h | 3 ++ indra/newview/llfloatermodelpreview.cpp | 73 ++++++++++++++++++++++++++++++++- indra/newview/llfloatermodelpreview.h | 4 +- indra/newview/llmeshrepository.cpp | 27 ++++++++++++ indra/newview/llmeshrepository.h | 4 ++ 8 files changed, 162 insertions(+), 2 deletions(-) diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp index 8741400e52..bad4deb4de 100644 --- a/indra/llmath/m4math.cpp +++ b/indra/llmath/m4math.cpp @@ -829,4 +829,54 @@ std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a) return s; } +LLSD LLMatrix4::getValue() const +{ + LLSD ret; + + ret[0] = mMatrix[0][0]; + ret[1] = mMatrix[0][1]; + ret[2] = mMatrix[0][2]; + ret[3] = mMatrix[0][3]; + + ret[4] = mMatrix[1][0]; + ret[5] = mMatrix[1][1]; + ret[6] = mMatrix[1][2]; + ret[7] = mMatrix[1][3]; + + ret[8] = mMatrix[2][0]; + ret[9] = mMatrix[2][1]; + ret[10] = mMatrix[2][2]; + ret[11] = mMatrix[2][3]; + + ret[12] = mMatrix[3][0]; + ret[13] = mMatrix[3][1]; + ret[14] = mMatrix[3][2]; + ret[15] = mMatrix[3][3]; + + return ret; +} + +void LLMatrix4::setValue(const LLSD& data) +{ + mMatrix[0][0] = data[0].asReal(); + mMatrix[0][1] = data[1].asReal(); + mMatrix[0][2] = data[2].asReal(); + mMatrix[0][3] = data[3].asReal(); + + mMatrix[1][0] = data[4].asReal(); + mMatrix[1][1] = data[5].asReal(); + mMatrix[1][2] = data[6].asReal(); + mMatrix[1][3] = data[7].asReal(); + + mMatrix[2][0] = data[8].asReal(); + mMatrix[2][1] = data[9].asReal(); + mMatrix[2][2] = data[10].asReal(); + mMatrix[2][3] = data[11].asReal(); + + mMatrix[3][0] = data[12].asReal(); + mMatrix[3][1] = data[13].asReal(); + mMatrix[3][2] = data[14].asReal(); + mMatrix[3][3] = data[15].asReal(); +} + diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h index 3588f36758..a7dce10397 100644 --- a/indra/llmath/m4math.h +++ b/indra/llmath/m4math.h @@ -119,6 +119,8 @@ public: ~LLMatrix4(void); // Destructor + LLSD getValue() const; + void setValue(const LLSD&); ////////////////////////////// // diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index eed82f924b..3669fef0dc 100755 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -60,6 +60,7 @@ LLModel::LLModel(LLVolumeParams& params, F32 detail) , mPelvisOffset( 0.0f ) { mDecompID = -1; + mLocalID = -1; } LLModel::~LLModel() diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index e9e33bdee5..addf527d8d 100755 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -205,6 +205,9 @@ public: std::vector mHullCenter; U32 mHullPoints; + //ID for storing this model in a .slm file + S32 mLocalID; + protected: void addVolumeFacesFromDomMesh(domMesh* mesh); virtual BOOL createVolumeFacesFromFile(const std::string& file_name); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index ce977b33bb..04dfcac20b 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -90,6 +90,7 @@ #include "llbutton.h" #include "llcheckboxctrl.h" #include "llradiogroup.h" +#include "llsdserialize.h" #include "llsliderctrl.h" #include "llspinctrl.h" #include "lltoggleablemenu.h" @@ -2561,6 +2562,71 @@ void LLModelPreview::rebuildUploadData() } +void LLModelPreview::saveUploadData(bool save_skinweights, bool save_joint_positions) +{ + if (!mLODFile[LLModel::LOD_HIGH].empty()) + { + std::string filename = mLODFile[LLModel::LOD_HIGH]; + + std::string::size_type i = filename.rfind("."); + if (i != std::string::npos) + { + filename.replace(i, filename.size()-1, ".slm"); + saveUploadData(filename, save_skinweights, save_joint_positions); + } + } +} + +void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions) +{ + std::set > meshes; + std::map mesh_binary; + + LLModel::hull empty_hull; + + LLSD data; + + S32 mesh_id = 0; + + //build list of unique models and initialize local id + for (U32 i = 0; i < mUploadData.size(); ++i) + { + LLModelInstance& instance = mUploadData[i]; + + if (meshes.find(instance.mModel) == meshes.end()) + { + instance.mModel->mLocalID = mesh_id++; + meshes.insert(instance.mModel); + + std::stringstream str; + + LLModel::convex_hull_decomposition& decomp = + instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? + instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : + instance.mModel->mConvexHullDecomp; + + LLModel::writeModel(str, + instance.mLOD[LLModel::LOD_PHYSICS], + instance.mLOD[LLModel::LOD_HIGH], + instance.mLOD[LLModel::LOD_MEDIUM], + instance.mLOD[LLModel::LOD_LOW], + instance.mLOD[LLModel::LOD_IMPOSTOR], + decomp, + empty_hull, save_skinweights, save_joint_positions); + + data["mesh"][instance.mModel->mLocalID] = str.str(); + } + + data["instance"][i] = instance.asLLSD(); + } + + llofstream out(filename, std::ios_base::out | std::ios_base::binary); + LLSDSerialize::toBinary(data, out); + out.flush(); + out.close(); +} + + void LLModelPreview::clearModel(S32 lod) { @@ -4317,8 +4383,13 @@ void LLFloaterModelPreview::onUpload(void* user_data) mp->mModelPreview->rebuildUploadData(); + bool upload_skinweights = mp->childGetValue("upload_skin").asBoolean(); + bool upload_joint_positions = mp->childGetValue("upload_joints").asBoolean(); + + mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions); + gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, - mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); + mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions); mp->closeFloater(false); } diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 910a45f9fe..5efac91ba3 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -288,6 +288,8 @@ public: void clearMaterials(); U32 calcResourceCost(); void rebuildUploadData(); + void saveUploadData(bool save_skinweights, bool save_joint_poisitions); + void saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_poisitions); void clearIncompatible(S32 lod); void updateStatusMessages(); void clearGLODGroup(); @@ -332,7 +334,7 @@ public: std::string mLODFile[LLModel::NUM_LODS]; bool mLoading; U32 mLoadState; - + std::map mViewOption; //GLOD object parameters (must rebuild object if these change) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 93e773d33b..47dc343f5e 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3584,3 +3584,30 @@ void LLPhysicsDecomp::Request::setStatusMessage(const std::string& msg) mStatusMessage = msg; } +LLSD LLModelInstance::asLLSD() +{ + LLSD ret; + + ret["mesh_id"] = mModel->mLocalID; + ret["label"] = mLabel; + ret["transform"] = mTransform.getValue(); + + for (U32 i = 0; i < mMaterial.size(); ++i) + { + ret["material"][i] = mMaterial[i].asLLSD(); + } + + return ret; +} + +LLSD LLImportMaterial::asLLSD() +{ + LLSD ret; + + ret["diffuse"]["filename"] = mDiffuseMapFilename; + ret["diffuse"]["label"] = mDiffuseMapLabel; + ret["diffuse"]["color"] = mDiffuseColor.getValue(); + ret["fullbright"] = mFullbright; + + return ret; +} diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index ccdcc03310..4d727bf1f2 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -101,6 +101,8 @@ public: { mDiffuseColor.set(1,1,1,1); } + + LLSD asLLSD(); }; class LLModelInstance @@ -120,6 +122,8 @@ public: : mModel(model), mLabel(label), mTransform(transform), mMaterial(materials) { } + + LLSD asLLSD(); }; class LLMeshSkinInfo -- cgit v1.2.3 From a2bcd2a872785ed6474268eaf9568c004dc639f5 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Mon, 21 Mar 2011 16:40:23 -0600 Subject: fix for SH-1162: [regression] Mesh Viewer Crashes on Enabling Lighting and Shadows --- indra/newview/lldrawpoolbump.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index bbce847fdc..0a642f494b 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -646,8 +646,6 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi break; } - llassert(bump); - if (bump) { if (channel == -2) -- cgit v1.2.3 From 6ff87e2840c585711e2927028a11ba5ce78a192a Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 22 Mar 2011 17:23:48 -0500 Subject: SH-1169 Import from slm instead of dae when appropriate. --- indra/llmath/llvolume.cpp | 34 ++--- indra/newview/app_settings/settings.xml | 11 ++ indra/newview/llfloatermodelpreview.cpp | 226 ++++++++++++++++++++++++++++---- indra/newview/llfloatermodelpreview.h | 2 + indra/newview/llmeshrepository.cpp | 22 ++++ indra/newview/llmeshrepository.h | 6 + 6 files changed, 252 insertions(+), 49 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index c4be176353..7a2f06da8f 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2162,7 +2162,7 @@ BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) LLSD header; { - if (!LLSDSerialize::deserialize(header, is, 1024*1024*1024)) + if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024)) { llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl; return FALSE; @@ -2174,34 +2174,18 @@ BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) "lowest_lod", "low_lod", "medium_lod", - "high_lod" + "high_lod", + "physics_shape", }; - S32 lod = llclamp((S32) mDetail, 0, 3); + const S32 MODEL_LODS = 5; - while (lod < 4 && - (header[nm[lod]]["offset"].asInteger() == -1 || - header[nm[lod]]["size"].asInteger() == 0 )) - { - ++lod; - } - - if (lod >= 4) - { - lod = llclamp((S32) mDetail, 0, 3); + S32 lod = llclamp((S32) mDetail, 0, MODEL_LODS); - while (lod >= 0 && - (header[nm[lod]]["offset"].asInteger() == -1 || - header[nm[lod]]["size"].asInteger() == 0) ) - { - --lod; - } - - if (lod < 0) - { - llwarns << "Mesh header missing LOD offsets. Not a valid mesh asset!" << llendl; - return FALSE; - } + if (header[nm[lod]]["offset"].asInteger() == -1 || + header[nm[lod]]["size"].asInteger() == 0 ) + { //cannot load requested LOD + return FALSE; } is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur); diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e27397ab1a..c11de57c42 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5523,6 +5523,17 @@ Value 1 + MeshImportUseSLM + + Comment + Use cached copy of last upload for a dae if available instead of loading dae file from scratch. + Persist + 1 + Type + Boolean + Value + 0 + MigrateCacheDirectory Comment diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 04dfcac20b..6145c6c16d 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -82,6 +82,7 @@ #include "llvoavatarself.h" #include "pipeline.h" #include "lluictrlfactory.h" +#include "llviewercontrol.h" #include "llviewermenu.h" #include "llviewermenufile.h" #include "llviewerregion.h" @@ -1088,8 +1089,15 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev if (mPreview) { + //only try to load from slm if viewer is configured to do so and this is the + //initial model load (not an LoD or physics shape) + mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mBaseModel.empty(); mPreview->setLoadState(STARTING); } + else + { + mTrySLM = false; + } } void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) @@ -1167,6 +1175,38 @@ void LLModelLoader::run() bool LLModelLoader::doLoadModel() { + //first, look for a .slm file of the same name that was modified later + //than the .dae + + if (mTrySLM) + { + std::string filename = mFilename; + + std::string::size_type i = filename.rfind("."); + if (i != std::string::npos) + { + filename.replace(i, filename.size()-1, ".slm"); + llstat slm_status; + if (LLFile::stat(filename, &slm_status) == 0) + { //slm file exists + llstat dae_status; + if (LLFile::stat(mFilename, &dae_status) != 0 || + dae_status.st_mtime < slm_status.st_mtime) + { + if (loadFromSLM(filename)) + { //slm successfully loaded, if this fails, fall through and + //try loading from dae + + mLod = -1; //successfully loading from an slm implicitly sets all + //LoDs + return true; + } + } + } + } + } + + //no suitable slm exists, load from the .dae file DAE dae; domCOLLADA* dom = dae.open(mFilename); @@ -1744,6 +1784,91 @@ void LLModelLoader::setLoadState(U32 state) } } +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, 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]; + + 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 loaded_model = new LLModel(volume_params, (F32) lod); + if (loaded_model->createVolumeFacesFromStream(str)) + { + loaded_model->mLocalID = i; + model[lod].push_back(loaded_model); + } + else + { + llassert(model[lod].empty()); + } + } + } + + 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; + + for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + if (!model[lod].empty()) + { + instance_list[i].mLOD[lod] = model[lod][idx]; + } + } + + instance_list[i].mModel = model[LLModel::LOD_HIGH][idx]; + } + + + //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, mExtents[0], mExtents[1], mFirstTransform); + } + + return true; +} + void LLModelLoader::loadModelCallback() { if (mPreview) @@ -2614,6 +2739,7 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw decomp, empty_hull, save_skinweights, save_joint_positions); + data["mesh"][instance.mModel->mLocalID] = str.str(); } @@ -2626,8 +2752,6 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw out.close(); } - - void LLModelPreview::clearModel(S32 lod) { if (lod < 0 || lod > LLModel::LOD_PHYSICS) @@ -2769,39 +2893,93 @@ void LLModelPreview::loadModelCallback(S32 lod) } mModelLoader->loadTextures() ; - mModel[lod] = mModelLoader->mModelList; - mScene[lod] = mModelLoader->mScene; - mVertexBuffer[lod].clear(); - if (lod == LLModel::LOD_PHYSICS) - { - mPhysicsMesh.clear(); - } + if (lod == -1) + { //populate all LoDs from model loader scene + mBaseModel.clear(); + mBaseScene.clear(); - setPreviewLOD(lod); + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { //for each LoD + //clear scene and model info + mScene[lod].clear(); + mModel[lod].clear(); + mVertexBuffer[lod].clear(); + + if (mModelLoader->mScene.begin()->second[0].mLOD[lod].notNull()) + { //if this LoD exists in the loaded scene - if (lod == LLModel::LOD_HIGH) - { //save a copy of the highest LOD for automatic LOD manipulation - if (mBaseModel.empty()) - { //first time we've loaded a model, auto-gen LoD - mGenLOD = true; + //copy scene to current LoD + mScene[lod] = mModelLoader->mScene; + + //touch up copied scene to look like current LoD + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + LLModelLoader::model_instance_list& list = iter->second; + + for (LLModelLoader::model_instance_list::iterator list_iter = list.begin(); list_iter != list.end(); ++list_iter) + { + //override displayed model with current LoD + list_iter->mModel = list_iter->mLOD[lod]; + + //add current model to current LoD's model list (LLModel::mLocalID makes a good vector index) + S32 idx = list_iter->mModel->mLocalID; + + if (mModel[lod].size() <= idx) + { //stretch model list to fit model at given index + mModel[lod].resize(idx+1); + } + + mModel[lod][idx] = list_iter->mModel; + } + } + } } - mBaseModel = mModel[lod]; - clearGLODGroup(); + //copy high lod to base scene for LoD generation + mBaseScene = mScene[LLModel::LOD_HIGH]; + mBaseModel = mModel[LLModel::LOD_HIGH]; - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); + mDirty = true; + resetPreviewTarget(); } + else + { //only replace given LoD + mModel[lod] = mModelLoader->mModelList; + mScene[lod] = mModelLoader->mScene; + mVertexBuffer[lod].clear(); - clearIncompatible(lod); + if (lod == LLModel::LOD_PHYSICS) + { + mPhysicsMesh.clear(); + } - mDirty = true; + setPreviewLOD(lod); - if (lod == LLModel::LOD_HIGH) - { - resetPreviewTarget(); + + if (lod == LLModel::LOD_HIGH) + { //save a copy of the highest LOD for automatic LOD manipulation + if (mBaseModel.empty()) + { //first time we've loaded a model, auto-gen LoD + mGenLOD = true; + } + + mBaseModel = mModel[lod]; + clearGLODGroup(); + + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + } + + clearIncompatible(lod); + + mDirty = true; + + if (lod == LLModel::LOD_HIGH) + { + resetPreviewTarget(); + } } mLoading = false; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 5efac91ba3..68fa0fa4c1 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -76,6 +76,7 @@ public: LLMatrix4 mTransform; BOOL mFirstTransform; LLVector3 mExtents[2]; + bool mTrySLM; std::map > mModel; @@ -97,6 +98,7 @@ public: virtual void run(); bool doLoadModel(); + bool loadFromSLM(const std::string& filename); void loadModelCallback(); void loadTextures() ; //called in the main thread. diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 47dc343f5e..a227627bc1 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3584,6 +3584,19 @@ void LLPhysicsDecomp::Request::setStatusMessage(const std::string& msg) mStatusMessage = msg; } +LLModelInstance::LLModelInstance(LLSD& data) +{ + mLocalMeshID = data["mesh_id"].asInteger(); + mLabel = data["label"].asString(); + mTransform.setValue(data["transform"]); + + for (U32 i = 0; i < data["material"].size(); ++i) + { + mMaterial.push_back(LLImportMaterial(data["material"][i])); + } +} + + LLSD LLModelInstance::asLLSD() { LLSD ret; @@ -3600,6 +3613,15 @@ LLSD LLModelInstance::asLLSD() return ret; } +LLImportMaterial::LLImportMaterial(LLSD& data) +{ + mDiffuseMapFilename = data["diffuse"]["filename"].asString(); + mDiffuseMapLabel = data["diffuse"]["label"].asString(); + mDiffuseColor.setValue(data["diffuse"]["color"]); + mFullbright = data["fullbright"].asBoolean(); +} + + LLSD LLImportMaterial::asLLSD() { LLSD ret; diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 4d727bf1f2..f0c0f308d5 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -102,6 +102,8 @@ public: mDiffuseColor.set(1,1,1,1); } + LLImportMaterial(LLSD& data); + LLSD asLLSD(); }; @@ -114,6 +116,7 @@ public: std::string mLabel; LLUUID mMeshID; + S32 mLocalMeshID; LLMatrix4 mTransform; std::vector mMaterial; @@ -121,8 +124,11 @@ public: LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::vector& materials) : mModel(model), mLabel(label), mTransform(transform), mMaterial(materials) { + mLocalMeshID = -1; } + LLModelInstance(LLSD& data); + LLSD asLLSD(); }; -- cgit v1.2.3 From a2c659378b8b7c8a4128c61b5cde91eccc9db4e6 Mon Sep 17 00:00:00 2001 From: Leyla Farazha Date: Wed, 23 Mar 2011 11:35:07 -0700 Subject: SH-1203 Remove "meshes" folder from inventory --- indra/newview/llinventorymodel.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 53835f0166..4cf2e723ec 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -631,6 +631,12 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) return mask; } + // We're hiding mesh types + if (item->getType() == LLAssetType::AT_MESH) + { + return mask; + } + LLViewerInventoryItem* old_item = getItem(item->getUUID()); LLPointer new_item; if(old_item) @@ -1272,6 +1278,12 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category) //llinfos << "LLInventoryModel::addCategory()" << llendl; if(category) { + // We aren't displaying the Meshes folder + if (category->mPreferredType == LLFolderType::FT_MESH) + { + return; + } + // try to localize default names first. See EXT-8319, EXT-7051. category->localizeName(); -- cgit v1.2.3 From e711e8af3d5f560fd93334d44eb7be1e01f02bec Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 23 Mar 2011 17:33:53 -0400 Subject: SH-1168 WIP: Disable SLM save if MeshImportUseSLM not set --- indra/newview/llfloatermodelpreview.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6145c6c16d..10f53dab01 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2704,6 +2704,11 @@ void LLModelPreview::saveUploadData(bool save_skinweights, bool save_joint_posit void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions) { + if (!gSavedSettings.getBOOL("MeshImportUseSLM")) + { + return; + } + std::set > meshes; std::map mesh_binary; -- cgit v1.2.3 From d2bb490702921b5ca9fdcd562c67844e2d4802e1 Mon Sep 17 00:00:00 2001 From: prep Date: Thu, 24 Mar 2011 09:48:34 -0400 Subject: Crash fix for SH-1176 and WIP for pelvis z offset --- indra/newview/llfloatermodelpreview.cpp | 20 ++++++++++++++------ indra/newview/llmeshrepository.cpp | 2 +- indra/newview/llvoavatar.cpp | 20 +++++++++++++++++++- indra/newview/llvoavatar.h | 1 + .../skins/default/xui/en/floater_model_preview.xml | 2 +- 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6145c6c16d..2587ab69c3 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1873,8 +1873,7 @@ void LLModelLoader::loadModelCallback() { if (mPreview) { - mPreview->loadModelCallback(mLod); - mPreview->mModelLoader = NULL; + mPreview->loadModelCallback(mLod); } while (!isStopped()) @@ -2494,8 +2493,13 @@ U32 LLModelPreview::calcResourceCost() U32 num_hulls = 0; F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f; - mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 32.0f; - + mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 8.0f; + + //if ( mFMP && mFMP->childGetValue("upload_joints").asBoolean() ) + //{ + // gAgentAvatarp->setPelvisOffset( mPelvisZOffset ); + //} + F32 streaming_cost = 0.f; F32 physics_cost = 0.f; for (U32 i = 0; i < mUploadData.size(); ++i) @@ -2990,8 +2994,12 @@ void LLModelPreview::loadModelCallback(S32 lod) void LLModelPreview::resetPreviewTarget() { - mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; - mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; + if ( mModelLoader ) + { + mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; + mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; + } + setPreviewTarget(mPreviewScale.magVec()*2.f); } diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index a227627bc1..60cbdcc98b 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1179,7 +1179,7 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 LLSD decomp; if (data_size > 0) - { + { std::string res_str((char*) data, data_size); std::istringstream stream(res_str); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 5f0e4bcded..7468281f65 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1333,7 +1333,17 @@ const LLVector3 LLVOAvatar::getRenderPosition() const } else if (isRoot()) { - return mDrawable->getPositionAgent(); + if ( !mHasPelvisOffset ) + { + return mDrawable->getPositionAgent(); + } + else + { + //Apply a pelvis fixup (as defined by the avs skin) + LLVector3 pos = mDrawable->getPositionAgent(); + pos[VZ] += mPelvisFixup; + return pos; + } } else { @@ -3810,6 +3820,14 @@ void LLVOAvatar::postPelvisSetRecalc( void ) updateHeadOffset(); } //------------------------------------------------------------------------ +// pelisPoke +//------------------------------------------------------------------------ +void LLVOAvatar::setPelvisOffset( F32 pelvisFixupAmount ) +{ + mHasPelvisOffset = true; + mPelvisFixup = pelvisFixupAmount; +} +//------------------------------------------------------------------------ // updateVisibility() //------------------------------------------------------------------------ void LLVOAvatar::updateVisibility() diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 7209b9f1e5..1552532a97 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -295,6 +295,7 @@ public: void setPelvisOffset( bool hasOffset, const LLVector3& translation, F32 offset ) ; bool hasPelvisOffset( void ) { return mHasPelvisOffset; } void postPelvisSetRecalc( void ); + void setPelvisOffset( F32 pelvixFixupAmount ); bool mHasPelvisOffset; LLVector3 mPelvisOffset; diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index e79dfcbc7d..5a726d1821 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -393,7 +393,7 @@ Pelvis Offset: - + -- cgit v1.2.3 From 673801e6448baefb2328fc50596f6156abb0b1e6 Mon Sep 17 00:00:00 2001 From: Leyla Farazha Date: Thu, 24 Mar 2011 12:31:24 -0700 Subject: SH-1205 Lock out ability to change sculpt stitching type or sculpt map when sculpt stitching type is set to mesh --- indra/newview/llfloatertools.cpp | 4 +++- indra/newview/llpanelobject.cpp | 14 +++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 257970aaaf..73c1f99fa0 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -787,7 +787,9 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) getChildView("Strength:")->setVisible( land_visible); } - bool show_mesh_cost = !gAgent.getRegion()->getCapability("GetMesh").empty() && gSavedSettings.getBOOL("MeshEnabled"); + bool show_mesh_cost = gAgent.getRegion() && + !gAgent.getRegion()->getCapability("GetMesh").empty() && + gSavedSettings.getBOOL("MeshEnabled"); getChildView("obj_count")->setVisible( !land_visible && !show_mesh_cost); getChildView("prim_count")->setVisible( !land_visible && !show_mesh_cost); diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 0300ea0c92..05e185dcfd 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1140,6 +1140,8 @@ void LLPanelObject::getState( ) if (selected_item == MI_SCULPT) { + + LLUUID id; LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); @@ -1169,10 +1171,12 @@ void LLPanelObject::getState( ) BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; isMesh = (sculpt_stitching == LL_SCULPT_TYPE_MESH); + mComboBaseType->setEnabled(!isMesh); + if (mCtrlSculptType) { mCtrlSculptType->setCurrentByIndex(sculpt_stitching); - mCtrlSculptType->setEnabled(editable); + mCtrlSculptType->setEnabled(editable && !isMesh); } if (mCtrlSculptMirror) @@ -1924,6 +1928,7 @@ void LLPanelObject::refresh() } bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && + gAgent.getRegion() && !gAgent.getRegion()->getCapability("GetMesh").empty(); getChildView("label physicsshapetype")->setVisible(enable_mesh); @@ -1940,15 +1945,14 @@ void LLPanelObject::refresh() getChild("Scale Y")->setMaxValue(max_scale); getChild("Scale Z")->setMaxValue(max_scale); - LLComboBox* sculpt_combo = getChild("sculpt type control"); - BOOL found = sculpt_combo->itemExists("Mesh"); + BOOL found = mCtrlSculptType->itemExists("Mesh"); if (enable_mesh && !found) { - sculpt_combo->add("Mesh"); + mCtrlSculptType->add("Mesh"); } else if (!enable_mesh && found) { - sculpt_combo->remove("Mesh"); + mCtrlSculptType->remove("Mesh"); } } -- cgit v1.2.3 From 971eac1aa26fecaf6a8bbb7ca568ed400866c197 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Fri, 25 Mar 2011 14:04:52 -0600 Subject: fix for SH-838: Crash if exit during mesh upload --- indra/newview/llmeshrepository.cpp | 70 +++++++++++++++++++++++++++++++++----- indra/newview/llmeshrepository.h | 6 ++-- 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 60cbdcc98b..a2792bcdc6 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -28,7 +28,7 @@ #include "apr_pools.h" #include "apr_dso.h" - +#include "llhttpstatuscodes.h" #include "llmeshrepository.h" #include "llagent.h" @@ -291,17 +291,21 @@ public: } else { - llwarns << status << ": " << reason << llendl; - llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl; + llwarns << status << ": " << reason << llendl; - if (status == 499) + if (status == HTTP_INTERNAL_ERROR) { + llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl; mThread->uploadModel(mData); } - else if (status == 400) + else if (status == HTTP_BAD_REQUEST) { llwarns << "Status 400 received from server, giving up." << llendl; } + else if (status == HTTP_NOT_FOUND) + { + llwarns <<"Status 404 received, server is disconnected, giving up." << llendl ; + } else { llerrs << "Unhandled status " << status << llendl; @@ -1381,7 +1385,8 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints) -: LLThread("mesh upload") +: LLThread("mesh upload"), + mDiscarded(FALSE) { mInstanceList = data; mUploadTextures = upload_textures; @@ -1475,8 +1480,26 @@ void LLMeshUploadThread::preStart() } } +void LLMeshUploadThread::discard() +{ + LLMutexLock lock(mMutex) ; + mDiscarded = TRUE ; +} + +BOOL LLMeshUploadThread::isDiscarded() +{ + LLMutexLock lock(mMutex) ; + return mDiscarded ; +} + void LLMeshUploadThread::run() { + if(isDiscarded()) + { + mFinished = true; + return ; + } + mCurlRequest = new LLCurlRequest(); std::set textures; @@ -1605,7 +1628,7 @@ void LLMeshUploadThread::run() tcount = llmin(count+PUSH_PER_PROCESS, 100); - while (!mInstanceQ.empty() && count < tcount) + while (!mInstanceQ.empty() && count < tcount && !isDiscarded()) { //create any objects waiting for upload count++; object_asset["objects"].append(createObject(mInstanceQ.front())); @@ -1614,7 +1637,7 @@ void LLMeshUploadThread::run() mCurlRequest->process(); - done = mInstanceQ.empty() && mConfirmedQ.empty() && mUploadQ.empty(); + done = isDiscarded() || (mInstanceQ.empty() && mConfirmedQ.empty() && mUploadQ.empty()); } while (!done || mCurlRequest->getQueued() > 0); @@ -1629,7 +1652,10 @@ void LLMeshUploadThread::run() object_asset["permissions"] = object_asset["objects"][0]["permissions"]; } - LLHTTPClient::post(url, object_asset, new LLHTTPClient::Responder()); + if(!isDiscarded()) + { + LLHTTPClient::post(url, object_asset, new LLHTTPClient::Responder()); + } mFinished = true; } @@ -2132,6 +2158,12 @@ void LLMeshRepository::shutdown() { llinfos << "Shutting down mesh repository." << llendl; + for (U32 i = 0; i < mUploads.size(); ++i) + { + llinfos << "Discard the pending mesh uploads " << llendl; + mUploads[i]->discard() ; //discard the uploading requests. + } + mThread->mSignal->signal(); while (!mThread->isStopped()) @@ -2750,6 +2782,11 @@ S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod) void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data) { + if(isDiscarded()) + { + return ; + } + //write model file to memory buffer std::stringstream ostr; @@ -2808,6 +2845,11 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data) void LLMeshUploadThread::sendCostRequest(LLTextureUploadData& data) { + if(isDiscarded()) + { + return ; + } + if (data.mTexture && data.mTexture->getDiscardLevel() >= 0) { LLSD asset_resources = LLSD::emptyMap(); @@ -2840,6 +2882,11 @@ void LLMeshUploadThread::sendCostRequest(LLTextureUploadData& data) void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data) { + if(isDiscarded()) + { + return ; + } + if (!data.mRSVP.empty()) { std::stringstream ostr; @@ -2872,6 +2919,11 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data) void LLMeshUploadThread::doUploadTexture(LLTextureUploadData& data) { + if(isDiscarded()) + { + return ; + } + if (!data.mRSVP.empty()) { std::stringstream ostr; diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index f0c0f308d5..4e349a1270 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -405,11 +405,12 @@ public: S32 mPendingConfirmations; S32 mPendingUploads; S32 mPendingCost; - bool mFinished; LLVector3 mOrigin; + bool mFinished; bool mUploadTextures; bool mUploadSkin; bool mUploadJoints; + BOOL mDiscarded ; LLHost mHost; std::string mUploadObjectAssetCapability; @@ -445,7 +446,8 @@ public: bool finished() { return mFinished; } virtual void run(); void preStart(); - + void discard() ; + BOOL isDiscarded(); }; class LLMeshRepository -- cgit v1.2.3 From 3528753a3a5e2f569872c49cdf6154833f483245 Mon Sep 17 00:00:00 2001 From: Leyla Farazha Date: Fri, 25 Mar 2011 14:10:35 -0700 Subject: SH-1104 Add additional panel before review step. --- indra/newview/llfloatermodelpreview.cpp | 5 +- indra/newview/llfloatermodelwizard.cpp | 33 ++++- indra/newview/llfloatermodelwizard.h | 1 + .../skins/default/xui/en/floater_model_wizard.xml | 150 ++++++++++++++++++++- 4 files changed, 183 insertions(+), 6 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 2587ab69c3..254f9f8a5e 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -4518,9 +4518,12 @@ void LLModelPreview::setPreviewLOD(S32 lod) mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); - // the wizard has two lod drop downs + // the wizard has three lod drop downs LLComboBox* combo_box2 = mFMP->getChild("preview_lod_combo2"); combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order + + LLComboBox* combo_box3 = mFMP->getChild("preview_lod_combo3"); + combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); diff --git a/indra/newview/llfloatermodelwizard.cpp b/indra/newview/llfloatermodelwizard.cpp index eafea1fe03..ad6e4ebe9c 100644 --- a/indra/newview/llfloatermodelwizard.cpp +++ b/indra/newview/llfloatermodelwizard.cpp @@ -46,6 +46,7 @@ static const std::string stateNames[]={ "choose_file", "optimize", "physics", + "physics2", "review", "upload"}; @@ -58,6 +59,7 @@ LLFloaterModelWizard::LLFloaterModelWizard(const LLSD& key) mCommitCallbackRegistrar.add("Wizard.Choose", boost::bind(&LLFloaterModelWizard::setState, this, CHOOSE_FILE)); mCommitCallbackRegistrar.add("Wizard.Optimize", boost::bind(&LLFloaterModelWizard::setState, this, OPTIMIZE)); mCommitCallbackRegistrar.add("Wizard.Physics", boost::bind(&LLFloaterModelWizard::setState, this, PHYSICS)); + mCommitCallbackRegistrar.add("Wizard.Physics2", boost::bind(&LLFloaterModelWizard::setState, this, PHYSICS2)); mCommitCallbackRegistrar.add("Wizard.Review", boost::bind(&LLFloaterModelWizard::setState, this, REVIEW)); mCommitCallbackRegistrar.add("Wizard.Upload", boost::bind(&LLFloaterModelWizard::setState, this, UPLOAD)); } @@ -125,15 +127,29 @@ void LLFloaterModelWizard::setState(int state) getChildView("cancel")->setVisible(true); } - if (state == REVIEW) + if (state == PHYSICS2) { if (mLastEnabledState < state) { executePhysicsStage("Decompose"); } - + mModelPreview->mViewOption["show_physics"] = true; + getChildView("next")->setVisible(true); + getChildView("next")->setEnabled(true); + getChildView("upload")->setVisible(false); + getChildView("close")->setVisible(false); + getChildView("back")->setVisible(true); + getChildView("back")->setEnabled(true); + getChildView("cancel")->setVisible(true); + } + + if (state == REVIEW) + { + + mModelPreview->mViewOption["show_physics"] = false; + getChildView("close")->setVisible(false); getChildView("next")->setVisible(false); getChildView("back")->setVisible(true); @@ -182,6 +198,18 @@ void LLFloaterModelWizard::updateButtons() button->setEnabled(FALSE); } } + + LLButton *physics_button = getChild(stateNames[PHYSICS]+"_btn"); + + if (mState == PHYSICS2) + { + physics_button->setVisible(false); + } + else + { + physics_button->setVisible(true); + } + } void LLFloaterModelWizard::loadModel() @@ -486,6 +514,7 @@ BOOL LLFloaterModelWizard::postBuild() getChild("next")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickNext, this)); getChild("preview_lod_combo")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1)); getChild("preview_lod_combo2")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1)); + getChild("preview_lod_combo3")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1)); getChild("accuracy_slider")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onAccuracyPerformance, this, _2)); getChild("upload")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onUpload, this)); getChild("physics_slider")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPhysicsChanged, this)); diff --git a/indra/newview/llfloatermodelwizard.h b/indra/newview/llfloatermodelwizard.h index 50e4ab1a96..b166d26295 100644 --- a/indra/newview/llfloatermodelwizard.h +++ b/indra/newview/llfloatermodelwizard.h @@ -80,6 +80,7 @@ private: CHOOSE_FILE = 0, OPTIMIZE, PHYSICS, + PHYSICS2, REVIEW, UPLOAD }; diff --git a/indra/newview/skins/default/xui/en/floater_model_wizard.xml b/indra/newview/skins/default/xui/en/floater_model_wizard.xml index f133d75eee..a6dd6c099d 100644 --- a/indra/newview/skins/default/xui/en/floater_model_wizard.xml +++ b/indra/newview/skins/default/xui/en/floater_model_wizard.xml @@ -45,6 +45,24 @@ +