Moved the set/getName() support from osg::Node etc into the osg::Obejct
base class
This commit is contained in:
parent
69cd27e37f
commit
27c4c6a956
@ -90,16 +90,7 @@ class OSG_EXPORT Node : public Object
|
||||
/** Traverse upwards : calls parents' accept method with NodeVisitor.*/
|
||||
virtual void ascend(NodeVisitor& nv);
|
||||
/** Traverse downwards : calls children's accept method with NodeVisitor.*/
|
||||
virtual void traverse(NodeVisitor& /*nv*/) {}
|
||||
|
||||
|
||||
/** Set the name of node using C++ style string.*/
|
||||
inline void setName( const std::string& name ) { _name = name; }
|
||||
/** Set the name of node using a C style string.*/
|
||||
inline void setName( const char* name ) { _name = name; }
|
||||
/** Get the name of node.*/
|
||||
inline const std::string& getName() const { return _name; }
|
||||
|
||||
virtual void traverse(NodeVisitor& /*nv*/) {}
|
||||
|
||||
/** A vector of osg::Group pointers which is used to store the parent(s) of node.*/
|
||||
typedef std::vector<Group*> ParentList;
|
||||
@ -313,8 +304,6 @@ class OSG_EXPORT Node : public Object
|
||||
mutable BoundingSphere _boundingSphere;
|
||||
mutable bool _boundingSphereComputed;
|
||||
|
||||
std::string _name;
|
||||
|
||||
void addParent(osg::Group* node);
|
||||
void removeParent(osg::Group* node);
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include <osg/CopyOp>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace osg {
|
||||
|
||||
// forward declare
|
||||
@ -74,6 +76,16 @@ class OSG_EXPORT Object : public Referenced
|
||||
virtual const char* className() const = 0;
|
||||
|
||||
|
||||
/** Set the name of object using C++ style string.*/
|
||||
inline void setName( const std::string& name ) { _name = name; }
|
||||
|
||||
/** Set the name of object using a C style string.*/
|
||||
inline void setName( const char* name ) { _name = name; }
|
||||
|
||||
/** Get the name of object.*/
|
||||
inline const std::string& getName() const { return _name; }
|
||||
|
||||
|
||||
enum DataVariance
|
||||
{
|
||||
DYNAMIC,
|
||||
@ -121,8 +133,8 @@ class OSG_EXPORT Object : public Referenced
|
||||
= new Node().*/
|
||||
virtual ~Object() {}
|
||||
|
||||
std::string _name;
|
||||
DataVariance _dataVariance;
|
||||
|
||||
ref_ptr<Referenced> _userData;
|
||||
|
||||
private:
|
||||
|
@ -100,11 +100,6 @@ class OSG_EXPORT Program : public osg::StateAttribute
|
||||
/** Query InfoLog from a glProgram */
|
||||
bool getGlProgramInfoLog(unsigned int contextID, std::string& log) const;
|
||||
|
||||
/** A name for use by the application */
|
||||
void setName( const std::string& name ) { _name = name; }
|
||||
void setName( const char* name ) { _name = name; }
|
||||
const std::string& getName() const { return _name; }
|
||||
|
||||
/** Mark internal glProgram for deletion.
|
||||
* Deletion requests are queued until they can be executed
|
||||
* in the proper GL context. */
|
||||
@ -221,7 +216,7 @@ class OSG_EXPORT Program : public osg::StateAttribute
|
||||
virtual ~Program();
|
||||
|
||||
protected: /*data*/
|
||||
std::string _name;
|
||||
|
||||
mutable osg::buffered_value< osg::ref_ptr<PerContextProgram> > _pcpList;
|
||||
AttribBindingList _attribBindingList;
|
||||
|
||||
|
@ -92,11 +92,6 @@ class OSG_EXPORT Shader : public osg::Object
|
||||
/** Query InfoLog from a glShader */
|
||||
bool getGlShaderInfoLog(unsigned int contextID, std::string& log) const;
|
||||
|
||||
/** A name for use by the application */
|
||||
void setName( const std::string& name ) { _name = name; }
|
||||
void setName( const char* name ) { _name = name; }
|
||||
const std::string& getName() const { return _name; };
|
||||
|
||||
/** Mark internal glShader for deletion.
|
||||
* Deletion requests are queued tuntil they can be executed
|
||||
* in the proper GL context. */
|
||||
@ -162,7 +157,6 @@ class OSG_EXPORT Shader : public osg::Object
|
||||
|
||||
protected: /*data*/
|
||||
Type _type;
|
||||
std::string _name;
|
||||
std::string _shaderSource;
|
||||
/** osg::Programs that this osg::Shader is attached to */
|
||||
typedef std::set< Program* > ProgramSet;
|
||||
|
@ -179,15 +179,15 @@ class OSG_EXPORT Uniform : public Object
|
||||
|
||||
|
||||
|
||||
/** Set the type of glUniform. */
|
||||
bool setType( Type t );
|
||||
bool setName( const std::string& name );
|
||||
|
||||
/** Get the name of glUniform. */
|
||||
const std::string& getName() const { return _name; }
|
||||
|
||||
/** Get the type of glUniform as enum. */
|
||||
const Type getType() const { return _type; }
|
||||
|
||||
/** Set the name of the glUniform, checking to make sure its only set once.*/
|
||||
void setName( const std::string& name );
|
||||
|
||||
/** Return the name of a Type enum as string. */
|
||||
static const char* getTypename( Type t );
|
||||
|
||||
@ -344,7 +344,6 @@ class OSG_EXPORT Uniform : public Object
|
||||
friend class osg::StateSet;
|
||||
|
||||
Type _type;
|
||||
std::string _name;
|
||||
|
||||
union
|
||||
{
|
||||
|
@ -41,7 +41,6 @@ Node::Node(const Node& node,const CopyOp& copyop):
|
||||
_initialBound(node._initialBound),
|
||||
_boundingSphere(node._boundingSphere),
|
||||
_boundingSphereComputed(node._boundingSphereComputed),
|
||||
_name(node._name),
|
||||
_parents(), // leave empty as parentList is managed by Group.
|
||||
_updateCallback(node._updateCallback),
|
||||
_numChildrenRequiringUpdateTraversal(0), // assume no children yet.
|
||||
|
@ -17,6 +17,7 @@ namespace osg
|
||||
|
||||
Object::Object(const Object& obj,const CopyOp& copyop):
|
||||
Referenced(),
|
||||
_name(obj._name),
|
||||
_dataVariance(obj._dataVariance),
|
||||
_userData(copyop(obj._userData.get())) {}
|
||||
|
||||
|
@ -106,7 +106,6 @@ Shader::Shader(Type type, const std::string& source) :
|
||||
Shader::Shader(const Shader& rhs, const osg::CopyOp& copyop):
|
||||
osg::Object( rhs, copyop ),
|
||||
_type(rhs._type),
|
||||
_name(rhs._name),
|
||||
_shaderSource(rhs._shaderSource)
|
||||
{
|
||||
}
|
||||
|
@ -28,15 +28,16 @@ using namespace osg;
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Uniform::Uniform() :
|
||||
_type(UNDEFINED), _name(""), _modifiedCount(0)
|
||||
_type(UNDEFINED), _modifiedCount(0)
|
||||
{
|
||||
setDataVariance(STATIC);
|
||||
}
|
||||
|
||||
|
||||
Uniform::Uniform( Type type, const std::string& name ) :
|
||||
_type(type), _name(name), _modifiedCount(0)
|
||||
_type(type), _modifiedCount(0)
|
||||
{
|
||||
setName(name);
|
||||
setDataVariance(STATIC);
|
||||
|
||||
switch( _type )
|
||||
@ -69,7 +70,7 @@ Uniform::Uniform( Type type, const std::string& name ) :
|
||||
}
|
||||
|
||||
Uniform::Uniform( const Uniform& rhs, const CopyOp& copyop ) :
|
||||
Object(rhs,copyop), _type(rhs._type), _name(rhs._name)
|
||||
Object(rhs,copyop), _type(rhs._type)
|
||||
{
|
||||
copyData( rhs );
|
||||
}
|
||||
@ -104,15 +105,14 @@ bool Uniform::setType( Type t )
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Uniform::setName( const std::string& name )
|
||||
void Uniform::setName( const std::string& name )
|
||||
{
|
||||
if( _name != "" )
|
||||
{
|
||||
osg::notify(osg::WARN) << "cannot change Uniform name" << std::endl;
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
_name = name;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -385,98 +385,114 @@ Uniform::Type Uniform::getGlApiType( Type t )
|
||||
// value constructors
|
||||
|
||||
Uniform::Uniform( const char* name, float f ) :
|
||||
_type(FLOAT), _name(name)
|
||||
_type(FLOAT)
|
||||
{
|
||||
setName(name);
|
||||
set( f );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, const osg::Vec2& v2 ) :
|
||||
_type(FLOAT_VEC2), _name(name)
|
||||
_type(FLOAT_VEC2)
|
||||
{
|
||||
setName(name);
|
||||
set( v2 );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, const osg::Vec3& v3 ) :
|
||||
_type(FLOAT_VEC3), _name(name)
|
||||
_type(FLOAT_VEC3)
|
||||
{
|
||||
setName(name);
|
||||
set( v3 );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, const osg::Vec4& v4 ) :
|
||||
_type(FLOAT_VEC4), _name(name)
|
||||
_type(FLOAT_VEC4)
|
||||
{
|
||||
setName(name);
|
||||
set( v4 );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, const osg::Matrix2& m2 ) :
|
||||
_type(FLOAT_MAT2), _name(name)
|
||||
_type(FLOAT_MAT2)
|
||||
{
|
||||
setName(name);
|
||||
set( m2 );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, const osg::Matrix3& m3 ) :
|
||||
_type(FLOAT_MAT3), _name(name)
|
||||
_type(FLOAT_MAT3)
|
||||
{
|
||||
setName(name);
|
||||
set( m3 );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, const osg::Matrixf& m4 ) :
|
||||
_type(FLOAT_MAT4), _name(name)
|
||||
_type(FLOAT_MAT4)
|
||||
{
|
||||
setName(name);
|
||||
set( m4 );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, const osg::Matrixd& m4 ) :
|
||||
_type(FLOAT_MAT4), _name(name)
|
||||
_type(FLOAT_MAT4)
|
||||
{
|
||||
setName(name);
|
||||
set( m4 );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, int i ) :
|
||||
_type(INT), _name(name)
|
||||
_type(INT)
|
||||
{
|
||||
setName(name);
|
||||
set( i );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, int i0, int i1 ) :
|
||||
_type(INT_VEC2), _name(name)
|
||||
_type(INT_VEC2)
|
||||
{
|
||||
setName(name);
|
||||
set( i0, i1 );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, int i0, int i1, int i2 ) :
|
||||
_type(INT_VEC3), _name(name)
|
||||
_type(INT_VEC3)
|
||||
{
|
||||
setName(name);
|
||||
set( i0, i1, i2 );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, int i0, int i1, int i2, int i3 ) :
|
||||
_type(INT_VEC4), _name(name)
|
||||
_type(INT_VEC4)
|
||||
{
|
||||
setName(name);
|
||||
set( i0, i1, i2, i3 );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, bool b ) :
|
||||
_type(BOOL), _name(name)
|
||||
_type(BOOL)
|
||||
{
|
||||
setName(name);
|
||||
set( b );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, bool b0, bool b1 ) :
|
||||
_type(BOOL_VEC2), _name(name)
|
||||
_type(BOOL_VEC2)
|
||||
{
|
||||
setName(name);
|
||||
set( b0, b1 );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, bool b0, bool b1, bool b2 ) :
|
||||
_type(BOOL_VEC3), _name(name)
|
||||
_type(BOOL_VEC3)
|
||||
{
|
||||
setName(name);
|
||||
set( b0, b1, b2 );
|
||||
}
|
||||
|
||||
Uniform::Uniform( const char* name, bool b0, bool b1, bool b2, bool b3 ) :
|
||||
_type(BOOL_VEC4), _name(name)
|
||||
_type(BOOL_VEC4)
|
||||
{
|
||||
setName(name);
|
||||
set( b0, b1, b2, b3 );
|
||||
}
|
||||
|
||||
|
@ -20,8 +20,9 @@
|
||||
#define VERSION_0009 9
|
||||
#define VERSION_0010 10
|
||||
#define VERSION_0011 11
|
||||
#define VERSION_0012 12
|
||||
|
||||
#define VERSION VERSION_0011
|
||||
#define VERSION VERSION_0012
|
||||
|
||||
|
||||
/* The BYTE_SEX tag is used to check the endian
|
||||
|
@ -38,9 +38,11 @@ void Node::write(DataOutputStream* out){
|
||||
|
||||
|
||||
// Write osg::node properties.
|
||||
|
||||
// Write Name
|
||||
out->writeString(getName());
|
||||
if ( out->getVersion() < VERSION_0012 )
|
||||
{
|
||||
// Write Name
|
||||
out->writeString(getName());
|
||||
}
|
||||
// Write culling active
|
||||
out->writeBool( getCullingActive());
|
||||
// Write Descriptions
|
||||
@ -102,8 +104,12 @@ void Node::read(DataInputStream* in){
|
||||
}
|
||||
else
|
||||
throw Exception("Node::read(): Could not cast this osg::Node to an osg::Object.");
|
||||
// Read name
|
||||
setName(in->readString());
|
||||
|
||||
if ( in->getVersion() < VERSION_0012 )
|
||||
{
|
||||
// Read name
|
||||
setName(in->readString());
|
||||
}
|
||||
// Read Culling active
|
||||
setCullingActive(in->readBool());
|
||||
// Read descriptions
|
||||
|
@ -17,31 +17,46 @@
|
||||
|
||||
using namespace ive;
|
||||
|
||||
void Object::write(DataOutputStream* out){
|
||||
// Write Object's identification.
|
||||
out->writeInt(IVEOBJECT);
|
||||
void Object::write(DataOutputStream* out)
|
||||
{
|
||||
// Write Object's identification.
|
||||
out->writeInt(IVEOBJECT);
|
||||
|
||||
// Write Object's properties.
|
||||
switch(getDataVariance()){
|
||||
if ( out->getVersion() >= VERSION_0012 )
|
||||
{
|
||||
// Write Name
|
||||
out->writeString(getName());
|
||||
}
|
||||
|
||||
// Write Object's properties.
|
||||
switch(getDataVariance())
|
||||
{
|
||||
case(osg::Object::STATIC): out->writeChar((char)0); break;
|
||||
case(osg::Object::DYNAMIC): out->writeChar((char)1); break;
|
||||
case(osg::Object::DYNAMIC): out->writeChar((char)1); break;
|
||||
}
|
||||
}
|
||||
|
||||
void Object::read(DataInputStream* in){
|
||||
// Read Object's identification.
|
||||
int id = in->peekInt();
|
||||
if(id == IVEOBJECT){
|
||||
// Code to read Object's properties.
|
||||
id = in->readInt();
|
||||
// Read Object's identification.
|
||||
int id = in->peekInt();
|
||||
if(id == IVEOBJECT)
|
||||
{
|
||||
// Code to read Object's properties.
|
||||
id = in->readInt();
|
||||
|
||||
char c = in->readChar();
|
||||
switch((int)c){
|
||||
case 0: setDataVariance(osg::Object::STATIC);break;
|
||||
case 1: setDataVariance(osg::Object::DYNAMIC);break;
|
||||
}
|
||||
}
|
||||
else{
|
||||
throw Exception("Object::read(): Expected Object identification");
|
||||
if ( in->getVersion() >= VERSION_0012 )
|
||||
{
|
||||
// Read name
|
||||
setName(in->readString());
|
||||
}
|
||||
|
||||
char c = in->readChar();
|
||||
switch((int)c){
|
||||
case 0: setDataVariance(osg::Object::STATIC);break;
|
||||
case 1: setDataVariance(osg::Object::DYNAMIC);break;
|
||||
}
|
||||
}
|
||||
else{
|
||||
throw Exception("Object::read(): Expected Object identification");
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,10 @@ void Shader::write(DataOutputStream* out){
|
||||
else
|
||||
throw Exception("Shader::write(): Could not cast this osg::Shader to an osg::Object.");
|
||||
|
||||
out->writeString(getName());
|
||||
if ( out->getVersion() < VERSION_0012 )
|
||||
{
|
||||
out->writeString(getName());
|
||||
}
|
||||
out->writeInt(getType());
|
||||
out->writeString(getShaderSource());
|
||||
|
||||
@ -59,8 +62,12 @@ void Shader::read(DataInputStream* in)
|
||||
throw Exception("Shader::read(): Expected Shader identification.");
|
||||
}
|
||||
|
||||
setName(in->readString());
|
||||
setType(static_cast<Type>(in->readInt()));
|
||||
setShaderSource(in->readString());
|
||||
if ( in->getVersion() < VERSION_0012 )
|
||||
{
|
||||
setName(in->readString());
|
||||
}
|
||||
|
||||
setType(static_cast<Type>(in->readInt()));
|
||||
setShaderSource(in->readString());
|
||||
|
||||
}
|
||||
|
@ -32,7 +32,11 @@ void Uniform::write(DataOutputStream* out){
|
||||
throw Exception("Uniform::write(): Could not cast this osg::Uniform to an osg::Object.");
|
||||
|
||||
out->writeInt(getType());
|
||||
out->writeString(getName());
|
||||
|
||||
if ( out->getVersion() < VERSION_0012 )
|
||||
{
|
||||
out->writeString(getName());
|
||||
}
|
||||
|
||||
switch( Uniform::getGlApiType(getType()) )
|
||||
{
|
||||
@ -151,7 +155,11 @@ void Uniform::read(DataInputStream* in)
|
||||
}
|
||||
|
||||
setType(static_cast<Type>(in->readInt()));
|
||||
setName(in->readString());
|
||||
|
||||
if ( in->getVersion() < VERSION_0012 )
|
||||
{
|
||||
setName(in->readString());
|
||||
}
|
||||
|
||||
switch( Uniform::getGlApiType(getType()) )
|
||||
{
|
||||
|
@ -29,13 +29,6 @@ bool Node_readLocalData(Object& obj, Input& fr)
|
||||
|
||||
Node& node = static_cast<Node&>(obj);
|
||||
|
||||
if (fr.matchSequence("name %s"))
|
||||
{
|
||||
node.setName(fr[1].getStr());
|
||||
fr+=2;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
unsigned int mask = node.getNodeMask();
|
||||
if (fr[0].matchWord("nodeMask") && fr[1].getUInt(mask))
|
||||
{
|
||||
@ -190,8 +183,6 @@ bool Node_writeLocalData(const Object& obj, Output& fw)
|
||||
{
|
||||
const Node& node = static_cast<const Node&>(obj);
|
||||
|
||||
if (!node.getName().empty()) fw.indent() << "name "<<fw.wrapString(node.getName())<< std::endl;
|
||||
|
||||
fw.indent() << "nodeMask 0x" << hex << node.getNodeMask() << dec << std::endl;
|
||||
|
||||
fw.indent() << "cullingActive ";
|
||||
|
@ -43,6 +43,13 @@ bool Object_readLocalData(Object& obj, Input& fr)
|
||||
}
|
||||
}
|
||||
|
||||
if (fr.matchSequence("name %s"))
|
||||
{
|
||||
obj.setName(fr[1].getStr());
|
||||
fr+=2;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
if (fr.matchSequence("UserData {"))
|
||||
{
|
||||
osg::notify(osg::DEBUG_INFO) << "Matched UserData {"<< std::endl;
|
||||
@ -71,6 +78,8 @@ bool Object_writeLocalData(const Object& obj, Output& fw)
|
||||
default: fw.indent() << "DataVariance DYNAMIC" << std::endl;break;
|
||||
}
|
||||
|
||||
if (!obj.getName().empty()) fw.indent() << "name "<<fw.wrapString(obj.getName())<< std::endl;
|
||||
|
||||
if (obj.getUserData())
|
||||
{
|
||||
const Object* object = dynamic_cast<const Object*>(obj.getUserData());
|
||||
|
@ -30,13 +30,6 @@ bool Program_readLocalData(Object& obj, Input& fr)
|
||||
|
||||
Program& program = static_cast<Program&>(obj);
|
||||
|
||||
if (fr.matchSequence("name %s"))
|
||||
{
|
||||
program.setName(fr[1].getStr());
|
||||
fr+=2;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
while(fr.matchSequence("AttribBindingLocation %i %w"))
|
||||
{
|
||||
unsigned int index;
|
||||
@ -80,8 +73,6 @@ bool Program_writeLocalData(const Object& obj,Output& fw)
|
||||
{
|
||||
const Program& program = static_cast<const Program&>(obj);
|
||||
|
||||
if (!program.getName().empty()) fw.indent() << "name "<<fw.wrapString(program.getName())<< std::endl;
|
||||
|
||||
const Program::AttribBindingList& abl = program.getAttribBindingList();
|
||||
Program::AttribBindingList::const_iterator i;
|
||||
for(i=abl.begin(); i!=abl.end(); i++)
|
||||
|
@ -38,13 +38,6 @@ bool Shader_readLocalData(Object& obj, Input& fr)
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
if (fr.matchSequence("name %s"))
|
||||
{
|
||||
shader.setName(fr[1].getStr());
|
||||
fr+=2;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
if (fr.matchSequence("code {")) {
|
||||
std::string code;
|
||||
fr += 2;
|
||||
@ -70,8 +63,6 @@ bool Shader_writeLocalData(const Object& obj,Output& fw)
|
||||
|
||||
fw.indent() << "type " << shader.getTypename() << std::endl;
|
||||
|
||||
if (!shader.getName().empty()) fw.indent() << "name "<<fw.wrapString(shader.getName())<< std::endl;
|
||||
|
||||
// split source text into individual lines
|
||||
std::vector<std::string> lines;
|
||||
std::istringstream iss(shader.getShaderSource());
|
||||
|
@ -34,13 +34,6 @@ bool Uniform_readLocalData(Object& obj, Input& fr)
|
||||
Uniform& uniform = static_cast<Uniform&>(obj);
|
||||
|
||||
|
||||
if (fr.matchSequence("name %s"))
|
||||
{
|
||||
uniform.setName(fr[1].getStr());
|
||||
fr+=2;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
if (fr[0].isWord())
|
||||
{
|
||||
uniform.setType( Uniform::getTypeId(fr[0].getStr()) );
|
||||
@ -187,9 +180,6 @@ bool Uniform_writeLocalData(const Object& obj,Output& fw)
|
||||
{
|
||||
const Uniform& uniform = static_cast<const Uniform&>(obj);
|
||||
|
||||
|
||||
fw.indent() << "name "<< fw.wrapString(uniform.getName()) << std::endl;
|
||||
|
||||
fw.indent() << Uniform::getTypename( uniform.getType() ) << " ";
|
||||
|
||||
switch( Uniform::getGlApiType(uniform.getType()) )
|
||||
|
Loading…
Reference in New Issue
Block a user