diff options
Diffstat (limited to 'indra')
78 files changed, 2849 insertions, 510 deletions
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 1f578eec5f..127b62f424 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 @@ -207,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}") 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 6d5b12d840..3ea742957e 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -94,6 +94,8 @@ LLAssetDictionary::LLAssetDictionary() addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "symbolic link", FALSE)); addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "symbolic folder link", FALSE)); + addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", FALSE)); + addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE)); }; diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index c7bbc2e74a..3304258000 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -114,8 +114,11 @@ public: AT_LINK_FOLDER = 25, // Inventory folder link - - AT_COUNT = 26, + + AT_MESH = 49, + // Mesh data in our proprietary SLM format + + AT_COUNT = 50, // +*********************************************************+ // | TO ADD AN ELEMENT TO THIS ENUM: | diff --git a/indra/llcommon/llfoldertype.cpp b/indra/llcommon/llfoldertype.cpp index 079e670b1a..b5e1977cf0 100644 --- a/indra/llcommon/llfoldertype.cpp +++ b/indra/llcommon/llfoldertype.cpp @@ -90,6 +90,9 @@ LLFolderDictionary::LLFolderDictionary() addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE)); addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE)); addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE)); + + addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE)); + addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE)); addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE)); diff --git a/indra/llcommon/llfoldertype.h b/indra/llcommon/llfoldertype.h index 7aa77f7f7e..409112a04e 100644 --- a/indra/llcommon/llfoldertype.h +++ b/indra/llcommon/llfoldertype.h @@ -86,9 +86,11 @@ public: FT_OUTFIT = 47, FT_MY_OUTFITS = 48, - FT_INBOX = 49, + FT_MESH = 49, - FT_COUNT = 50, + FT_INBOX = 50, + + FT_COUNT = 51, FT_NONE = -1 }; diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 37370e44e7..b1175836b7 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 4ef5df0b28..c268625064 100644 --- a/indra/llinventory/llinventorytype.cpp +++ b/indra/llinventory/llinventorytype.cpp @@ -89,6 +89,8 @@ 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_MESH, new InventoryEntry("mesh", "mesh", 1, LLAssetType::AT_MESH)); + } @@ -123,6 +125,33 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] = LLInventoryType::IT_NONE, // AT_LINK LLInventoryType::IT_NONE, // AT_LINK_FOLDER + + 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/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h index e515b8a304..af426b9007 100644 --- a/indra/llinventory/llinventorytype.h +++ b/indra/llinventory/llinventorytype.h @@ -67,7 +67,9 @@ public: IT_WEARABLE = 18, IT_ANIMATION = 19, IT_GESTURE = 20, - IT_COUNT = 21, + + IT_MESH = 22, + IT_COUNT = 23, IT_NONE = -1 }; diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index df4c618ac1..fb2de92e35 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 @@ -1673,7 +1676,9 @@ 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 if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE) { @@ -1688,7 +1693,8 @@ 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 +1845,424 @@ 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 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) +{ + 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 << "Mesh header parse error. 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 || + 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; + } + } + + 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(); + + if (face_count == 0) + { + llerrs << "WTF?" << llendl; + } + + 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() || face.mIndices.size() < 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) + { + 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 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; +} + +BOOL LLVolume::isTetrahedron() +{ + return mIsTetrahedron; +} + +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) + }; + + face.mExtents[0].setVec(-x,-x,-x); + face.mExtents[1].setVec(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; + mIsTetrahedron = TRUE; +} + +void LLVolume::copyVolumeFaces(LLVolume* volume) +{ + mVolumeFaces = volume->mVolumeFaces; + mSculptLevel = 0; + mIsTetrahedron = FALSE; +} + + +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 +2288,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 +2336,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 @@ -2198,6 +2631,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) @@ -2309,7 +2747,6 @@ bool LLVolumeParams::operator<(const LLVolumeParams ¶ms) const return mSculptID < params.mSculptID; } - return mSculptType < params.mSculptType; @@ -3379,22 +3816,29 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &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 +4038,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 +4549,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 +4578,8 @@ bool LLVolumeParams::fromLLSD(LLSD& sd) { mPathParams.fromLLSD(sd["path"]); mProfileParams.fromLLSD(sd["profile"]); + sculptFromLLSD(sd["sculpt"]); + return true; } @@ -4157,6 +4622,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 +5482,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..59c60ccd92 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -186,9 +186,13 @@ 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; +const S32 LL_SCULPT_MESH_MAX_FACES = 8; class LLProfileParams { @@ -575,6 +579,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 +641,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 +804,7 @@ public: BOOL create(LLVolume* volume, BOOL partial_build = FALSE); void createBinormals(); - + class VertexData { public: @@ -806,6 +812,10 @@ public: LLVector3 mNormal; LLVector3 mBinormal; LLVector2 mTexCoord; + + bool operator<(const VertexData& rhs) const; + bool operator==(const VertexData& rhs) const; + bool compareNormal(const VertexData& rhs, F32 angle_cutoff) const; }; enum @@ -851,8 +861,7 @@ class LLVolume : public LLRefCount { friend class LLVolumeLODGroup; -private: - LLVolume(const LLVolume&); // Don't implement +protected: ~LLVolume(); // use unref public: @@ -874,7 +883,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; } @@ -896,7 +905,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 @@ -946,6 +956,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,11 +968,17 @@ private: protected: BOOL generate(); void createVolumeFaces(); +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 53641fceab..419e0015ba 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; @@ -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/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 0ab1081200..047b99c861 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -505,7 +505,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 7332f5c954..a8d25e3b03 100644 --- a/indra/llmessage/lltransfersourceasset.cpp +++ b/indra/llmessage/lltransfersourceasset.cpp @@ -270,6 +270,7 @@ bool is_asset_fetch_by_id_allowed(LLAssetType::EType type) case LLAssetType::AT_BODYPART: case LLAssetType::AT_ANIMATION: case LLAssetType::AT_GESTURE: + case LLAssetType::AT_MESH: rv = true; break; default: @@ -294,6 +295,7 @@ bool is_asset_id_knowable(LLAssetType::EType type) case LLAssetType::AT_GESTURE: 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 68a3d54597..af78ed7936 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 @@ -34,6 +37,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 5ad758072c..4c6d244f3c 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -743,7 +743,11 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai setNumTEs(mVolumep->getNumFaces()); return TRUE; } - + +#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; @@ -941,6 +945,13 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai setTE(te_num, *(old_tes.getTexture(face_mapping[face_bit]))); } } +#else + // build the new object + sVolumeManager->unrefVolume(mVolumep); + mVolumep = volumep; + + setNumTEs(mVolumep->getNumFaces()); +#endif return TRUE; } @@ -1083,7 +1094,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) { @@ -1364,7 +1375,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/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) diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index 3643bf44f7..f9e134e1e5 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -459,3 +459,4 @@ void LLUICtrlFactory::connect(LLView* parent, LLView* child) { parent->addChild(child); } + 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 dd3fc10fa2..23f8b4b9ca 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -37,11 +37,13 @@ include(UnixInstall) include(LLKDU) include(ViewerMiscLibs) include(LLLogin) +include(GLOD) include(CMakeCopyIfDifferent) include_directories( ${DBUSGLIB_INCLUDE_DIRS} ${ELFIO_INCLUDE_DIR} + ${GLOD_INCLUDE_DIR} ${LLAUDIO_INCLUDE_DIRS} ${LLCHARACTER_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} @@ -60,6 +62,8 @@ include_directories( ${LSCRIPT_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS}/lscript_compile ${LLLOGIN_INCLUDE_DIRS} + ${LIBS_PREBUILT_DIR}/include/collada + ${LIBS_PREBUILT_DIR}/include/collada/1.4 ) set(viewer_SOURCE_FILES @@ -175,6 +179,7 @@ set(viewer_SOURCE_FILES llfloaterhelpbrowser.cpp llfloaterhud.cpp llfloaterimagepreview.cpp + llfloaterimportcollada.cpp llfloaterinspect.cpp llfloaterinventory.cpp llfloaterjoystick.cpp @@ -185,6 +190,7 @@ set(viewer_SOURCE_FILES llfloatermediabrowser.cpp llfloatermediasettings.cpp llfloatermemleak.cpp + llfloatermodelpreview.cpp llfloaternamedesc.cpp llfloaternearbymedia.cpp llfloaternotificationsconsole.cpp @@ -679,6 +685,7 @@ set(viewer_HEADER_FILES llfloaterhelpbrowser.h llfloaterhud.h llfloaterimagepreview.h + llfloaterimportcollada.h llfloaterinspect.h llfloaterinventory.h llfloaterjoystick.h @@ -689,6 +696,7 @@ set(viewer_HEADER_FILES llfloatermediabrowser.h llfloatermediasettings.h llfloatermemleak.h + llfloatermodelpreview.h llfloaternamedesc.h llfloaternearbymedia.h llfloaternotificationsconsole.h @@ -1188,6 +1196,7 @@ if (WINDOWS) ${DINPUT_LIBRARY} ${DXGUID_LIBRARY} kernel32 + libboost_system odbc32 odbccp32 ole32 @@ -1519,6 +1528,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 b301d784f9..4ed2927ce6 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7441,7 +7441,19 @@ <key>Value</key> <integer>0</integer> </map> - <key>SafeMode</key> + <key>MeshThreadCount</key> + <map> + <key>Comment</key> + <string>Number of threads to use for loading meshes.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>8</integer> + </map> + + <key>SafeMode</key> <map> <key>Comment</key> <string>Reset preferences, run in safe mode.</string> 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 1d03cc8823..6b1897d077 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -42,6 +42,7 @@ #include "llnotify.h" #include "llinventoryobserver.h" #include "llinventorypanel.h" +#include "llfloaterimportcollada.h" #include "llpermissionsflags.h" #include "llpreviewnotecard.h" #include "llpreviewscript.h" @@ -65,6 +66,7 @@ #include "llnotificationsutil.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. @@ -72,6 +74,120 @@ static const S32 FILE_COUNT_DISPLAY_THRESHOLD = 5; void dialog_refresh_all(); +static 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<LLViewerInventoryItem> 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) @@ -89,9 +205,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), @@ -139,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); @@ -197,16 +315,36 @@ 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) +{ +} + +// 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 @@ -220,95 +358,32 @@ 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); - LLNotificationsUtil::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<LLViewerInventoryItem> 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. - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); - if (active_panel) - { - active_panel->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) - { - active_panel->openSelected(); - } - //LLFloaterInventory::dumpSelectionInformation((void*)view); - // restore keyboard focus + 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); LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); - gFocusMgr.setKeyboardFocus(focus); - } - } - else - { - llwarns << "Can't find a folder to put it in" << llendl; - } - // remove the "Uploading..." message - LLUploadDialog::modalUploadFinished(); - + // continue uploading for bulk uploads + // *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,19 +400,42 @@ 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, LLFolderType::FT_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, + LLFolderType::FT_NONE, + LLInventoryType::IT_NONE, + next_owner_perms, + group_perms, + everyone_perms, + display_name, + callback, + LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(), + userdata); } + + LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], TRUE); } LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data, @@ -391,17 +489,19 @@ void LLSendTexLayerResponder::error(U32 statusNum, const std::string& reason) mBakedUploadData = NULL; // deleted in onTextureUploadComplete() } -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) { } @@ -584,3 +684,472 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content) break; } } + + +///////////////////////////////////////////////////// +// LLNewAgentInventoryVariablePriceResponder::Impl // +///////////////////////////////////////////////////// +class LLNewAgentInventoryVariablePriceResponder::Impl +{ +public: + Impl( + const LLUUID& vfile_id, + LLAssetType::EType asset_type, + const LLSD& inventory_data) : + mVFileID(vfile_id), + 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 + { + return (mFileName.empty() ? mVFileID.asString() : mFileName); + } + + LLUUID getVFileID() const + { + return mVFileID; + } + + std::string getFilename() const + { + return mFileName; + } + + LLAssetType::EType getAssetType() const + { + return mAssetType; + } + + 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 LLSD& error) + { + 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"); + } + } + + void onTransportError() + { + displayCannotUploadReason( + "The server is experiencing unexpected difficulties."); + } + + void onTransportError(const LLSD& error) + { + 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( + "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<LLNewAgentInventoryVariablePriceResponder> 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 + switch(option) + { + case 0: + { + confirmUpload(confirmation_url, responder); + } + break; + case 1: + default: + break; + } + + return false; + } + + void confirmUpload( + const std::string& confirmation_url, + boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder> 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; +}; + +/////////////////////////////////////////////// +// LLNewAgentInventoryVariablePriceResponder // +/////////////////////////////////////////////// +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); +} + +LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResponder() +{ + delete mImpl; +} + +void LLNewAgentInventoryVariablePriceResponder::errorWithContent( + U32 statusNum, + const std::string& reason, + const LLSD& content) +{ + lldebugs + << "LLNewAgentInventoryVariablePrice::error " << statusNum + << " reason: " << reason << llendl; + + if ( content.has("error") ) + { + static const std::string _ERROR = "error"; + + mImpl->onTransportError(content[_ERROR]); + } + 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 _STATE = "state"; + + static const std::string _COMPLETE = "complete"; + 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 + if ( content.has(_ERROR) ) + { + onApplicationLevelError(content[_ERROR]); + return; + } + + std::string state = content[_STATE]; + LLAssetType::EType asset_type = mImpl->getAssetType(); + + 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 ( _CONFIRM_UPLOAD == state ) + { + showConfirmationDialog( + content[_UPLOAD_PRICE].asInteger(), + content[_RESOURCE_COST].asInteger(), + content[_RSVP].asString()); + } + else + { + onApplicationLevelError(""); + } +} + +void LLNewAgentInventoryVariablePriceResponder::onApplicationLevelError( + const LLSD& error) +{ + mImpl->onApplicationLevelError(error); +} + +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! + + // 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<LLNewAgentInventoryVariablePriceResponder>(this)); + } + else + { + LLSD substitutions; + LLSD payload; + + substitutions["PRICE"] = upload_price; + + payload["confirmation_url"] = confirmation_url; + + // 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<LLNewAgentInventoryVariablePriceResponder>(this))); + } +} diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index e656351305..c869988203 100644 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -61,15 +61,60 @@ 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 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 +// 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, + LLAssetType::EType asset_type, + const LLSD& inventory_info); + + LLNewAgentInventoryVariablePriceResponder( + const std::string& file_name, + LLAssetType::EType asset_type, + 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 LLSD& error); + virtual void showConfirmationDialog( + S32 upload_price, + S32 resource_cost, + const std::string& confirmation_url); + +private: + class Impl; + Impl* mImpl; }; class LLBakedUploadData; 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 5f845c3721..4778865c4b 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 eef774426a..698d8572aa 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1057,7 +1057,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..8dfb333530 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -55,12 +55,14 @@ 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 #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 // @@ -175,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 \ @@ -193,6 +199,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; @@ -542,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) { @@ -1088,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(); @@ -1212,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 ab2455620f..10736c7dd0 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -93,6 +93,8 @@ public: FFLOAD_XML = 6, FFLOAD_SLOBJECT = 7, FFLOAD_RAW = 8, + FFLOAD_MODEL = 9, + FFLOAD_COLLADA = 10, }; enum ESaveFilter @@ -198,4 +200,6 @@ public: ~LLFilePicker(); }; +const std::string upload_pick(void* data); + #endif diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index 0b5da40be4..6ac5165bba 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 4c28d5e2df..59bfc77723 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -126,6 +126,8 @@ std::string ICON_NAME[ICON_NAME_COUNT] = "Inv_LinkItem", "Inv_LinkFolder" + + "inv_item_mesh.tga" }; // +=================================================+ @@ -880,6 +882,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; @@ -2205,6 +2215,9 @@ LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::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) @@ -2630,6 +2643,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; @@ -3574,6 +3588,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(); @@ -4822,6 +4837,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<std::string> items; + std::vector<std::string> 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); + } + + + hide_context_entries(menu, items, disabled_items); +} + + + LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_type, const LLUUID& uuid,LLInventoryModel* model) { @@ -4870,6 +4944,12 @@ LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_ break; + case LLAssetType::AT_MESH: + action = new LLMeshBridgeAction(uuid,model); + break; + + + default: break; } @@ -5107,6 +5187,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 63be9dcdb8..ce5594be84 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -82,6 +82,8 @@ enum EInventoryIcon LINKITEM_ICON_NAME, LINKFOLDER_ICON_NAME, + + MESH_ICON_NAME, ICON_NAME_COUNT }; @@ -598,7 +600,6 @@ protected: static std::string sPrefix; }; - class LLLinkFolderBridge : public LLItemBridge { friend class LLInvFVBridge; @@ -619,6 +620,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) // @@ -779,6 +799,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/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; } diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 6210973dae..516020797d 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -158,6 +158,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/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 4f8aff6f78..11c65a39f9 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -819,6 +819,7 @@ BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_ANIMATION: case DAD_GESTURE: case DAD_CALLINGCARD: + case DAD_MESH: accept = LLToolDragAndDrop::isInventoryDropAcceptable(object, (LLViewerInventoryItem*)cargo_data); if(accept && drop) { @@ -1402,6 +1403,117 @@ LLUIImagePtr LLTaskWearableBridge::getIcon() const return get_item_icon(mAssetType, LLInventoryType::IT_WEARABLE, mFlags, FALSE ); } +///---------------------------------------------------------------------------- +/// Class LLTaskMeshBridge +///---------------------------------------------------------------------------- + +class LLTaskMeshBridge : public LLTaskInvFVBridge +{ +public: + LLTaskMeshBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name); + + virtual LLUIImagePtr getIcon() const; + virtual void openItem(); + virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); +}; + +LLTaskMeshBridge::LLTaskMeshBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) +{ +} + +LLUIImagePtr LLTaskMeshBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_MESH, LLInventoryType::IT_MESH, 0, FALSE); +} + +void LLTaskMeshBridge::openItem() +{ + // open mesh +} + + +// virtual +void LLTaskMeshBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if (action == "mesh action") + { + LLInventoryItem* item = findItem(); + if(item) + { + // do action + } + } + LLTaskInvFVBridge::performAction(folder, model, action); +} + +void LLTaskMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + LLInventoryItem* item = findItem(); + if(!item) return; + std::vector<std::string> items; + std::vector<std::string> disabled_items; + + if(item->getPermissions().getOwner() != gAgent.getID() + && item->getSaleInfo().isForSale()) + { + items.push_back(std::string("Task Buy")); + + std::string label= LLTrans::getString("Buy"); + // Check the price of the item. + S32 price = getPrice(); + if (-1 == price) + { + llwarns << "label_buy_task_bridged_item: Invalid price" << llendl; + } + else + { + std::ostringstream info; + info << LLTrans::getString("BuyforL$") << price; + label.assign(info.str()); + } + + const LLView::child_list_t *list = menu.getChildList(); + LLView::child_list_t::const_iterator itor; + for (itor = list->begin(); itor != list->end(); ++itor) + { + std::string name = (*itor)->getName(); + LLMenuItemCallGL* menu_itemp = dynamic_cast<LLMenuItemCallGL*>(*itor); + if (name == "Task Buy" && menu_itemp) + { + menu_itemp->setLabel(label); + } + } + } + else + { + items.push_back(std::string("Task Open")); + if (!isItemCopyable()) + { + disabled_items.push_back(std::string("Task Open")); + } + } + items.push_back(std::string("Task Properties")); + if(isItemRenameable()) + { + items.push_back(std::string("Task Rename")); + } + if(isItemRemovable()) + { + items.push_back(std::string("Task Remove")); + } + + + hide_context_entries(menu, items, disabled_items); +} + ///---------------------------------------------------------------------------- /// LLTaskInvFVBridge impl @@ -1483,6 +1595,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: diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 1605838b94..d965b3031e 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -178,7 +178,6 @@ LLObjectSelection *get_null_object_selection() // Build time optimization, generate this function once here template class LLSelectMgr* LLSingleton<class LLSelectMgr>::getInstance(); - //----------------------------------------------------------------------------- // LLSelectMgr() //----------------------------------------------------------------------------- @@ -5322,6 +5321,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() //----------------------------------------------------------------------------- @@ -5339,6 +5410,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 6641be335a..2d377f1ec0 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 6ca6734598..6856a7d71b 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 5f7c2f5080..2180f47218 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -291,7 +291,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; @@ -1154,7 +1154,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 2d0a14dc70..03c3900235 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -387,6 +387,16 @@ LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary() addEntry(DAD_LINK, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &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() @@ -1917,6 +1927,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/llviewerassettype.cpp b/indra/newview/llviewerassettype.cpp index b382ff6306..4c088a72b7 100644 --- a/indra/newview/llviewerassettype.cpp +++ b/indra/newview/llviewerassettype.cpp @@ -85,6 +85,8 @@ LLViewerAssetDictionary::LLViewerAssetDictionary() addEntry(LLViewerAssetType::AT_LINK, new ViewerAssetEntry(DAD_LINK)); addEntry(LLViewerAssetType::AT_LINK_FOLDER, new ViewerAssetEntry(DAD_LINK)); + addEntry(LLViewerAssetType::AT_MESH, new ViewerAssetEntry(DAD_MESH)); + addEntry(LLViewerAssetType::AT_NONE, new ViewerAssetEntry(DAD_NONE)); }; diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 5b733ed817..bcb811680c 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -870,12 +870,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->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw()); - if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) { gPipeline.renderDeferredLighting(); @@ -1098,7 +1092,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 158c857031..3678c14e35 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -74,6 +74,7 @@ #include "llimpanel.h" #include "llfloaterinspect.h" #include "llfloaterinventory.h" +#include "llfloaterimportcollada.h" #include "llfloaterjoystick.h" #include "llfloaterlagmeter.h" #include "llfloaterland.h" @@ -128,6 +129,8 @@ #include "llpreviewtexture.h" #include "llsyswellwindow.h" #include "llscriptfloater.h" +#include "llfloatermodelpreview.h" + // *NOTE: Please add files in alphabetical order to keep merges easy. @@ -175,6 +178,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHUD>); LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloater>); + LLFloaterReg::add("import_collada", "floater_import_collada.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImportCollada>); LLFloaterReg::add("im_container", "floater_im_container.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloaterContainer>); LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>); LLFloaterReg::add("inventory", "floater_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInventory>); @@ -253,7 +257,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("upload_anim", "floater_animation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAnimPreview>, "upload"); LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImagePreview>, "upload"); LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundPreview>, "upload"); - + LLFloaterReg::add("upload_model", "floater_model_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterModelPreview>, "upload"); LLFloaterReg::add("volume_pulldown", "floater_volume_pulldown.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVolumePulldown>); LLFloaterReg::add("voice_controls", "floater_voice_controls.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLCallFloater>); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index e68594ed6f..10b997ae3a 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -159,7 +159,6 @@ LLMenuItemCallGL* gBusyMenu = NULL; // Local prototypes // File Menu -const char* upload_pick(void* data); void handle_compress_image(void*); @@ -440,6 +439,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<LLMenuItemCallGL>("Set Away", TRUE); gBusyMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Busy", TRUE); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 4b0dc8f668..89e16a3dd1 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -39,6 +39,8 @@ #include "llfilepicker.h" #include "llfloaterreg.h" #include "llfloaterbuycurrency.h" +#include "llfloaterimportcollada.h" +#include "llfloatermodelpreview.h" #include "llfloatersnapshot.h" #include "llinventorymodel.h" // gInventory #include "llresourcedata.h" @@ -55,7 +57,7 @@ #include "llappviewer.h" #include "lluploaddialog.h" #include "lltrans.h" - +#include "llfloaterimportcollada.h" // linden libraries #include "llassetuploadresponders.h" @@ -63,6 +65,7 @@ #include "llhttpclient.h" #include "llnotificationsutil.h" #include "llsdserialize.h" +#include "llsdutil.h" #include "llstring.h" #include "lltransactiontypes.h" #include "lluuid.h" @@ -102,6 +105,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) { @@ -116,6 +120,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; @@ -259,6 +265,33 @@ 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) + { + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::showInstance("upload_model"); + if (fmp) + { + fmp->loadModel(3); + } + + return TRUE; + } +}; + class LLFileUploadSound : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -320,10 +353,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, LLFolderType::FT_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, + LLFolderType::FT_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() @@ -492,17 +536,20 @@ void handle_compress_image(void*) } } -void upload_new_resource(const std::string& src_filename, std::string name, - std::string desc, S32 compression_info, - LLFolderType::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) +LLUUID upload_new_resource( + const std::string& src_filename, + std::string name, + std::string desc, + S32 compression_info, + LLFolderType::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(); @@ -527,7 +574,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, short_name.c_str()); args["FILE"] = short_name; upload_error(error_message, "NofileExtension", filename, args); - return; + return LLUUID(); } else if( exten == "bmp") { @@ -541,7 +588,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, args["FILE"] = src_filename; args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); - return; + return LLUUID(); } } else if( exten == "tga") @@ -556,7 +603,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, args["FILE"] = src_filename; args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); - return; + return LLUUID(); } } else if( exten == "jpg" || exten == "jpeg") @@ -571,7 +618,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, args["FILE"] = src_filename; args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); - return; + return LLUUID(); } } else if( exten == "png") @@ -586,7 +633,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, args["FILE"] = src_filename; args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); - return; + return LLUUID(); } } else if(exten == "wav") @@ -614,7 +661,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args); break; } - return; + return LLUUID(); } } else if(exten == "tmp") @@ -654,7 +701,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, 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) @@ -682,7 +729,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, 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 @@ -724,7 +771,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, 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); @@ -738,7 +785,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, { 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 { @@ -784,9 +831,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 { @@ -800,9 +859,15 @@ void upload_new_resource(const std::string& src_filename, std::string name, } LLFilePicker::instance().reset(); } + + return uuid; } -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; @@ -903,70 +968,97 @@ 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, LLFolderType::FT_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, + LLFolderType::FT_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, - LLFolderType::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) +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) - { - return ; - } + LLAssetID uuid = generate_asset_id_for_new_upload(tid); - 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 ); - } + increase_new_upload_stats(asset_type); - if(LLInventoryType::IT_NONE == inv_type) - { - inv_type = LLInventoryType::defaultForAssetType(asset_type); - } - LLStringUtil::stripNonprintable(name); - LLStringUtil::stripNonprintable(desc); - if(name.empty()) - { - name = "(No Name)"; - } - if(desc.empty()) - { - desc = "(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; +} + +LLSD generate_new_resource_upload_capability_body( + LLAssetType::EType asset_type, + const std::string& name, + const std::string& desc, + LLFolderType::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 == LLFolderType::FT_NONE) ? + (LLFolderType::EType) 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, + LLFolderType::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; @@ -976,26 +1068,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 == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(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 == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(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 { @@ -1033,18 +1131,158 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty { 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_price_resource( + const LLTransactionID &tid, + LLAssetType::EType asset_type, + std::string name, + std::string desc, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + const LLSD& asset_resources) +{ + 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 == LLFolderType::FT_NONE) ? (LLFolderType::EType)asset_type : destination_folder_type) << llendl; + lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl; + + std::string url = gAgent.getRegion()->getCapability( + "NewFileAgentInventoryVariablePrice"); + + if ( !url.empty() ) + { + lldebugs + << "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); + + body["asset_resources"] = asset_resources; + + LLHTTPClient::post( + url, + body, + new LLNewAgentInventoryVariablePriceResponder( + uuid, + asset_type, + body)); + + return TRUE; + } + else + { + return FALSE; + } +} + +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"); 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 da78537a29..800325df0b 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -41,33 +41,62 @@ class LLTransactionID; void init_menu_file(); -void upload_new_resource(const std::string& src_filename, - std::string name, - std::string desc, - S32 compression_info, - LLFolderType::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); +LLUUID upload_new_resource( + const std::string& src_filename, + std::string name, + std::string desc, + S32 compression_info, + LLFolderType::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, - LLFolderType::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, + LLFolderType::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_price_resource( + const LLTransactionID& tid, + LLAssetType::EType type, + std::string name, + std::string desc, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + 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 diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 507e34348b..f6dfe46840 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -4682,6 +4682,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 d1c9840a97..8317837520 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 e0091145ce..569ceea431 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -534,6 +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; default: llassert(0); } diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 0d29efaedf..6bd63a56e9 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -678,7 +678,7 @@ BOOL LLViewerTexture::createGLTexture(S32 discard_level, const LLImageRaw* image llassert_always(mGLTexturep.notNull()) ; BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category) ; - + if(ret) { mFullWidth = mGLTexturep->getCurrentWidth() ; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 8529a93527..a532c9da64 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -3717,140 +3717,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. diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index cf61994fea..7debfb9186 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -36,6 +36,8 @@ #include "llvovolume.h" +#include <sstream> + #include "llviewercontrol.h" #include "lldir.h" #include "llflexibleobject.h" @@ -59,6 +61,7 @@ #include "lltexturefetch.h" #include "llviewercamera.h" #include "llviewertexturelist.h" +#include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llviewertextureanim.h" #include "llworld.h" @@ -87,6 +90,12 @@ LLPointer<LLObjectMediaNavigateClient> 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"); + // Implementation class of LLMediaDataClientObject. See llmediadataclient.h class LLMediaDataClientObjectImpl : public LLMediaDataClientObject @@ -596,6 +605,7 @@ void LLVOVolume::updateTextures() void LLVOVolume::updateTextureVirtualSize() { + LLFastTimer ftm(FTM_VOLUME_TEXTURES); // Update the pixel area of all faces if(mDrawable.isNull() || !mDrawable->isVisible()) @@ -688,46 +698,52 @@ void LLVOVolume::updateTextureVirtualSize() if (isSculpted()) { LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLUUID id = sculpt_params->getSculptTexture(); - mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); - if (mSculptTexture.notNull()) + LLUUID id = sculpt_params->getSculptTexture(); + U8 sculpt_type = sculpt_params->getSculptType(); + + if ((sculpt_type & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) { - mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(), - (S32)LLViewerTexture::BOOST_SCULPTED)); - mSculptTexture->setForSculpt() ; - - if(!mSculptTexture->isCachedRawImageReady()) + mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + + if (mSculptTexture.notNull()) { - S32 lod = llmin(mLOD, 3); - F32 lodf = ((F32)(lod + 1.0f)/4.f); - F32 tex_size = lodf * LLViewerTexture::sMaxSculptRez ; - mSculptTexture->addTextureStats(2.f * tex_size * tex_size, FALSE); + mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(), + (S32)LLViewerTexture::BOOST_SCULPTED)); + mSculptTexture->setForSculpt() ; - //if the sculpty very close to the view point, load first - { + if(!mSculptTexture->isCachedRawImageReady()) + { + S32 lod = llmin(mLOD, 3); + F32 lodf = ((F32)(lod + 1.0f)/4.f); + F32 tex_size = lodf * LLViewerTexture::sMaxSculptRez ; + mSculptTexture->addTextureStats(2.f * tex_size * tex_size, FALSE); + + //if the sculpty very close to the view point, load first + { LLVector3 lookAt = getPositionAgent() - camera->getOrigin(); - F32 dist = lookAt.normVec() ; + F32 dist = lookAt.normVec() ; F32 cos_angle_to_view_dir = lookAt * camera->getXAxis() ; - mSculptTexture->setAdditionalDecodePriority(0.8f * LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist)) ; + mSculptTexture->setAdditionalDecodePriority(0.8f * LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist)) ; + } } - } - S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture - S32 current_discard = getVolume() ? getVolume()->getSculptLevel() : -2 ; + S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture + S32 current_discard = getVolume() ? getVolume()->getSculptLevel() : -2 ; - 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 (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", + 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())); + } } } } @@ -745,7 +761,7 @@ void LLVOVolume::updateTextureVirtualSize() *camera)); } } - + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) { setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize))); @@ -841,8 +857,10 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline) return mDrawable; } -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) @@ -881,19 +899,33 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail if (isSculpted()) { - mSculptTexture = LLViewerTextureManager::getFetchedTexture(volume_params.getSculptID(), TRUE, LLViewerTexture::BOOST_NONE, 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) - { - gGLActive = TRUE; - sculpt(); - gGLActive = FALSE; + if (getVolume()->getNumVolumeFaces() == 0 || getVolume()->isTetrahedron()) + { + //load request not yet issued, request pipeline load this mesh + LLUUID asset_id = volume_params.getSculptID(); + gPipeline.loadMesh(this, asset_id, LLVolumeLODGroup::getVolumeDetailFromScale(getVolume()->getDetail())); } - else + } + else // otherwise is sculptie + { + mSculptTexture = LLViewerTextureManager::getFetchedTexture(volume_params.getSculptID(), TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + + if (mSculptTexture.notNull()) { - sculpt(); + //ignore sculpt GL usage since bao fixed this in a separate branch + if (!gGLActive) + { + gGLActive = TRUE; + sculpt(); + gGLActive = FALSE; + } + else + { + sculpt(); + } } } } @@ -907,6 +939,15 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail return FALSE; } + + +void LLVOVolume::notifyMeshLoaded() +{ + mSculptChanged = TRUE; + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); + dirtySpatialGroup(TRUE); +} + // sculpt replaces generate() for sculpted surfaces void LLVOVolume::sculpt() { @@ -1081,6 +1122,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); @@ -1167,6 +1213,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); @@ -2421,6 +2471,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)) @@ -2731,6 +2798,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(); @@ -2789,7 +2880,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 @@ -3381,6 +3472,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); @@ -3665,7 +3761,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 06e214b41e..964a1d79d8 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -183,6 +183,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); @@ -228,6 +233,7 @@ public: U32 getVolumeInterfaceID() const; virtual BOOL isFlexible() const; virtual BOOL isSculpted() const; + virtual BOOL isMesh() const; virtual BOOL hasLightTexture() const; BOOL isVolumeGlobal() const; @@ -252,6 +258,7 @@ public: void mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, std::string new_location); 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); @@ -267,9 +274,11 @@ public: LLVector3 getApproximateFaceNormal(U8 face_id); + void notifyMeshLoaded(); + // Returns 'true' iff the media data for this object is in flight bool isMediaDataBeingFetched() const; - + protected: S32 computeLODDetail(F32 distance, F32 radius); BOOL calcLOD(); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 282eddf380..610804c5eb 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), @@ -401,6 +403,7 @@ void LLPipeline::init() stop_glerror(); + mMeshMutex = new LLMutex(NULL); for (U32 i = 0; i < 2; ++i) { mSpotLightFade[i] = 1.f; @@ -475,6 +478,9 @@ void LLPipeline::cleanup() //delete mWLSkyPool; mWLSkyPool = NULL; + delete mMeshMutex; + mMeshMutex = NULL; + releaseGLBuffers(); mBloomImagep = NULL; @@ -1806,6 +1812,7 @@ void LLPipeline::rebuildPriorityGroups() } mGroupQ1.clear(); + } void LLPipeline::rebuildGroups() @@ -1874,6 +1881,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();) @@ -3424,27 +3433,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); } } @@ -5842,6 +5838,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); + } } @@ -6919,6 +6921,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(); } @@ -7267,14 +7287,12 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) LLGLDisable cull(GL_CULL_FACE); updateCull(camera, ref_result, 1); stateSort(camera, ref_result); - } - 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; } @@ -8894,3 +8912,246 @@ 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[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[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(), detail)); + } + else + { //fetch asset and load when done + gAssetStorage->getAssetData(mesh_id, LLAssetType::AT_MESH, + 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->isTetrahedron() && lod->getNumVolumeFaces() > 0) + { + volume->copyVolumeFaces(lod); + group->derefLOD(lod); + return; + } + + group->derefLOD(lod); + } + + //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->isTetrahedron() && lod->getNumVolumeFaces() > 0) + { + volume->copyVolumeFaces(lod); + group->derefLOD(lod); + return; + } + + group->derefLOD(lod); + } + } + else + { + llerrs << "WTF?" << llendl; + } + + //nothing found, so make a tetrahedron + volume->makeTetrahedron(); + } +} + +//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, 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; +} + +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); + volume_params.setSculptID(mMeshID, LL_SCULPT_TYPE_MESH); + 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<LLMeshThread*> stopping_threads; + + for (std::list<LLMeshThread*>::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; + } + + S32 detail = mesh->mDetailIndex; + + //get list of objects waiting to be notified this mesh is loaded + mesh_load_map::iterator obj_iter = mLoadingMeshes[detail].find(mesh->mMeshID); + + if (mesh->mVolume && obj_iter != mLoadingMeshes[detail].end()) + { + //make sure target volume is still valid + BOOL valid = FALSE; + + for (std::set<LLUUID>::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) + { + if (mesh->mVolume->getNumVolumeFaces() <= 0) + { + llwarns << "Mesh loading returned empty volume." << llendl; + mesh->mVolume->makeTetrahedron(); + } + + mesh->mTargetVolume->copyVolumeFaces(mesh->mVolume); + + for (std::set<LLUUID>::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[detail].erase(mesh->mMeshID); + } + + delete mesh; + --mMeshThreadCount; + } + + mLoadedMeshes = stopping_threads; +} + diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 67004a5f2d..f41f6173a9 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, S32 detail = 0); + void addTrianglesDrawn(S32 count); BOOL hasRenderType(const U32 type) const { return (type && (mRenderTypeMask & (1<<type))) ? TRUE : FALSE; } BOOL hasRenderDebugFeatureMask(const U32 mask) const { return (mRenderDebugFeatureMask & mask) ? TRUE : FALSE; } @@ -675,6 +679,37 @@ public: protected: std::vector<LLFace*> mSelectedFaces; + + typedef std::map<LLUUID, std::set<LLUUID> > mesh_load_map; + mesh_load_map mLoadingMeshes[4]; + + LLMutex* mMeshMutex; + + class LLMeshThread : public LLThread + { + public: + LLPointer<LLVolume> mVolume; + LLVolume* mTargetVolume; + LLUUID mMeshID; + F32 mDetail; + S32 mDetailIndex; + LLMeshThread(LLUUID mesh_id, LLVolume* target, S32 detail = -1); + ~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<LLMeshThread*> mLoadedMeshes; + std::list<LLMeshThread*> mPendingMeshes; + U32 mMeshThreadCount; + + void meshLoaded(LLMeshThread* mesh_thread); + void notifyLoadedMeshes(); + LLPointer<LLViewerFetchedTexture> mFaceSelectImagep; LLPointer<LLViewerTexture> mBloomImagep; LLPointer<LLViewerTexture> mBloomImage2p; diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index b1116dc0d2..3cbaa8c6ca 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -736,6 +736,8 @@ with the same filename but different name <texture name="icon_popular.tga" /> <texture name="icon_top_pick.tga" /> + <texture name="inv_folder_mesh.tga"/> + <texture name="inv_item_mesh.tga"/> <texture name="lag_status_critical.tga" /> <texture name="lag_status_good.tga" /> <texture name="lag_status_warning.tga" /> diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index 2ff99dcf5a..056d08e6da 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -144,17 +144,20 @@ 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. google-perftools Copyright (c) 2005, Google Inc. 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 Pth Copyright (C) 1999-2006 Ralf S. Engelschall <rse@gnu.org> SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) diff --git a/indra/newview/skins/default/xui/en/floater_inventory.xml b/indra/newview/skins/default/xui/en/floater_inventory.xml index ff9f0daee6..4434f5b421 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory.xml @@ -41,4 +41,25 @@ name="Inventory Panel" top="15" width="467" /> + <menu_item_call + label="Model (L$[COST])..." + layout="topleft" + name="Upload Model"> + <menu_item_call.on_click + function="File.UploadModel" + parameter="" /> + <menu_item_call.on_enable + function="File.EnableUpload" /> + </menu_item_call> + <menu_item_call + label="Scene..." + layout="topleft" + name="Upload Scene"> + <menu_item_call.on_click + function="File.UploadScene" + parameter="" /> + <menu_item_call.on_enable + function="File.EnableUpload" /> + </menu_item_call> + <menu_item_call </floater> diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index e3851de8e7..6675f4c02c 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1990,6 +1990,9 @@ even though the user gets a free copy. label="Cylinder" name="Cylinder" value="Cylinder" /> + <combo_box.item + label="Mesh" + value="Mesh" /> </combo_box> </panel> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 37136af680..3a9e76f7a7 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2512,10 +2512,10 @@ name="Fast Alpha"> <menu_item_check.on_check function="CheckControl" - parameter="RenderDebugGL" /> + parameter="RenderFastAlpha" /> <menu_item_check.on_click function="ToggleControl" - parameter="RenderDebugGL" /> + parameter="RenderFastAlpha" /> </menu_item_check> <menu_item_check label="Animation Textures" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index d8eb65322b..c2bc2e0d85 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -5766,7 +5766,7 @@ Attachment has been saved. Unable to find the help topic for this element. </notification> - <notification + <notification icon="alertmodal.tga" name="ObjectMediaFailure" type="alertmodal"> @@ -5796,6 +5796,28 @@ Your voice has been muted by moderator. name="okbutton" yestext="OK"/> </notification> + + <notification + icon="alertmodal.tga" + name="ConfirmClearTeleportHistory" + type="alertmodal"> +Are you sure you want to delete your teleport history? + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="UploadCostConfirmation" + type="alertmodal"> +This upload will cost L$[PRICE], do you wish to continue with the upload? + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="Upload"/> + </notification> <notification icon="alertmodal.tga" diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml index 37d59de66f..94a54f08e4 100644 --- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml @@ -16,7 +16,7 @@ <filter_editor text_pad_left="14" follows="left|top|right" - font="SanSerif" + font="SanSerif" height="20" label="Filter" layout="topleft" @@ -61,7 +61,7 @@ height="30" layout="bottomleft" left="0" - visible="true" + visible="true" name="bottom_panel" width="330"> <button @@ -112,7 +112,7 @@ mouse_opaque="false" name="Inventory Menu" top="15" - visible="true" + visible="true" width="290"> <menu height="101" @@ -170,6 +170,26 @@ function="File.EnableUpload" /> </menu_item_call> <menu_item_call + label="Model (L$[COST])..." + layout="topleft" + name="Upload Model"> + <menu_item_call.on_click + function="File.UploadModel" + parameter="" /> + <menu_item_call.on_enable + function="File.EnableUpload" /> + </menu_item_call> + <menu_item_call + label="Scene..." + layout="topleft" + name="Upload Scene"> + <menu_item_call.on_click + function="File.UploadScene" + parameter="" /> + <menu_item_call.on_enable + function="File.EnableUpload" /> + </menu_item_call> + <menu_item_call label="Bulk (L$[COST] per file)..." layout="topleft" name="Bulk Upload"> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index b014b8d1c0..883215a269 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -1876,6 +1876,7 @@ this texture in your inventory <string name="InvFolder favorite">Favorites</string> <string name="InvFolder Current Outfit">Current Outfit</string> <string name="InvFolder My Outfits">My Outfits</string> + <string name="InvFolder Meshes">Meshes</string> <!-- are used for Friends and Friends/All folders in Inventory "Calling cards" folder. See EXT-694--> <string name="InvFolder Friends">Friends</string> diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 4133315480..801ca3bf72 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -304,9 +304,15 @@ 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") self.enable_no_crt_manifest_check() - + # Media plugins - QuickTime if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"): self.path("media_plugin_quicktime.dll") |