From fe022adfa637d4f4f08d48576c75b5148573c8ed Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Fri, 17 Jun 2011 09:59:37 -0600 Subject: fix for SH-1783: [PUBLIC] Crash when adding a physics shape. --- indra/newview/llfloatermodelpreview.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index ab6753b4be..75728fdeeb 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -3107,18 +3107,20 @@ void LLModelPreview::rebuildUploadData() } } - for (U32 i = 0; i < LLModel::NUM_LODS; i++) - { //fill LOD slots based on reference model index - if (!mModel[i].empty()) - { - instance.mLOD[i] = mModel[i][idx]; - } - else - { - instance.mLOD[i] = NULL; + if(idx < mBaseModel.size()) + { + for (U32 i = 0; i < LLModel::NUM_LODS; i++) + { //fill LOD slots based on reference model index + if (mModel[i].size() > idx) + { + instance.mLOD[i] = mModel[i][idx]; + } + else + { + instance.mLOD[i] = NULL; + } } } - instance.mTransform = mat; mUploadData.push_back(instance); } -- cgit v1.3 From 15235061e8a8f64dd94640d27eadfce23ccb76f6 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Sat, 18 Jun 2011 01:02:03 -0500 Subject: SH-828 Fix for using uninitialized data when normals or texture coordinates are absent from collada file (can now upload meshes without normals or texture coordinates). --- indra/llmath/llvolume.cpp | 141 ++++++++++--- indra/llprimitive/llmodel.cpp | 355 +++++++++++++++----------------- indra/newview/llfloatermodelpreview.cpp | 56 +++-- 3 files changed, 318 insertions(+), 234 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 8c81f27784..7c7c4306da 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2379,11 +2379,16 @@ bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)co bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const { bool retval = false; - if (rhs.mData[POSITION].equals3(mData[POSITION]) && rhs.mTexCoord == mTexCoord) + + const F32 epsilon = 0.00001f; + + if (rhs.mData[POSITION].equals3(mData[POSITION], epsilon) && + abs(rhs.mTexCoord[0]-mTexCoord[0]) < epsilon && + abs(rhs.mTexCoord[1]-mTexCoord[1]) < epsilon) { if (angle_cutoff > 1.f) { - retval = (mData[NORMAL].equals3(rhs.mData[NORMAL])); + retval = (mData[NORMAL].equals3(rhs.mData[NORMAL], epsilon)); } else { @@ -2499,38 +2504,52 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) } { - U16* n = (U16*) &(norm[0]); - for (U32 j = 0; j < num_verts; ++j) + if (!norm.empty()) + { + U16* n = (U16*) &(norm[0]); + for (U32 j = 0; j < num_verts; ++j) + { + norm_out->set((F32) n[0], (F32) n[1], (F32) n[2]); + norm_out->div(65535.f); + norm_out->mul(2.f); + norm_out->sub(1.f); + norm_out++; + n += 3; + } + } + else { - norm_out->set((F32) n[0], (F32) n[1], (F32) n[2]); - norm_out->div(65535.f); - norm_out->mul(2.f); - norm_out->sub(1.f); - norm_out++; - n += 3; + memset(norm_out, 0, sizeof(LLVector4a)*num_verts); } } { - U16* t = (U16*) &(tc[0]); - for (U32 j = 0; j < num_verts; j+=2) + if (!tc.empty()) { - if (j < num_verts-1) - { - tc_out->set((F32) t[0], (F32) t[1], (F32) t[2], (F32) t[3]); - } - else + U16* t = (U16*) &(tc[0]); + for (U32 j = 0; j < num_verts; j+=2) { - tc_out->set((F32) t[0], (F32) t[1], 0.f, 0.f); - } + if (j < num_verts-1) + { + tc_out->set((F32) t[0], (F32) t[1], (F32) t[2], (F32) t[3]); + } + else + { + tc_out->set((F32) t[0], (F32) t[1], 0.f, 0.f); + } - t += 4; + t += 4; - tc_out->div(65535.f); - tc_out->mul(tc_range); - tc_out->add(min_tc4); + tc_out->div(65535.f); + tc_out->mul(tc_range); + tc_out->add(min_tc4); - tc_out++; + tc_out++; + } + } + else + { + memset(tc_out, 0, sizeof(LLVector2)*num_verts); } } @@ -2656,6 +2675,25 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) min.setMin(min, face.mPositions[i]); max.setMax(max, face.mPositions[i]); } + + if (face.mTexCoords) + { + LLVector2& min_tc = face.mTexCoordExtents[0]; + LLVector2& max_tc = face.mTexCoordExtents[1]; + + min_tc = face.mTexCoords[0]; + max_tc = face.mTexCoords[0]; + + for (U32 j = 1; j < face.mNumVertices; ++j) + { + update_min_max(min_tc, max_tc, face.mTexCoords[j]); + } + } + else + { + face.mTexCoordExtents[0].set(0,0); + face.mTexCoordExtents[1].set(1,1); + } } } } @@ -5696,8 +5734,23 @@ BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv) { cv.setPosition(mPositions[index]); - cv.setNormal(mNormals[index]); - cv.mTexCoord = mTexCoords[index]; + if (mNormals) + { + cv.setNormal(mNormals[index]); + } + else + { + cv.getNormal().clear(); + } + + if (mTexCoords) + { + cv.mTexCoord = mTexCoords[index]; + } + else + { + cv.mTexCoord.clear(); + } } bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const @@ -5727,7 +5780,10 @@ void LLVolumeFace::optimize(F32 angle_cutoff) LLVolumeFace new_face; //map of points to vector of vertices at that point - VertexMapData::PointMap point_map; + std::map > point_map; + + LLVector4a range; + range.setSub(mExtents[1],mExtents[0]); //remove redundant vertices for (U32 i = 0; i < mNumIndices; ++i) @@ -5738,7 +5794,19 @@ void LLVolumeFace::optimize(F32 angle_cutoff) getVertexData(index, cv); BOOL found = FALSE; - VertexMapData::PointMap::iterator point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr())); + + LLVector4a pos; + pos.setSub(mPositions[index], mExtents[0]); + pos.div(range); + + U64 pos64 = 0; + + pos64 = (U16) (pos[0]*65535); + pos64 = pos64 | (((U64) (pos[1]*65535)) << 16); + pos64 = pos64 | (((U64) (pos[2]*65535)) << 32); + + std::map >::iterator point_iter = point_map.find(pos64); + if (point_iter != point_map.end()) { //duplicate point might exist for (U32 j = 0; j < point_iter->second.size(); ++j) @@ -5770,11 +5838,26 @@ void LLVolumeFace::optimize(F32 angle_cutoff) } else { - point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d); + point_map[pos64].push_back(d); } } } + llassert(new_face.mNumIndices == mNumIndices); + llassert(new_face.mNumVertices <= mNumVertices); + + if (angle_cutoff > 1.f && !mNormals) + { + ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!mTexCoords) + { + ll_aligned_free_16(new_face.mTexCoords); + new_face.mTexCoords = NULL; + } + swapData(new_face); } diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index e0cfa07614..7c9dba9597 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -27,6 +27,7 @@ #include "linden_common.h" #include "llmodel.h" +#include "llmemory.h" #include "llconvexdecomposition.h" #include "llsdserialize.h" #include "llvector4a.h" @@ -71,88 +72,10 @@ LLModel::~LLModel() } } -void load_face_from_dom_inputs(LLVolumeFace& face, const domInputLocalOffset_Array& inputs, U32 min_idx, U32 max_idx) -{ - for (U32 j = 0; j < inputs.getCount(); ++j) - { - if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[j]->getSemantic()) == 0) - { //found vertex array - const domURIFragmentType& uri = inputs[j]->getSource(); - daeElementRef elem = uri.getElement(); - domVertices* vertices = (domVertices*) elem.cast(); - - domInputLocal_Array& v_inp = vertices->getInput_array(); - if (inputs[j]->getOffset() != 0) - { - llerrs << "Vertex array offset MUST be zero." << llendl; - } - - for (U32 k = 0; k < v_inp.getCount(); ++k) - { - if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0) - { - const domURIFragmentType& uri = v_inp[k]->getSource(); - - daeElementRef elem = uri.getElement(); - domSource* src = (domSource*) elem.cast(); - - if (src->getTechnique_common()->getAccessor()->getStride() != 3) - { - llerrs << "Vertex array stride MUST be three." << llendl; - } - - domListOfFloats& v = src->getFloat_array()->getValue(); - - LLVector4a min; - min.set(v[min_idx], v[min_idx+1], v[min_idx+2]); - LLVector4a max = min; - - for (U32 j = min_idx; j <= max_idx; ++j) - { //copy vertex array - face.mPositions[j-min_idx].set(v[j*3+0], v[j*3+1], v[j*3+2]); - update_min_max(min, max, face.mPositions[j-min_idx]); - } - - face.mExtents[0] = min; - face.mExtents[1] = max; - } - } - } - - if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[j]->getSemantic()) == 0) - { - //found normal array for this triangle list - const domURIFragmentType& uri = inputs[j]->getSource(); - daeElementRef elem = uri.getElement(); - domSource* src = (domSource*) elem.cast(); - domListOfFloats& n = src->getFloat_array()->getValue(); - - for (U32 j = min_idx; j <= max_idx; ++j) - { - LLVector4a* norm = (LLVector4a*) face.mNormals + (j-min_idx); - norm->set(n[j*3+0], n[j*3+1], n[j*3+2]); - norm->normalize3(); - } - } - else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[j]->getSemantic()) == 0) - { //found texCoords - const domURIFragmentType& uri = inputs[j]->getSource(); - daeElementRef elem = uri.getElement(); - domSource* src = (domSource*) elem.cast(); - domListOfFloats& u = src->getFloat_array()->getValue(); - - for (U32 j = min_idx; j <= max_idx; ++j) - { - face.mTexCoords[j-min_idx].setVec(u[j*2+0], u[j*2+1]); - } - } - } -} bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S32& tc_offset, S32& norm_offset, S32 &idx_stride, domSource* &pos_source, domSource* &tc_source, domSource* &norm_source) { - idx_stride = 0; for (U32 j = 0; j < inputs.getCount(); ++j) @@ -271,14 +194,13 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector& fa cv.mTexCoord.setVec(tc[idx[i+tc_offset]*2+0], tc[idx[i+tc_offset]*2+1]); } - + if (norm_source) { cv.setNormal(LLVector4a(n[idx[i+norm_offset]*3+0], n[idx[i+norm_offset]*3+1], n[idx[i+norm_offset]*3+2])); } - BOOL found = FALSE; @@ -329,10 +251,22 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector& fa { face_list.push_back(face); face_list.rbegin()->fillFromLegacyData(verts, indices); + LLVolumeFace& new_face = *face_list.rbegin(); + if (!norm_source) + { + ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!tc_source) + { + ll_aligned_free_16(face.mTexCoords); + new_face.mTexCoords = NULL; + } + face = LLVolumeFace(); point_map.clear(); } - } if (!verts.empty()) @@ -348,6 +282,18 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector& fa face_list.push_back(face); face_list.rbegin()->fillFromLegacyData(verts, indices); + LLVolumeFace& new_face = *face_list.rbegin(); + if (!norm_source) + { + ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!tc_source) + { + ll_aligned_free_16(face.mTexCoords); + new_face.mTexCoords = NULL; + } } return LLModel::NO_ERRORS ; @@ -433,14 +379,14 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector& fac cv.mTexCoord.setVec(tc[idx[cur_idx+tc_offset]*2+0], tc[idx[cur_idx+tc_offset]*2+1]); } - + if (norm_source) { cv.getNormal().set(n[idx[cur_idx+norm_offset]*3+0], n[idx[cur_idx+norm_offset]*3+1], n[idx[cur_idx+norm_offset]*3+2]); } - + cur_idx += idx_stride; BOOL found = FALSE; @@ -524,6 +470,19 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector& fac { face_list.push_back(face); face_list.rbegin()->fillFromLegacyData(verts, indices); + LLVolumeFace& new_face = *face_list.rbegin(); + if (!norm_source) + { + ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!tc_source) + { + ll_aligned_free_16(face.mTexCoords); + new_face.mTexCoords = NULL; + } + face = LLVolumeFace(); verts.clear(); indices.clear(); @@ -540,10 +499,23 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector& fac { material = std::string(poly->getMaterial()); } - + materials.push_back(material); face_list.push_back(face); face_list.rbegin()->fillFromLegacyData(verts, indices); + + LLVolumeFace& new_face = *face_list.rbegin(); + if (!norm_source) + { + ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!tc_source) + { + ll_aligned_free_16(face.mTexCoords); + new_face.mTexCoords = NULL; + } } return LLModel::NO_ERRORS ; @@ -557,7 +529,6 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector& fac const domInputLocalOffset_Array& inputs = poly->getInput_array(); - S32 v_offset = -1; S32 n_offset = -1; S32 t_offset = -1; @@ -662,15 +633,14 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector& fac n->get(n_idx+1), n->get(n_idx+2)); } - + if (t) { U32 t_idx = idx[j*stride+t_offset]*2; vert.mTexCoord.setVec(t->get(t_idx), t->get(t_idx+1)); } - - + verts.push_back(vert); } } @@ -733,6 +703,19 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector& fac materials.push_back(material); face_list.push_back(face); face_list.rbegin()->fillFromLegacyData(new_verts, indices); + + LLVolumeFace& new_face = *face_list.rbegin(); + if (!n) + { + ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!t) + { + ll_aligned_free_16(face.mTexCoords); + new_face.mTexCoords = NULL; + } } return LLModel::NO_ERRORS ; @@ -817,9 +800,9 @@ BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh) if (getNumVolumeFaces() > 0) { - optimizeVolumeFaces(); normalizeVolumeFaces(); - + optimizeVolumeFaces(); + if (getNumVolumeFaces() > 0) { return TRUE; @@ -853,81 +836,10 @@ void LLModel::offsetMesh( const LLVector3& pivotPoint ) void LLModel::optimizeVolumeFaces() { -#if 0 //VECTORIZE ? - for (std::vector::iterator iter = mVolumeFaces.begin(); iter != mVolumeFaces.end(); ) - { - std::vector::iterator cur_iter = iter++; - LLVolumeFace& face = *cur_iter; - - for (S32 i = 0; i < (S32) face.mNumIndices; i += 3) - { //remove zero area triangles - U16 i0 = face.mIndices[i+0]; - U16 i1 = face.mIndices[i+1]; - U16 i2 = face.mIndices[i+2]; - - if (i0 == i1 || - i1 == i2 || - i0 == i2) - { //duplicate index in triangle, remove triangle - face.mIndices.erase(face.mIndices.begin()+i, face.mIndices.begin()+i+3); - i -= 3; - } - else - { - LLVolumeFace::VertexData& v0 = face.mVertices[i0]; - LLVolumeFace::VertexData& v1 = face.mVertices[i1]; - LLVolumeFace::VertexData& v2 = face.mVertices[i2]; - - if (v0.mPosition == v1.mPosition || - v1.mPosition == v2.mPosition || - v2.mPosition == v0.mPosition) - { //zero area triangle, delete - face.mIndices.erase(face.mIndices.begin()+i, face.mIndices.begin()+i+3); - i-=3; - } - } - } - - //remove unreference vertices - std::vector ref; - ref.resize(face.mNumVertices); - - for (U32 i = 0; i < ref.size(); ++i) - { - ref[i] = false; - } - - for (U32 i = 0; i < face.mNumIndices; ++i) - { - ref[face.mIndices[i]] = true; - } - - U32 unref_count = 0; - for (U32 i = 0; i < ref.size(); ++i) - { - if (!ref[i]) - { - //vertex is unreferenced - face.mVertices.erase(face.mVertices.begin()+(i-unref_count)); - U16 idx = (U16) (i-unref_count); - - for (U32 j = 0; j < face.mNumIndices; ++j) - { //decrement every index array value greater than idx - if (face.mIndices[j] > idx) - { - --face.mIndices[j]; - } - } - ++unref_count; - } - } - - if (face.mVertices.empty() || face.mIndices.empty()) - { //face is empty, remove it - iter = mVolumeFaces.erase(cur_iter); - } + for (U32 i = 0; i < getNumVolumeFaces(); ++i) + { + mVolumeFaces[i].optimize(); } -#endif } // Shrink the model to fit @@ -962,6 +874,25 @@ void LLModel::normalizeVolumeFaces() update_min_max(min, max, face.mExtents[0]); update_min_max(min, max, face.mExtents[1]); + + if (face.mTexCoords) + { + LLVector2& min_tc = face.mTexCoordExtents[0]; + LLVector2& max_tc = face.mTexCoordExtents[1]; + + min_tc = face.mTexCoords[0]; + max_tc = face.mTexCoords[0]; + + for (U32 j = 1; j < face.mNumVertices; ++j) + { + update_min_max(min_tc, max_tc, face.mTexCoords[j]); + } + } + else + { + face.mTexCoordExtents[0].set(0,0); + face.mTexCoordExtents[1].set(1,1); + } } // Now that we have the extents of the model @@ -1029,8 +960,11 @@ void LLModel::normalizeVolumeFaces() { pos[j].add(trans); pos[j].mul(scale); - norm[j].mul(inv_scale); - norm[j].normalize3(); + if (norm && !norm[j].equals3(LLVector4a::getZero())) + { + norm[j].mul(inv_scale); + norm[j].normalize3(); + } } } @@ -1073,8 +1007,26 @@ void LLModel::setVolumeFaceData( face.resizeIndices(num_indices); LLVector4a::memcpyNonAliased16((F32*) face.mPositions, (F32*) pos.get(), num_verts*4*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32)); + if (norm.get()) + { + LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32)); + } + else + { + ll_aligned_free_16(face.mNormals); + face.mNormals = NULL; + } + + if (tc.get()) + { + LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32)); + } + else + { + ll_aligned_free_16(face.mTexCoords); + face.mTexCoords = NULL; + } + U32 size = (num_indices*2+0xF)&~0xF; LLVector4a::memcpyNonAliased16((F32*) face.mIndices, (F32*) ind.get(), size); } @@ -1477,9 +1429,8 @@ LLSD LLModel::writeModel( { //for each vert F32* pos = face.mPositions[j].getF32ptr(); - F32* norm = face.mNormals[j].getF32ptr(); - - //position + normal + + //position for (U32 k = 0; k < 3; ++k) { //for each component //convert to 16-bit normalized across domain @@ -1489,29 +1440,41 @@ LLSD LLModel::writeModel( //write to binary buffer verts[vert_idx++] = buff[0]; verts[vert_idx++] = buff[1]; - - //convert to 16-bit normalized - val = (U16) ((norm[k]+1.f)*0.5f*65535); + } - //write to binary buffer - normals[norm_idx++] = buff[0]; - normals[norm_idx++] = buff[1]; + if (face.mNormals) + { //normals + F32* norm = face.mNormals[j].getF32ptr(); + + for (U32 k = 0; k < 3; ++k) + { //for each component + //convert to 16-bit normalized + U16 val = (U16) ((norm[k]+1.f)*0.5f*65535); + U8* buff = (U8*) &val; + + //write to binary buffer + normals[norm_idx++] = buff[0]; + normals[norm_idx++] = buff[1]; + } } + F32* src_tc = (F32*) face.mTexCoords[j].mV; //texcoord - for (U32 k = 0; k < 2; ++k) - { //for each component - //convert to 16-bit normalized - U16 val = (U16) ((src_tc[k]-min_tc.mV[k])/tc_range.mV[k]*65535); - - U8* buff = (U8*) &val; - //write to binary buffer - tc[tc_idx++] = buff[0]; - tc[tc_idx++] = buff[1]; + if (face.mTexCoords) + { + for (U32 k = 0; k < 2; ++k) + { //for each component + //convert to 16-bit normalized + U16 val = (U16) ((src_tc[k]-min_tc.mV[k])/tc_range.mV[k]*65535); + + U8* buff = (U8*) &val; + //write to binary buffer + tc[tc_idx++] = buff[0]; + tc[tc_idx++] = buff[1]; + } } - } U32 idx_idx = 0; @@ -1525,12 +1488,20 @@ LLSD LLModel::writeModel( //write out face data mdl[model_names[idx]][i]["PositionDomain"]["Min"] = min_pos.getValue(); mdl[model_names[idx]][i]["PositionDomain"]["Max"] = max_pos.getValue(); - mdl[model_names[idx]][i]["TexCoord0Domain"]["Min"] = min_tc.getValue(); - mdl[model_names[idx]][i]["TexCoord0Domain"]["Max"] = max_tc.getValue(); - mdl[model_names[idx]][i]["Position"] = verts; - mdl[model_names[idx]][i]["Normal"] = normals; - mdl[model_names[idx]][i]["TexCoord0"] = tc; + + if (face.mNormals) + { + mdl[model_names[idx]][i]["Normal"] = normals; + } + + if (face.mTexCoords) + { + mdl[model_names[idx]][i]["TexCoord0Domain"]["Min"] = min_tc.getValue(); + mdl[model_names[idx]][i]["TexCoord0Domain"]["Max"] = max_tc.getValue(); + mdl[model_names[idx]][i]["TexCoord0"] = tc; + } + mdl[model_names[idx]][i]["TriangleList"] = indices; if (skinning) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 866cc39eec..a4683b4874 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -3719,7 +3719,9 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim U32 tri_count = 0; for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) { - mVertexBuffer[5][mdl][i]->setBuffer(type_mask); + LLVertexBuffer* buff = mVertexBuffer[5][mdl][i]; + buff->setBuffer(type_mask & buff->getTypeMask()); + U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); if (num_indices > 2) { @@ -3841,6 +3843,8 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim for (GLint i = 0; i < patch_count; ++i) { + type_mask = mVertexBuffer[5][base][i]->getTypeMask(); + LLPointer buff = new LLVertexBuffer(type_mask, 0); if (sizes[i*2+1] > 0 && sizes[i*2] > 0) @@ -3865,8 +3869,15 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim LLStrider index; buff->getVertexStrider(pos); - buff->getNormalStrider(norm); - buff->getTexCoord0Strider(tc); + if (type_mask & LLVertexBuffer::MAP_NORMAL) + { + buff->getNormalStrider(norm); + } + if (type_mask & LLVertexBuffer::MAP_TEXCOORD0) + { + buff->getTexCoord0Strider(tc); + } + buff->getIndexStrider(index); target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); @@ -4462,7 +4473,16 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) bool skinned = include_skin_weights && !mdl->mSkinWeights.empty(); - U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + U32 mask = LLVertexBuffer::MAP_VERTEX; + + if (vf.mNormals) + { + mask |= LLVertexBuffer::MAP_NORMAL; + } + if (vf.mTexCoords) + { + mask |= LLVertexBuffer::MAP_TEXCOORD0; + } if (skinned) { @@ -4480,8 +4500,6 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) LLStrider weights_strider; vb->getVertexStrider(vertex_strider); - vb->getNormalStrider(normal_strider); - vb->getTexCoord0Strider(tc_strider); vb->getIndexStrider(index_strider); if (skinned) @@ -4490,8 +4508,18 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) } LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); + + if (vf.mTexCoords) + { + vb->getTexCoord0Strider(tc_strider); + LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); + } + + if (vf.mNormals) + { + vb->getNormalStrider(normal_strider); + LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); + } if (skinned) { @@ -4750,6 +4778,8 @@ BOOL LLModelPreview::render() const F32 BRIGHTNESS = 0.9f; gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); + const U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + LLGLEnable normalize(GL_NORMALIZE); if (!mBaseModel.empty() && mVertexBuffer[5].empty()) @@ -4798,8 +4828,8 @@ BOOL LLModelPreview::render() for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) { LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + + buffer->setBuffer(type_mask & buffer->getTypeMask()); if (textures) { @@ -4918,7 +4948,7 @@ BOOL LLModelPreview::render() { LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + buffer->setBuffer(type_mask & buffer->getTypeMask()); buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -4984,7 +5014,7 @@ BOOL LLModelPreview::render() { LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + buffer->setBuffer(type_mask & buffer->getTypeMask()); LLStrider pos_strider; buffer->getVertexStrider(pos_strider, 0); @@ -5109,7 +5139,7 @@ BOOL LLModelPreview::render() position[j] = v; } - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + buffer->setBuffer(type_mask & buffer->getTypeMask()); glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); -- cgit v1.3 From d625706d84cbb69d99497d3ee328105907867181 Mon Sep 17 00:00:00 2001 From: Seth ProductEngine Date: Wed, 22 Jun 2011 19:31:03 +0300 Subject: SH-1725 WIP Floater upload model wizard update: - XUI changed according to latest mockups - Added switching to advanced upload floater - Added "Recalculate geometry" and "Recalculate physics" buttons --- indra/newview/llfloatermodelpreview.cpp | 7 + indra/newview/llfloatermodelpreview.h | 1 + indra/newview/llfloatermodelwizard.cpp | 146 ++-- indra/newview/llfloatermodelwizard.h | 12 +- .../skins/default/xui/en/floater_model_wizard.xml | 771 ++++++++------------- 5 files changed, 390 insertions(+), 547 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 9721fc9224..06a1225905 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -544,6 +544,13 @@ void LLFloaterModelPreview::loadModel(S32 lod) (new LLMeshFilePicker(mModelPreview, lod))->getFile(); } +void LLFloaterModelPreview::loadModel(S32 lod, const std::string& file_name) +{ + mModelPreview->mLoading = true; + + mModelPreview->loadModel(file_name, lod); +} + //static void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata) { diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index ccd6fef953..d78135779e 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -185,6 +185,7 @@ public: void updateResourceCost(); void loadModel(S32 lod); + void loadModel(S32 lod, const std::string& file_name); void onViewOptionChecked(const LLSD& userdata); bool isViewOptionChecked(const LLSD& userdata); diff --git a/indra/newview/llfloatermodelwizard.cpp b/indra/newview/llfloatermodelwizard.cpp index 707c8288df..61b8032625 100644 --- a/indra/newview/llfloatermodelwizard.cpp +++ b/indra/newview/llfloatermodelwizard.cpp @@ -46,12 +46,18 @@ static const std::string stateNames[]={ "choose_file", "optimize", "physics", - "physics2", "review", "upload"}; +static void swap_controls(LLUICtrl* first_ctrl, LLUICtrl* second_ctrl, bool first_ctr_visible); + LLFloaterModelWizard::LLFloaterModelWizard(const LLSD& key) : LLFloater(key) + ,mRecalculateGeometryBtn(NULL) + ,mRecalculatePhysicsBtn(NULL) + ,mRecalculatingPhysicsBtn(NULL) + ,mCalculateWeightsBtn(NULL) + ,mCalculatingWeightsBtn(NULL) { mLastEnabledState = CHOOSE_FILE; sInstance = this; @@ -59,7 +65,6 @@ LLFloaterModelWizard::LLFloaterModelWizard(const LLSD& key) mCommitCallbackRegistrar.add("Wizard.Choose", boost::bind(&LLFloaterModelWizard::setState, this, CHOOSE_FILE)); mCommitCallbackRegistrar.add("Wizard.Optimize", boost::bind(&LLFloaterModelWizard::setState, this, OPTIMIZE)); mCommitCallbackRegistrar.add("Wizard.Physics", boost::bind(&LLFloaterModelWizard::setState, this, PHYSICS)); - mCommitCallbackRegistrar.add("Wizard.Physics2", boost::bind(&LLFloaterModelWizard::setState, this, PHYSICS2)); mCommitCallbackRegistrar.add("Wizard.Review", boost::bind(&LLFloaterModelWizard::setState, this, REVIEW)); mCommitCallbackRegistrar.add("Wizard.Upload", boost::bind(&LLFloaterModelWizard::setState, this, UPLOAD)); } @@ -91,6 +96,8 @@ void LLFloaterModelWizard::setState(int state) getChildView("next")->setVisible(true); getChildView("upload")->setVisible(false); getChildView("cancel")->setVisible(true); + mCalculateWeightsBtn->setVisible(false); + mCalculatingWeightsBtn->setVisible(false); } if (state == OPTIMIZE) @@ -108,6 +115,8 @@ void LLFloaterModelWizard::setState(int state) getChildView("next")->setVisible(true); getChildView("upload")->setVisible(false); getChildView("cancel")->setVisible(true); + mCalculateWeightsBtn->setVisible(false); + mCalculatingWeightsBtn->setVisible(false); } if (state == PHYSICS) @@ -119,30 +128,14 @@ void LLFloaterModelWizard::setState(int state) mModelPreview->mViewOption["show_physics"] = true; - getChildView("next")->setVisible(true); - getChildView("upload")->setVisible(false); - getChildView("close")->setVisible(false); - getChildView("back")->setVisible(true); - getChildView("back")->setEnabled(true); - getChildView("cancel")->setVisible(true); - } - - if (state == PHYSICS2) - { - if (mLastEnabledState < state) - { - executePhysicsStage("Decompose"); - } - - mModelPreview->mViewOption["show_physics"] = true; - - getChildView("next")->setVisible(true); - getChildView("next")->setEnabled(true); + getChildView("next")->setVisible(false); getChildView("upload")->setVisible(false); getChildView("close")->setVisible(false); getChildView("back")->setVisible(true); getChildView("back")->setEnabled(true); getChildView("cancel")->setVisible(true); + mCalculateWeightsBtn->setVisible(true); + mCalculatingWeightsBtn->setVisible(false); } if (state == REVIEW) @@ -156,6 +149,8 @@ void LLFloaterModelWizard::setState(int state) getChildView("back")->setEnabled(true); getChildView("upload")->setVisible(true); getChildView("cancel")->setVisible(true); + mCalculateWeightsBtn->setVisible(false); + mCalculatingWeightsBtn->setVisible(false); } if (state == UPLOAD) @@ -165,6 +160,8 @@ void LLFloaterModelWizard::setState(int state) getChildView("back")->setVisible(false); getChildView("upload")->setVisible(false); getChildView("cancel")->setVisible(false); + mCalculateWeightsBtn->setVisible(false); + mCalculatingWeightsBtn->setVisible(false); } updateButtons(); @@ -198,18 +195,48 @@ void LLFloaterModelWizard::updateButtons() button->setEnabled(FALSE); } } +} - LLButton *physics_button = getChild(stateNames[PHYSICS]+"_btn"); - - if (mState == PHYSICS2) +void LLFloaterModelWizard::onClickSwitchToAdvanced() +{ + LLFloaterModelPreview* floater_preview = LLFloaterReg::getTypedInstance("upload_model"); + if (!floater_preview) { - physics_button->setVisible(false); + llwarns << "FLoater model preview not found." << llendl; + return; } - else + + // Open floater model preview + floater_preview->openFloater(); + + // Close the wizard + closeFloater(); + + std::string filename = getChild("lod_file")->getValue().asString(); + if (!filename.empty()) { - physics_button->setVisible(true); + // Re-load the model to the floater model preview if it has been loaded + // into the wizard. + floater_preview->loadModel(3, filename); } +} + +void LLFloaterModelWizard::onClickRecalculateGeometry() +{ + S32 val = getChild("accuracy_slider")->getValue().asInteger(); + + mModelPreview->genLODs(-1, NUM_LOD - val); + mModelPreview->refresh(); +} + +void LLFloaterModelWizard::onClickRecalculatePhysics() +{ + // Hide the "Recalculate physics" button and show the "Recalculating..." + // button instead. + swap_controls(mRecalculatePhysicsBtn, mRecalculatingPhysicsBtn, false); + + executePhysicsStage("Decompose"); } void LLFloaterModelWizard::loadModel() @@ -471,6 +498,11 @@ void LLFloaterModelWizard::DecompRequest::completed() { executePhysicsStage("Simplify"); } + else + { + // Decomp request is complete so we can enable the "Recalculate physics" button again. + swap_controls(sInstance->mRecalculatePhysicsBtn, sInstance->mRecalculatingPhysicsBtn, true); + } } @@ -488,10 +520,22 @@ BOOL LLFloaterModelWizard::postBuild() getChild("next")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickNext, this)); getChild("preview_lod_combo")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1)); getChild("preview_lod_combo2")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1)); - getChild("preview_lod_combo3")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1)); - getChild("accuracy_slider")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onAccuracyPerformance, this, _2)); getChild("upload")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onUpload, this)); - getChild("physics_slider")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPhysicsChanged, this)); + getChild("switch_to_advanced")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickSwitchToAdvanced, this)); + + mRecalculateGeometryBtn = getChild("recalculate_geometry_btn"); + mRecalculateGeometryBtn->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickRecalculateGeometry, this)); + + mRecalculatePhysicsBtn = getChild("recalculate_physics_btn"); + mRecalculatePhysicsBtn->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickRecalculatePhysics, this)); + + mRecalculatingPhysicsBtn = getChild("recalculating_physics_btn"); + + mCalculateWeightsBtn = getChild("calculate"); + // *TODO: Change the callback to upload fee request. + mCalculateWeightsBtn->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickNext, this)); + + mCalculatingWeightsBtn = getChild("calculating"); LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; @@ -532,22 +576,19 @@ void LLFloaterModelWizard::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F panel->childSetText("dimension_x", llformat("%.1f", x)); panel->childSetText("dimension_y", llformat("%.1f", y)); panel->childSetText("dimension_z", llformat("%.1f", z)); - panel->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); - panel->childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost)); } } + + childSetTextArg("review_prim_equiv", "[EQUIV]", llformat("%d", mModelPreview->mResourceCost)); + + // *TODO: Get the actual upload fee. + childSetTextArg("review_fee", "[FEE]", llformat("%d", 0)); + childSetTextArg("charged_fee", "[FEE]", llformat("%d", 0)); } void LLFloaterModelWizard::modelLoadedCallback() { mLastEnabledState = CHOOSE_FILE; - getChild("confirm_checkbox")->set(FALSE); - updateButtons(); -} - -void LLFloaterModelWizard::onPhysicsChanged() -{ - mLastEnabledState = PHYSICS; updateButtons(); } @@ -562,16 +603,6 @@ void LLFloaterModelWizard::onUpload() } -void LLFloaterModelWizard::onAccuracyPerformance(const LLSD& data) -{ - int val = (int) data.asInteger(); - - mModelPreview->genLODs(-1, NUM_LOD-val); - - mModelPreview->refresh(); -} - - void LLFloaterModelWizard::onPreviewLODCommit(LLUICtrl* ctrl) { if (!mModelPreview) @@ -601,11 +632,6 @@ void LLFloaterModelWizard::refresh() getChildView("next")->setEnabled(model_loaded); } - if (mState == REVIEW) - { - getChildView("upload")->setEnabled(getChild("confirm_checkbox")->getValue().asBoolean()); - } - } void LLFloaterModelWizard::draw() @@ -613,12 +639,11 @@ void LLFloaterModelWizard::draw() refresh(); LLFloater::draw(); - LLRect r = getRect(); - - mModelPreview->update(); if (mModelPreview) { + mModelPreview->update(); + gGL.color3f(1.f, 1.f, 1.f); gGL.getTexUnit(0)->bind(mModelPreview); @@ -652,3 +677,10 @@ void LLFloaterModelWizard::draw() gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } } + +// static +void swap_controls(LLUICtrl* first_ctrl, LLUICtrl* second_ctrl, bool first_ctr_visible) +{ + first_ctrl->setVisible(first_ctr_visible); + second_ctrl->setVisible(!first_ctr_visible); +} diff --git a/indra/newview/llfloatermodelwizard.h b/indra/newview/llfloatermodelwizard.h index b166d26295..c32977f4b0 100644 --- a/indra/newview/llfloatermodelwizard.h +++ b/indra/newview/llfloatermodelwizard.h @@ -66,7 +66,6 @@ public: void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost); void modelLoadedCallback(); - void onPhysicsChanged(); void initDecompControls(); LLPhysicsDecomp::decomp_params mDecompParams; @@ -80,13 +79,15 @@ private: CHOOSE_FILE = 0, OPTIMIZE, PHYSICS, - PHYSICS2, REVIEW, UPLOAD }; void setState(int state); void updateButtons(); + void onClickSwitchToAdvanced(); + void onClickRecalculateGeometry(); + void onClickRecalculatePhysics(); void onClickCancel(); void onClickBack(); void onClickNext(); @@ -94,7 +95,6 @@ private: bool onEnableBack(); void loadModel(); void onPreviewLODCommit(LLUICtrl*); - void onAccuracyPerformance(const LLSD& data); void onUpload(); LLModelPreview* mModelPreview; @@ -106,7 +106,11 @@ private: U32 mLastEnabledState; - + LLButton* mRecalculateGeometryBtn; + LLButton* mRecalculatePhysicsBtn; + LLButton* mRecalculatingPhysicsBtn; + LLButton* mCalculateWeightsBtn; + LLButton* mCalculatingWeightsBtn; }; diff --git a/indra/newview/skins/default/xui/en/floater_model_wizard.xml b/indra/newview/skins/default/xui/en/floater_model_wizard.xml index c3f7b70ca7..1d6ded5391 100644 --- a/indra/newview/skins/default/xui/en/floater_model_wizard.xml +++ b/indra/newview/skins/default/xui/en/floater_model_wizard.xml @@ -45,24 +45,6 @@ - - Filename: + width="320"> + Choose model file to upload + width="230" /> - Model Preview: + left="10" + name="Cache location" + width="320"> + Second Life supports COLLADA (.dae) files @@ -225,7 +220,7 @@ top_pad="10" width="130" height="14" - left="340" + left_delta="0" text_color="White" word_wrap="true"> Dimensions (meters): @@ -238,15 +233,7 @@ text_color="White" name="dimensions" left_delta="0"> - X: Y: Z: - - - | | + X Y Z - - Note: - - -Advanced users familiar with 3d content creation tools may prefer to use the [secondlife:///app/openfloater/upload_model Advanced Mesh Import Window] . - + + WARNING: + + + You will not be able to complete the final step of uploading this model to the Second Life servers. [secondlife:///app/floater/learn_more Find out how] to set up y + @@ -291,7 +281,7 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se height="388" top_delta="0" name="optimize_panel" - visible="false" + visible="true" width="535" left="0"> - Optimize + Optimize model - This wizard has optimized your model to improve performance. You may adjust the results of the optimization process bellow or click Next to continue. + We have optimized the model for performance. Adjust it further if you wish. - - Model Preview: - - - - High - - - Medium - - - Low - - - Lowest - - - - - Higher Performance - Faster rendering but less detailed; lowers Resource (prim) cost. - Higher Accuracy - More detailed model but slower; increases Resource (prim) cost. + Performance + Faster rendering +Less detail +Lower prim weight + Accuracy + Slower rendering +More detail +Higher prim weight - - ' - - - - - - Resource Cost: [COST] - - Dimensions (meters): - - - X: Y: Z: - - - | | + + ' + + ' + + + + Geometry preview - - - + + + + + High detail + + + Medium detail + + + Low detail + + + Lowest detail + + @@ -549,7 +512,7 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se font="SansSerifBig" text_color="White" layout="topleft"> - Physics + Adjust physics - The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used: + We will create a shape for the outer hull of the model. Adjust the shape's detail level as needed for the intended purpose of your model. - Higher Performance - Faster rendering but less detailed; lowers Resource (prim) cost. - Higher Accuracy - More detailed model but slower; increases Resource (prim) cost. + Performance + Faster rendering +Less detail +Lower prim weight + Accuracy + Slower rendering +More detail +Higher prim weight - ' ' ' ' ' ' ' ' ' ' ' - Recommended for solid objects - Recommended for buildings - Recommended for vehicles - - - - - Resource Cost: [COST] - - - - - - - - Physics - - - - Preview the physics shape below then click Next to continue. To modify the physics shape, click the Back button. - - - - Model Preview: + top="25" + width="22" /> + Examples: +Moving objects +Flying objects +Vehicles + Examples: +Small static objects +Less detailed objects +Simple furniture + Examples: +Static objects +Detailed objects +Buildings + + + + Physics preview - + + + - High + High detail - Medium + Medium detail - Low + Low detail - Lowest + Lowest detail - - - - Dimensions (meters): - - - X: Y: Z: - - - | | - - - - - Resource Cost: [COST] - + - - Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload. - - - - - Model Preview: - - - - High - - - Medium - - - Low - - - Lowest - - - - - - Dimensions (meters): - - - X: Y: Z: - - - | | - - - - + name="content" + bg_opaque_color="DkGray2" + background_visible="true" + background_opaque="true"> + Impact to parcel/region: [EQUIV] prim equivalents + + Your account will be charged an upload fee of L$ [FEE]. + + By clicking the upload button, you confirm that you have the appropriate rights to the material contained in the model. + - Resource Cost: [COST] - This is the cost to your Region's prim/object limit, at default scale - Physics Cost: [COST] - This is the cost to your Region's prim/object limit, at default scale - Upload Fee: - This is the amount the upload will cost. - - I confirm that I have the appropriate rights to the material contained in this model. [secondlife:///app/floater/learn_more Learn more] @@ -954,44 +721,76 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se height="10" font="SansSerifBig" layout="topleft"> - Upload Complete! + Upload complete - Congratulations! Your model has been sucessfully uploaded. You will find the model in the Objects folder in your inventory. + left="25"> + Your model has been uploaded. + + + You will find it in the Objects folder in your inventory. + + Your account has been charged L$ [FEE]. -