summaryrefslogtreecommitdiff
path: root/indra/newview/llvopartgroup.cpp
diff options
context:
space:
mode:
authorAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 21:25:21 +0200
committerAndrey Lihatskiy <alihatskiy@productengine.com>2024-05-22 22:40:26 +0300
commite2e37cced861b98de8c1a7c9c0d3a50d2d90e433 (patch)
tree1bb897489ce524986f6196201c10ac0d8861aa5f /indra/newview/llvopartgroup.cpp
parent069ea06848f766466f1a281144c82a0f2bd79f3a (diff)
Fix line endlings
Diffstat (limited to 'indra/newview/llvopartgroup.cpp')
-rw-r--r--indra/newview/llvopartgroup.cpp1968
1 files changed, 984 insertions, 984 deletions
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index 68281f2276..fa4dbd586e 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -1,984 +1,984 @@
-/**
- * @file llvopartgroup.cpp
- * @brief Group of particle systems
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llvopartgroup.h"
-
-#include "lldrawpoolalpha.h"
-
-#include "llfasttimer.h"
-#include "message.h"
-#include "v2math.h"
-
-#include "llagentcamera.h"
-#include "lldrawable.h"
-#include "llface.h"
-#include "llsky.h"
-#include "llviewercamera.h"
-#include "llviewerpartsim.h"
-#include "llviewerregion.h"
-#include "pipeline.h"
-#include "llspatialpartition.h"
-
-extern U64MicrosecondsImplicit gFrameTime;
-
-void LLVOPartGroup::initClass()
-{
-}
-
-//static
-void LLVOPartGroup::restoreGL()
-{
-
- //TODO: optimize out binormal mask here. Specular and normal coords as well.
-#if 0
- sVB = new LLVertexBuffer(VERTEX_DATA_MASK | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2);
- U32 count = LL_MAX_PARTICLE_COUNT;
- if (!sVB->allocateBuffer(count*4, count*6))
- {
- LL_WARNS() << "Failed to allocate Vertex Buffer to "
- << count*4 << " vertices and "
- << count * 6 << " indices" << LL_ENDL;
- // we are likelly to crash at following getTexCoord0Strider(), so unref and return
- sVB = NULL;
- return;
- }
-
- //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->unmapBuffer();
-#endif
-
-}
-
-//static
-void LLVOPartGroup::destroyGL()
-{
-}
-
-bool ll_is_part_idx_allocated(S32 idx, S32* start, S32* end)
-{
- /*while (start < end)
- {
- if (*start == idx)
- { //not allocated (in free list)
- return false;
- }
- ++start;
- }*/
-
- //allocated (not in free list)
- return false;
-}
-
-LLVOPartGroup::LLVOPartGroup(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
- : LLAlphaObject(id, pcode, regionp),
- mViewerPartGroupp(NULL)
-{
- setNumTEs(1);
- setTETexture(0, LLUUID::null);
- mbCanSelect = false; // users can't select particle systems
-}
-
-
-LLVOPartGroup::~LLVOPartGroup()
-{
-}
-
-bool LLVOPartGroup::isActive() const
-{
- return false;
-}
-
-F32 LLVOPartGroup::getBinRadius()
-{
- return mViewerPartGroupp->getBoxSide();
-}
-
-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);
-}
-
-void LLVOPartGroup::idleUpdate(LLAgent &agent, const F64 &time)
-{
-}
-
-void LLVOPartGroup::setPixelAreaAndAngle(LLAgent &agent)
-{
- // mPixelArea is calculated during render
- F32 mid_scale = getMidScale();
- F32 range = (getRenderPosition()-LLViewerCamera::getInstance()->getOrigin()).length();
-
- if (range < 0.001f || isHUDAttachment()) // range == zero
- {
- mAppAngle = 180.f;
- }
- else
- {
- mAppAngle = (F32) atan2( mid_scale, range) * RAD_TO_DEG;
- }
-}
-
-void LLVOPartGroup::updateTextures()
-{
- // Texture stats for particles need to be updated in a different way...
-}
-
-
-LLDrawable* LLVOPartGroup::createDrawable(LLPipeline *pipeline)
-{
- pipeline->allocDrawable(this);
- mDrawable->setLit(false);
- mDrawable->setRenderType(LLPipeline::RENDER_TYPE_PARTICLES);
- return mDrawable;
-}
-
- const F32 MAX_PARTICLE_AREA_SCALE = 0.02f; // some tuned constant, limits on how much particle area to draw
-
- LLUUID LLVOPartGroup::getPartOwner(S32 idx)
- {
- LLUUID ret = LLUUID::null;
-
- if (idx < (S32) mViewerPartGroupp->mParticles.size())
- {
- ret = mViewerPartGroupp->mParticles[idx]->mPartSourcep->getOwnerUUID();
- }
-
- return ret;
- }
-
- LLUUID LLVOPartGroup::getPartSource(S32 idx)
- {
- LLUUID ret = LLUUID::null;
-
- if (idx < (S32) mViewerPartGroupp->mParticles.size())
- {
- LLViewerPart* part = mViewerPartGroupp->mParticles[idx];
- if (part && part->mPartSourcep.notNull() &&
- part->mPartSourcep->mSourceObjectp.notNull())
- {
- LLViewerObject* source = part->mPartSourcep->mSourceObjectp;
- ret = source->getID();
- }
- }
-
- return ret;
- }
-
-
-F32 LLVOPartGroup::getPartSize(S32 idx)
-{
- if (idx < (S32) mViewerPartGroupp->mParticles.size())
- {
- return mViewerPartGroupp->mParticles[idx]->mScale.mV[0];
- }
-
- return 0.f;
-}
-
-void LLVOPartGroup::getBlendFunc(S32 idx, LLRender::eBlendFactor& src, LLRender::eBlendFactor& dst)
-{
- if (idx < (S32) mViewerPartGroupp->mParticles.size())
- {
- LLViewerPart* part = mViewerPartGroupp->mParticles[idx];
- src = (LLRender::eBlendFactor) part->mBlendFuncSource;
- dst = (LLRender::eBlendFactor) part->mBlendFuncDest;
- }
-}
-
-LLVector3 LLVOPartGroup::getCameraPosition() const
-{
- return gAgentCamera.getCameraPositionAgent();
-}
-
-bool LLVOPartGroup::updateGeometry(LLDrawable *drawable)
-{
- LL_PROFILE_ZONE_SCOPED;
-
- dirtySpatialGroup();
-
- S32 num_parts = mViewerPartGroupp->getCount();
- LLFace *facep;
- LLSpatialGroup* group = drawable->getSpatialGroup();
- if (!group && num_parts)
- {
- drawable->movePartition();
- group = drawable->getSpatialGroup();
- }
-
- if (group && group->isVisible())
- {
- dirtySpatialGroup();
- }
-
- if (!num_parts)
- {
- if (group && drawable->getNumFaces())
- {
- group->setState(LLSpatialGroup::GEOM_DIRTY);
- }
- drawable->setNumFaces(0, NULL, getTEImage(0));
- LLPipeline::sCompiles++;
- return true;
- }
-
- if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES)))
- {
- return true;
- }
-
- if (num_parts > drawable->getNumFaces())
- {
- drawable->setNumFacesFast(num_parts+num_parts/4, NULL, getTEImage(0));
- }
-
- F32 tot_area = 0;
-
- F32 max_area = LLViewerPartSim::getMaxPartCount() * MAX_PARTICLE_AREA_SCALE;
- F32 pixel_meter_ratio = LLViewerCamera::getInstance()->getPixelMeterRatio();
- pixel_meter_ratio *= pixel_meter_ratio;
-
- LLViewerPartSim::checkParticleCount(mViewerPartGroupp->mParticles.size()) ;
-
- S32 count=0;
- mDepth = 0.f;
- S32 i = 0 ;
- LLVector3 camera_agent = getCameraPosition();
-
- F32 max_scale = 0.f;
-
-
- for (i = 0 ; i < (S32)mViewerPartGroupp->mParticles.size(); i++)
- {
- const LLViewerPart *part = mViewerPartGroupp->mParticles[i];
-
-
- //remember the largest particle
- max_scale = llmax(max_scale, part->mScale.mV[0], part->mScale.mV[1]);
-
- if (part->mFlags & LLPartData::LL_PART_RIBBON_MASK)
- { //include ribbon segment length in scale
- const LLVector3* pos_agent = NULL;
- if (part->mParent)
- {
- pos_agent = &(part->mParent->mPosAgent);
- }
- else if (part->mPartSourcep.notNull())
- {
- pos_agent = &(part->mPartSourcep->mPosAgent);
- }
-
- if (pos_agent)
- {
- F32 dist = (*pos_agent-part->mPosAgent).length();
-
- max_scale = llmax(max_scale, dist);
- }
- }
-
- LLVector3 part_pos_agent(part->mPosAgent);
- LLVector3 at(part_pos_agent - camera_agent);
-
-
- F32 camera_dist_squared = at.lengthSquared();
- F32 inv_camera_dist_squared;
- if (camera_dist_squared > 1.f)
- inv_camera_dist_squared = 1.f / camera_dist_squared;
- else
- inv_camera_dist_squared = 1.f;
-
- llassert(llfinite(inv_camera_dist_squared));
- llassert(!llisnan(inv_camera_dist_squared));
-
- F32 area = part->mScale.mV[0] * part->mScale.mV[1] * inv_camera_dist_squared;
- tot_area = llmax(tot_area, area);
-
- if (tot_area > max_area)
- {
- break;
- }
-
- count++;
-
- facep = drawable->getFace(i);
- if (!facep)
- {
- LL_WARNS() << "No face found for index " << i << "!" << LL_ENDL;
- continue;
- }
-
- facep->setTEOffset(i);
- const F32 NEAR_PART_DIST_SQ = 5.f*5.f; // Only discard particles > 5 m from the camera
- const F32 MIN_PART_AREA = .005f*.005f; // only less than 5 mm x 5 mm at 1 m from camera
-
- if (camera_dist_squared > NEAR_PART_DIST_SQ && area < MIN_PART_AREA)
- {
- facep->setSize(0, 0);
- continue;
- }
-
- facep->setSize(4, 6);
-
- facep->setViewerObject(this);
-
- if (part->mFlags & LLPartData::LL_PART_EMISSIVE_MASK)
- {
- facep->setState(LLFace::FULLBRIGHT);
- }
- else
- {
- facep->clearState(LLFace::FULLBRIGHT);
- }
-
- facep->mCenterLocal = part->mPosAgent;
- facep->setFaceColor(part->mColor);
- facep->setTexture(part->mImagep);
-
- //check if this particle texture is replaced by a parcel media texture.
- if(part->mImagep.notNull() && part->mImagep->hasParcelMedia())
- {
- part->mImagep->getParcelMedia()->addMediaToFace(facep) ;
- }
-
- mPixelArea = tot_area * pixel_meter_ratio;
- const F32 area_scale = 10.f; // scale area to increase priority a bit
- facep->setVirtualSize(mPixelArea*area_scale);
- }
- for (i = count; i < drawable->getNumFaces(); i++)
- {
- LLFace* facep = drawable->getFace(i);
- if (!facep)
- {
- LL_WARNS() << "No face found for index " << i << "!" << LL_ENDL;
- continue;
- }
- facep->setTEOffset(i);
- facep->setSize(0, 0);
- }
-
- //record max scale (used to stretch bounding box for visibility culling)
-
- mScale.set(max_scale, max_scale, max_scale);
-
- mDrawable->movePartition();
- LLPipeline::sCompiles++;
- return true;
-}
-
-
-bool LLVOPartGroup::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
- S32 face,
- bool pick_transparent,
- bool pick_rigged,
- bool pick_unselectable,
- 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;
-}
-
-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 && !part.mVelocity.isExactlyZero())
- {
- 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<LLColor4U>& emissivep,
- LLStrider<U16>& indicesp)
-{
- if (idx >= (S32) mViewerPartGroupp->mParticles.size())
- {
- return;
- }
-
- const LLViewerPart &part = *((LLViewerPart*) (mViewerPartGroupp->mParticles[idx]));
-
- getGeometry(part, verticesp);
-
- LLColor4U pcolor;
- LLColor4U color = part.mColor;
-
- LLColor4U pglow;
-
- if (part.mFlags & LLPartData::LL_PART_RIBBON_MASK)
- { //make sure color blends properly
- if (part.mParent)
- {
- pglow = part.mParent->mGlow;
- pcolor = part.mParent->mColor;
- }
- else
- {
- pglow = LLColor4U(0, 0, 0, (U8) ll_round(255.f*part.mStartGlow));
- pcolor = part.mStartColor;
- }
- }
- else
- {
- pglow = part.mGlow;
- pcolor = color;
- }
-
- *colorsp++ = pcolor;
- *colorsp++ = pcolor;
- *colorsp++ = color;
- *colorsp++ = color;
-
- //if (pglow.mV[3] || part.mGlow.mV[3])
- { //only write glow if it is not zero
- *emissivep++ = pglow;
- *emissivep++ = pglow;
- *emissivep++ = part.mGlow;
- *emissivep++ = part.mGlow;
- }
-
-
- if (!(part.mFlags & LLPartData::LL_PART_EMISSIVE_MASK))
- { //not fullbright, needs normal
- LLVector3 normal = -LLViewerCamera::getInstance()->getXAxis();
- *normalsp++ = normal;
- *normalsp++ = normal;
- *normalsp++ = normal;
- *normalsp++ = normal;
- }
-}
-
-U32 LLVOPartGroup::getPartitionType() const
-{
- return LLViewerRegion::PARTITION_PARTICLE;
-}
-
-LLParticlePartition::LLParticlePartition(LLViewerRegion* regionp)
-: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, true, regionp)
-{
- mRenderPass = LLRenderPass::PASS_ALPHA;
- mDrawableType = LLPipeline::RENDER_TYPE_PARTICLES;
- mPartitionType = LLViewerRegion::PARTITION_PARTICLE;
- mSlopRatio = 0.f;
- mLODPeriod = 1;
-}
-
-LLHUDParticlePartition::LLHUDParticlePartition(LLViewerRegion* regionp) :
- LLParticlePartition(regionp)
-{
- mDrawableType = LLPipeline::RENDER_TYPE_HUD_PARTICLES;
- mPartitionType = LLViewerRegion::PARTITION_HUD_PARTICLE;
-}
-
-void LLParticlePartition::rebuildGeom(LLSpatialGroup* group)
-{
- LL_PROFILE_ZONE_SCOPED;
- LL_PROFILE_GPU_ZONE("particle vbo");
- if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY))
- {
- return;
- }
-
- if (group->changeLOD())
- {
- group->mLastUpdateDistance = group->mDistance;
- group->mLastUpdateViewAngle = group->mViewAngle;
- }
-
- group->clearDrawMap();
-
- //get geometry count
- U32 index_count = 0;
- U32 vertex_count = 0;
-
- addGeometryCount(group, vertex_count, index_count);
-
-
- if (vertex_count > 0 && index_count > 0)
- {
- group->mBuilt = 1.f;
- if (group->mVertexBuffer.isNull() ||
- group->mVertexBuffer->getNumVerts() < vertex_count || group->mVertexBuffer->getNumIndices() < index_count)
- {
- group->mVertexBuffer = new LLVertexBuffer(LLVOPartGroup::VERTEX_DATA_MASK);
- group->mVertexBuffer->allocateBuffer(vertex_count, index_count);
-
- // initialize index and texture coordinates only when buffer is reallocated
- U16* indicesp = (U16*)group->mVertexBuffer->mapIndexBuffer(0, index_count);
-
- U16 geom_idx = 0;
- for (U32 i = 0; i < index_count; i += 6)
- {
- *indicesp++ = geom_idx + 0;
- *indicesp++ = geom_idx + 1;
- *indicesp++ = geom_idx + 2;
-
- *indicesp++ = geom_idx + 1;
- *indicesp++ = geom_idx + 3;
- *indicesp++ = geom_idx + 2;
-
- geom_idx += 4;
- }
-
- LLStrider<LLVector2> texcoordsp;
-
- group->mVertexBuffer->getTexCoord0Strider(texcoordsp);
-
- for (U32 i = 0; i < vertex_count; i += 4)
- {
- *texcoordsp++ = LLVector2(0.f, 1.f);
- *texcoordsp++ = LLVector2(0.f, 0.f);
- *texcoordsp++ = LLVector2(1.f, 1.f);
- *texcoordsp++ = LLVector2(1.f, 0.f);
- }
-
- }
-
-
- getGeometry(group);
- }
- else
- {
- group->mVertexBuffer = NULL;
- group->mBufferMap.clear();
- }
-
- group->mLastUpdateTime = gFrameTimeSeconds;
- group->clearState(LLSpatialGroup::GEOM_DIRTY);
-}
-
-void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count)
-{
- mFaceList.clear();
-
- LLViewerCamera* camera = LLViewerCamera::getInstance();
- for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
- {
- LLDrawable* drawablep = (LLDrawable*)(*i)->getDrawable();
-
- if (!drawablep || drawablep->isDead())
- {
- continue;
- }
-
- LLAlphaObject* obj = (LLAlphaObject*) drawablep->getVObj().get();
- obj->mDepth = 0.f;
-
- U32 count = 0;
- for (S32 j = 0; j < drawablep->getNumFaces(); ++j)
- {
- drawablep->updateFaceSize(j);
-
- LLFace* facep = drawablep->getFace(j);
- if ( !facep || !facep->hasGeometry())
- {
- continue;
- }
-
- vertex_count += facep->getGeomCount();
- index_count += facep->getIndicesCount();
-
- count++;
- facep->mDistance = (facep->mCenterLocal - camera->getOrigin()) * camera->getAtAxis();
- obj->mDepth += facep->mDistance;
-
- mFaceList.push_back(facep);
- llassert(facep->getIndicesCount() < 65536);
- }
-
- obj->mDepth /= count;
- }
-}
-
-
-void LLParticlePartition::getGeometry(LLSpatialGroup* group)
-{
- LL_PROFILE_ZONE_SCOPED;
-
- std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater());
-
- group->clearDrawMap();
-
- LLVertexBuffer* buffer = group->mVertexBuffer;
-
- LLStrider<LLVector4a> verticesp;
- LLStrider<LLVector3> normalsp;
- LLStrider<LLColor4U> colorsp;
- LLStrider<LLColor4U> emissivep;
-
- buffer->getVertexStrider(verticesp);
- buffer->getNormalStrider(normalsp);
- buffer->getColorStrider(colorsp);
- buffer->getEmissiveStrider(emissivep);
-
- S32 geom_idx = 0;
- S32 indices_idx = 0;
-
- LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[mRenderPass];
-
- for (std::vector<LLFace*>::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i)
- {
- LLFace* facep = *i;
- LLAlphaObject* object = (LLAlphaObject*) facep->getViewerObject();
-
- facep->setGeomIndex(geom_idx);
- facep->setIndicesIndex(indices_idx);
-
- LLStrider<LLVector4a> cur_vert = verticesp + geom_idx;
- LLStrider<LLVector3> cur_norm = normalsp + geom_idx;
- LLStrider<LLColor4U> cur_col = colorsp + geom_idx;
- LLStrider<LLColor4U> cur_glow = emissivep + geom_idx;
-
- // not actually used
- LLStrider<LLVector2> cur_tc;
- LLStrider<U16> cur_idx;
-
-
- geom_idx += 4;
- indices_idx += 6;
-
- LLColor4U* start_glow = cur_glow.get();
-
- object->getGeometry(facep->getTEOffset(), cur_vert, cur_norm, cur_tc, cur_col, cur_glow, cur_idx);
-
- bool has_glow = false;
-
- if (cur_glow.get() != start_glow)
- {
- has_glow = true;
- }
-
- llassert(facep->getGeomCount() == 4);
- llassert(facep->getIndicesCount() == 6);
-
- S32 idx = draw_vec.size()-1;
-
- bool fullbright = facep->isState(LLFace::FULLBRIGHT);
-
- bool batched = false;
-
- LLRender::eBlendFactor bf_src = LLRender::BF_SOURCE_ALPHA;
- LLRender::eBlendFactor bf_dst = LLRender::BF_ONE_MINUS_SOURCE_ALPHA;
-
- object->getBlendFunc(facep->getTEOffset(), bf_src, bf_dst);
-
-
- if (idx >= 0)
- {
- LLDrawInfo* info = draw_vec[idx];
-
- if (info->mTexture == facep->getTexture() &&
- info->mHasGlow == has_glow &&
- info->mFullbright == fullbright &&
- info->mBlendFuncDst == bf_dst &&
- info->mBlendFuncSrc == bf_src)
- {
- if (draw_vec[idx]->mEnd == facep->getGeomIndex()-1)
- {
- batched = true;
- info->mCount += facep->getIndicesCount();
- info->mEnd += facep->getGeomCount();
- }
- else if (draw_vec[idx]->mStart == facep->getGeomIndex()+facep->getGeomCount()+1)
- {
- batched = true;
- info->mCount += facep->getIndicesCount();
- info->mStart -= facep->getGeomCount();
- info->mOffset = facep->getIndicesStart();
- }
- }
- }
-
- if (!batched)
- {
- U32 start = facep->getGeomIndex();
- U32 end = start + facep->getGeomCount()-1;
- U32 offset = facep->getIndicesStart();
- U32 count = facep->getIndicesCount();
- LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(),
- buffer, fullbright);
-
- info->mBlendFuncDst = bf_dst;
- info->mBlendFuncSrc = bf_src;
- info->mHasGlow = has_glow;
- draw_vec.push_back(info);
- //for alpha sorting
- facep->setDrawInfo(info);
- }
- }
-
- buffer->unmapBuffer();
- mFaceList.clear();
-}
-
-F32 LLParticlePartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
-{
- return 1024.f;
-}
-
-U32 LLVOHUDPartGroup::getPartitionType() const
-{
- return LLViewerRegion::PARTITION_HUD_PARTICLE;
-}
-
-LLDrawable* LLVOHUDPartGroup::createDrawable(LLPipeline *pipeline)
-{
- pipeline->allocDrawable(this);
- mDrawable->setLit(false);
- mDrawable->setRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
- return mDrawable;
-}
-
-LLVector3 LLVOHUDPartGroup::getCameraPosition() const
-{
- return LLVector3(-1,0,0);
-}
-
+/**
+ * @file llvopartgroup.cpp
+ * @brief Group of particle systems
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llvopartgroup.h"
+
+#include "lldrawpoolalpha.h"
+
+#include "llfasttimer.h"
+#include "message.h"
+#include "v2math.h"
+
+#include "llagentcamera.h"
+#include "lldrawable.h"
+#include "llface.h"
+#include "llsky.h"
+#include "llviewercamera.h"
+#include "llviewerpartsim.h"
+#include "llviewerregion.h"
+#include "pipeline.h"
+#include "llspatialpartition.h"
+
+extern U64MicrosecondsImplicit gFrameTime;
+
+void LLVOPartGroup::initClass()
+{
+}
+
+//static
+void LLVOPartGroup::restoreGL()
+{
+
+ //TODO: optimize out binormal mask here. Specular and normal coords as well.
+#if 0
+ sVB = new LLVertexBuffer(VERTEX_DATA_MASK | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2);
+ U32 count = LL_MAX_PARTICLE_COUNT;
+ if (!sVB->allocateBuffer(count*4, count*6))
+ {
+ LL_WARNS() << "Failed to allocate Vertex Buffer to "
+ << count*4 << " vertices and "
+ << count * 6 << " indices" << LL_ENDL;
+ // we are likelly to crash at following getTexCoord0Strider(), so unref and return
+ sVB = NULL;
+ return;
+ }
+
+ //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->unmapBuffer();
+#endif
+
+}
+
+//static
+void LLVOPartGroup::destroyGL()
+{
+}
+
+bool ll_is_part_idx_allocated(S32 idx, S32* start, S32* end)
+{
+ /*while (start < end)
+ {
+ if (*start == idx)
+ { //not allocated (in free list)
+ return false;
+ }
+ ++start;
+ }*/
+
+ //allocated (not in free list)
+ return false;
+}
+
+LLVOPartGroup::LLVOPartGroup(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
+ : LLAlphaObject(id, pcode, regionp),
+ mViewerPartGroupp(NULL)
+{
+ setNumTEs(1);
+ setTETexture(0, LLUUID::null);
+ mbCanSelect = false; // users can't select particle systems
+}
+
+
+LLVOPartGroup::~LLVOPartGroup()
+{
+}
+
+bool LLVOPartGroup::isActive() const
+{
+ return false;
+}
+
+F32 LLVOPartGroup::getBinRadius()
+{
+ return mViewerPartGroupp->getBoxSide();
+}
+
+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);
+}
+
+void LLVOPartGroup::idleUpdate(LLAgent &agent, const F64 &time)
+{
+}
+
+void LLVOPartGroup::setPixelAreaAndAngle(LLAgent &agent)
+{
+ // mPixelArea is calculated during render
+ F32 mid_scale = getMidScale();
+ F32 range = (getRenderPosition()-LLViewerCamera::getInstance()->getOrigin()).length();
+
+ if (range < 0.001f || isHUDAttachment()) // range == zero
+ {
+ mAppAngle = 180.f;
+ }
+ else
+ {
+ mAppAngle = (F32) atan2( mid_scale, range) * RAD_TO_DEG;
+ }
+}
+
+void LLVOPartGroup::updateTextures()
+{
+ // Texture stats for particles need to be updated in a different way...
+}
+
+
+LLDrawable* LLVOPartGroup::createDrawable(LLPipeline *pipeline)
+{
+ pipeline->allocDrawable(this);
+ mDrawable->setLit(false);
+ mDrawable->setRenderType(LLPipeline::RENDER_TYPE_PARTICLES);
+ return mDrawable;
+}
+
+ const F32 MAX_PARTICLE_AREA_SCALE = 0.02f; // some tuned constant, limits on how much particle area to draw
+
+ LLUUID LLVOPartGroup::getPartOwner(S32 idx)
+ {
+ LLUUID ret = LLUUID::null;
+
+ if (idx < (S32) mViewerPartGroupp->mParticles.size())
+ {
+ ret = mViewerPartGroupp->mParticles[idx]->mPartSourcep->getOwnerUUID();
+ }
+
+ return ret;
+ }
+
+ LLUUID LLVOPartGroup::getPartSource(S32 idx)
+ {
+ LLUUID ret = LLUUID::null;
+
+ if (idx < (S32) mViewerPartGroupp->mParticles.size())
+ {
+ LLViewerPart* part = mViewerPartGroupp->mParticles[idx];
+ if (part && part->mPartSourcep.notNull() &&
+ part->mPartSourcep->mSourceObjectp.notNull())
+ {
+ LLViewerObject* source = part->mPartSourcep->mSourceObjectp;
+ ret = source->getID();
+ }
+ }
+
+ return ret;
+ }
+
+
+F32 LLVOPartGroup::getPartSize(S32 idx)
+{
+ if (idx < (S32) mViewerPartGroupp->mParticles.size())
+ {
+ return mViewerPartGroupp->mParticles[idx]->mScale.mV[0];
+ }
+
+ return 0.f;
+}
+
+void LLVOPartGroup::getBlendFunc(S32 idx, LLRender::eBlendFactor& src, LLRender::eBlendFactor& dst)
+{
+ if (idx < (S32) mViewerPartGroupp->mParticles.size())
+ {
+ LLViewerPart* part = mViewerPartGroupp->mParticles[idx];
+ src = (LLRender::eBlendFactor) part->mBlendFuncSource;
+ dst = (LLRender::eBlendFactor) part->mBlendFuncDest;
+ }
+}
+
+LLVector3 LLVOPartGroup::getCameraPosition() const
+{
+ return gAgentCamera.getCameraPositionAgent();
+}
+
+bool LLVOPartGroup::updateGeometry(LLDrawable *drawable)
+{
+ LL_PROFILE_ZONE_SCOPED;
+
+ dirtySpatialGroup();
+
+ S32 num_parts = mViewerPartGroupp->getCount();
+ LLFace *facep;
+ LLSpatialGroup* group = drawable->getSpatialGroup();
+ if (!group && num_parts)
+ {
+ drawable->movePartition();
+ group = drawable->getSpatialGroup();
+ }
+
+ if (group && group->isVisible())
+ {
+ dirtySpatialGroup();
+ }
+
+ if (!num_parts)
+ {
+ if (group && drawable->getNumFaces())
+ {
+ group->setState(LLSpatialGroup::GEOM_DIRTY);
+ }
+ drawable->setNumFaces(0, NULL, getTEImage(0));
+ LLPipeline::sCompiles++;
+ return true;
+ }
+
+ if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES)))
+ {
+ return true;
+ }
+
+ if (num_parts > drawable->getNumFaces())
+ {
+ drawable->setNumFacesFast(num_parts+num_parts/4, NULL, getTEImage(0));
+ }
+
+ F32 tot_area = 0;
+
+ F32 max_area = LLViewerPartSim::getMaxPartCount() * MAX_PARTICLE_AREA_SCALE;
+ F32 pixel_meter_ratio = LLViewerCamera::getInstance()->getPixelMeterRatio();
+ pixel_meter_ratio *= pixel_meter_ratio;
+
+ LLViewerPartSim::checkParticleCount(mViewerPartGroupp->mParticles.size()) ;
+
+ S32 count=0;
+ mDepth = 0.f;
+ S32 i = 0 ;
+ LLVector3 camera_agent = getCameraPosition();
+
+ F32 max_scale = 0.f;
+
+
+ for (i = 0 ; i < (S32)mViewerPartGroupp->mParticles.size(); i++)
+ {
+ const LLViewerPart *part = mViewerPartGroupp->mParticles[i];
+
+
+ //remember the largest particle
+ max_scale = llmax(max_scale, part->mScale.mV[0], part->mScale.mV[1]);
+
+ if (part->mFlags & LLPartData::LL_PART_RIBBON_MASK)
+ { //include ribbon segment length in scale
+ const LLVector3* pos_agent = NULL;
+ if (part->mParent)
+ {
+ pos_agent = &(part->mParent->mPosAgent);
+ }
+ else if (part->mPartSourcep.notNull())
+ {
+ pos_agent = &(part->mPartSourcep->mPosAgent);
+ }
+
+ if (pos_agent)
+ {
+ F32 dist = (*pos_agent-part->mPosAgent).length();
+
+ max_scale = llmax(max_scale, dist);
+ }
+ }
+
+ LLVector3 part_pos_agent(part->mPosAgent);
+ LLVector3 at(part_pos_agent - camera_agent);
+
+
+ F32 camera_dist_squared = at.lengthSquared();
+ F32 inv_camera_dist_squared;
+ if (camera_dist_squared > 1.f)
+ inv_camera_dist_squared = 1.f / camera_dist_squared;
+ else
+ inv_camera_dist_squared = 1.f;
+
+ llassert(llfinite(inv_camera_dist_squared));
+ llassert(!llisnan(inv_camera_dist_squared));
+
+ F32 area = part->mScale.mV[0] * part->mScale.mV[1] * inv_camera_dist_squared;
+ tot_area = llmax(tot_area, area);
+
+ if (tot_area > max_area)
+ {
+ break;
+ }
+
+ count++;
+
+ facep = drawable->getFace(i);
+ if (!facep)
+ {
+ LL_WARNS() << "No face found for index " << i << "!" << LL_ENDL;
+ continue;
+ }
+
+ facep->setTEOffset(i);
+ const F32 NEAR_PART_DIST_SQ = 5.f*5.f; // Only discard particles > 5 m from the camera
+ const F32 MIN_PART_AREA = .005f*.005f; // only less than 5 mm x 5 mm at 1 m from camera
+
+ if (camera_dist_squared > NEAR_PART_DIST_SQ && area < MIN_PART_AREA)
+ {
+ facep->setSize(0, 0);
+ continue;
+ }
+
+ facep->setSize(4, 6);
+
+ facep->setViewerObject(this);
+
+ if (part->mFlags & LLPartData::LL_PART_EMISSIVE_MASK)
+ {
+ facep->setState(LLFace::FULLBRIGHT);
+ }
+ else
+ {
+ facep->clearState(LLFace::FULLBRIGHT);
+ }
+
+ facep->mCenterLocal = part->mPosAgent;
+ facep->setFaceColor(part->mColor);
+ facep->setTexture(part->mImagep);
+
+ //check if this particle texture is replaced by a parcel media texture.
+ if(part->mImagep.notNull() && part->mImagep->hasParcelMedia())
+ {
+ part->mImagep->getParcelMedia()->addMediaToFace(facep) ;
+ }
+
+ mPixelArea = tot_area * pixel_meter_ratio;
+ const F32 area_scale = 10.f; // scale area to increase priority a bit
+ facep->setVirtualSize(mPixelArea*area_scale);
+ }
+ for (i = count; i < drawable->getNumFaces(); i++)
+ {
+ LLFace* facep = drawable->getFace(i);
+ if (!facep)
+ {
+ LL_WARNS() << "No face found for index " << i << "!" << LL_ENDL;
+ continue;
+ }
+ facep->setTEOffset(i);
+ facep->setSize(0, 0);
+ }
+
+ //record max scale (used to stretch bounding box for visibility culling)
+
+ mScale.set(max_scale, max_scale, max_scale);
+
+ mDrawable->movePartition();
+ LLPipeline::sCompiles++;
+ return true;
+}
+
+
+bool LLVOPartGroup::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
+ S32 face,
+ bool pick_transparent,
+ bool pick_rigged,
+ bool pick_unselectable,
+ 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;
+}
+
+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 && !part.mVelocity.isExactlyZero())
+ {
+ 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<LLColor4U>& emissivep,
+ LLStrider<U16>& indicesp)
+{
+ if (idx >= (S32) mViewerPartGroupp->mParticles.size())
+ {
+ return;
+ }
+
+ const LLViewerPart &part = *((LLViewerPart*) (mViewerPartGroupp->mParticles[idx]));
+
+ getGeometry(part, verticesp);
+
+ LLColor4U pcolor;
+ LLColor4U color = part.mColor;
+
+ LLColor4U pglow;
+
+ if (part.mFlags & LLPartData::LL_PART_RIBBON_MASK)
+ { //make sure color blends properly
+ if (part.mParent)
+ {
+ pglow = part.mParent->mGlow;
+ pcolor = part.mParent->mColor;
+ }
+ else
+ {
+ pglow = LLColor4U(0, 0, 0, (U8) ll_round(255.f*part.mStartGlow));
+ pcolor = part.mStartColor;
+ }
+ }
+ else
+ {
+ pglow = part.mGlow;
+ pcolor = color;
+ }
+
+ *colorsp++ = pcolor;
+ *colorsp++ = pcolor;
+ *colorsp++ = color;
+ *colorsp++ = color;
+
+ //if (pglow.mV[3] || part.mGlow.mV[3])
+ { //only write glow if it is not zero
+ *emissivep++ = pglow;
+ *emissivep++ = pglow;
+ *emissivep++ = part.mGlow;
+ *emissivep++ = part.mGlow;
+ }
+
+
+ if (!(part.mFlags & LLPartData::LL_PART_EMISSIVE_MASK))
+ { //not fullbright, needs normal
+ LLVector3 normal = -LLViewerCamera::getInstance()->getXAxis();
+ *normalsp++ = normal;
+ *normalsp++ = normal;
+ *normalsp++ = normal;
+ *normalsp++ = normal;
+ }
+}
+
+U32 LLVOPartGroup::getPartitionType() const
+{
+ return LLViewerRegion::PARTITION_PARTICLE;
+}
+
+LLParticlePartition::LLParticlePartition(LLViewerRegion* regionp)
+: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, true, regionp)
+{
+ mRenderPass = LLRenderPass::PASS_ALPHA;
+ mDrawableType = LLPipeline::RENDER_TYPE_PARTICLES;
+ mPartitionType = LLViewerRegion::PARTITION_PARTICLE;
+ mSlopRatio = 0.f;
+ mLODPeriod = 1;
+}
+
+LLHUDParticlePartition::LLHUDParticlePartition(LLViewerRegion* regionp) :
+ LLParticlePartition(regionp)
+{
+ mDrawableType = LLPipeline::RENDER_TYPE_HUD_PARTICLES;
+ mPartitionType = LLViewerRegion::PARTITION_HUD_PARTICLE;
+}
+
+void LLParticlePartition::rebuildGeom(LLSpatialGroup* group)
+{
+ LL_PROFILE_ZONE_SCOPED;
+ LL_PROFILE_GPU_ZONE("particle vbo");
+ if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY))
+ {
+ return;
+ }
+
+ if (group->changeLOD())
+ {
+ group->mLastUpdateDistance = group->mDistance;
+ group->mLastUpdateViewAngle = group->mViewAngle;
+ }
+
+ group->clearDrawMap();
+
+ //get geometry count
+ U32 index_count = 0;
+ U32 vertex_count = 0;
+
+ addGeometryCount(group, vertex_count, index_count);
+
+
+ if (vertex_count > 0 && index_count > 0)
+ {
+ group->mBuilt = 1.f;
+ if (group->mVertexBuffer.isNull() ||
+ group->mVertexBuffer->getNumVerts() < vertex_count || group->mVertexBuffer->getNumIndices() < index_count)
+ {
+ group->mVertexBuffer = new LLVertexBuffer(LLVOPartGroup::VERTEX_DATA_MASK);
+ group->mVertexBuffer->allocateBuffer(vertex_count, index_count);
+
+ // initialize index and texture coordinates only when buffer is reallocated
+ U16* indicesp = (U16*)group->mVertexBuffer->mapIndexBuffer(0, index_count);
+
+ U16 geom_idx = 0;
+ for (U32 i = 0; i < index_count; i += 6)
+ {
+ *indicesp++ = geom_idx + 0;
+ *indicesp++ = geom_idx + 1;
+ *indicesp++ = geom_idx + 2;
+
+ *indicesp++ = geom_idx + 1;
+ *indicesp++ = geom_idx + 3;
+ *indicesp++ = geom_idx + 2;
+
+ geom_idx += 4;
+ }
+
+ LLStrider<LLVector2> texcoordsp;
+
+ group->mVertexBuffer->getTexCoord0Strider(texcoordsp);
+
+ for (U32 i = 0; i < vertex_count; i += 4)
+ {
+ *texcoordsp++ = LLVector2(0.f, 1.f);
+ *texcoordsp++ = LLVector2(0.f, 0.f);
+ *texcoordsp++ = LLVector2(1.f, 1.f);
+ *texcoordsp++ = LLVector2(1.f, 0.f);
+ }
+
+ }
+
+
+ getGeometry(group);
+ }
+ else
+ {
+ group->mVertexBuffer = NULL;
+ group->mBufferMap.clear();
+ }
+
+ group->mLastUpdateTime = gFrameTimeSeconds;
+ group->clearState(LLSpatialGroup::GEOM_DIRTY);
+}
+
+void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count)
+{
+ mFaceList.clear();
+
+ LLViewerCamera* camera = LLViewerCamera::getInstance();
+ for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
+ {
+ LLDrawable* drawablep = (LLDrawable*)(*i)->getDrawable();
+
+ if (!drawablep || drawablep->isDead())
+ {
+ continue;
+ }
+
+ LLAlphaObject* obj = (LLAlphaObject*) drawablep->getVObj().get();
+ obj->mDepth = 0.f;
+
+ U32 count = 0;
+ for (S32 j = 0; j < drawablep->getNumFaces(); ++j)
+ {
+ drawablep->updateFaceSize(j);
+
+ LLFace* facep = drawablep->getFace(j);
+ if ( !facep || !facep->hasGeometry())
+ {
+ continue;
+ }
+
+ vertex_count += facep->getGeomCount();
+ index_count += facep->getIndicesCount();
+
+ count++;
+ facep->mDistance = (facep->mCenterLocal - camera->getOrigin()) * camera->getAtAxis();
+ obj->mDepth += facep->mDistance;
+
+ mFaceList.push_back(facep);
+ llassert(facep->getIndicesCount() < 65536);
+ }
+
+ obj->mDepth /= count;
+ }
+}
+
+
+void LLParticlePartition::getGeometry(LLSpatialGroup* group)
+{
+ LL_PROFILE_ZONE_SCOPED;
+
+ std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater());
+
+ group->clearDrawMap();
+
+ LLVertexBuffer* buffer = group->mVertexBuffer;
+
+ LLStrider<LLVector4a> verticesp;
+ LLStrider<LLVector3> normalsp;
+ LLStrider<LLColor4U> colorsp;
+ LLStrider<LLColor4U> emissivep;
+
+ buffer->getVertexStrider(verticesp);
+ buffer->getNormalStrider(normalsp);
+ buffer->getColorStrider(colorsp);
+ buffer->getEmissiveStrider(emissivep);
+
+ S32 geom_idx = 0;
+ S32 indices_idx = 0;
+
+ LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[mRenderPass];
+
+ for (std::vector<LLFace*>::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i)
+ {
+ LLFace* facep = *i;
+ LLAlphaObject* object = (LLAlphaObject*) facep->getViewerObject();
+
+ facep->setGeomIndex(geom_idx);
+ facep->setIndicesIndex(indices_idx);
+
+ LLStrider<LLVector4a> cur_vert = verticesp + geom_idx;
+ LLStrider<LLVector3> cur_norm = normalsp + geom_idx;
+ LLStrider<LLColor4U> cur_col = colorsp + geom_idx;
+ LLStrider<LLColor4U> cur_glow = emissivep + geom_idx;
+
+ // not actually used
+ LLStrider<LLVector2> cur_tc;
+ LLStrider<U16> cur_idx;
+
+
+ geom_idx += 4;
+ indices_idx += 6;
+
+ LLColor4U* start_glow = cur_glow.get();
+
+ object->getGeometry(facep->getTEOffset(), cur_vert, cur_norm, cur_tc, cur_col, cur_glow, cur_idx);
+
+ bool has_glow = false;
+
+ if (cur_glow.get() != start_glow)
+ {
+ has_glow = true;
+ }
+
+ llassert(facep->getGeomCount() == 4);
+ llassert(facep->getIndicesCount() == 6);
+
+ S32 idx = draw_vec.size()-1;
+
+ bool fullbright = facep->isState(LLFace::FULLBRIGHT);
+
+ bool batched = false;
+
+ LLRender::eBlendFactor bf_src = LLRender::BF_SOURCE_ALPHA;
+ LLRender::eBlendFactor bf_dst = LLRender::BF_ONE_MINUS_SOURCE_ALPHA;
+
+ object->getBlendFunc(facep->getTEOffset(), bf_src, bf_dst);
+
+
+ if (idx >= 0)
+ {
+ LLDrawInfo* info = draw_vec[idx];
+
+ if (info->mTexture == facep->getTexture() &&
+ info->mHasGlow == has_glow &&
+ info->mFullbright == fullbright &&
+ info->mBlendFuncDst == bf_dst &&
+ info->mBlendFuncSrc == bf_src)
+ {
+ if (draw_vec[idx]->mEnd == facep->getGeomIndex()-1)
+ {
+ batched = true;
+ info->mCount += facep->getIndicesCount();
+ info->mEnd += facep->getGeomCount();
+ }
+ else if (draw_vec[idx]->mStart == facep->getGeomIndex()+facep->getGeomCount()+1)
+ {
+ batched = true;
+ info->mCount += facep->getIndicesCount();
+ info->mStart -= facep->getGeomCount();
+ info->mOffset = facep->getIndicesStart();
+ }
+ }
+ }
+
+ if (!batched)
+ {
+ U32 start = facep->getGeomIndex();
+ U32 end = start + facep->getGeomCount()-1;
+ U32 offset = facep->getIndicesStart();
+ U32 count = facep->getIndicesCount();
+ LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(),
+ buffer, fullbright);
+
+ info->mBlendFuncDst = bf_dst;
+ info->mBlendFuncSrc = bf_src;
+ info->mHasGlow = has_glow;
+ draw_vec.push_back(info);
+ //for alpha sorting
+ facep->setDrawInfo(info);
+ }
+ }
+
+ buffer->unmapBuffer();
+ mFaceList.clear();
+}
+
+F32 LLParticlePartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
+{
+ return 1024.f;
+}
+
+U32 LLVOHUDPartGroup::getPartitionType() const
+{
+ return LLViewerRegion::PARTITION_HUD_PARTICLE;
+}
+
+LLDrawable* LLVOHUDPartGroup::createDrawable(LLPipeline *pipeline)
+{
+ pipeline->allocDrawable(this);
+ mDrawable->setLit(false);
+ mDrawable->setRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
+ return mDrawable;
+}
+
+LLVector3 LLVOHUDPartGroup::getCameraPosition() const
+{
+ return LLVector3(-1,0,0);
+}
+