void LLVOTree::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax) { F32 radius = getScale().length()*0.05f; LLVector3 center = getRenderPosition(); F32 sz = mBillboardScale*mBillboardRatio*radius*0.5f; LLVector3 size(sz,sz,sz); center += LLVector3(0, 0, size.mV[2]) * getRotation(); newMin.set(center-size); newMax.set(center+size); mDrawable->setPositionGroup(center); }
LLVector3 LLModel::getTransformedCenter(const LLMatrix4& mat) { LLVector3 ret; if (!mVolumeFaces.empty()) { LLMatrix4a m; m.loadu(mat); LLVector4a minv,maxv; LLVector4a t; m.affineTransform(mVolumeFaces[0].mPositions[0], t); minv = maxv = t; for (S32 i = 0; i < (S32)mVolumeFaces.size(); ++i) { LLVolumeFace& face = mVolumeFaces[i]; for (U32 j = 0; j < (U32)face.mNumVertices; ++j) { m.affineTransform(face.mPositions[j],t); update_min_max(minv, maxv, t); } } minv.add(maxv); minv.mul(0.5f); ret.set(minv.getF32ptr()); } return ret; }
void LLDrawable::updateDistance(LLCamera& camera, bool force_update) { if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD) { llwarns << "Attempted to update distance for non-world camera." << llendl; return; } //switch LOD with the spatial group to avoid artifacts //LLSpatialGroup* sg = getSpatialGroup(); LLVector3 pos; //if (!sg || sg->changeLOD()) { LLVOVolume* volume = getVOVolume(); if (volume) { if (getSpatialGroup()) { pos.set(getPositionGroup().getF32ptr()); } else { pos = getPositionAgent(); } if (isState(LLDrawable::HAS_ALPHA)) { for (S32 i = 0; i < getNumFaces(); i++) { LLFace* facep = getFace(i); if (force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA) { LLVector4a box; box.setSub(facep->mExtents[1], facep->mExtents[0]); box.mul(0.25f); LLVector3 v = (facep->mCenterLocal-camera.getOrigin()); const LLVector3& at = camera.getAtAxis(); for (U32 j = 0; j < 3; j++) { v.mV[j] -= box[j] * at.mV[j]; } facep->mDistance = v * camera.getAtAxis(); } } } } else { pos = LLVector3(getPositionGroup().getF32ptr()); } pos -= camera.getOrigin(); mDistanceWRTCamera = llround(pos.magVec(), 0.01f); mVObjp->updateLOD(); } }
BOOL LLVOTree::updateGeometry(LLDrawable *drawable) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_TREE); if (mReferenceBuffer.isNull() || mDrawable->getFace(0)->mVertexBuffer.isNull()) { const F32 SRR3 = 0.577350269f; // sqrt(1/3) const F32 SRR2 = 0.707106781f; // sqrt(1/2) U32 i, j; U32 slices = MAX_SLICES; S32 max_indices = LEAF_INDICES; S32 max_vertices = LEAF_VERTICES; S32 lod; LLFace *face = drawable->getFace(0); face->mCenterAgent = getPositionAgent(); face->mCenterLocal = face->mCenterAgent; for (lod = 0; lod < 4; lod++) { slices = sLODSlices[lod]; sLODVertexOffset[lod] = max_vertices; sLODVertexCount[lod] = slices*slices; sLODIndexOffset[lod] = max_indices; sLODIndexCount[lod] = (slices-1)*(slices-1)*6; max_indices += sLODIndexCount[lod]; max_vertices += sLODVertexCount[lod]; } mReferenceBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, gSavedSettings.getBOOL("RenderAnimateTrees") ? GL_STATIC_DRAW_ARB : 0); mReferenceBuffer->allocateBuffer(max_vertices, max_indices, TRUE); LLStrider<LLVector3> vertices; LLStrider<LLVector3> normals; LLStrider<LLVector2> tex_coords; LLStrider<U16> indicesp; mReferenceBuffer->getVertexStrider(vertices); mReferenceBuffer->getNormalStrider(normals); mReferenceBuffer->getTexCoord0Strider(tex_coords); mReferenceBuffer->getIndexStrider(indicesp); S32 vertex_count = 0; S32 index_count = 0; // First leaf *(normals++) = LLVector3(-SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f); vertex_count++; *(normals++) = LLVector3(SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f); vertex_count++; *(normals++) = LLVector3(-SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f); vertex_count++; *(normals++) = LLVector3(SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f); vertex_count++; *(indicesp++) = 0; index_count++; *(indicesp++) = 1; index_count++; *(indicesp++) = 2; index_count++; *(indicesp++) = 0; index_count++; *(indicesp++) = 3; index_count++; *(indicesp++) = 1; index_count++; // Same leaf, inverse winding/normals *(normals++) = LLVector3(-SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f); vertex_count++; *(normals++) = LLVector3(SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f); vertex_count++; *(normals++) = LLVector3(-SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f); vertex_count++; *(normals++) = LLVector3(SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f); vertex_count++; *(indicesp++) = 4; index_count++; *(indicesp++) = 6; index_count++; *(indicesp++) = 5; index_count++; *(indicesp++) = 4; index_count++; *(indicesp++) = 5; index_count++; *(indicesp++) = 7; index_count++; // next leaf *(normals++) = LLVector3(SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f); vertex_count++; *(normals++) = LLVector3(SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f); vertex_count++; *(normals++) = LLVector3(SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f); vertex_count++; *(normals++) = LLVector3(SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f); vertex_count++; *(indicesp++) = 8; index_count++; *(indicesp++) = 9; index_count++; *(indicesp++) = 10; index_count++; *(indicesp++) = 8; index_count++; *(indicesp++) = 11; index_count++; *(indicesp++) = 9; index_count++; // other side of same leaf *(normals++) = LLVector3(-SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f); vertex_count++; *(normals++) = LLVector3(-SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f); vertex_count++; *(normals++) = LLVector3(-SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f); vertex_count++; *(normals++) = LLVector3(-SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f); vertex_count++; *(indicesp++) = 12; index_count++; *(indicesp++) = 14; index_count++; *(indicesp++) = 13; index_count++; *(indicesp++) = 12; index_count++; *(indicesp++) = 13; index_count++; *(indicesp++) = 15; index_count++; // Generate geometry for the cylinders // Different LOD's // Generate the vertices // Generate the indices for (lod = 0; lod < 4; lod++) { slices = sLODSlices[lod]; F32 base_radius = 0.65f; F32 top_radius = base_radius * sSpeciesTable[mSpecies]->mTaper; //llinfos << "Species " << ((U32) mSpecies) << ", taper = " << sSpeciesTable[mSpecies].mTaper << llendl; //llinfos << "Droop " << mDroop << ", branchlength: " << mBranchLength << llendl; F32 angle = 0; F32 angle_inc = 360.f/(slices-1); F32 z = 0.f; F32 z_inc = 1.f; if (slices > 3) { z_inc = 1.f/(slices - 3); } F32 radius = base_radius; F32 x1,y1; F32 noise_scale = sSpeciesTable[mSpecies]->mNoiseMag; LLVector3 nvec; const F32 cap_nudge = 0.1f; // Height to 'peak' the caps on top/bottom of branch const S32 fractal_depth = 5; F32 nvec_scale = 1.f * sSpeciesTable[mSpecies]->mNoiseScale; F32 nvec_scalez = 4.f * sSpeciesTable[mSpecies]->mNoiseScale; F32 tex_z_repeat = sSpeciesTable[mSpecies]->mRepeatTrunkZ; F32 start_radius; F32 nangle = 0; F32 height = 1.f; F32 r0; for (i = 0; i < slices; i++) { if (i == 0) { z = - cap_nudge; r0 = 0.0; } else if (i == (slices - 1)) { z = 1.f + cap_nudge;//((i - 2) * z_inc) + cap_nudge; r0 = 0.0; } else { z = (i - 1) * z_inc; r0 = base_radius + (top_radius - base_radius)*z; } for (j = 0; j < slices; j++) { if (slices - 1 == j) { angle = 0.f; } else { angle = j*angle_inc; } nangle = angle; x1 = cos(angle * DEG_TO_RAD); y1 = sin(angle * DEG_TO_RAD); LLVector2 tc; // This isn't totally accurate. Should compute based on slope as well. start_radius = r0 * (1.f + 1.2f*fabs(z - 0.66f*height)/height); nvec.set( cos(nangle * DEG_TO_RAD)*start_radius*nvec_scale, sin(nangle * DEG_TO_RAD)*start_radius*nvec_scale, z*nvec_scalez); // First and last slice at 0 radius (to bring in top/bottom of structure) radius = start_radius + turbulence3((F32*)&nvec.mV, (F32)fractal_depth)*noise_scale; if (slices - 1 == j) { // Not 0.5 for slight slop factor to avoid edges on leaves tc = LLVector2(0.490f, (1.f - z/2.f)*tex_z_repeat); } else { tc = LLVector2((angle/360.f)*0.5f, (1.f - z/2.f)*tex_z_repeat); } *(vertices++) = LLVector3(x1*radius, y1*radius, z); *(normals++) = LLVector3(x1, y1, 0.f); *(tex_coords++) = tc; vertex_count++; } } for (i = 0; i < (slices - 1); i++) { for (j = 0; j < (slices - 1); j++) { S32 x1_offset = j+1; if ((j+1) == slices) { x1_offset = 0; } // Generate the matching quads *(indicesp) = j + (i*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = j + ((i+1)*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = j + (i*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = x1_offset + (i*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; } } slices /= 2; } mReferenceBuffer->setBuffer(0); llassert(vertex_count == max_vertices); llassert(index_count == max_indices); } if (gLLWindEnabled || gSavedSettings.getBOOL("RenderAnimateTrees")) { mDrawable->getFace(0)->mVertexBuffer = mReferenceBuffer; } else { //generate tree mesh updateMesh(); } return TRUE; }
//----------------------------------------------------------------------------- // solve() //----------------------------------------------------------------------------- void LLJointSolverRP3::solve() { // llinfos << llendl; // llinfos << "LLJointSolverRP3::solve()" << llendl; //------------------------------------------------------------------------- // setup joints in their base rotations //------------------------------------------------------------------------- mJointA->setRotation( mJointABaseRotation ); mJointB->setRotation( mJointBBaseRotation ); //------------------------------------------------------------------------- // get joint positions in world space //------------------------------------------------------------------------- LLVector3 aPos = mJointA->getWorldPosition(); LLVector3 bPos = mJointB->getWorldPosition(); LLVector3 cPos = mJointC->getWorldPosition(); LLVector3 gPos = mJointGoal->getWorldPosition(); // llinfos << "bPosLocal = " << mJointB->getPosition() << llendl; // llinfos << "cPosLocal = " << mJointC->getPosition() << llendl; // llinfos << "bRotLocal = " << mJointB->getRotation() << llendl; // llinfos << "cRotLocal = " << mJointC->getRotation() << llendl; // llinfos << "aPos : " << aPos << llendl; // llinfos << "bPos : " << bPos << llendl; // llinfos << "cPos : " << cPos << llendl; // llinfos << "gPos : " << gPos << llendl; //------------------------------------------------------------------------- // get the poleVector in world space //------------------------------------------------------------------------- LLVector3 poleVec = mPoleVector; if ( mJointA->getParent() ) { LLVector4a pole_veca; pole_veca.load3(mPoleVector.mV); mJointA->getParent()->getWorldMatrix().rotate(pole_veca,pole_veca); poleVec.set(pole_veca.getF32ptr()); } //------------------------------------------------------------------------- // compute the following: // vector from A to B // vector from B to C // vector from A to C // vector from A to G (goal) //------------------------------------------------------------------------- LLVector3 abVec = bPos - aPos; LLVector3 bcVec = cPos - bPos; LLVector3 acVec = cPos - aPos; LLVector3 agVec = gPos - aPos; // llinfos << "abVec : " << abVec << llendl; // llinfos << "bcVec : " << bcVec << llendl; // llinfos << "acVec : " << acVec << llendl; // llinfos << "agVec : " << agVec << llendl; //------------------------------------------------------------------------- // compute needed lengths of those vectors //------------------------------------------------------------------------- F32 abLen = abVec.magVec(); F32 bcLen = bcVec.magVec(); F32 agLen = agVec.magVec(); // llinfos << "abLen : " << abLen << llendl; // llinfos << "bcLen : " << bcLen << llendl; // llinfos << "agLen : " << agLen << llendl; //------------------------------------------------------------------------- // compute component vector of (A->B) orthogonal to (A->C) //------------------------------------------------------------------------- LLVector3 abacCompOrthoVec = abVec - acVec * ((abVec * acVec)/(acVec * acVec)); // llinfos << "abacCompOrthoVec : " << abacCompOrthoVec << llendl; //------------------------------------------------------------------------- // compute the normal of the original ABC plane (and store for later) //------------------------------------------------------------------------- LLVector3 abcNorm; if (!mbUseBAxis) { if( are_parallel(abVec, bcVec, 0.001f) ) { // the current solution is maxed out, so we use the axis that is // orthogonal to both poleVec and A->B if ( are_parallel(poleVec, abVec, 0.001f) ) { // ACK! the problem is singular if ( are_parallel(poleVec, agVec, 0.001f) ) { // the solutions is also singular return; } else { abcNorm = poleVec % agVec; } } else { abcNorm = poleVec % abVec; } } else { abcNorm = abVec % bcVec; } } else { abcNorm = mBAxis * mJointB->getWorldRotation(); } //------------------------------------------------------------------------- // compute rotation of B //------------------------------------------------------------------------- // angle between A->B and B->C F32 abbcAng = angle_between(abVec, bcVec); // vector orthogonal to A->B and B->C LLVector3 abbcOrthoVec = abVec % bcVec; if (abbcOrthoVec.magVecSquared() < 0.001f) { abbcOrthoVec = poleVec % abVec; abacCompOrthoVec = poleVec; } abbcOrthoVec.normVec(); F32 agLenSq = agLen * agLen; // angle arm for extension F32 cosTheta = (agLenSq - abLen*abLen - bcLen*bcLen) / (2.0f * abLen * bcLen); if (cosTheta > 1.0f) cosTheta = 1.0f; else if (cosTheta < -1.0f) cosTheta = -1.0f; F32 theta = acos(cosTheta); LLQuaternion bRot(theta - abbcAng, abbcOrthoVec); // llinfos << "abbcAng : " << abbcAng << llendl; // llinfos << "abbcOrthoVec : " << abbcOrthoVec << llendl; // llinfos << "agLenSq : " << agLenSq << llendl; // llinfos << "cosTheta : " << cosTheta << llendl; // llinfos << "theta : " << theta << llendl; // llinfos << "bRot : " << bRot << llendl; // llinfos << "theta abbcAng theta-abbcAng: " << theta*180.0/F_PI << " " << abbcAng*180.0f/F_PI << " " << (theta - abbcAng)*180.0f/F_PI << llendl; //------------------------------------------------------------------------- // compute rotation that rotates new A->C to A->G //------------------------------------------------------------------------- // rotate B->C by bRot bcVec = bcVec * bRot; // update A->C acVec = abVec + bcVec; LLQuaternion cgRot; cgRot.shortestArc( acVec, agVec ); // llinfos << "bcVec : " << bcVec << llendl; // llinfos << "acVec : " << acVec << llendl; // llinfos << "cgRot : " << cgRot << llendl; // update A->B and B->C with rotation from C to G abVec = abVec * cgRot; bcVec = bcVec * cgRot; abcNorm = abcNorm * cgRot; acVec = abVec + bcVec; //------------------------------------------------------------------------- // compute the normal of the APG plane //------------------------------------------------------------------------- if (are_parallel(agVec, poleVec, 0.001f)) { // the solution plane is undefined ==> we're done return; } LLVector3 apgNorm = poleVec % agVec; apgNorm.normVec(); if (!mbUseBAxis) { //--------------------------------------------------------------------- // compute the normal of the new ABC plane // (only necessary if we're NOT using mBAxis) //--------------------------------------------------------------------- if( are_parallel(abVec, bcVec, 0.001f) ) { // G is either too close or too far away // we'll use the old ABCnormal } else { abcNorm = abVec % bcVec; } abcNorm.normVec(); } //------------------------------------------------------------------------- // calcuate plane rotation //------------------------------------------------------------------------- LLQuaternion pRot; if ( are_parallel( abcNorm, apgNorm, 0.001f) ) { if (abcNorm * apgNorm < 0.0f) { // we must be PI radians off ==> rotate by PI around agVec pRot.setQuat(F_PI, agVec); } else { // we're done } } else { pRot.shortestArc( abcNorm, apgNorm ); } // llinfos << "abcNorm = " << abcNorm << llendl; // llinfos << "apgNorm = " << apgNorm << llendl; // llinfos << "pRot = " << pRot << llendl; //------------------------------------------------------------------------- // compute twist rotation //------------------------------------------------------------------------- LLQuaternion twistRot( mTwist, agVec ); // llinfos << "twist : " << mTwist*180.0/F_PI << llendl; // llinfos << "agNormVec: " << agNormVec << llendl; // llinfos << "twistRot : " << twistRot << llendl; //------------------------------------------------------------------------- // compute rotation of A //------------------------------------------------------------------------- LLQuaternion aRot = cgRot * pRot * twistRot; //------------------------------------------------------------------------- // apply the rotations //------------------------------------------------------------------------- mJointB->setWorldRotation( mJointB->getWorldRotation() * bRot ); mJointA->setWorldRotation( mJointA->getWorldRotation() * aRot ); }
// <FS:Ansariel> Extended TP history void LLTeleportHistoryFlatItem::setLocalPos(const LLVector3& local_pos) { mLocalPos.set(local_pos); }
void LLModel::Decomposition::fromLLSD(LLSD& decomp) { if (decomp.has("HullList") && decomp.has("Positions")) { // updated for const-correctness. gcc is picky about this type of thing - Nyx const LLSD::Binary& hulls = decomp["HullList"].asBinary(); const LLSD::Binary& position = decomp["Positions"].asBinary(); U16* p = (U16*) &position[0]; mHull.resize(hulls.size()); LLVector3 min; LLVector3 max; LLVector3 range; if (decomp.has("Min")) { min.setValue(decomp["Min"]); max.setValue(decomp["Max"]); } else { min.set(-0.5f, -0.5f, -0.5f); max.set(0.5f, 0.5f, 0.5f); } range = max-min; for (U32 i = 0; i < hulls.size(); ++i) { U16 count = (hulls[i] == 0) ? 256 : hulls[i]; std::set<U64> valid; //must have at least 4 points //llassert(count > 3); for (U32 j = 0; j < count; ++j) { U64 test = (U64) p[0] | ((U64) p[1] << 16) | ((U64) p[2] << 32); //point must be unique //llassert(valid.find(test) == valid.end()); valid.insert(test); mHull[i].push_back(LLVector3( (F32) p[0]/65535.f*range.mV[0]+min.mV[0], (F32) p[1]/65535.f*range.mV[1]+min.mV[1], (F32) p[2]/65535.f*range.mV[2]+min.mV[2])); p += 3; } //each hull must contain at least 4 unique points //llassert(valid.size() > 3); } } if (decomp.has("BoundingVerts")) { const LLSD::Binary& position = decomp["BoundingVerts"].asBinary(); U16* p = (U16*) &position[0]; LLVector3 min; LLVector3 max; LLVector3 range; if (decomp.has("Min")) { min.setValue(decomp["Min"]); max.setValue(decomp["Max"]); } else { min.set(-0.5f, -0.5f, -0.5f); max.set(0.5f, 0.5f, 0.5f); } range = max-min; size_t count = position.size()/6; for (U32 j = 0; j < count; ++j) { mBaseHull.push_back(LLVector3( (F32) p[0]/65535.f*range.mV[0]+min.mV[0], (F32) p[1]/65535.f*range.mV[1]+min.mV[1], (F32) p[2]/65535.f*range.mV[2]+min.mV[2])); p += 3; } } else { //empty base hull mesh to indicate decomposition has been loaded //but contains no base hull mBaseHullMesh.clear(); } }
BOOL LLFace::getGeometryVolume(const LLVolume& volume, const S32 &f, const LLMatrix4& mat_vert_in, const LLMatrix3& mat_norm_in, const U16 &index_offset, bool force_rebuild) { llassert(verify()); const LLVolumeFace &vf = volume.getVolumeFace(f); S32 num_vertices = (S32)vf.mNumVertices; S32 num_indices = (S32) vf.mNumIndices; if (mVertexBuffer.notNull()) { if (num_indices + (S32) mIndicesIndex > mVertexBuffer->getNumIndices()) { llwarns << "Index buffer overflow!" << llendl; llwarns << "Indices Count: " << mIndicesCount << " VF Num Indices: " << num_indices << " Indices Index: " << mIndicesIndex << " VB Num Indices: " << mVertexBuffer->getNumIndices() << llendl; llwarns << "Last Indices Count: " << mLastIndicesCount << " Last Indices Index: " << mLastIndicesIndex << " Face Index: " << f << " Pool Type: " << mPoolType << llendl; return FALSE; } if (num_vertices + mGeomIndex > mVertexBuffer->getNumVerts()) { llwarns << "Vertex buffer overflow!" << llendl; return FALSE; } } LLStrider<LLVector3> vertices; LLStrider<LLVector2> tex_coords; LLStrider<LLVector2> tex_coords2; LLStrider<LLVector3> normals; LLStrider<LLColor4U> colors; LLStrider<LLVector3> binormals; LLStrider<U16> indicesp; #if MESH_ENABLED LLStrider<LLVector4> weights; #endif //MESH_ENABLED BOOL full_rebuild = force_rebuild || mDrawablep->isState(LLDrawable::REBUILD_VOLUME); BOOL global_volume = mDrawablep->getVOVolume()->isVolumeGlobal(); LLVector3 scale; if (global_volume) { scale.setVec(1,1,1); } else { scale = mVObjp->getScale(); } bool rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION); bool rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR); bool rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD); bool rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); bool rebuild_binormal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_BINORMAL); #if MESH_ENABLED bool rebuild_weights = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_WEIGHT4); #endif //MESH_ENABLED const LLTextureEntry *tep = mVObjp->getTE(f); if (!tep) rebuild_color = FALSE; // can't get color when tep is NULL U8 bump_code = tep ? tep->getBumpmap() : 0; BOOL is_static = mDrawablep->isStatic(); BOOL is_global = is_static; LLVector3 center_sum(0.f, 0.f, 0.f); if (is_global) { setState(GLOBAL); } else { clearState(GLOBAL); } LLColor4U color = (tep ? LLColor4U(tep->getColor()) : LLColor4U::white); if (rebuild_color) // FALSE if tep == NULL { if (tep) { GLfloat alpha[4] = { 0.00f, 0.25f, 0.5f, 0.75f }; if (getPoolType() != LLDrawPool::POOL_ALPHA && (LLPipeline::sRenderDeferred || (LLPipeline::sRenderBump && tep->getShiny()))) { color.mV[3] = U8 (alpha[tep->getShiny()] * 255); } } } // INDICES if (full_rebuild) { mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex); for (U32 i = 0; i < (U32) num_indices; i++) { indicesp[i] = vf.mIndices[i] + index_offset; } //mVertexBuffer->setBuffer(0); } LLMatrix4a mat_normal; mat_normal.loadu(mat_norm_in); //if it's not fullbright and has no normals, bake sunlight based on face normal //bool bake_sunlight = !getTextureEntry()->getFullbright() && // !mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; if (rebuild_tcoord) { bool do_xform; if (tep) { r = tep->getRotation(); os = tep->mOffsetS; ot = tep->mOffsetT; ms = tep->mScaleS; mt = tep->mScaleT; cos_ang = cos(r); sin_ang = sin(r); if (cos_ang != 1.f || sin_ang != 0.f || os != 0.f || ot != 0.f || ms != 1.f || mt != 1.f) { do_xform = true; } else { do_xform = false; } } else { do_xform = false; } //bump setup LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f ); LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f); LLVector4a bump_t_primary_light_ray(0.f, 0.f, 0.f); LLQuaternion bump_quat; if (mDrawablep->isActive()) { bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); } if (bump_code) { mVObjp->getVolume()->genBinormals(f); F32 offset_multiple; switch( bump_code ) { case BE_NO_BUMP: offset_multiple = 0.f; break; case BE_BRIGHTNESS: case BE_DARKNESS: if( mTexture.notNull() && mTexture->hasGLTexture()) { // Offset by approximately one texel S32 cur_discard = mTexture->getDiscardLevel(); S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() ); max_size <<= cur_discard; const F32 ARTIFICIAL_OFFSET = 2.f; offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; } else { offset_multiple = 1.f/256; } break; default: // Standard bumpmap textures. Assumed to be 256x256 offset_multiple = 1.f / 256; break; } F32 s_scale = 1.f; F32 t_scale = 1.f; if( tep ) { tep->getScale( &s_scale, &t_scale ); } // Use the nudged south when coming from above sun angle, such // that emboss mapping always shows up on the upward faces of cubes when // it's noon (since a lot of builders build with the sun forced to noon). LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; LLVector3 moon_ray = gSky.getMoonDirection(); LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV); bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV); } U8 texgen = getTextureEntry()->getTexGen(); if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT) { //planar texgen needs binormals mVObjp->getVolume()->genBinormals(f); } U8 tex_mode = 0; if (isState(TEXTURE_ANIM)) { LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; tex_mode = vobj->mTexAnimMode; if (!tex_mode) { clearState(TEXTURE_ANIM); } else { os = ot = 0.f; r = 0.f; cos_ang = 1.f; sin_ang = 0.f; ms = mt = 1.f; do_xform = false; } if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) { //don't override texture transform during tc bake tex_mode = 0; } } LLVector4a scalea; scalea.load3(scale.mV); bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); bool do_tex_mat = tex_mode && mTextureMatrix; if (!do_bump) { //not in atlas or not bump mapped, might be able to do a cheap update mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex); if (texgen != LLTextureEntry::TEX_GEN_PLANAR) { if (!do_tex_mat) { if (!do_xform) { tex_coords.assignArray((U8*) vf.mTexCoords, sizeof(vf.mTexCoords[0]), num_vertices); } else { for (S32 i = 0; i < num_vertices; i++) { LLVector2 tc(vf.mTexCoords[i]); xform(tc, cos_ang, sin_ang, os, ot, ms, mt); *tex_coords++ = tc; } } } else { //do tex mat, no texgen, no atlas, no bump for (S32 i = 0; i < num_vertices; i++) { LLVector2 tc(vf.mTexCoords[i]); //LLVector4a& norm = vf.mNormals[i]; //LLVector4a& center = *(vf.mCenter); LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); tmp = tmp * *mTextureMatrix; tc.mV[0] = tmp.mV[0]; tc.mV[1] = tmp.mV[1]; *tex_coords++ = tc; } } } else { //no bump, no atlas, tex gen planar if (do_tex_mat) { for (S32 i = 0; i < num_vertices; i++) { LLVector2 tc(vf.mTexCoords[i]); LLVector4a& norm = vf.mNormals[i]; LLVector4a& center = *(vf.mCenter); LLVector4a vec = vf.mPositions[i]; vec.mul(scalea); planarProjection(tc, norm, center, vec); LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); tmp = tmp * *mTextureMatrix; tc.mV[0] = tmp.mV[0]; tc.mV[1] = tmp.mV[1]; *tex_coords++ = tc; } } else { for (S32 i = 0; i < num_vertices; i++) { LLVector2 tc(vf.mTexCoords[i]); LLVector4a& norm = vf.mNormals[i]; LLVector4a& center = *(vf.mCenter); LLVector4a vec = vf.mPositions[i]; vec.mul(scalea); planarProjection(tc, norm, center, vec); xform(tc, cos_ang, sin_ang, os, ot, ms, mt); *tex_coords++ = tc; } } } //mVertexBuffer->setBuffer(0); } else { //either bump mapped or in atlas, just do the whole expensive loop mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex); std::vector<LLVector2> bump_tc; for (S32 i = 0; i < num_vertices; i++) { LLVector2 tc(vf.mTexCoords[i]); LLVector4a& norm = vf.mNormals[i]; LLVector4a& center = *(vf.mCenter); if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) { LLVector4a vec = vf.mPositions[i]; vec.mul(scalea); switch (texgen) { case LLTextureEntry::TEX_GEN_PLANAR: planarProjection(tc, norm, center, vec); break; case LLTextureEntry::TEX_GEN_SPHERICAL: sphericalProjection(tc, norm, center, vec); break; case LLTextureEntry::TEX_GEN_CYLINDRICAL: cylindricalProjection(tc, norm, center, vec); break; default: break; } } if (tex_mode && mTextureMatrix) { LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); tmp = tmp * *mTextureMatrix; tc.mV[0] = tmp.mV[0]; tc.mV[1] = tmp.mV[1]; } else { xform(tc, cos_ang, sin_ang, os, ot, ms, mt); } *tex_coords++ = tc; if (do_bump) { bump_tc.push_back(tc); } } //mVertexBuffer->setBuffer(0); if (do_bump) { mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex); for (S32 i = 0; i < num_vertices; i++) { LLVector4a tangent; tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]); LLMatrix4a tangent_to_object; tangent_to_object.setRows(tangent, vf.mBinormals[i], vf.mNormals[i]); LLVector4a t; tangent_to_object.rotate(binormal_dir, t); LLVector4a binormal; mat_normal.rotate(t, binormal); //VECTORIZE THIS if (mDrawablep->isActive()) { LLVector3 t; t.set(binormal.getF32ptr()); t *= bump_quat; binormal.load3(t.mV); } binormal.normalize3fast(); LLVector2 tc = bump_tc[i]; tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() ); *tex_coords2++ = tc; } //mVertexBuffer->setBuffer(0); } } } if (rebuild_pos) { llassert(num_vertices > 0); mVertexBuffer->getVertexStrider(vertices, mGeomIndex); LLMatrix4a mat_vert; mat_vert.loadu(mat_vert_in); LLVector4a* src = vf.mPositions; LLVector4a position; for (S32 i = 0; i < num_vertices; i++) { mat_vert.affineTransform(src[i], position); vertices[i].set(position.getF32ptr()); } //mVertexBuffer->setBuffer(0); } if (rebuild_normal) { mVertexBuffer->getNormalStrider(normals, mGeomIndex); for (S32 i = 0; i < num_vertices; i++) { LLVector4a normal; mat_normal.rotate(vf.mNormals[i], normal); normal.normalize3fast(); normals[i].set(normal.getF32ptr()); } //mVertexBuffer->setBuffer(0); } if (rebuild_binormal) { mVertexBuffer->getBinormalStrider(binormals, mGeomIndex); for (S32 i = 0; i < num_vertices; i++) { LLVector4a binormal; mat_normal.rotate(vf.mBinormals[i], binormal); binormal.normalize3fast(); binormals[i].set(binormal.getF32ptr()); } //mVertexBuffer->setBuffer(0); } #if MESH_ENABLED if (rebuild_weights && vf.mWeights) { mVertexBuffer->getWeight4Strider(weights, mGeomIndex); weights.assignArray((U8*) vf.mWeights, sizeof(vf.mWeights[0]), num_vertices); //mVertexBuffer->setBuffer(0); } #endif //MESH_ENABLED if (rebuild_color) { mVertexBuffer->getColorStrider(colors, mGeomIndex); for (S32 i = 0; i < num_vertices; i++) { colors[i] = color; } //mVertexBuffer->setBuffer(0); } if (rebuild_tcoord) { mTexExtents[0].setVec(0,0); mTexExtents[1].setVec(1,1); xform(mTexExtents[0], cos_ang, sin_ang, os, ot, ms, mt); xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt); F32 es = vf.mTexCoordExtents[1].mV[0] - vf.mTexCoordExtents[0].mV[0] ; F32 et = vf.mTexCoordExtents[1].mV[1] - vf.mTexCoordExtents[0].mV[1] ; mTexExtents[0][0] *= es ; mTexExtents[1][0] *= es ; mTexExtents[0][1] *= et ; mTexExtents[1][1] *= et ; } mLastVertexBuffer = mVertexBuffer; mLastGeomCount = mGeomCount; mLastGeomIndex = mGeomIndex; mLastIndicesCount = mIndicesCount; mLastIndicesIndex = mIndicesIndex; return TRUE; }