Merge remote-tracking branch 'shyotl/master'
This commit is contained in:
@@ -312,11 +312,11 @@ LLGLenum LLGLTexture::getPrimaryFormat() const
|
||||
return mGLTexturep->getPrimaryFormat() ;
|
||||
}
|
||||
|
||||
BOOL LLGLTexture::getIsAlphaMask() const
|
||||
BOOL LLGLTexture::getIsAlphaMask(const F32 max_rmse) const
|
||||
{
|
||||
llassert(mGLTexturep.notNull()) ;
|
||||
|
||||
return mGLTexturep->getIsAlphaMask() ;
|
||||
return mGLTexturep->getIsAlphaMask(max_rmse) ;
|
||||
}
|
||||
|
||||
BOOL LLGLTexture::getMask(const LLVector2 &tc)
|
||||
|
||||
@@ -140,7 +140,7 @@ public:
|
||||
BOOL getBoundRecently() const;
|
||||
S32 getTextureMemory() const ;
|
||||
LLGLenum getPrimaryFormat() const;
|
||||
BOOL getIsAlphaMask() const ;
|
||||
BOOL getIsAlphaMask(const F32 max_rmse) const ;
|
||||
LLTexUnit::eTextureType getTarget(void) const ;
|
||||
BOOL getMask(const LLVector2 &tc);
|
||||
F32 getTimePassedSinceLastBound();
|
||||
|
||||
@@ -482,7 +482,11 @@ void LLImageGL::init(BOOL usemipmaps)
|
||||
mHasExplicitFormat = FALSE;
|
||||
mAutoGenMips = FALSE;
|
||||
|
||||
mCanMask = TRUE;
|
||||
mIsMask = FALSE;
|
||||
mMaskRMSE = 1.f ;
|
||||
|
||||
|
||||
mNeedsAlphaAndPickMask = TRUE ;
|
||||
mAlphaStride = 0 ;
|
||||
mAlphaOffset = 0 ;
|
||||
@@ -1749,7 +1753,7 @@ void LLImageGL::setNeedsAlphaAndPickMask(BOOL need_mask)
|
||||
else //do not need alpha mask
|
||||
{
|
||||
mAlphaOffset = INVALID_OFFSET ;
|
||||
mIsMask = FALSE;
|
||||
mCanMask = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1773,7 +1777,7 @@ void LLImageGL::calcAlphaChannelOffsetAndStride()
|
||||
break;
|
||||
case GL_RGB:
|
||||
mNeedsAlphaAndPickMask = FALSE ;
|
||||
mIsMask = FALSE;
|
||||
mCanMask = FALSE;
|
||||
return ; //no alpha channel.
|
||||
case GL_RGBA:
|
||||
mAlphaStride = 4;
|
||||
@@ -1820,17 +1824,20 @@ void LLImageGL::calcAlphaChannelOffsetAndStride()
|
||||
llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl;
|
||||
|
||||
mNeedsAlphaAndPickMask = FALSE ;
|
||||
mIsMask = FALSE;
|
||||
mCanMask = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<LLGLuint, std::list<std::pair<std::string,std::string> > > sTextureMaskMap;
|
||||
void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
|
||||
{
|
||||
if(!mNeedsAlphaAndPickMask)
|
||||
if(!mNeedsAlphaAndPickMask || !mCanMask)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
F64 sum = 0;
|
||||
|
||||
U32 length = w * h;
|
||||
U32 alphatotal = 0;
|
||||
|
||||
@@ -1871,11 +1878,19 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
|
||||
const U32 asum = (s1+s2+s3+s4);
|
||||
alphatotal += asum;
|
||||
sample[asum/(16*4)] += 4;
|
||||
|
||||
S32 avg = (s1+s2+s3+s4)/4;
|
||||
if(avg >=128)
|
||||
{
|
||||
avg-=255;
|
||||
}
|
||||
sum+=F64(avg*avg*4)/F64(length);
|
||||
}
|
||||
|
||||
|
||||
rowstart += 2 * w * mAlphaStride;
|
||||
}
|
||||
|
||||
length *= 2; // we sampled everything twice, essentially
|
||||
}
|
||||
else
|
||||
@@ -1887,9 +1902,17 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
|
||||
alphatotal += s1;
|
||||
++sample[s1/16];
|
||||
current += mAlphaStride;
|
||||
|
||||
if(i%2==0)
|
||||
{
|
||||
S32 avg = (s1+current[mAlphaStride])/2;
|
||||
if(avg >=128)
|
||||
avg-=255;
|
||||
sum+=F64(avg*avg*2)/F64(length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if more than 1/16th of alpha samples are mid-range, this
|
||||
// shouldn't be treated as a 1-bit mask
|
||||
|
||||
@@ -1898,7 +1921,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
|
||||
// this to be an intentional effect and don't treat as a mask.
|
||||
|
||||
U32 midrangetotal = 0;
|
||||
for (U32 i = 2; i < 13; i++)
|
||||
for (U32 i = 3; i < 13; i++)
|
||||
{
|
||||
midrangetotal += sample[i];
|
||||
}
|
||||
@@ -1923,6 +1946,22 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
|
||||
{
|
||||
mIsMask = TRUE;
|
||||
}
|
||||
|
||||
mMaskRMSE = sqrt(sum)/255.0;
|
||||
|
||||
std::list<std::pair<std::string,std::string> > &data = sTextureMaskMap[getTexName()];
|
||||
data.clear();
|
||||
data.push_back(std::make_pair("RMSE", llformat("%f",mMaskRMSE)));
|
||||
data.push_back(std::make_pair(" sum", llformat("%lf",sum)));
|
||||
data.push_back(std::make_pair(" n", llformat("%u",h*w)));
|
||||
data.push_back(std::make_pair("legacymask", mIsMask ? "TRUE" : "FALSE"));
|
||||
data.push_back(std::make_pair(" index", llformat("%u",getTexName())));
|
||||
data.push_back(std::make_pair(" length", llformat("%u",length)));
|
||||
data.push_back(std::make_pair(" stride", llformat("%i",S32(mAlphaOffset))));
|
||||
data.push_back(std::make_pair(" split", llformat("%u|%u|%u",lowerhalftotal,midrangetotal,upperhalftotal)));
|
||||
data.push_back(std::make_pair(" alphatotal", llformat("%u",alphatotal)));
|
||||
data.push_back(std::make_pair(" alphatotal/48", llformat("%u",length/48)));
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
@@ -142,7 +142,7 @@ public:
|
||||
BOOL getHasGLTexture() const { return mTexName != 0; }
|
||||
LLGLuint getTexName() const { return mTexName; }
|
||||
|
||||
BOOL getIsAlphaMask() const { return mIsMask; }
|
||||
BOOL getIsAlphaMask(const F32 max_rmse) const { return mCanMask && (max_rmse < 0.f ? (bool)mIsMask : (mMaskRMSE <= max_rmse)); }
|
||||
|
||||
BOOL getIsResident(BOOL test_now = FALSE); // not const
|
||||
|
||||
@@ -192,7 +192,9 @@ private:
|
||||
S8 mHasExplicitFormat; // If false (default), GL format is f(mComponents)
|
||||
S8 mAutoGenMips;
|
||||
|
||||
BOOL mCanMask;
|
||||
BOOL mIsMask;
|
||||
F32 mMaskRMSE;
|
||||
BOOL mNeedsAlphaAndPickMask;
|
||||
S8 mAlphaStride ;
|
||||
S8 mAlphaOffset ;
|
||||
|
||||
@@ -490,7 +490,7 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
|
||||
pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
|
||||
index++;
|
||||
|
||||
uv[index].set(uv_center_rect.mLeft, uv_center_rect.mBottom);
|
||||
uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
|
||||
pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
|
||||
index++;
|
||||
|
||||
|
||||
@@ -206,6 +206,28 @@
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>0.25</real>
|
||||
</map>
|
||||
<key>SHUseRMSEAutoMask</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Use alternative method of detecing suitable textures for alphamasking. Less prone to excluding textures than standard method.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<real>1</real>
|
||||
</map>
|
||||
<key>SHAlphaMaskMaxRMSE</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Sets the maximum random mean square error cutoff used when detecting suitable textures for alphamasking. (SHUseRMSEAutoMask must be TRUE for this to have any effect)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>0.09</real>
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
|
||||
@@ -1067,9 +1067,11 @@ bool LLFace::canRenderAsMask()
|
||||
|
||||
const LLTextureEntry* te = getTextureEntry();
|
||||
|
||||
static const LLCachedControl<bool> use_rmse_auto_mask("SHUseRMSEAutoMask",false);
|
||||
static const LLCachedControl<F32> alpha_mas_max_rmse("SHAlphaMaskMaxRMSE",.09f);
|
||||
if ((te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha
|
||||
(te->getGlow() == 0.f) && // glowing masks are hard to implement - don't mask
|
||||
getTexture()->getIsAlphaMask()) // texture actually qualifies for masking (lazily recalculated but expensive)
|
||||
getTexture()->getIsAlphaMask(use_rmse_auto_mask ? alpha_mas_max_rmse : -1.f)) // texture actually qualifies for masking (lazily recalculated but expensive)
|
||||
{
|
||||
if (LLPipeline::sRenderDeferred)
|
||||
{
|
||||
|
||||
@@ -630,6 +630,11 @@ bool LLFloaterReporter::validateReport()
|
||||
// Ensure user selected a category from the list
|
||||
LLSD category_sd = childGetValue("category_combo");
|
||||
U8 category = (U8)category_sd.asInteger();
|
||||
if(category >= 100) //This is here for reasons (like shenanigans)
|
||||
{
|
||||
LLNotificationsUtil::add("HelpReportNope");
|
||||
return false;
|
||||
}
|
||||
if (category == 0)
|
||||
{
|
||||
if ( mReportType != BUG_REPORT )
|
||||
|
||||
@@ -282,9 +282,12 @@ void LLPreviewTexture::draw()
|
||||
interior.getHeight(),
|
||||
mImage);
|
||||
|
||||
if (mAlphaMaskResult != mImage->getIsAlphaMask())
|
||||
static const LLCachedControl<bool> use_rmse_auto_mask("SHUseRMSEAutoMask",false);
|
||||
static const LLCachedControl<F32> alpha_mas_max_rmse("SHAlphaMaskMaxRMSE",.09f);
|
||||
if (mAlphaMaskResult != mImage->getIsAlphaMask(use_rmse_auto_mask ? alpha_mas_max_rmse : -1.f))
|
||||
{
|
||||
if (!mImage->getIsAlphaMask())
|
||||
mAlphaMaskResult = !mAlphaMaskResult;
|
||||
if (!mAlphaMaskResult)
|
||||
{
|
||||
childSetColor("alphanote", LLColor4::green);
|
||||
childSetText("alphanote", getString("No Alpha"));
|
||||
@@ -294,7 +297,7 @@ void LLPreviewTexture::draw()
|
||||
childSetColor("alphanote", LLColor4::red);
|
||||
childSetText("alphanote", getString("Has Alpha"));
|
||||
}
|
||||
mAlphaMaskResult = mImage->getIsAlphaMask();
|
||||
|
||||
}
|
||||
// Pump the texture priority
|
||||
F32 pixel_area = mLoadingFullImage ? (F32)MAX_IMAGE_AREA : (F32)(interior.getWidth() * interior.getHeight() );
|
||||
|
||||
@@ -937,6 +937,8 @@ LLObjectSelectionHandle LLSelectMgr::setHoverObject(LLViewerObject *objectp, S32
|
||||
|
||||
mHoverObjects->mPrimaryObject = objectp;
|
||||
|
||||
LLViewerObject* primary_obj = objectp;
|
||||
|
||||
objectp = objectp->getRootEdit();
|
||||
|
||||
// is the requested object the same as the existing hover object root?
|
||||
@@ -962,6 +964,8 @@ LLObjectSelectionHandle LLSelectMgr::setHoverObject(LLViewerObject *objectp, S32
|
||||
requestObjectPropertiesFamily(objectp);
|
||||
}
|
||||
|
||||
mHoverObjects->mPrimaryObject = primary_obj;
|
||||
|
||||
return mHoverObjects;
|
||||
}
|
||||
|
||||
|
||||
@@ -674,6 +674,8 @@ void settings_setup_listeners()
|
||||
gSavedSettings.getControl("RenderDebugTextureBind")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
|
||||
gSavedSettings.getControl("RenderAutoMaskAlphaDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
|
||||
gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
|
||||
gSavedSettings.getControl("SHUseRMSEAutoMask")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
|
||||
gSavedSettings.getControl("SHAlphaMaskMaxRMSE")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
|
||||
gSavedSettings.getControl("RenderObjectBump")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
|
||||
gSavedSettings.getControl("RenderMaxVBOSize")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
|
||||
//See LL jira VWR-3258 comment section. Implemented by LL in 2.1 -Shyotl
|
||||
|
||||
@@ -1587,6 +1587,9 @@ void init_debug_rendering_menu(LLMenuGL* menu)
|
||||
|
||||
item = new LLMenuItemCheckGL("Automatic Alpha Masks (deferred)", menu_toggle_control, NULL, menu_check_control, (void*)"RenderAutoMaskAlphaDeferred");
|
||||
menu->addChild(item);
|
||||
|
||||
item = new LLMenuItemCheckGL("Aggressive Alpha Masking", menu_toggle_control, NULL, menu_check_control, (void*)"SHUseRMSEAutoMask");
|
||||
menu->addChild(item);
|
||||
|
||||
item = new LLMenuItemCheckGL("Animate Textures", menu_toggle_control, NULL, menu_check_control, (void*)"AnimateTextures");
|
||||
menu->addChild(item);
|
||||
@@ -2296,8 +2299,12 @@ public:
|
||||
for (S32 i = 0; i < img->getNumVolumes(); ++i)
|
||||
{
|
||||
LLVOVolume* volume = (*(img->getVolumeList()))[i];
|
||||
if (volume && volume->isSculpted() && !volume->isMesh())
|
||||
volume->notifyMeshLoaded();
|
||||
if (volume && volume->isSculpted())
|
||||
{
|
||||
LLSculptParams *sculpt_params = (LLSculptParams *)volume->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
|
||||
if(sculpt_params->getSculptTexture() == id)
|
||||
volume->notifyMeshLoaded();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2359,6 +2366,16 @@ class LLObjectReloadTextures : public view_listener_t
|
||||
iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++)
|
||||
{
|
||||
LLViewerObject* object = (*iter)->getObject();
|
||||
object->markForUpdate(TRUE);
|
||||
|
||||
if(object->isSculpted() && !object->isMesh())
|
||||
{
|
||||
LLSculptParams *sculpt_params = (LLSculptParams *)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
|
||||
if(sculpt_params)
|
||||
{
|
||||
texture_list.addTexture(LLViewerTextureManager::getFetchedTexture(sculpt_params->getSculptTexture()));
|
||||
}
|
||||
}
|
||||
|
||||
for (U8 i = 0; i < object->getNumTEs(); i++)
|
||||
{
|
||||
@@ -2366,14 +2383,6 @@ class LLObjectReloadTextures : public view_listener_t
|
||||
{
|
||||
texture_list.addTexture(object->getTEImage(i));
|
||||
}
|
||||
if(object->isSculpted() && !object->isMesh())
|
||||
{
|
||||
LLSculptParams *sculpt_params = (LLSculptParams *)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
|
||||
if(sculpt_params)
|
||||
{
|
||||
texture_list.addTexture(LLViewerTextureManager::getFetchedTexture(sculpt_params->getSculptTexture()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -122,6 +122,8 @@ public:
|
||||
LLViewerTexture(const LLImageRaw* raw, BOOL usemipmaps) ;
|
||||
LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ;
|
||||
|
||||
void setNeedsAlphaAndPickMask(BOOL need_mask) { if(mGLTexturep)mGLTexturep->setNeedsAlphaAndPickMask(need_mask); }
|
||||
|
||||
virtual S8 getType() const;
|
||||
virtual BOOL isMissingAsset()const ;
|
||||
virtual void dump(); // debug info to llinfos
|
||||
|
||||
@@ -274,6 +274,8 @@ extern void toggle_debug_menus(void*);
|
||||
// LLDebugText
|
||||
//
|
||||
|
||||
extern std::map<LLGLuint, std::list<std::pair<std::string,std::string> > > sTextureMaskMap;
|
||||
|
||||
class LLDebugText
|
||||
{
|
||||
private:
|
||||
@@ -336,6 +338,46 @@ public:
|
||||
addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc;
|
||||
}
|
||||
}
|
||||
static const LLCachedControl<bool> analyze_target_texture("AnalyzeTargetTexture", false);
|
||||
if(analyze_target_texture)
|
||||
{
|
||||
static LLViewerObject* lastObject = NULL;
|
||||
LLSelectNode* nodep = LLSelectMgr::instance().getPrimaryHoverNode();
|
||||
LLObjectSelectionHandle handle = LLSelectMgr::instance().getHoverObjects();
|
||||
if(nodep || handle.notNull())
|
||||
{
|
||||
|
||||
LLViewerObject* obj1 = nodep ? nodep->getObject() : NULL;
|
||||
LLViewerObject* obj2 = handle ? handle->getPrimaryObject() : NULL;
|
||||
LLViewerObject* obj = obj1 ? obj1 : obj2;
|
||||
//llinfos << std::hex << obj1 << " " << obj2 << std::dec << llendl;
|
||||
if(obj)
|
||||
{
|
||||
S32 te = nodep ? nodep->getLastSelectedTE() : -1;
|
||||
if(te > 0)
|
||||
{
|
||||
LLViewerTexture* imagep = obj->getTEImage(te);
|
||||
if(imagep && imagep != (LLViewerTexture*)LLViewerFetchedTexture::sDefaultImagep.get())
|
||||
{
|
||||
LLGLuint tex = imagep->getTexName();
|
||||
std::map<LLGLuint, std::list<std::pair<std::string,std::string> > >::iterator it = sTextureMaskMap.find(tex);
|
||||
if(it != sTextureMaskMap.end())
|
||||
{
|
||||
std::list<std::pair<std::string,std::string> >::reverse_iterator it2 = it->second.rbegin();
|
||||
for(;it2!=it->second.rend();++it2)
|
||||
{
|
||||
addText(xpos, ypos, llformat(" %s: %s", it2->first.c_str(), it2->second.c_str())); ypos += y_inc;
|
||||
}
|
||||
}
|
||||
static const LLCachedControl<bool> use_rmse_auto_mask("SHUseRMSEAutoMask",false);
|
||||
static const LLCachedControl<F32> alpha_mas_max_rmse("SHAlphaMaskMaxRMSE",.09f);
|
||||
addText(xpos, ypos, llformat("Mask: %s", imagep->getIsAlphaMask(use_rmse_auto_mask ? alpha_mas_max_rmse : -1.f) ? "TRUE":"FALSE")); ypos += y_inc;
|
||||
addText(xpos, ypos, llformat("ID: %s", imagep->getID().asString())); ypos += y_inc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if LL_WINDOWS
|
||||
static const LLCachedControl<bool> debug_show_memory("DebugShowMemory");
|
||||
|
||||
@@ -298,6 +298,7 @@ void LLSkyTex::create(const F32 brightness)
|
||||
|
||||
void LLSkyTex::createGLImage(S32 which)
|
||||
{
|
||||
mTexture[which]->setNeedsAlphaAndPickMask(false); //Needed, else analyzeAlpha is called every frame for each texture.
|
||||
mTexture[which]->createGLTexture(0, mImageRaw[which], 0, TRUE, LLViewerTexture::LOCAL);
|
||||
mTexture[which]->setAddressMode(LLTexUnit::TAM_CLAMP);
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
Fraud > Pyramid scheme or chain letter
|
||||
</combo_item><combo_item name="Fraud__US$" value="50">
|
||||
Fraud > US$
|
||||
</combo_item><combo_item name="Ridiculous3" value="71">
|
||||
</combo_item><combo_item name="Ridiculous3" value="100">
|
||||
Freud > User has taken an interest in their mother
|
||||
</combo_item><combo_item name="Harassment__Advert_farms___visual_spam" value="51">
|
||||
Harassment > Advert farms / visual spam
|
||||
@@ -139,7 +139,7 @@
|
||||
Harassment > Solicting/inciting others to violate ToS
|
||||
</combo_item><combo_item name="Harassment__Verbal_abuse" value="56">
|
||||
Harassment > Verbal abuse
|
||||
</combo_item><combo_item name="Ridiculous1" value="69">
|
||||
</combo_item><combo_item name="Ridiculous1" value="100">
|
||||
Harassment > User keeps licking finger and touching me
|
||||
</combo_item><combo_item name="Indecency__Broadly_offensive_content_or_conduct" value="57">
|
||||
Indecency > Broadly offensive content or conduct
|
||||
@@ -164,7 +164,7 @@
|
||||
Land > Encroachment > Particles
|
||||
</combo_item><combo_item name="Land__Encroachment__Trees_plants" value="65">
|
||||
Land > Encroachment > Trees/plants
|
||||
</combo_item><combo_item name="Ridiculous2" value="70">
|
||||
</combo_item><combo_item name="Ridiculous2" value="100">
|
||||
Land > Encroachment > User won't stay on their side of the car
|
||||
</combo_item><combo_item name="Wagering_gambling" value="67">
|
||||
Wagering/gambling
|
||||
|
||||
@@ -4953,6 +4953,15 @@ Be as specific as you can, including steps to reproduce the bug if possible.
|
||||
Entering an accurate description helps us file and process bug reports.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="HelpReportNope"
|
||||
type="alertmodal">
|
||||
Do not meddle in the affairs of wizards, for they are subtle and quick to anger. - J.R.R. Tolkien
|
||||
|
||||
Please choose a legitimate category if you actually have something to report.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="HelpReportAbuseContainsCopyright"
|
||||
|
||||
Reference in New Issue
Block a user