void LLVOClouds::getGeometry(S32 idx,
								LLStrider<LLVector4a>& verticesp,
								LLStrider<LLVector3>& normalsp, 
								LLStrider<LLVector2>& texcoordsp,
								LLStrider<LLColor4U>& colorsp, 
								LLStrider<LLColor4U>& emissivep,
								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);
	
	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;

	*colorsp++ = color;
	*colorsp++ = color;
	*colorsp++ = color;
	*colorsp++ = color;

	*normalsp++   = normal;
	*normalsp++   = normal;
	*normalsp++   = normal;
	*normalsp++   = normal;
}
//-----------------------------------------------------------------------------
// apply()
//-----------------------------------------------------------------------------
void LLPolyMorphTarget::apply( ESex avatar_sex )
{
	if (!mMorphData || mNumMorphMasksPending > 0)
	{
		return;
	}

	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];
			norm.normalize3fast();
			normals[vert_index_mesh] = norm;

			// calculate new binormals
			LLVector4a binorm = mMorphData->mBinormals[vert_index_morph];
			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);
	}
}
//-----------------------------------------------------------------------------
// 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);
}
예제 #4
0
void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
{
	if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
	{
		LL_WARNS() << "Attempted to update distance for non-world camera." << LL_ENDL;
		return;
	}

	if (gShiftFrame)
	{
		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 (facep && 
						(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 = ll_round(pos.magVec(), 0.01f);
		mVObjp->updateLOD();
	}
}
예제 #5
0
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;
	}
}
예제 #6
0
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
	const LLMatrix4a& mat = 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();
}
예제 #7
0
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;
			}
		}
		else
		{
			static const LLCachedControl<bool> draw_orphans("ShyotlDrawOrphanAttachments",false);
			if(!draw_orphans)
				return;
		}
	}
	

	LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
	group->rebound();
	
	LLVector4a center;
	const LLVector4a* exts = getSpatialExtents();
	center.setAdd(exts[0], exts[1]);
	center.mul(0.5f);
	LLVector4a size;
	size.setSub(exts[1], exts[0]);
	size.mul(0.5f);

	if ((LLPipeline::sShadowRender && camera_in.AABBInFrustum(center, size)) ||
		LLPipeline::sImpostorRender ||
		(camera_in.AABBInFrustumNoFarClip(center, size) && 
		AABBSphereIntersect(exts[0], exts[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);
		}		
	}
}
예제 #8
0
// 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; 
	}
}
예제 #9
0
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;
}
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;
}
예제 #11
0
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;
}
예제 #12
0
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;
}