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(); }
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(); } }
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; }
BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) { //VECTORIZE THIS //get area of circle around face LLVector4a center; center.load3(getPositionAgent().mV); LLVector4a size; size.setSub(mExtents[1], mExtents[0]); size.mul(0.5f); LLViewerCamera* camera = LLViewerCamera::getInstance(); F32 size_squared = size.dot3(size).getF32(); LLVector4a lookAt; LLVector4a t; t.load3(camera->getOrigin().mV); lookAt.setSub(center, t); F32 dist = lookAt.getLength3().getF32(); dist = llmax(dist-size.getLength3().getF32(), 0.f); lookAt.normalize3fast() ; //get area of circle around node F32 app_angle = atanf((F32) sqrt(size_squared) / dist); radius = app_angle*LLDrawable::sCurPixelAngle; mPixelArea = radius*radius * 3.14159f; LLVector4a x_axis; x_axis.load3(camera->getXAxis().mV); cos_angle_to_view_dir = lookAt.dot3(x_axis).getF32(); if(dist < mBoundingSphereRadius) //camera is very close { cos_angle_to_view_dir = 1.0f; mImportanceToCamera = 1.0f; } else { mImportanceToCamera = LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist); } return true; }
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; }
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 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); }
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); }
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; }
bool LLViewerOctreeCull::checkProjectionArea(const LLVector4a& center, const LLVector4a& size, const LLVector3& shift, F32 pixel_threshold, F32 near_radius) { LLVector3 local_orig = mCamera->getOrigin() - shift; LLVector4a origin; origin.load3(local_orig.mV); LLVector4a lookAt; lookAt.setSub(center, origin); F32 distance = lookAt.getLength3().getF32(); if(distance <= near_radius) { return true; //always load close-by objects } // treat object as if it were near_radius meters closer than it actually was. // this allows us to get some temporal coherence on visibility...objects that can be reached quickly will tend to be visible distance -= near_radius; F32 squared_rad = size.dot3(size).getF32(); return squared_rad / distance > pixel_threshold; }
//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)); }
BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, LLVector4a& intersection, BOOL debug_render) { if (!mVisible || mHidden) { return FALSE; } // don't pick text that isn't bound to a viewerobject if (!mSourceObject || mSourceObject->mDrawable.isNull()) { return FALSE; } F32 alpha_factor = 1.f; LLColor4 text_color = mColor; if (mDoFade) { if (mLastDistance > mFadeDistance) { alpha_factor = llmax(0.f, 1.f - (mLastDistance - mFadeDistance)/mFadeRange); text_color.mV[3] = text_color.mV[3]*alpha_factor; } } if (text_color.mV[3] < 0.01f) { return FALSE; } mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f)); LLVector3 position = mPositionAgent; if (mSourceObject) { //get intersection of eye through mPositionAgent to plane of source object //using this position keeps the camera from focusing on some seemingly random //point several meters in front of the nametag const LLVector3& p = mSourceObject->getPositionAgent(); const LLVector3& n = LLViewerCamera::getInstance()->getAtAxis(); const LLVector3& eye = LLViewerCamera::getInstance()->getOrigin(); LLVector3 ray = position-eye; ray.normalize(); LLVector3 delta = p-position; F32 dist = delta*n; F32 dt = dist/(ray*n); position += ray*dt; } // scale screen size of borders down LLVector3 x_pixel_vec; LLVector3 y_pixel_vec; LLViewerCamera::getInstance()->getPixelVectors(position, y_pixel_vec, x_pixel_vec); LLVector3 width_vec = mWidth * x_pixel_vec; LLVector3 height_vec = mHeight * y_pixel_vec; LLCoordGL screen_pos; LLViewerCamera::getInstance()->projectPosAgentToScreen(position, screen_pos, FALSE); LLVector2 screen_offset; screen_offset = updateScreenPos(mPositionOffset); LLVector3 render_position = position + (x_pixel_vec * screen_offset.mV[VX]) + (y_pixel_vec * screen_offset.mV[VY]); LLVector3 bg_pos = render_position + (F32)mOffsetY * y_pixel_vec - (width_vec / 2.f) - (height_vec); LLVector3 v[] = { bg_pos, bg_pos + width_vec, bg_pos + width_vec + height_vec, bg_pos + height_vec, }; LLVector4a dir; dir.setSub(end,start); F32 a, b, t; LLVector4a v0,v1,v2,v3; v0.load3(v[0].mV); v1.load3(v[1].mV); v2.load3(v[2].mV); v3.load3(v[3].mV); if (LLTriangleRayIntersect(v0, v1, v2, start, dir, a, b, t) || LLTriangleRayIntersect(v2, v3, v0, start, dir, a, b, t) ) { if (t <= 1.f) { dir.mul(t); intersection.setAdd(start, dir); return TRUE; } } return FALSE; }
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(); }
void LLVOPartGroup::getGeometry(const LLViewerPart& part, LLStrider<LLVector4a>& verticesp) { if (part.mFlags & LLPartData::LL_PART_RIBBON_MASK) { LLVector4a axis, pos, paxis, ppos; F32 scale, pscale; pos.load3(part.mPosAgent.mV); axis.load3(part.mAxis.mV); scale = part.mScale.mV[0]; if (part.mParent) { ppos.load3(part.mParent->mPosAgent.mV); paxis.load3(part.mParent->mAxis.mV); pscale = part.mParent->mScale.mV[0]; } else { //use source object as position if (part.mPartSourcep->mSourceObjectp.notNull()) { LLVector3 v = LLVector3(0,0,1); v *= part.mPartSourcep->mSourceObjectp->getRenderRotation(); paxis.load3(v.mV); ppos.load3(part.mPartSourcep->mPosAgent.mV); pscale = part.mStartScale.mV[0]; } else { //no source object, no parent, nothing to draw ppos = pos; pscale = scale; paxis = axis; } } LLVector4a p0, p1, p2, p3; scale *= 0.5f; pscale *= 0.5f; axis.mul(scale); paxis.mul(pscale); p0.setAdd(pos, axis); p1.setSub(pos,axis); p2.setAdd(ppos, paxis); p3.setSub(ppos, paxis); (*verticesp++) = p2; (*verticesp++) = p3; (*verticesp++) = p0; (*verticesp++) = p1; } else { LLVector4a part_pos_agent; part_pos_agent.load3(part.mPosAgent.mV); LLVector4a camera_agent; camera_agent.load3(getCameraPosition().mV); LLVector4a at; at.setSub(part_pos_agent, camera_agent); LLVector4a up(0, 0, 1); LLVector4a right; right.setCross3(at, up); right.normalize3fast(); up.setCross3(right, at); up.normalize3fast(); if (part.mFlags & LLPartData::LL_PART_FOLLOW_VELOCITY_MASK) { LLVector4a normvel; normvel.load3(part.mVelocity.mV); normvel.normalize3fast(); LLVector2 up_fracs; up_fracs.mV[0] = normvel.dot3(right).getF32(); up_fracs.mV[1] = normvel.dot3(up).getF32(); up_fracs.normalize(); LLVector4a new_up; LLVector4a new_right; //new_up = up_fracs.mV[0] * right + up_fracs.mV[1]*up; LLVector4a t = right; t.mul(up_fracs.mV[0]); new_up = up; new_up.mul(up_fracs.mV[1]); new_up.add(t); //new_right = up_fracs.mV[1] * right - up_fracs.mV[0]*up; t = right; t.mul(up_fracs.mV[1]); new_right = up; new_right.mul(up_fracs.mV[0]); t.sub(new_right); up = new_up; right = t; up.normalize3fast(); right.normalize3fast(); } right.mul(0.5f*part.mScale.mV[0]); up.mul(0.5f*part.mScale.mV[1]); //HACK -- the verticesp->mV[3] = 0.f here are to set the texture index to 0 (particles don't use texture batching, maybe they should) // this works because there is actually a 4th float stored after the vertex position which is used as a texture index // also, somebody please VECTORIZE THIS LLVector4a ppapu; LLVector4a ppamu; ppapu.setAdd(part_pos_agent, up); ppamu.setSub(part_pos_agent, up); verticesp->setSub(ppapu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setSub(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setAdd(ppapu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setAdd(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; } }
void LLVOPartGroup::getGeometry(S32 idx, LLStrider<LLVector4a>& verticesp, LLStrider<LLVector3>& normalsp, LLStrider<LLVector2>& texcoordsp, LLStrider<LLColor4U>& colorsp, LLStrider<U16>& indicesp) { if (idx >= (S32) mViewerPartGroupp->mParticles.size()) { return; } const LLViewerPart &part = *((LLViewerPart*) (mViewerPartGroupp->mParticles[idx])); U32 vert_offset = mDrawable->getFace(idx)->getGeomIndex(); LLVector4a part_pos_agent; part_pos_agent.load3(part.mPosAgent.mV); LLVector4a camera_agent; camera_agent.load3(getCameraPosition().mV); LLVector4a at; at.setSub(part_pos_agent, camera_agent); LLVector4a up(0, 0, 1); LLVector4a right; right.setCross3(at, up); right.normalize3fast(); up.setCross3(right, at); up.normalize3fast(); if (part.mFlags & LLPartData::LL_PART_FOLLOW_VELOCITY_MASK) { LLVector4a normvel; normvel.load3(part.mVelocity.mV); normvel.normalize3fast(); LLVector2 up_fracs; up_fracs.mV[0] = normvel.dot3(right).getF32(); up_fracs.mV[1] = normvel.dot3(up).getF32(); up_fracs.normalize(); LLVector4a new_up; LLVector4a new_right; //new_up = up_fracs.mV[0] * right + up_fracs.mV[1]*up; LLVector4a t = right; t.mul(up_fracs.mV[0]); new_up = up; new_up.mul(up_fracs.mV[1]); new_up.add(t); //new_right = up_fracs.mV[1] * right - up_fracs.mV[0]*up; t = right; t.mul(up_fracs.mV[1]); new_right = up; new_right.mul(up_fracs.mV[0]); t.sub(new_right); up = new_up; right = t; up.normalize3fast(); right.normalize3fast(); } right.mul(0.5f*part.mScale.mV[0]); up.mul(0.5f*part.mScale.mV[1]); LLVector3 normal = -LLViewerCamera::getInstance()->getXAxis(); //HACK -- the verticesp->mV[3] = 0.f here are to set the texture index to 0 (particles don't use texture batching, maybe they should) // this works because there is actually a 4th float stored after the vertex position which is used as a texture index // also, somebody please VECTORIZE THIS LLVector4a ppapu; LLVector4a ppamu; ppapu.setAdd(part_pos_agent, up); ppamu.setSub(part_pos_agent, up); verticesp->setSub(ppapu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setSub(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setAdd(ppapu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setAdd(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; //*verticesp++ = part_pos_agent + up - right; //*verticesp++ = part_pos_agent - up - right; //*verticesp++ = part_pos_agent + up + right; //*verticesp++ = part_pos_agent - up + right; *colorsp++ = part.mColor; *colorsp++ = part.mColor; *colorsp++ = part.mColor; *colorsp++ = part.mColor; *texcoordsp++ = LLVector2(0.f, 1.f); *texcoordsp++ = LLVector2(0.f, 0.f); *texcoordsp++ = LLVector2(1.f, 1.f); *texcoordsp++ = LLVector2(1.f, 0.f); *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *indicesp++ = vert_offset + 0; *indicesp++ = vert_offset + 1; *indicesp++ = vert_offset + 2; *indicesp++ = vert_offset + 1; *indicesp++ = vert_offset + 3; *indicesp++ = vert_offset + 2; }
void LLVOClouds::getGeometry(S32 idx, LLStrider<LLVector4a>& verticesp, LLStrider<LLVector3>& normalsp, LLStrider<LLVector2>& texcoordsp, LLStrider<LLColor4U>& colorsp, LLStrider<U16>& indicesp) { if (idx >= mCloudGroupp->getNumPuffs()) { return; } LLDrawable* drawable = mDrawable; LLFace *facep = drawable->getFace(idx); if (!facep->hasGeometry()) { return; } const LLCloudPuff &puff = mCloudGroupp->getPuff(idx); LLColor4 float_color(LLColor3(gSky.getSunDiffuseColor() + gSky.getSunAmbientColor()),puff.getAlpha()); LLColor4U color; color.setVec(float_color); facep->setFaceColor(float_color); U32 vert_offset = facep->getGeomIndex(); LLVector4a part_pos_agent; part_pos_agent.load3(facep->mCenterLocal.mV); LLVector4a at; at.load3(LLViewerCamera::getInstance()->getAtAxis().mV); LLVector4a up(0, 0, 1); LLVector4a right; right.setCross3(at, up); right.normalize3fast(); up.setCross3(right, at); up.normalize3fast(); right.mul(0.5f*CLOUD_PUFF_WIDTH); up.mul(0.5f*CLOUD_PUFF_HEIGHT); LLVector3 normal(0.f,0.f,-1.f); //HACK -- the verticesp->mV[3] = 0.f here are to set the texture index to 0 (particles don't use texture batching, maybe they should) // this works because there is actually a 4th float stored after the vertex position which is used as a texture index // also, somebody please VECTORIZE THIS LLVector4a ppapu; LLVector4a ppamu; ppapu.setAdd(part_pos_agent, up); ppamu.setSub(part_pos_agent, up); verticesp->setSub(ppapu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setSub(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setAdd(ppapu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setAdd(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; // *verticesp++ = puff_pos_agent - right + up; // *verticesp++ = puff_pos_agent - right - up; // *verticesp++ = puff_pos_agent + right + up; // *verticesp++ = puff_pos_agent + right - up; *colorsp++ = color; *colorsp++ = color; *colorsp++ = color; *colorsp++ = color; *texcoordsp++ = LLVector2(0.f, 1.f); *texcoordsp++ = LLVector2(0.f, 0.f); *texcoordsp++ = LLVector2(1.f, 1.f); *texcoordsp++ = LLVector2(1.f, 0.f); *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *indicesp++ = vert_offset + 0; *indicesp++ = vert_offset + 1; *indicesp++ = vert_offset + 2; *indicesp++ = vert_offset + 1; *indicesp++ = vert_offset + 3; *indicesp++ = vert_offset + 2; }
bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance) { // small area check { LLVector4a edge1; edge1.setSub( a, b ); LLVector4a edge2; edge2.setSub( a, c ); ////////////////////////////////////////////////////////////////////////// /// Linden Modified ////////////////////////////////////////////////////////////////////////// // If no one edge is more than 10x longer than any other edge, we weaken // the tolerance by a factor of 1e-4f. LLVector4a edge3; edge3.setSub( c, b ); const F32 len1sq = edge1.dot3(edge1).getF32(); const F32 len2sq = edge2.dot3(edge2).getF32(); const F32 len3sq = edge3.dot3(edge3).getF32(); bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq); bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq); bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq); if ( abOK && acOK && cbOK ) { tolerance *= 1e-4f; } ////////////////////////////////////////////////////////////////////////// /// End Modified ////////////////////////////////////////////////////////////////////////// LLVector4a cross; cross.setCross3( edge1, edge2 ); LLVector4a edge1b; edge1b.setSub( b, a ); LLVector4a edge2b; edge2b.setSub( b, c ); LLVector4a crossb; crossb.setCross3( edge1b, edge2b ); if ( ( cross.dot3(cross).getF32() < tolerance ) || ( crossb.dot3(crossb).getF32() < tolerance )) { return true; } } // point triangle distance check { LLVector4a Q; Q.setSub(a, b); LLVector4a R; R.setSub(c, b); const F32 QQ = dot3fpu(Q, Q); const F32 RR = dot3fpu(R, R); const F32 QR = dot3fpu(R, Q); volatile F32 QQRR = QQ * RR; volatile F32 QRQR = QR * QR; F32 Det = (QQRR - QRQR); if( Det == 0.0f ) { return true; } } return false; }
BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, S32 *face_hitp, LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) { if (!lineSegmentBoundingBox(start, end)) { return FALSE; } LLVector4a da; da.setSub(end, start); LLVector3 delta(da.getF32ptr()); LLVector3 pdelta = delta; pdelta.mV[2] = 0; F32 plength = pdelta.length(); F32 tdelta = 1.f/plength; LLVector3 v_start(start.getF32ptr()); LLVector3 origin = v_start - mRegionp->getOriginAgent(); if (mRegionp->getLandHeightRegion(origin) > origin.mV[2]) { //origin is under ground, treat as no intersection return FALSE; } //step one meter at a time until intersection point found //VECTORIZE THIS const LLVector4a* exta = mDrawable->getSpatialExtents(); LLVector3 ext[2]; ext[0].set(exta[0].getF32ptr()); ext[1].set(exta[1].getF32ptr()); F32 rad = (delta*tdelta).magVecSquared(); F32 t = 0.f; while ( t <= 1.f) { LLVector3 sample = origin + delta*t; if (AABBSphereIntersectR2(ext[0], ext[1], sample+mRegionp->getOriginAgent(), rad)) { F32 height = mRegionp->getLandHeightRegion(sample); if (height > sample.mV[2]) { //ray went below ground, positive intersection //quick and dirty binary search to get impact point tdelta = -tdelta*0.5f; F32 err_dist = 0.001f; F32 dist = fabsf(sample.mV[2] - height); while (dist > err_dist && tdelta*tdelta > 0.0f) { t += tdelta; sample = origin+delta*t; height = mRegionp->getLandHeightRegion(sample); if ((tdelta < 0 && height < sample.mV[2]) || (height > sample.mV[2] && tdelta > 0)) { //jumped over intersection point, go back tdelta = -tdelta; } tdelta *= 0.5f; dist = fabsf(sample.mV[2] - height); } if (intersection) { F32 height = mRegionp->getLandHeightRegion(sample); if (fabsf(sample.mV[2]-height) < delta.length()*tdelta) { sample.mV[2] = mRegionp->getLandHeightRegion(sample); } intersection->load3((sample + mRegionp->getOriginAgent()).mV); } if (normal) { normal->load3((mRegionp->getLand().resolveNormalGlobal(mRegionp->getPosGlobalFromRegion(sample))).mV); } return TRUE; } } t += tdelta; if (t > 1 && t < 1.f+tdelta*0.99f) { //make sure end point is checked (saves vertical lines coming up negative) t = 1.f; } } return FALSE; }
//----------------------------------------------------------------------------- // applyMask() //----------------------------------------------------------------------------- void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert) { LLVector4a *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL; if (!mVertMask) { mVertMask = new LLPolyVertexMask(mMorphData); mNumMorphMasksPending--; } else { // remove effect of previous mask F32 *maskWeights = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL; if (maskWeights) { LLVector4a *coords = mMesh->getWritableCoords(); LLVector4a *scaled_normals = mMesh->getScaledNormals(); LLVector4a *scaled_binormals = mMesh->getScaledBinormals(); LLVector2 *tex_coords = mMesh->getWritableTexCoords(); LLVector4Logical clothing_mask; clothing_mask.clear(); clothing_mask.setElement<0>(); clothing_mask.setElement<1>(); clothing_mask.setElement<2>(); for(U32 vert = 0; vert < mMorphData->mNumIndices; vert++) { F32 lastMaskWeight = mLastWeight * maskWeights[vert]; S32 out_vert = mMorphData->mVertexIndices[vert]; // remove effect of existing masked morph LLVector4a t; t = mMorphData->mCoords[vert]; t.mul(lastMaskWeight); coords[out_vert].sub(t); t = mMorphData->mNormals[vert]; t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR); scaled_normals[out_vert].sub(t); t = mMorphData->mBinormals[vert]; t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR); scaled_binormals[out_vert].sub(t); tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * lastMaskWeight; if (clothing_weights) { LLVector4a clothing_offset = mMorphData->mCoords[vert]; clothing_offset.mul(lastMaskWeight); LLVector4a* clothing_weight = &clothing_weights[out_vert]; LLVector4a t; t.setSub(*clothing_weight, clothing_offset); clothing_weight->setSelectWithMask(clothing_mask, t, *clothing_weight); } } } } // set last weight to 0, since we've removed the effect of this morph mLastWeight = 0.f; mVertMask->generateMask(maskTextureData, width, height, num_components, invert, clothing_weights); apply(mLastSex); }
// 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; } }
void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results, BOOL for_select) { if (!gPipeline.hasRenderType(mDrawableType)) { return; } //HACK don't draw attachments for avatars that haven't been visible in more than a frame LLViewerObject *vobj = mDrawable->getVObj(); if (vobj && vobj->isAttachment() && !vobj->isHUDAttachment()) { LLDrawable* av; LLDrawable* parent = mDrawable->getParent(); if (parent) { LLViewerObject* objparent = parent->getVObj(); av = objparent->mDrawable; LLSpatialGroup* group = av->getSpatialGroup(); BOOL impostor = FALSE; BOOL loaded = FALSE; if (objparent->isAvatar()) { LLVOAvatar* avatarp = (LLVOAvatar*) objparent; if (avatarp->isVisible()) { impostor = objparent->isAvatar() && ((LLVOAvatar*) objparent)->isImpostor(); loaded = objparent->isAvatar() && ((LLVOAvatar*) objparent)->isFullyLoaded(); } else { return; } } if (!group || LLDrawable::getCurrentFrame() - av->mVisible > 1 || impostor || !loaded) { return; } } } LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); group->rebound(); LLVector4a center; center.setAdd(mExtents[0], mExtents[1]); center.mul(0.5f); LLVector4a size; size.setSub(mExtents[1], mExtents[0]); size.mul(0.5f); if ((LLPipeline::sShadowRender && camera_in.AABBInFrustum(center, size)) || LLPipeline::sImpostorRender || (camera_in.AABBInFrustumNoFarClip(center, size) && AABBSphereIntersect(mExtents[0], mExtents[1], camera_in.getOrigin(), camera_in.mFrustumCornerDist))) { if (!LLPipeline::sImpostorRender && !LLPipeline::sShadowRender && LLPipeline::calcPixelArea(center, size, camera_in) < FORCE_INVISIBLE_AREA) { return; } LLDrawable::setVisible(camera_in); if (for_select) { results->push_back(mDrawable); if (mDrawable->getVObj()) { LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren(); for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); iter != child_list.end(); iter++) { LLViewerObject* child = *iter; LLDrawable* drawable = child->mDrawable; results->push_back(drawable); } } } else { LLCamera trans_camera = transformCamera(camera_in); LLOctreeMarkNotCulled culler(&trans_camera); culler.traverse(mOctree); } } }
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; }