Refactor: Expand tabs to 4 spaces
This commit is contained in:
@@ -51,216 +51,216 @@ using namespace Assimp;
|
||||
// The constructor processes the given scene and adds a mesh there.
|
||||
SkeletonMeshBuilder::SkeletonMeshBuilder( aiScene* pScene, aiNode* root, bool bKnobsOnly)
|
||||
{
|
||||
// nothing to do if there's mesh data already present at the scene
|
||||
if( pScene->mNumMeshes > 0 || pScene->mRootNode == NULL)
|
||||
return;
|
||||
// nothing to do if there's mesh data already present at the scene
|
||||
if( pScene->mNumMeshes > 0 || pScene->mRootNode == NULL)
|
||||
return;
|
||||
|
||||
if (!root)
|
||||
root = pScene->mRootNode;
|
||||
if (!root)
|
||||
root = pScene->mRootNode;
|
||||
|
||||
mKnobsOnly = bKnobsOnly;
|
||||
mKnobsOnly = bKnobsOnly;
|
||||
|
||||
// build some faces around each node
|
||||
CreateGeometry( root );
|
||||
// build some faces around each node
|
||||
CreateGeometry( root );
|
||||
|
||||
// create a mesh to hold all the generated faces
|
||||
pScene->mNumMeshes = 1;
|
||||
pScene->mMeshes = new aiMesh*[1];
|
||||
pScene->mMeshes[0] = CreateMesh();
|
||||
// and install it at the root node
|
||||
root->mNumMeshes = 1;
|
||||
root->mMeshes = new unsigned int[1];
|
||||
root->mMeshes[0] = 0;
|
||||
// create a mesh to hold all the generated faces
|
||||
pScene->mNumMeshes = 1;
|
||||
pScene->mMeshes = new aiMesh*[1];
|
||||
pScene->mMeshes[0] = CreateMesh();
|
||||
// and install it at the root node
|
||||
root->mNumMeshes = 1;
|
||||
root->mMeshes = new unsigned int[1];
|
||||
root->mMeshes[0] = 0;
|
||||
|
||||
// create a dummy material for the mesh
|
||||
pScene->mNumMaterials = 1;
|
||||
pScene->mMaterials = new aiMaterial*[1];
|
||||
pScene->mMaterials[0] = CreateMaterial();
|
||||
// create a dummy material for the mesh
|
||||
pScene->mNumMaterials = 1;
|
||||
pScene->mMaterials = new aiMaterial*[1];
|
||||
pScene->mMaterials[0] = CreateMaterial();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Recursively builds a simple mesh representation for the given node
|
||||
void SkeletonMeshBuilder::CreateGeometry( const aiNode* pNode)
|
||||
{
|
||||
// add a joint entry for the node.
|
||||
const unsigned int vertexStartIndex = mVertices.size();
|
||||
// add a joint entry for the node.
|
||||
const unsigned int vertexStartIndex = mVertices.size();
|
||||
|
||||
// now build the geometry.
|
||||
if( pNode->mNumChildren > 0 && !mKnobsOnly)
|
||||
{
|
||||
// If the node has children, we build little pointers to each of them
|
||||
for( unsigned int a = 0; a < pNode->mNumChildren; a++)
|
||||
{
|
||||
// find a suitable coordinate system
|
||||
const aiMatrix4x4& childTransform = pNode->mChildren[a]->mTransformation;
|
||||
aiVector3D childpos( childTransform.a4, childTransform.b4, childTransform.c4);
|
||||
float distanceToChild = childpos.Length();
|
||||
if( distanceToChild < 0.0001f)
|
||||
continue;
|
||||
aiVector3D up = aiVector3D( childpos).Normalize();
|
||||
// now build the geometry.
|
||||
if( pNode->mNumChildren > 0 && !mKnobsOnly)
|
||||
{
|
||||
// If the node has children, we build little pointers to each of them
|
||||
for( unsigned int a = 0; a < pNode->mNumChildren; a++)
|
||||
{
|
||||
// find a suitable coordinate system
|
||||
const aiMatrix4x4& childTransform = pNode->mChildren[a]->mTransformation;
|
||||
aiVector3D childpos( childTransform.a4, childTransform.b4, childTransform.c4);
|
||||
float distanceToChild = childpos.Length();
|
||||
if( distanceToChild < 0.0001f)
|
||||
continue;
|
||||
aiVector3D up = aiVector3D( childpos).Normalize();
|
||||
|
||||
aiVector3D orth( 1.0f, 0.0f, 0.0f);
|
||||
if( std::fabs( orth * up) > 0.99f)
|
||||
orth.Set( 0.0f, 1.0f, 0.0f);
|
||||
aiVector3D orth( 1.0f, 0.0f, 0.0f);
|
||||
if( std::fabs( orth * up) > 0.99f)
|
||||
orth.Set( 0.0f, 1.0f, 0.0f);
|
||||
|
||||
aiVector3D front = (up ^ orth).Normalize();
|
||||
aiVector3D side = (front ^ up).Normalize();
|
||||
aiVector3D front = (up ^ orth).Normalize();
|
||||
aiVector3D side = (front ^ up).Normalize();
|
||||
|
||||
unsigned int localVertexStart = mVertices.size();
|
||||
mVertices.push_back( -front * distanceToChild * 0.1f);
|
||||
mVertices.push_back( childpos);
|
||||
mVertices.push_back( -side * distanceToChild * 0.1f);
|
||||
mVertices.push_back( -side * distanceToChild * 0.1f);
|
||||
mVertices.push_back( childpos);
|
||||
mVertices.push_back( front * distanceToChild * 0.1f);
|
||||
mVertices.push_back( front * distanceToChild * 0.1f);
|
||||
mVertices.push_back( childpos);
|
||||
mVertices.push_back( side * distanceToChild * 0.1f);
|
||||
mVertices.push_back( side * distanceToChild * 0.1f);
|
||||
mVertices.push_back( childpos);
|
||||
mVertices.push_back( -front * distanceToChild * 0.1f);
|
||||
unsigned int localVertexStart = mVertices.size();
|
||||
mVertices.push_back( -front * distanceToChild * 0.1f);
|
||||
mVertices.push_back( childpos);
|
||||
mVertices.push_back( -side * distanceToChild * 0.1f);
|
||||
mVertices.push_back( -side * distanceToChild * 0.1f);
|
||||
mVertices.push_back( childpos);
|
||||
mVertices.push_back( front * distanceToChild * 0.1f);
|
||||
mVertices.push_back( front * distanceToChild * 0.1f);
|
||||
mVertices.push_back( childpos);
|
||||
mVertices.push_back( side * distanceToChild * 0.1f);
|
||||
mVertices.push_back( side * distanceToChild * 0.1f);
|
||||
mVertices.push_back( childpos);
|
||||
mVertices.push_back( -front * distanceToChild * 0.1f);
|
||||
|
||||
mFaces.push_back( Face( localVertexStart + 0, localVertexStart + 1, localVertexStart + 2));
|
||||
mFaces.push_back( Face( localVertexStart + 3, localVertexStart + 4, localVertexStart + 5));
|
||||
mFaces.push_back( Face( localVertexStart + 6, localVertexStart + 7, localVertexStart + 8));
|
||||
mFaces.push_back( Face( localVertexStart + 9, localVertexStart + 10, localVertexStart + 11));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the node has no children, it's an end node. Put a little knob there instead
|
||||
aiVector3D ownpos( pNode->mTransformation.a4, pNode->mTransformation.b4, pNode->mTransformation.c4);
|
||||
float sizeEstimate = ownpos.Length() * 0.18f;
|
||||
mFaces.push_back( Face( localVertexStart + 0, localVertexStart + 1, localVertexStart + 2));
|
||||
mFaces.push_back( Face( localVertexStart + 3, localVertexStart + 4, localVertexStart + 5));
|
||||
mFaces.push_back( Face( localVertexStart + 6, localVertexStart + 7, localVertexStart + 8));
|
||||
mFaces.push_back( Face( localVertexStart + 9, localVertexStart + 10, localVertexStart + 11));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the node has no children, it's an end node. Put a little knob there instead
|
||||
aiVector3D ownpos( pNode->mTransformation.a4, pNode->mTransformation.b4, pNode->mTransformation.c4);
|
||||
float sizeEstimate = ownpos.Length() * 0.18f;
|
||||
|
||||
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
|
||||
|
||||
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
|
||||
mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
|
||||
|
||||
mFaces.push_back( Face( vertexStartIndex + 0, vertexStartIndex + 1, vertexStartIndex + 2));
|
||||
mFaces.push_back( Face( vertexStartIndex + 3, vertexStartIndex + 4, vertexStartIndex + 5));
|
||||
mFaces.push_back( Face( vertexStartIndex + 6, vertexStartIndex + 7, vertexStartIndex + 8));
|
||||
mFaces.push_back( Face( vertexStartIndex + 9, vertexStartIndex + 10, vertexStartIndex + 11));
|
||||
mFaces.push_back( Face( vertexStartIndex + 12, vertexStartIndex + 13, vertexStartIndex + 14));
|
||||
mFaces.push_back( Face( vertexStartIndex + 15, vertexStartIndex + 16, vertexStartIndex + 17));
|
||||
mFaces.push_back( Face( vertexStartIndex + 18, vertexStartIndex + 19, vertexStartIndex + 20));
|
||||
mFaces.push_back( Face( vertexStartIndex + 21, vertexStartIndex + 22, vertexStartIndex + 23));
|
||||
}
|
||||
mFaces.push_back( Face( vertexStartIndex + 0, vertexStartIndex + 1, vertexStartIndex + 2));
|
||||
mFaces.push_back( Face( vertexStartIndex + 3, vertexStartIndex + 4, vertexStartIndex + 5));
|
||||
mFaces.push_back( Face( vertexStartIndex + 6, vertexStartIndex + 7, vertexStartIndex + 8));
|
||||
mFaces.push_back( Face( vertexStartIndex + 9, vertexStartIndex + 10, vertexStartIndex + 11));
|
||||
mFaces.push_back( Face( vertexStartIndex + 12, vertexStartIndex + 13, vertexStartIndex + 14));
|
||||
mFaces.push_back( Face( vertexStartIndex + 15, vertexStartIndex + 16, vertexStartIndex + 17));
|
||||
mFaces.push_back( Face( vertexStartIndex + 18, vertexStartIndex + 19, vertexStartIndex + 20));
|
||||
mFaces.push_back( Face( vertexStartIndex + 21, vertexStartIndex + 22, vertexStartIndex + 23));
|
||||
}
|
||||
|
||||
unsigned int numVertices = mVertices.size() - vertexStartIndex;
|
||||
if( numVertices > 0)
|
||||
{
|
||||
// create a bone affecting all the newly created vertices
|
||||
aiBone* bone = new aiBone;
|
||||
mBones.push_back( bone);
|
||||
bone->mName = pNode->mName;
|
||||
unsigned int numVertices = mVertices.size() - vertexStartIndex;
|
||||
if( numVertices > 0)
|
||||
{
|
||||
// create a bone affecting all the newly created vertices
|
||||
aiBone* bone = new aiBone;
|
||||
mBones.push_back( bone);
|
||||
bone->mName = pNode->mName;
|
||||
|
||||
// calculate the bone offset matrix by concatenating the inverse transformations of all parents
|
||||
bone->mOffsetMatrix = aiMatrix4x4( pNode->mTransformation).Inverse();
|
||||
for( aiNode* parent = pNode->mParent; parent != NULL; parent = parent->mParent)
|
||||
bone->mOffsetMatrix = aiMatrix4x4( parent->mTransformation).Inverse() * bone->mOffsetMatrix;
|
||||
// calculate the bone offset matrix by concatenating the inverse transformations of all parents
|
||||
bone->mOffsetMatrix = aiMatrix4x4( pNode->mTransformation).Inverse();
|
||||
for( aiNode* parent = pNode->mParent; parent != NULL; parent = parent->mParent)
|
||||
bone->mOffsetMatrix = aiMatrix4x4( parent->mTransformation).Inverse() * bone->mOffsetMatrix;
|
||||
|
||||
// add all the vertices to the bone's influences
|
||||
bone->mNumWeights = numVertices;
|
||||
bone->mWeights = new aiVertexWeight[numVertices];
|
||||
for( unsigned int a = 0; a < numVertices; a++)
|
||||
bone->mWeights[a] = aiVertexWeight( vertexStartIndex + a, 1.0f);
|
||||
// add all the vertices to the bone's influences
|
||||
bone->mNumWeights = numVertices;
|
||||
bone->mWeights = new aiVertexWeight[numVertices];
|
||||
for( unsigned int a = 0; a < numVertices; a++)
|
||||
bone->mWeights[a] = aiVertexWeight( vertexStartIndex + a, 1.0f);
|
||||
|
||||
// HACK: (thom) transform all vertices to the bone's local space. Should be done before adding
|
||||
// them to the array, but I'm tired now and I'm annoyed.
|
||||
aiMatrix4x4 boneToMeshTransform = aiMatrix4x4( bone->mOffsetMatrix).Inverse();
|
||||
for( unsigned int a = vertexStartIndex; a < mVertices.size(); a++)
|
||||
mVertices[a] = boneToMeshTransform * mVertices[a];
|
||||
}
|
||||
// HACK: (thom) transform all vertices to the bone's local space. Should be done before adding
|
||||
// them to the array, but I'm tired now and I'm annoyed.
|
||||
aiMatrix4x4 boneToMeshTransform = aiMatrix4x4( bone->mOffsetMatrix).Inverse();
|
||||
for( unsigned int a = vertexStartIndex; a < mVertices.size(); a++)
|
||||
mVertices[a] = boneToMeshTransform * mVertices[a];
|
||||
}
|
||||
|
||||
// and finally recurse into the children list
|
||||
for( unsigned int a = 0; a < pNode->mNumChildren; a++)
|
||||
CreateGeometry( pNode->mChildren[a]);
|
||||
// and finally recurse into the children list
|
||||
for( unsigned int a = 0; a < pNode->mNumChildren; a++)
|
||||
CreateGeometry( pNode->mChildren[a]);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Creates the mesh from the internally accumulated stuff and returns it.
|
||||
aiMesh* SkeletonMeshBuilder::CreateMesh()
|
||||
{
|
||||
aiMesh* mesh = new aiMesh();
|
||||
aiMesh* mesh = new aiMesh();
|
||||
|
||||
// add points
|
||||
mesh->mNumVertices = mVertices.size();
|
||||
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
||||
std::copy( mVertices.begin(), mVertices.end(), mesh->mVertices);
|
||||
// add points
|
||||
mesh->mNumVertices = mVertices.size();
|
||||
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
||||
std::copy( mVertices.begin(), mVertices.end(), mesh->mVertices);
|
||||
|
||||
mesh->mNormals = new aiVector3D[mesh->mNumVertices];
|
||||
mesh->mNormals = new aiVector3D[mesh->mNumVertices];
|
||||
|
||||
// add faces
|
||||
mesh->mNumFaces = mFaces.size();
|
||||
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||
for( unsigned int a = 0; a < mesh->mNumFaces; a++)
|
||||
{
|
||||
const Face& inface = mFaces[a];
|
||||
aiFace& outface = mesh->mFaces[a];
|
||||
outface.mNumIndices = 3;
|
||||
outface.mIndices = new unsigned int[3];
|
||||
outface.mIndices[0] = inface.mIndices[0];
|
||||
outface.mIndices[1] = inface.mIndices[1];
|
||||
outface.mIndices[2] = inface.mIndices[2];
|
||||
// add faces
|
||||
mesh->mNumFaces = mFaces.size();
|
||||
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||
for( unsigned int a = 0; a < mesh->mNumFaces; a++)
|
||||
{
|
||||
const Face& inface = mFaces[a];
|
||||
aiFace& outface = mesh->mFaces[a];
|
||||
outface.mNumIndices = 3;
|
||||
outface.mIndices = new unsigned int[3];
|
||||
outface.mIndices[0] = inface.mIndices[0];
|
||||
outface.mIndices[1] = inface.mIndices[1];
|
||||
outface.mIndices[2] = inface.mIndices[2];
|
||||
|
||||
// Compute per-face normals ... we don't want the bones to be smoothed ... they're built to visualize
|
||||
// the skeleton, so it's good if there's a visual difference to the rest of the geometry
|
||||
aiVector3D nor = ((mVertices[inface.mIndices[2]] - mVertices[inface.mIndices[0]]) ^
|
||||
(mVertices[inface.mIndices[1]] - mVertices[inface.mIndices[0]]));
|
||||
// Compute per-face normals ... we don't want the bones to be smoothed ... they're built to visualize
|
||||
// the skeleton, so it's good if there's a visual difference to the rest of the geometry
|
||||
aiVector3D nor = ((mVertices[inface.mIndices[2]] - mVertices[inface.mIndices[0]]) ^
|
||||
(mVertices[inface.mIndices[1]] - mVertices[inface.mIndices[0]]));
|
||||
|
||||
if (nor.Length() < 1e-5f) /* ensure that FindInvalidData won't remove us ...*/
|
||||
nor = aiVector3D(1.f,0.f,0.f);
|
||||
if (nor.Length() < 1e-5f) /* ensure that FindInvalidData won't remove us ...*/
|
||||
nor = aiVector3D(1.f,0.f,0.f);
|
||||
|
||||
for (unsigned int n = 0; n < 3; ++n)
|
||||
mesh->mNormals[inface.mIndices[n]] = nor;
|
||||
}
|
||||
for (unsigned int n = 0; n < 3; ++n)
|
||||
mesh->mNormals[inface.mIndices[n]] = nor;
|
||||
}
|
||||
|
||||
// add the bones
|
||||
mesh->mNumBones = mBones.size();
|
||||
mesh->mBones = new aiBone*[mesh->mNumBones];
|
||||
std::copy( mBones.begin(), mBones.end(), mesh->mBones);
|
||||
// add the bones
|
||||
mesh->mNumBones = mBones.size();
|
||||
mesh->mBones = new aiBone*[mesh->mNumBones];
|
||||
std::copy( mBones.begin(), mBones.end(), mesh->mBones);
|
||||
|
||||
// default
|
||||
mesh->mMaterialIndex = 0;
|
||||
// default
|
||||
mesh->mMaterialIndex = 0;
|
||||
|
||||
return mesh;
|
||||
return mesh;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Creates a dummy material and returns it.
|
||||
aiMaterial* SkeletonMeshBuilder::CreateMaterial()
|
||||
{
|
||||
aiMaterial* matHelper = new aiMaterial;
|
||||
aiMaterial* matHelper = new aiMaterial;
|
||||
|
||||
// Name
|
||||
aiString matName( std::string( "SkeletonMaterial"));
|
||||
matHelper->AddProperty( &matName, AI_MATKEY_NAME);
|
||||
// Name
|
||||
aiString matName( std::string( "SkeletonMaterial"));
|
||||
matHelper->AddProperty( &matName, AI_MATKEY_NAME);
|
||||
|
||||
// Prevent backface culling
|
||||
const int no_cull = 1;
|
||||
matHelper->AddProperty(&no_cull,1,AI_MATKEY_TWOSIDED);
|
||||
// Prevent backface culling
|
||||
const int no_cull = 1;
|
||||
matHelper->AddProperty(&no_cull,1,AI_MATKEY_TWOSIDED);
|
||||
|
||||
return matHelper;
|
||||
return matHelper;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user