MAINT-2268 Add right-click->"Mute Particle Owner" feature
parent
ac6a19d456
commit
b8f74b42a7
|
|
@ -121,7 +121,7 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
|
|||
BOOL LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
// don't pick transparent so users can't "pay" transparent objects
|
||||
mPick = gViewerWindow->pickImmediate(x, y, FALSE);
|
||||
mPick = gViewerWindow->pickImmediate(x, y, FALSE, TRUE);
|
||||
mPick.mKeyMask = mask;
|
||||
|
||||
// claim not handled so UI focus stays same
|
||||
|
|
@ -1711,6 +1711,13 @@ BOOL LLToolPie::handleRightClickPick()
|
|||
showVisualContextMenuEffect();
|
||||
}
|
||||
}
|
||||
else if (mPick.mParticleOwnerID.notNull())
|
||||
{
|
||||
if (gMenuMuteParticle && mPick.mParticleOwnerID != gAgent.getID())
|
||||
{
|
||||
gMenuMuteParticle->show(x,y);
|
||||
}
|
||||
}
|
||||
|
||||
LLTool::handleRightMouseDown(x, y, mask);
|
||||
// We handled the event.
|
||||
|
|
|
|||
|
|
@ -165,6 +165,7 @@ LLContextMenu *gMenuObject = NULL;
|
|||
LLContextMenu *gMenuAttachmentSelf = NULL;
|
||||
LLContextMenu *gMenuAttachmentOther = NULL;
|
||||
LLContextMenu *gMenuLand = NULL;
|
||||
LLContextMenu *gMenuMuteParticle = NULL;
|
||||
|
||||
const std::string SAVE_INTO_TASK_INVENTORY("Save Object Back to Object Contents");
|
||||
|
||||
|
|
@ -423,6 +424,9 @@ void init_menus()
|
|||
gMenuLand = LLUICtrlFactory::createFromFile<LLContextMenu>(
|
||||
"menu_land.xml", gMenuHolder, registry);
|
||||
|
||||
gMenuMuteParticle = LLUICtrlFactory::createFromFile<LLContextMenu>(
|
||||
"menu_mute_particle.xml", gMenuHolder, registry);
|
||||
|
||||
///
|
||||
/// set up the colors
|
||||
///
|
||||
|
|
@ -2457,6 +2461,9 @@ void cleanup_menus()
|
|||
delete gMenuLand;
|
||||
gMenuLand = NULL;
|
||||
|
||||
delete gMenuMuteParticle;
|
||||
gMenuMuteParticle = NULL;
|
||||
|
||||
delete gMenuBarView;
|
||||
gMenuBarView = NULL;
|
||||
|
||||
|
|
@ -2810,6 +2817,13 @@ bool enable_object_edit()
|
|||
return enable;
|
||||
}
|
||||
|
||||
bool enable_mute_particle()
|
||||
{
|
||||
const LLPickInfo& pick = LLToolPie::getInstance()->getPick();
|
||||
|
||||
return pick.mParticleOwnerID != LLUUID::null && pick.mParticleOwnerID != gAgent.getID();
|
||||
}
|
||||
|
||||
// mutually exclusive - show either edit option or build in menu
|
||||
bool enable_object_build()
|
||||
{
|
||||
|
|
@ -6245,6 +6259,33 @@ class LLLandEdit : public view_listener_t
|
|||
}
|
||||
};
|
||||
|
||||
class LLMuteParticle : public view_listener_t
|
||||
{
|
||||
bool handleEvent(const LLSD& userdata)
|
||||
{
|
||||
LLUUID id = LLToolPie::getInstance()->getPick().mParticleOwnerID;
|
||||
|
||||
if (id.notNull())
|
||||
{
|
||||
std::string name;
|
||||
gCacheName->getFullName(id, name);
|
||||
|
||||
LLMute mute(id, name, LLMute::AGENT);
|
||||
if (LLMuteList::getInstance()->isMuted(mute.mID))
|
||||
{
|
||||
LLMuteList::getInstance()->remove(mute);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLMuteList::getInstance()->add(mute);
|
||||
LLPanelBlockedList::showPanelAndSelect(mute.mID);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class LLWorldEnableBuyLand : public view_listener_t
|
||||
{
|
||||
bool handleEvent(const LLSD& userdata)
|
||||
|
|
@ -8657,6 +8698,9 @@ void initialize_menus()
|
|||
view_listener_t::addMenu(new LLLandBuyPass(), "Land.BuyPass");
|
||||
view_listener_t::addMenu(new LLLandEdit(), "Land.Edit");
|
||||
|
||||
// Particle muting
|
||||
view_listener_t::addMenu(new LLMuteParticle(), "Particle.Mute");
|
||||
|
||||
view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass");
|
||||
commit.add("Land.Buy", boost::bind(&handle_buy_land));
|
||||
|
||||
|
|
@ -8679,6 +8723,7 @@ void initialize_menus()
|
|||
enable.add("EnablePayObject", boost::bind(&enable_pay_object));
|
||||
enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar));
|
||||
enable.add("EnableEdit", boost::bind(&enable_object_edit));
|
||||
enable.add("EnableMuteParticle", boost::bind(&enable_mute_particle));
|
||||
enable.add("VisibleBuild", boost::bind(&enable_object_build));
|
||||
commit.add("Pathfinding.Linksets.Select", boost::bind(&LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects));
|
||||
enable.add("EnableSelectInPathfindingLinksets", boost::bind(&enable_object_select_in_pathfinding_linksets));
|
||||
|
|
|
|||
|
|
@ -172,6 +172,7 @@ extern LLContextMenu *gMenuObject;
|
|||
extern LLContextMenu *gMenuAttachmentSelf;
|
||||
extern LLContextMenu *gMenuAttachmentOther;
|
||||
extern LLContextMenu *gMenuLand;
|
||||
extern LLContextMenu *gMenuMuteParticle;
|
||||
|
||||
// Needed to build menus when attachment site list available
|
||||
extern LLMenuGL* gAttachSubMenu;
|
||||
|
|
|
|||
|
|
@ -225,6 +225,8 @@ LLFrameTimer gAwayTriggerTimer;
|
|||
BOOL gShowOverlayTitle = FALSE;
|
||||
|
||||
LLViewerObject* gDebugRaycastObject = NULL;
|
||||
LLVOPartGroup* gDebugRaycastParticle = NULL;
|
||||
LLVector3 gDebugRaycastParticleIntersection;
|
||||
LLVector3 gDebugRaycastIntersection;
|
||||
LLVector2 gDebugRaycastTexCoord;
|
||||
LLVector3 gDebugRaycastNormal;
|
||||
|
|
@ -2811,6 +2813,8 @@ void LLViewerWindow::updateUI()
|
|||
&gDebugRaycastBinormal,
|
||||
&gDebugRaycastStart,
|
||||
&gDebugRaycastEnd);
|
||||
|
||||
gDebugRaycastParticle = gPipeline.lineSegmentIntersectParticle(gDebugRaycastStart, gDebugRaycastEnd, &gDebugRaycastParticleIntersection, NULL);
|
||||
}
|
||||
|
||||
updateMouseDelta();
|
||||
|
|
@ -3633,7 +3637,7 @@ void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback
|
|||
pick_transparent = TRUE;
|
||||
}
|
||||
|
||||
LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, TRUE, callback);
|
||||
LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, FALSE, TRUE, callback);
|
||||
schedulePick(pick_info);
|
||||
}
|
||||
|
||||
|
|
@ -3689,7 +3693,7 @@ void LLViewerWindow::returnEmptyPicks()
|
|||
}
|
||||
|
||||
// Performs the GL object/land pick.
|
||||
LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent)
|
||||
LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent, BOOL pick_particle)
|
||||
{
|
||||
BOOL in_build_mode = LLFloaterReg::instanceVisible("build");
|
||||
if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha)
|
||||
|
|
@ -3698,10 +3702,10 @@ LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_trans
|
|||
// "Show Debug Alpha" means no object actually transparent
|
||||
pick_transparent = TRUE;
|
||||
}
|
||||
|
||||
|
||||
// shortcut queueing in mPicks and just update mLastPick in place
|
||||
MASK key_mask = gKeyboard->currentMask(TRUE);
|
||||
mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask, pick_transparent, TRUE, NULL);
|
||||
mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask, pick_transparent, pick_particle, TRUE, NULL);
|
||||
mLastPick.fetchResults();
|
||||
|
||||
return mLastPick;
|
||||
|
|
@ -5107,13 +5111,15 @@ LLPickInfo::LLPickInfo()
|
|||
mNormal(),
|
||||
mBinormal(),
|
||||
mHUDIcon(NULL),
|
||||
mPickTransparent(FALSE)
|
||||
mPickTransparent(FALSE),
|
||||
mPickParticle(FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos,
|
||||
MASK keyboard_mask,
|
||||
BOOL pick_transparent,
|
||||
BOOL pick_particle,
|
||||
BOOL pick_uv_coords,
|
||||
void (*pick_callback)(const LLPickInfo& pick_info))
|
||||
: mMousePt(mouse_pos),
|
||||
|
|
@ -5128,7 +5134,8 @@ LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos,
|
|||
mNormal(),
|
||||
mBinormal(),
|
||||
mHUDIcon(NULL),
|
||||
mPickTransparent(pick_transparent)
|
||||
mPickTransparent(pick_transparent),
|
||||
mPickParticle(pick_particle)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -5142,20 +5149,34 @@ void LLPickInfo::fetchResults()
|
|||
LLHUDIcon* hit_icon = gViewerWindow->cursorIntersectIcon(mMousePt.mX, mMousePt.mY, 512.f, &intersection);
|
||||
|
||||
F32 icon_dist = 0.f;
|
||||
LLVector3 start;
|
||||
LLVector3 end;
|
||||
LLVector3 particle_end;
|
||||
|
||||
if (hit_icon)
|
||||
{
|
||||
icon_dist = (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec();
|
||||
}
|
||||
LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f,
|
||||
NULL, -1, mPickTransparent, &face_hit,
|
||||
&intersection, &uv, &normal, &binormal);
|
||||
&intersection, &uv, &normal, &binormal, &start, &end);
|
||||
|
||||
mPickPt = mMousePt;
|
||||
|
||||
U32 te_offset = face_hit > -1 ? face_hit : 0;
|
||||
|
||||
//unproject relative clicked coordinate from window coordinate using GL
|
||||
|
||||
if (mPickParticle)
|
||||
{ //get the end point of line segement to use for particle raycast
|
||||
if (hit_object)
|
||||
{
|
||||
particle_end = intersection;
|
||||
}
|
||||
else
|
||||
{
|
||||
particle_end = end;
|
||||
}
|
||||
}
|
||||
|
||||
LLViewerObject* objectp = hit_object;
|
||||
|
||||
if (hit_icon &&
|
||||
|
|
@ -5166,6 +5187,7 @@ void LLPickInfo::fetchResults()
|
|||
mHUDIcon = hit_icon;
|
||||
mPickType = PICK_ICON;
|
||||
mPosGlobal = mHUDIcon->getPositionGlobal();
|
||||
|
||||
}
|
||||
else if (objectp)
|
||||
{
|
||||
|
|
@ -5210,6 +5232,18 @@ void LLPickInfo::fetchResults()
|
|||
}
|
||||
}
|
||||
|
||||
if (mPickParticle)
|
||||
{ //search for closest particle to click origin out to intersection point
|
||||
S32 part_face = -1;
|
||||
|
||||
LLVOPartGroup* group = gPipeline.lineSegmentIntersectParticle(start, particle_end, NULL, &part_face);
|
||||
if (group)
|
||||
{
|
||||
mParticleOwnerID = group->getPartOwner(part_face);
|
||||
mParticleSourceID = group->getPartSource(part_face);
|
||||
}
|
||||
}
|
||||
|
||||
if (mPickCallback)
|
||||
{
|
||||
mPickCallback(*this);
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ class LLWindow;
|
|||
class LLRootView;
|
||||
class LLWindowListener;
|
||||
class LLViewerWindowListener;
|
||||
class LLVOPartGroup;
|
||||
class LLPopupView;
|
||||
|
||||
#define PICK_HALF_WIDTH 5
|
||||
|
|
@ -86,7 +87,8 @@ public:
|
|||
LLPickInfo();
|
||||
LLPickInfo(const LLCoordGL& mouse_pos,
|
||||
MASK keyboard_mask,
|
||||
BOOL pick_transparent,
|
||||
BOOL pick_transparent,
|
||||
BOOL pick_particle,
|
||||
BOOL pick_surface_info,
|
||||
void (*pick_callback)(const LLPickInfo& pick_info));
|
||||
|
||||
|
|
@ -107,6 +109,8 @@ public:
|
|||
LLVector3d mPosGlobal;
|
||||
LLVector3 mObjectOffset;
|
||||
LLUUID mObjectID;
|
||||
LLUUID mParticleOwnerID;
|
||||
LLUUID mParticleSourceID;
|
||||
S32 mObjectFace;
|
||||
LLHUDIcon* mHUDIcon;
|
||||
LLVector3 mIntersection;
|
||||
|
|
@ -116,6 +120,7 @@ public:
|
|||
LLVector3 mNormal;
|
||||
LLVector3 mBinormal;
|
||||
BOOL mPickTransparent;
|
||||
BOOL mPickParticle;
|
||||
void getSurfaceInfo();
|
||||
|
||||
private:
|
||||
|
|
@ -354,7 +359,7 @@ public:
|
|||
void returnEmptyPicks();
|
||||
|
||||
void pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(const LLPickInfo& pick_info), BOOL pick_transparent = FALSE);
|
||||
LLPickInfo pickImmediate(S32 x, S32 y, BOOL pick_transparent);
|
||||
LLPickInfo pickImmediate(S32 x, S32 y, BOOL pick_transparent, BOOL pick_particle = FALSE);
|
||||
LLHUDIcon* cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth,
|
||||
LLVector3* intersection);
|
||||
|
||||
|
|
@ -494,6 +499,8 @@ extern LLFrameTimer gAwayTimer; // tracks time before setting the avatar awa
|
|||
extern LLFrameTimer gAwayTriggerTimer; // how long the avatar has been away
|
||||
|
||||
extern LLViewerObject* gDebugRaycastObject;
|
||||
extern LLVOPartGroup* gDebugRaycastParticle;
|
||||
extern LLVector3 gDebugRaycastParticleIntersection;
|
||||
extern LLVector3 gDebugRaycastIntersection;
|
||||
extern LLVector2 gDebugRaycastTexCoord;
|
||||
extern LLVector3 gDebugRaycastNormal;
|
||||
|
|
|
|||
|
|
@ -232,6 +232,37 @@ LLDrawable* LLVOPartGroup::createDrawable(LLPipeline *pipeline)
|
|||
|
||||
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())
|
||||
|
|
@ -385,20 +416,68 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void LLVOPartGroup::getGeometry(S32 idx,
|
||||
LLStrider<LLVector4a>& verticesp,
|
||||
LLStrider<LLVector3>& normalsp,
|
||||
LLStrider<LLVector2>& texcoordsp,
|
||||
LLStrider<LLColor4U>& colorsp,
|
||||
LLStrider<U16>& indicesp)
|
||||
|
||||
BOOL LLVOPartGroup::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
|
||||
S32 face,
|
||||
BOOL pick_transparent,
|
||||
S32* face_hit,
|
||||
LLVector3* intersection,
|
||||
LLVector2* tex_coord,
|
||||
LLVector3* normal,
|
||||
LLVector3* bi_normal)
|
||||
{
|
||||
if (idx >= (S32) mViewerPartGroupp->mParticles.size())
|
||||
LLVector4a starta, enda;
|
||||
starta.load3(start.mV);
|
||||
enda.load3(end.mV);
|
||||
|
||||
LLVector4a dir;
|
||||
dir.setSub(enda, starta);
|
||||
|
||||
F32 closest_t = 2.f;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
for (U32 idx = 0; idx < mViewerPartGroupp->mParticles.size(); ++idx)
|
||||
{
|
||||
return;
|
||||
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], starta, dir, a,b,t) ||
|
||||
LLTriangleRayIntersect(v[1], v[3], v[2], starta, 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);
|
||||
intersect.add(starta);
|
||||
intersection->set(intersect.getF32ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const LLViewerPart &part = *((LLViewerPart*) (mViewerPartGroupp->mParticles[idx]));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LLVOPartGroup::getGeometry(const LLViewerPart& part,
|
||||
LLStrider<LLVector4a>& verticesp)
|
||||
{
|
||||
LLVector4a part_pos_agent;
|
||||
part_pos_agent.load3(part.mPosAgent.mV);
|
||||
LLVector4a camera_agent;
|
||||
|
|
@ -449,8 +528,6 @@ void LLVOPartGroup::getGeometry(S32 idx,
|
|||
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
|
||||
|
|
@ -469,6 +546,25 @@ void LLVOPartGroup::getGeometry(S32 idx,
|
|||
(*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]));
|
||||
|
||||
getGeometry(part, verticesp);
|
||||
|
||||
*colorsp++ = part.mColor;
|
||||
*colorsp++ = part.mColor;
|
||||
|
|
@ -477,6 +573,7 @@ void LLVOPartGroup::getGeometry(S32 idx,
|
|||
|
||||
if (!(part.mFlags & LLPartData::LL_PART_EMISSIVE_MASK))
|
||||
{ //not fullbright, needs normal
|
||||
LLVector3 normal = -LLViewerCamera::getInstance()->getXAxis();
|
||||
*normalsp++ = normal;
|
||||
*normalsp++ = normal;
|
||||
*normalsp++ = normal;
|
||||
|
|
|
|||
|
|
@ -69,11 +69,23 @@ public:
|
|||
virtual void updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax);
|
||||
virtual U32 getPartitionType() const;
|
||||
|
||||
/*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
|
||||
S32 face,
|
||||
BOOL pick_transparent,
|
||||
S32* face_hit,
|
||||
LLVector3* intersection,
|
||||
LLVector2* tex_coord,
|
||||
LLVector3* normal,
|
||||
LLVector3* bi_normal);
|
||||
|
||||
/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent);
|
||||
/*virtual*/ void updateTextures();
|
||||
|
||||
/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
|
||||
/*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
|
||||
void getGeometry(const LLViewerPart& part,
|
||||
LLStrider<LLVector4a>& verticesp);
|
||||
|
||||
void getGeometry(S32 idx,
|
||||
LLStrider<LLVector4a>& verticesp,
|
||||
LLStrider<LLVector3>& normalsp,
|
||||
|
|
@ -83,6 +95,9 @@ public:
|
|||
|
||||
void updateFaceSize(S32 idx) { }
|
||||
F32 getPartSize(S32 idx);
|
||||
LLUUID getPartOwner(S32 idx);
|
||||
LLUUID getPartSource(S32 idx);
|
||||
|
||||
void setViewerPartGroup(LLViewerPartGroup *part_groupp) { mViewerPartGroupp = part_groupp; }
|
||||
LLViewerPartGroup* getViewerPartGroup() { return mViewerPartGroupp; }
|
||||
|
||||
|
|
|
|||
|
|
@ -5023,6 +5023,42 @@ void LLPipeline::renderDebug()
|
|||
gUIProgram.bind();
|
||||
}
|
||||
|
||||
if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST) && !hud_only)
|
||||
{ //draw crosshairs on particle intersection
|
||||
if (gDebugRaycastParticle)
|
||||
{
|
||||
if (LLGLSLShader::sNoFixedFunction)
|
||||
{ //this debug display requires shaders
|
||||
gDebugProgram.bind();
|
||||
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
|
||||
LLVector3 center = gDebugRaycastParticleIntersection;
|
||||
LLVector3 size(0.1f, 0.1f, 0.1f);
|
||||
|
||||
LLVector3 p[6];
|
||||
|
||||
p[0] = center + size.scaledVec(LLVector3(1,0,0));
|
||||
p[1] = center + size.scaledVec(LLVector3(-1,0,0));
|
||||
p[2] = center + size.scaledVec(LLVector3(0,1,0));
|
||||
p[3] = center + size.scaledVec(LLVector3(0,-1,0));
|
||||
p[4] = center + size.scaledVec(LLVector3(0,0,1));
|
||||
p[5] = center + size.scaledVec(LLVector3(0,0,-1));
|
||||
|
||||
gGL.begin(LLRender::LINES);
|
||||
gGL.diffuseColor3f(1.f, 1.f, 0.f);
|
||||
for (U32 i = 0; i < 6; i++)
|
||||
{
|
||||
gGL.vertex3fv(p[i].mV);
|
||||
}
|
||||
gGL.end();
|
||||
gGL.flush();
|
||||
|
||||
gDebugProgram.unbind();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
|
||||
{
|
||||
LLVertexBuffer::unbind();
|
||||
|
|
@ -6600,6 +6636,48 @@ BOOL LLPipeline::getRenderHighlights(void*)
|
|||
return sRenderHighlight;
|
||||
}
|
||||
|
||||
LLVOPartGroup* LLPipeline::lineSegmentIntersectParticle(const LLVector3& start, const LLVector3& end, LLVector3* intersection,
|
||||
S32* face_hit)
|
||||
{
|
||||
LLVector3 local_end = end;
|
||||
|
||||
LLVector3 position;
|
||||
|
||||
LLDrawable* drawable = NULL;
|
||||
|
||||
for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
|
||||
iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
|
||||
{
|
||||
LLViewerRegion* region = *iter;
|
||||
|
||||
LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_PARTICLE);
|
||||
if (part && hasRenderType(part->mDrawableType))
|
||||
{
|
||||
LLDrawable* hit = part->lineSegmentIntersect(start, local_end, TRUE, face_hit, &position, NULL, NULL, NULL);
|
||||
if (hit)
|
||||
{
|
||||
drawable = hit;
|
||||
local_end = position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLVOPartGroup* ret = NULL;
|
||||
if (drawable)
|
||||
{
|
||||
//make sure we're returning an LLVOPartGroup
|
||||
llassert(drawable->getVObj()->getPCode() == LLViewerObject::LL_VO_PART_GROUP);
|
||||
ret = (LLVOPartGroup*) drawable->getVObj().get();
|
||||
}
|
||||
|
||||
if (intersection)
|
||||
{
|
||||
*intersection = position;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end,
|
||||
BOOL pick_transparent,
|
||||
S32* face_hit,
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ class LLRenderFunc;
|
|||
class LLCubeMap;
|
||||
class LLCullResult;
|
||||
class LLVOAvatar;
|
||||
class LLVOPartGroup;
|
||||
class LLGLSLShader;
|
||||
class LLCurlRequest;
|
||||
|
||||
|
|
@ -193,6 +194,12 @@ public:
|
|||
LLVector3* normal = NULL, // return the surface normal at the intersection point
|
||||
LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point
|
||||
);
|
||||
|
||||
//get the closest particle to start between start and end, returns the LLVOPartGroup and particle index
|
||||
LLVOPartGroup* lineSegmentIntersectParticle(const LLVector3& start, const LLVector3& end, LLVector3* intersection,
|
||||
S32* face_hit);
|
||||
|
||||
|
||||
LLViewerObject* lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end,
|
||||
BOOL pick_transparent,
|
||||
S32* face_hit, // return the face hit
|
||||
|
|
|
|||
|
|
@ -104,4 +104,15 @@
|
|||
<menu_item_call.on_enable
|
||||
function="Object.EnableInspect" />
|
||||
</menu_item_call>
|
||||
<menu_item_separator
|
||||
layout="topleft" />
|
||||
<menu_item_call
|
||||
enabled="false"
|
||||
label="Mute Particle Owner"
|
||||
name="Mute Particle">
|
||||
<menu_item_call.on_click
|
||||
function="Particle.Mute" />
|
||||
<menu_item_call.on_enable
|
||||
function="EnableMuteParticle" />
|
||||
</menu_item_call>
|
||||
</context_menu>
|
||||
|
|
|
|||
|
|
@ -135,4 +135,15 @@ name="Edit Outfit">
|
|||
<menu_item_call.on_enable
|
||||
function="Attachment.EnableDrop" />
|
||||
</menu_item_call>
|
||||
<menu_item_separator
|
||||
layout="topleft" />
|
||||
<menu_item_call
|
||||
enabled="false"
|
||||
label="Mute Particle Owner"
|
||||
name="Mute Particle">
|
||||
<menu_item_call.on_click
|
||||
function="Particle.Mute" />
|
||||
<menu_item_call.on_enable
|
||||
function="EnableMuteParticle" />
|
||||
</menu_item_call>
|
||||
</context_menu>
|
||||
|
|
|
|||
|
|
@ -95,4 +95,15 @@
|
|||
<menu_item_call.on_enable
|
||||
function="EnablePayAvatar" />
|
||||
</menu_item_call>
|
||||
<menu_item_separator
|
||||
layout="topleft" />
|
||||
<menu_item_call
|
||||
enabled="false"
|
||||
label="Mute Particle Owner"
|
||||
name="Mute Particle">
|
||||
<menu_item_call.on_click
|
||||
function="Particle.Mute" />
|
||||
<menu_item_call.on_enable
|
||||
function="EnableMuteParticle" />
|
||||
</menu_item_call>
|
||||
</context_menu>
|
||||
|
|
|
|||
|
|
@ -261,4 +261,15 @@
|
|||
<menu_item_call.on_visible
|
||||
function="IsGodCustomerService"/>
|
||||
</menu_item_call>
|
||||
<menu_item_separator
|
||||
layout="topleft" />
|
||||
<menu_item_call
|
||||
enabled="false"
|
||||
label="Mute Particle Owner"
|
||||
name="Mute Particle">
|
||||
<menu_item_call.on_click
|
||||
function="Particle.Mute" />
|
||||
<menu_item_call.on_enable
|
||||
function="EnableMuteParticle" />
|
||||
</menu_item_call>
|
||||
</context_menu>
|
||||
|
|
|
|||
|
|
@ -61,4 +61,15 @@
|
|||
<menu_item_call.on_enable
|
||||
function="EnableEdit" />
|
||||
</menu_item_call>
|
||||
<menu_item_separator
|
||||
layout="topleft" />
|
||||
<menu_item_call
|
||||
enabled="false"
|
||||
label="Mute Particle Owner"
|
||||
name="Mute Particle">
|
||||
<menu_item_call.on_click
|
||||
function="Particle.Mute" />
|
||||
<menu_item_call.on_enable
|
||||
function="EnableMuteParticle" />
|
||||
</menu_item_call>
|
||||
</context_menu>
|
||||
|
|
|
|||
|
|
@ -196,4 +196,15 @@
|
|||
<menu_item_call.on_enable
|
||||
function="Object.EnableDelete" />
|
||||
</menu_item_call>
|
||||
<menu_item_separator
|
||||
layout="topleft" />
|
||||
<menu_item_call
|
||||
enabled="false"
|
||||
label="Mute Particle Owner"
|
||||
name="Mute Particle">
|
||||
<menu_item_call.on_click
|
||||
function="Particle.Mute" />
|
||||
<menu_item_call.on_enable
|
||||
function="EnableMuteParticle" />
|
||||
</menu_item_call>
|
||||
</context_menu>
|
||||
|
|
|
|||
Loading…
Reference in New Issue