/* For each vertex, given: B - binormal T - tangent N - normal P - position The resulting texture coordinate <u,v> is: u = 2(B dot P) v = 2(T dot P) */ void planarProjection(LLVector2 &tc, const LLVector4a& normal, const LLVector4a ¢er, const LLVector4a& vec) { LLVector4a binormal; F32 d = normal[0]; if (d >= 0.5f || d <= -0.5f) { if (d < 0) { binormal.set(0,-1,0); } else { binormal.set(0, 1, 0); } } else { if (normal[1] > 0) { binormal.set(-1,0,0); } else { binormal.set(1,0,0); } } LLVector4a tangent; tangent.setCross3(binormal,normal); tc.mV[1] = -((tangent.dot3(vec).getF32())*2 - 0.5f); tc.mV[0] = 1.0f+((binormal.dot3(vec).getF32())*2 - 0.5f); }
LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data, F32 scale, const std::string &name) { LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); cloned_morph_data->mName = name; LLVector4a sc; sc.splat(scale); LLVector4a nsc; nsc.set(scale, -scale, scale, scale); for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) { if (cloned_morph_data->mCoords[v][1] < 0) { cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],nsc); cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v],nsc); cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],nsc); } else { cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],sc); cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v], sc); cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],sc); } } return cloned_morph_data; }
//static void LLVOPartGroup::restoreGL() { //TODO: optimize out binormal mask here. Specular and normal coords as well. sVB = new LLVertexBuffer(VERTEX_DATA_MASK | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, GL_STREAM_DRAW_ARB); U32 count = LL_MAX_PARTICLE_COUNT; sVB->allocateBuffer(count*4, count*6, true); //indices and texcoords are always the same, set once LLStrider<U16> indicesp; LLStrider<LLVector4a> verticesp; sVB->getIndexStrider(indicesp); sVB->getVertexStrider(verticesp); LLVector4a v; v.set(0,0,0,0); U16 vert_offset = 0; for (U32 i = 0; i < LL_MAX_PARTICLE_COUNT; i++) { *indicesp++ = vert_offset + 0; *indicesp++ = vert_offset + 1; *indicesp++ = vert_offset + 2; *indicesp++ = vert_offset + 1; *indicesp++ = vert_offset + 3; *indicesp++ = vert_offset + 2; *verticesp++ = v; vert_offset += 4; } LLStrider<LLVector2> texcoordsp; sVB->getTexCoord0Strider(texcoordsp); for (U32 i = 0; i < LL_MAX_PARTICLE_COUNT; i++) { *texcoordsp++ = LLVector2(0.f, 1.f); *texcoordsp++ = LLVector2(0.f, 0.f); *texcoordsp++ = LLVector2(1.f, 1.f); *texcoordsp++ = LLVector2(1.f, 0.f); } sVB->flush(); }
//static void LLVOPartGroup::restoreGL() { sVB = new LLVertexBuffer(VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); U32 count = LL_MAX_PARTICLE_COUNT; sVB->allocateBuffer(count*4, count*6, true); //indices and texcoords are always the same, set once LLStrider<U16> indicesp; LLStrider<LLVector4a> verticesp; sVB->getIndexStrider(indicesp); sVB->getVertexStrider(verticesp); LLVector4a v; v.set(0,0,0,0); U16 vert_offset = 0; for (U32 i = 0; i < LL_MAX_PARTICLE_COUNT; i++) { *indicesp++ = vert_offset + 0; *indicesp++ = vert_offset + 1; *indicesp++ = vert_offset + 2; *indicesp++ = vert_offset + 1; *indicesp++ = vert_offset + 3; *indicesp++ = vert_offset + 2; *verticesp++ = v; vert_offset += 4; } LLStrider<LLVector2> texcoordsp; sVB->getTexCoord0Strider(texcoordsp); for (U32 i = 0; i < LL_MAX_PARTICLE_COUNT; i++) { *texcoordsp++ = LLVector2(0.f, 1.f); *texcoordsp++ = LLVector2(0.f, 0.f); *texcoordsp++ = LLVector2(1.f, 1.f); *texcoordsp++ = LLVector2(1.f, 0.f); } sVB->flush(); }
void LLPolyMorphTarget::apply( ESex avatar_sex ) { if (!mMorphData || mNumMorphMasksPending > 0) { return; } LL_RECORD_BLOCK_TIME(FTM_APPLY_MORPH_TARGET); mLastSex = avatar_sex; // Check for NaN condition (NaN is detected if a variable doesn't equal itself. if (mCurWeight != mCurWeight) { mCurWeight = 0.0; } if (mLastWeight != mLastWeight) { mLastWeight = mCurWeight+.001; } // perform differential update of morph F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight); // store last weight mLastWeight += delta_weight; if (delta_weight != 0.f) { llassert(!mMesh->isLOD()); LLVector4a *coords = mMesh->getWritableCoords(); LLVector4a *scaled_normals = mMesh->getScaledNormals(); LLVector4a *normals = mMesh->getWritableNormals(); LLVector4a *scaled_binormals = mMesh->getScaledBinormals(); LLVector4a *binormals = mMesh->getWritableBinormals(); LLVector4a *clothing_weights = mMesh->getWritableClothingWeights(); LLVector2 *tex_coords = mMesh->getWritableTexCoords(); F32 *maskWeightArray = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL; for(U32 vert_index_morph = 0; vert_index_morph < mMorphData->mNumIndices; vert_index_morph++) { S32 vert_index_mesh = mMorphData->mVertexIndices[vert_index_morph]; F32 maskWeight = 1.f; if (maskWeightArray) { maskWeight = maskWeightArray[vert_index_morph]; } LLVector4a pos = mMorphData->mCoords[vert_index_morph]; pos.mul(delta_weight*maskWeight); coords[vert_index_mesh].add(pos); if (getInfo()->mIsClothingMorph && clothing_weights) { LLVector4a clothing_offset = mMorphData->mCoords[vert_index_morph]; clothing_offset.mul(delta_weight * maskWeight); LLVector4a* clothing_weight = &clothing_weights[vert_index_mesh]; clothing_weight->add(clothing_offset); clothing_weight->getF32ptr()[VW] = maskWeight; } // calculate new normals based on half angles LLVector4a norm = mMorphData->mNormals[vert_index_morph]; norm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR); scaled_normals[vert_index_mesh].add(norm); norm = scaled_normals[vert_index_mesh]; // guard against degenerate input data before we create NaNs below! // norm.normalize3fast(); normals[vert_index_mesh] = norm; // calculate new binormals LLVector4a binorm = mMorphData->mBinormals[vert_index_morph]; // guard against degenerate input data before we create NaNs below! // if (!binorm.isFinite3() || (binorm.dot3(binorm).getF32() <= F_APPROXIMATELY_ZERO)) { binorm.set(1,0,0,1); } binorm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR); scaled_binormals[vert_index_mesh].add(binorm); LLVector4a tangent; tangent.setCross3(scaled_binormals[vert_index_mesh], norm); LLVector4a& normalized_binormal = binormals[vert_index_mesh]; normalized_binormal.setCross3(norm, tangent); normalized_binormal.normalize3fast(); tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight; } // now apply volume changes for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); iter++ ) { LLPolyVolumeMorph* volume_morph = &(*iter); LLVector3 scale_delta = volume_morph->mScale * delta_weight; LLVector3 pos_delta = volume_morph->mPos * delta_weight; volume_morph->mVolume->setScale(volume_morph->mVolume->getScale() + scale_delta); volume_morph->mVolume->setPosition(volume_morph->mVolume->getPosition() + pos_delta); } } if (mNext) { mNext->apply(avatar_sex); } }
void LLSpatialBridge::updateSpatialExtents() { LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0); { LLFastTimer ftm(FTM_CULL_REBOUND); root->rebound(); } LLVector4a offset; LLVector4a size = root->mBounds[1]; //VECTORIZE THIS LLMatrix4a mat; mat.loadu(mDrawable->getXform()->getWorldMatrix()); LLVector4a t; t.splat(0.f); LLVector4a center; mat.affineTransform(t, center); mat.rotate(root->mBounds[0], offset); center.add(offset); LLVector4a v[4]; //get 4 corners of bounding box mat.rotate(size,v[0]); LLVector4a scale; scale.set(-1.f, -1.f, 1.f); scale.mul(size); mat.rotate(scale, v[1]); scale.set(1.f, -1.f, -1.f); scale.mul(size); mat.rotate(scale, v[2]); scale.set(-1.f, 1.f, -1.f); scale.mul(size); mat.rotate(scale, v[3]); LLVector4a& newMin = mExtents[0]; LLVector4a& newMax = mExtents[1]; newMin = newMax = center; for (U32 i = 0; i < 4; i++) { LLVector4a delta; delta.setAbs(v[i]); LLVector4a min; min.setSub(center, delta); LLVector4a max; max.setAdd(center, delta); newMin.setMin(newMin, min); newMax.setMax(newMax, max); } LLVector4a diagonal; diagonal.setSub(newMax, newMin); mRadius = diagonal.getLength3().getF32() * 0.5f; mPositionGroup.setAdd(newMin,newMax); mPositionGroup.mul(0.5f); updateBinRadius(); }
// Shrink the model to fit // on a 1x1x1 cube centered at the origin. // The positions and extents // multiplied by mNormalizedScale // and offset by mNormalizedTranslation // to be the "original" extents and position. // Also, the positions will fit // within the unit cube. void LLModel::normalizeVolumeFaces() { // ensure we don't have too many faces if (mVolumeFaces.size() > LL_SCULPT_MESH_MAX_FACES) mVolumeFaces.resize(LL_SCULPT_MESH_MAX_FACES); if (!mVolumeFaces.empty()) { LLVector4a min, max; // For all of the volume faces // in the model, loop over // them and see what the extents // of the volume along each axis. min = mVolumeFaces[0].mExtents[0]; max = mVolumeFaces[0].mExtents[1]; for (U32 i = 1; i < mVolumeFaces.size(); ++i) { LLVolumeFace& face = mVolumeFaces[i]; 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 < (U32)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 // we can compute the offset needed to center // the model at the origin. // Compute center of the model // and make it negative to get translation // needed to center at origin. LLVector4a trans; trans.setAdd(min, max); trans.mul(-0.5f); // Compute the total size along all // axes of the model. LLVector4a size; size.setSub(max, min); // Prevent division by zero. F32 x = size[0]; F32 y = size[1]; F32 z = size[2]; F32 w = size[3]; if (fabs(x)<F_APPROXIMATELY_ZERO) { x = 1.0; } if (fabs(y)<F_APPROXIMATELY_ZERO) { y = 1.0; } if (fabs(z)<F_APPROXIMATELY_ZERO) { z = 1.0; } size.set(x,y,z,w); // Compute scale as reciprocal of size LLVector4a scale; scale.splat(1.f); scale.div(size); LLVector4a inv_scale(1.f); inv_scale.div(scale); for (U32 i = 0; i < mVolumeFaces.size(); ++i) { LLVolumeFace& face = mVolumeFaces[i]; // We shrink the extents so // that they fall within // the unit cube. face.mExtents[0].add(trans); face.mExtents[0].mul(scale); face.mExtents[1].add(trans); face.mExtents[1].mul(scale); // For all the positions, we scale // the positions to fit within the unit cube. LLVector4a* pos = (LLVector4a*) face.mPositions; LLVector4a* norm = (LLVector4a*) face.mNormals; for (U32 j = 0; j < (U32)face.mNumVertices; ++j) { pos[j].add(trans); pos[j].mul(scale); if (norm && !norm[j].equals3(LLVector4a::getZero())) { norm[j].mul(inv_scale); norm[j].normalize3(); } } } // mNormalizedScale is the scale at which // we would need to multiply the model // by to get the original size of the // model instead of the normalized size. LLVector4a normalized_scale; normalized_scale.splat(1.f); normalized_scale.div(scale); mNormalizedScale.set(normalized_scale.getF32ptr()); mNormalizedTranslation.set(trans.getF32ptr()); mNormalizedTranslation *= -1.f; } }
BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, const LLMatrix4& mat_vert_in, const LLMatrix3& mat_normal_in, BOOL global_volume) { LLMemType mt1(LLMemType::MTYPE_DRAWABLE); //get bounding box if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION #if MESH_ENABLED | LLDrawable::REBUILD_RIGGED #endif //MESH_ENABLED )) { //VECTORIZE THIS LLMatrix4a mat_vert; mat_vert.loadu(mat_vert_in); LLMatrix4a mat_normal; mat_normal.loadu(mat_normal_in); //if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) //{ //vertex buffer no longer valid // mVertexBuffer = NULL; // mLastVertexBuffer = NULL; //} //VECTORIZE THIS LLVector4a min,max; if (f >= volume.getNumVolumeFaces()) { llwarns << "Generating bounding box for invalid face index!" << llendl; f = 0; } const LLVolumeFace &face = volume.getVolumeFace(f); min = face.mExtents[0]; max = face.mExtents[1]; llassert(less_than_max_mag(min)); llassert(less_than_max_mag(max)); //min, max are in volume space, convert to drawable render space LLVector4a center; LLVector4a t; t.setAdd(min, max); t.mul(0.5f); mat_vert.affineTransform(t, center); LLVector4a size; size.setSub(max, min); size.mul(0.5f); llassert(less_than_max_mag(min)); llassert(less_than_max_mag(max)); if (!global_volume) { //VECTORIZE THIS LLVector4a scale; scale.load3(mDrawablep->getVObj()->getScale().mV); size.mul(scale); } mat_normal.mMatrix[0].normalize3fast(); mat_normal.mMatrix[1].normalize3fast(); mat_normal.mMatrix[2].normalize3fast(); LLVector4a v[4]; //get 4 corners of bounding box mat_normal.rotate(size,v[0]); //VECTORIZE THIS LLVector4a scale; scale.set(-1.f, -1.f, 1.f); scale.mul(size); mat_normal.rotate(scale, v[1]); scale.set(1.f, -1.f, -1.f); scale.mul(size); mat_normal.rotate(scale, v[2]); scale.set(-1.f, 1.f, -1.f); scale.mul(size); mat_normal.rotate(scale, v[3]); LLVector4a& newMin = mExtents[0]; LLVector4a& newMax = mExtents[1]; newMin = newMax = center; llassert(less_than_max_mag(center)); for (U32 i = 0; i < 4; i++) { LLVector4a delta; delta.setAbs(v[i]); LLVector4a min; min.setSub(center, delta); LLVector4a max; max.setAdd(center, delta); newMin.setMin(newMin,min); newMax.setMax(newMax,max); llassert(less_than_max_mag(newMin)); llassert(less_than_max_mag(newMax)); } if (!mDrawablep->isActive()) { LLVector4a offset; offset.load3(mDrawablep->getRegion()->getOriginAgent().mV); newMin.add(offset); newMax.add(offset); llassert(less_than_max_mag(newMin)); llassert(less_than_max_mag(newMax)); } t.setAdd(newMin, newMax); t.mul(0.5f); llassert(less_than_max_mag(t)); //VECTORIZE THIS mCenterLocal.set(t.getF32ptr()); llassert(less_than_max_mag(newMin)); llassert(less_than_max_mag(newMax)); t.setSub(newMax,newMin); mBoundingSphereRadius = t.getLength3().getF32()*0.5f; updateCenterAgent(); } return TRUE; }