const LLVector3 LLDrawable::getPositionAgent() const { if (getVOVolume()) { if (isActive()) { if (!isRoot()) { LLVector4a pos; pos.load3(mVObjp->getPosition().mV); getRenderMatrix().affineTransform(pos,pos); return LLVector3(pos.getF32ptr()); } else { return LLVector3(getRenderMatrix().getRow<3>().getF32ptr()); } } else { return mVObjp->getPositionAgent(); } } else { return getWorldPosition(); } }
void LLVOCacheEntry::calcSceneContribution(const LLVector4a& camera_origin, bool needs_update, U32 last_update, F32 max_dist) { if(!needs_update && getVisible() >= last_update) { return; //no need to update } LLVector4a lookAt; lookAt.setSub(getPositionGroup(), camera_origin); F32 distance = lookAt.getLength3().getF32(); distance -= sNearRadius; if(distance <= 0.f) { //nearby objects, set a large number const F32 LARGE_SCENE_CONTRIBUTION = 1000.f; //a large number to force to load the object. mSceneContrib = LARGE_SCENE_CONTRIBUTION; } else { F32 rad = getBinRadius(); max_dist += rad; if(distance + sNearRadius < max_dist) { mSceneContrib = (rad * rad) / distance; } else { mSceneContrib = 0.f; //out of draw distance, not to load } } setVisible(); }
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; }
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(); } }
void LLVOPartGroup::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { const LLVector3& pos_agent = getPositionAgent(); newMin.load3( (pos_agent - mScale).mV); newMax.load3( (pos_agent + mScale).mV); LLVector4a pos; pos.load3(pos_agent.mV); mDrawable->setPositionGroup(pos); }
U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center) { LLVector4a origin; origin.load3(camera->getOrigin().mV); S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7; return (U8*) (sOcclusionIndices+cypher*8); }
U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center) { LLVector4a origin; origin.load3(camera->getOrigin().mV); S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7; return cypher*8; }
BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts) { S32 i, num_faces; LLDrawable* drawablep = volumep->mDrawable; if (!drawablep) { return FALSE; } LLVolume* volume = volumep->getVolume(); if (!volume) { return FALSE; } LLVOVolume* vo_volume = (LLVOVolume*) volumep; vo_volume->updateRelativeXform(); LLMatrix4 mat = vo_volume->getRelativeXform(); LLMatrix4 render_mat(vo_volume->getRenderRotation(), LLVector4(vo_volume->getRenderPosition())); LLMatrix4a render_mata; render_mata.loadu(render_mat); LLMatrix4a mata; mata.loadu(mat); num_faces = volume->getNumVolumeFaces(); for (i = 0; i < num_faces; i++) { const LLVolumeFace& face = volume->getVolumeFace(i); for (U32 v = 0; v < face.mNumVertices; v++) { const LLVector4a& src_vec = face.mPositions[v]; LLVector4a vec; mata.affineTransform(src_vec, vec); if (drawablep->isActive()) { LLVector4a t = vec; render_mata.affineTransform(t, vec); } BOOL in_frustum = pointInFrustum(LLVector3(vec.getF32ptr())) > 0; if (( !in_frustum && all_verts) || (in_frustum && !all_verts)) { return !all_verts; } } } return all_verts; }
//virtual bool LLViewerOctreeGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut) { const OctreeNode* node = mOctreeNode; if (node->isEmpty()) { //don't do anything if there are no objects if (empty && mOctreeNode->getParent()) { //only root is allowed to be empty OCT_ERRS << "Empty leaf found in octree." << LL_ENDL; } return false; } LLVector4a& newMin = mObjectExtents[0]; LLVector4a& newMax = mObjectExtents[1]; if (hasState(OBJECT_DIRTY)) { //calculate new bounding box clearState(OBJECT_DIRTY); //initialize bounding box to first element OctreeNode::const_element_iter i = node->getDataBegin(); LLViewerOctreeEntry* entry = *i; const LLVector4a* minMax = entry->getSpatialExtents(); newMin = minMax[0]; newMax = minMax[1]; for (++i; i != node->getDataEnd(); ++i) { entry = *i; minMax = entry->getSpatialExtents(); update_min_max(newMin, newMax, minMax[0]); update_min_max(newMin, newMax, minMax[1]); } mObjectBounds[0].setAdd(newMin, newMax); mObjectBounds[0].mul(0.5f); mObjectBounds[1].setSub(newMax, newMin); mObjectBounds[1].mul(0.5f); } if (empty) { minOut = newMin; maxOut = newMax; } else { minOut.setMin(minOut, newMin); maxOut.setMax(maxOut, newMax); } return TRUE; }
/* 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); }
LLVector4a LLDriverParam::getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { LLVector4a sum; sum.clear(); for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) { LLDrivenEntry* driven = &(*iter); sum.add(driven->mParam->getVertexDistortion( index, poly_mesh )); } return sum; }
bool less_than_max_mag(const LLVector4a& vec) { LLVector4a MAX_MAG; MAX_MAG.splat(1024.f*1024.f); LLVector4a val; val.setAbs(vec); S32 lt = val.lessThan(MAX_MAG).getGatheredBits() & 0x7; return lt == 0x7; }
void LLVOSurfacePatch::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) { LLVector3 posAgent = getPositionAgent(); LLVector3 scale = getScale(); scale.mV[VZ] = llmax(scale.mV[VZ], 1.f); newMin.load3( (posAgent-scale*0.5f).mV); // Changing to 2.f makes the culling a -little- better, but still wrong newMax.load3( (posAgent+scale*0.5f).mV); LLVector4a pos; pos.setAdd(newMin,newMax); pos.mul(0.5f); mDrawable->setPositionGroup(pos); }
BOOL LLVOPartGroup::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, S32* face_hit, LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* bi_normal) { LLVector4a dir; dir.setSub(end, start); F32 closest_t = 2.f; BOOL ret = FALSE; for (U32 idx = 0; idx < mViewerPartGroupp->mParticles.size(); ++idx) { const LLViewerPart &part = *((LLViewerPart*) (mViewerPartGroupp->mParticles[idx])); LLVector4a v[4]; LLStrider<LLVector4a> verticesp; verticesp = v; getGeometry(part, verticesp); F32 a,b,t; if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, a,b,t) || LLTriangleRayIntersect(v[1], v[3], v[2], start, dir, a,b,t)) { if (t >= 0.f && t <= 1.f && t < closest_t) { ret = TRUE; closest_t = t; if (face_hit) { *face_hit = idx; } if (intersection) { LLVector4a intersect = dir; intersect.mul(closest_t); intersection->setAdd(intersect, start); } } } } return ret; }
//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(); }
LLViewerOctreeGroup::LLViewerOctreeGroup(OctreeNode* node) : mOctreeNode(node), mState(CLEAN) { LLVector4a tmp; tmp.splat(0.f); mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] = mObjectExtents[0] = mObjectExtents[1] = tmp; mBounds[0] = node->getCenter(); mBounds[1] = node->getSize(); mOctreeNode->addListener(this); }
//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 LLVOTree::updateSpatialExtents(LLVector4a& newMin, LLVector4a& 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.load3((center-size).mV); newMax.load3((center+size).mV); LLVector4a pos; pos.load3(center.mV); mDrawable->setPositionGroup(pos); }
void LLDrawable::shiftPos(const LLVector4a &shift_vector) { if (isDead()) { llwarns << "Shifting dead drawable" << llendl; return; } if (mParent) { mXform.setPosition(mVObjp->getPosition()); } else { mXform.setPosition(mVObjp->getPositionAgent()); } mXform.setRotation(mVObjp->getRotation()); mXform.setScale(1,1,1); mXform.updateMatrix(); if (isStatic()) { LLVOVolume* volume = getVOVolume(); if (!volume) { gPipeline.markRebuild(this, LLDrawable::REBUILD_ALL, TRUE); } for (S32 i = 0; i < getNumFaces(); i++) { LLFace *facep = getFace(i); facep->mCenterAgent += LLVector3(shift_vector.getF32ptr()); facep->mExtents[0].add(shift_vector); facep->mExtents[1].add(shift_vector); if (!volume && facep->hasGeometry()) { facep->clearVertexBuffer(); } } mExtents[0].add(shift_vector); mExtents[1].add(shift_vector); mPositionGroup.add(shift_vector); } else if (mSpatialBridge) { mSpatialBridge->shiftPos(shift_vector); } else if (isAvatar()) { mExtents[0].add(shift_vector); mExtents[1].add(shift_vector); mPositionGroup.add(shift_vector); } mVObjp->onShift(shift_vector); }
LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data, const LLVector3 &direction, const std::string &name) { LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); cloned_morph_data->mName = name; LLVector4a dir; dir.load3(direction.mV); for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) { cloned_morph_data->mCoords[v] = dir; cloned_morph_data->mNormals[v].clear(); cloned_morph_data->mBinormals[v].clear(); } return cloned_morph_data; }
const LLVector4a &LLDriverParam::getAvgDistortion() { // It's not actually correct to take the average of averages, but it good enough here. LLVector4a sum; sum.clear(); S32 count = 0; for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) { LLDrivenEntry* driven = &(*iter); sum.add(driven->mParam->getAvgDistortion()); count++; } sum.mul( 1.f/(F32)count); mDefaultVec = sum; return mDefaultVec; }
void LLVolumeImplFlexible::onShift(const LLVector4a &shift_vector) { //VECTORIZE THIS LLVector3 shift(shift_vector.getF32ptr()); for (int section = 0; section < (1<<FLEXIBLE_OBJECT_MAX_SECTIONS)+1; ++section) { mSection[section].mPosition += shift; } }
void LLVOWater::updateSpatialExtents(LLVector4a &newMin, LLVector4a& newMax) { LLVector4a pos; pos.load3(getPositionAgent().mV); LLVector4a scale; scale.load3(getScale().mV); scale.mul(0.5f); newMin.setSub(pos, scale); newMax.setAdd(pos, scale); pos.setAdd(newMin,newMax); pos.mul(0.5f); mDrawable->setPositionGroup(pos); }
BOOL LLOcclusionCullingGroup::earlyFail(LLCamera* camera, const LLVector4a* bounds) { if (camera->getOrigin().isExactlyZero()) { return FALSE; } static LLCachedControl<F32> vel("SHOcclusionFudge",SG_OCCLUSION_FUDGE); LLVector4a fudge(vel*2.f); const LLVector4a& c = bounds[0]; static LLVector4a r; r.setAdd(bounds[1], fudge); /*if (r.magVecSquared() > 1024.0*1024.0) { return TRUE; }*/ LLVector4a e; e.load3(camera->getOrigin().mV); LLVector4a min; min.setSub(c,r); LLVector4a max; max.setAdd(c,r); S32 lt = e.lessThan(min).getGatheredBits() & 0x7; if (lt) { return FALSE; } S32 gt = e.greaterThan(max).getGatheredBits() & 0x7; if (gt) { return FALSE; } return TRUE; }
void LLVOCacheEntry::setBoundingInfo(const LLVector3& pos, const LLVector3& scale) { LLVector4a center, newMin, newMax; center.load3(pos.mV); LLVector4a size; size.load3(scale.mV); newMin.setSub(center, size); newMax.setAdd(center, size); setPositionGroup(center); setSpatialExtents(newMin, newMax); if(getNumOfChildren() > 0) //has children { updateParentBoundingInfo(); } else { setBinRadius(llmin(size.getLength3().getF32() * 4.f, 256.f)); } }
bool LLVOCacheEntry::isAnyVisible(const LLVector4a& camera_origin, const LLVector4a& local_camera_origin, F32 dist_threshold) { LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*)getGroup(); if(!group) { return false; } //any visible bool vis = group->isAnyRecentlyVisible(); //not ready to remove if(!vis) { S32 cur_vis = llmax(group->getAnyVisible(), (S32)getVisible()); vis = (cur_vis + sMinFrameRange > LLViewerOctreeEntryData::getCurrentFrame()); } //within the back sphere if(!vis && !mParentID && !group->isOcclusionState(LLOcclusionCullingGroup::OCCLUDED)) { LLVector4a lookAt; if(mBSphereRadius > 0.f) { lookAt.setSub(mBSphereCenter, local_camera_origin); dist_threshold += mBSphereRadius; } else { lookAt.setSub(getPositionGroup(), camera_origin); dist_threshold += getBinRadius(); } vis = (lookAt.dot3(lookAt).getF32() < dist_threshold * dist_threshold); } return vis; }
void LLVOPartGroup::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { const LLVector3& pos_agent = getPositionAgent(); LLVector4a scale; LLVector4a p; p.load3(pos_agent.mV); scale.splat(mScale.mV[0]+mViewerPartGroupp->getBoxSide()*0.5f); newMin.setSub(p, scale); newMax.setAdd(p,scale); llassert(newMin.isFinite3()); llassert(newMax.isFinite3()); llassert(p.isFinite3()); mDrawable->setPositionGroup(p); }
// static void LLViewerJointMesh::updateGeometry(LLFace *mFace, LLPolyMesh *mMesh) { LLStrider<LLVector3> o_vertices; LLStrider<LLVector3> o_normals; //get vertex and normal striders LLVertexBuffer* buffer = mFace->getVertexBuffer(); buffer->getVertexStrider(o_vertices, 0); buffer->getNormalStrider(o_normals, 0); F32* __restrict vert = o_vertices[0].mV; F32* __restrict norm = o_normals[0].mV; const F32* __restrict weights = mMesh->getWeights(); const LLVector4a* __restrict coords = (LLVector4a*) mMesh->getCoords(); const LLVector4a* __restrict normals = (LLVector4a*) mMesh->getNormals(); U32 offset = mMesh->mFaceVertexOffset*4; vert += offset; norm += offset; for (U32 index = 0; index < mMesh->getNumVertices(); index++) { // equivalent to joint = floorf(weights[index]); S32 joint = _mm_cvtt_ss2si(_mm_load_ss(weights+index)); F32 w = weights[index] - joint; LLMatrix4a gBlendMat; if (w != 0.f) { // blend between matrices and apply gBlendMat.setLerp(gJointMatAligned[joint+0], gJointMatAligned[joint+1], w); LLVector4a res; gBlendMat.affineTransform(coords[index], res); res.store4a(vert+index*4); gBlendMat.rotate(normals[index], res); res.store4a(norm+index*4); } else { // No lerp required in this case. LLVector4a res; gJointMatAligned[joint].affineTransform(coords[index], res); res.store4a(vert+index*4); gJointMatAligned[joint].rotate(normals[index], res); res.store4a(norm+index*4); } } buffer->flush(); }
S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r) { F32 d = 0.f; F32 t; LLVector4a origina; origina.load3(origin.mV); LLVector4a v; v.setSub(min, origina); if (v.dot3(v) < r) { v.setSub(max, origina); if (v.dot3(v) < r) { return 2; } } for (U32 i = 0; i < 3; i++) { if (origin.mV[i] < min[i]) { t = min[i] - origin.mV[i]; d += t*t; } else if (origin.mV[i] > max[i]) { t = origin.mV[i] - max[i]; d += t*t; } if (d > r) { return 0; } } return 1; }
//make the parent bounding box to include this child void LLVOCacheEntry::updateParentBoundingInfo(const LLVOCacheEntry* child) { const LLVector4a* child_exts = child->getSpatialExtents(); LLVector4a newMin, newMax; newMin = child_exts[0]; newMax = child_exts[1]; //move to regional space. { const LLVector4a& parent_pos = getPositionGroup(); newMin.add(parent_pos); newMax.add(parent_pos); } //update parent's bbox(min, max) const LLVector4a* parent_exts = getSpatialExtents(); update_min_max(newMin, newMax, parent_exts[0]); update_min_max(newMin, newMax, parent_exts[1]); for(S32 i = 0; i < 4; i++) { llclamp(newMin[i], 0.f, 256.f); llclamp(newMax[i], 0.f, 256.f); } setSpatialExtents(newMin, newMax); //update parent's bbox center LLVector4a center; center.setAdd(newMin, newMax); center.mul(0.5f); setPositionGroup(center); //update parent's bbox size vector LLVector4a size; size.setSub(newMax, newMin); size.mul(0.5f); setBinRadius(llmin(size.getLength3().getF32() * 4.f, 256.f)); }