mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-18 06:37:12 +02:00
Removed "springiness" bits.
This commit is contained in:
parent
8413a3cacd
commit
299dbb93ea
5 changed files with 58 additions and 211 deletions
|
@ -1331,14 +1331,11 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
geometry.staticExtents.reset();
|
||||
geometry.meshExtents.reset();
|
||||
|
||||
QVariantHash springs = mapping.value("spring").toHash();
|
||||
QVariant defaultSpring = springs.value("default");
|
||||
for (QHash<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
|
||||
ExtractedMesh& extracted = it.value();
|
||||
|
||||
// accumulate local transforms
|
||||
QString modelID = models.contains(it.key()) ? it.key() : parentMap.value(it.key());
|
||||
extracted.mesh.springiness = springs.value(models.value(modelID).name, defaultSpring).toFloat();
|
||||
glm::mat4 modelTransform = getGlobalTransform(parentMap, models, modelID);
|
||||
|
||||
// compute the mesh extents from the transformed vertices
|
||||
|
@ -1591,49 +1588,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
}
|
||||
}
|
||||
extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex);
|
||||
|
||||
// extract spring edges, connections if springy
|
||||
if (extracted.mesh.springiness > 0.0f) {
|
||||
QSet<QPair<int, int> > edges;
|
||||
|
||||
extracted.mesh.vertexConnections.resize(extracted.mesh.vertices.size());
|
||||
foreach (const FBXMeshPart& part, extracted.mesh.parts) {
|
||||
for (int i = 0; i < part.quadIndices.size(); i += 4) {
|
||||
int index0 = part.quadIndices.at(i);
|
||||
int index1 = part.quadIndices.at(i + 1);
|
||||
int index2 = part.quadIndices.at(i + 2);
|
||||
int index3 = part.quadIndices.at(i + 3);
|
||||
|
||||
edges.insert(QPair<int, int>(qMin(index0, index1), qMax(index0, index1)));
|
||||
edges.insert(QPair<int, int>(qMin(index1, index2), qMax(index1, index2)));
|
||||
edges.insert(QPair<int, int>(qMin(index2, index3), qMax(index2, index3)));
|
||||
edges.insert(QPair<int, int>(qMin(index3, index0), qMax(index3, index0)));
|
||||
|
||||
extracted.mesh.vertexConnections[index0].append(QPair<int, int>(index3, index1));
|
||||
extracted.mesh.vertexConnections[index1].append(QPair<int, int>(index0, index2));
|
||||
extracted.mesh.vertexConnections[index2].append(QPair<int, int>(index1, index3));
|
||||
extracted.mesh.vertexConnections[index3].append(QPair<int, int>(index2, index0));
|
||||
}
|
||||
for (int i = 0; i < part.triangleIndices.size(); i += 3) {
|
||||
int index0 = part.triangleIndices.at(i);
|
||||
int index1 = part.triangleIndices.at(i + 1);
|
||||
int index2 = part.triangleIndices.at(i + 2);
|
||||
|
||||
edges.insert(QPair<int, int>(qMin(index0, index1), qMax(index0, index1)));
|
||||
edges.insert(QPair<int, int>(qMin(index1, index2), qMax(index1, index2)));
|
||||
edges.insert(QPair<int, int>(qMin(index2, index0), qMax(index2, index0)));
|
||||
|
||||
extracted.mesh.vertexConnections[index0].append(QPair<int, int>(index2, index1));
|
||||
extracted.mesh.vertexConnections[index1].append(QPair<int, int>(index0, index2));
|
||||
extracted.mesh.vertexConnections[index2].append(QPair<int, int>(index1, index0));
|
||||
}
|
||||
}
|
||||
|
||||
for (QSet<QPair<int, int> >::const_iterator edge = edges.constBegin(); edge != edges.constEnd(); edge++) {
|
||||
extracted.mesh.springEdges.append(*edge);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
geometry.meshes.append(extracted.mesh);
|
||||
}
|
||||
|
||||
|
@ -1797,7 +1752,6 @@ FBXGeometry readSVO(const QByteArray& model) {
|
|||
// and one mesh with one cluster and one part
|
||||
FBXMesh mesh;
|
||||
mesh.isEye = false;
|
||||
mesh.springiness = 0.0f;
|
||||
|
||||
FBXCluster cluster = { 0 };
|
||||
mesh.clusters.append(cluster);
|
||||
|
|
|
@ -130,10 +130,6 @@ public:
|
|||
bool isEye;
|
||||
|
||||
QVector<FBXBlendshape> blendshapes;
|
||||
|
||||
float springiness;
|
||||
QVector<QPair<int, int> > springEdges;
|
||||
QVector<QVarLengthArray<QPair<int, int>, 4> > vertexConnections;
|
||||
};
|
||||
|
||||
/// An attachment to an FBX document.
|
||||
|
|
|
@ -565,8 +565,8 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {
|
|||
networkMesh.vertexBuffer.bind();
|
||||
networkMesh.vertexBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||
|
||||
// if we don't need to do any blending or springing, then the positions/normals can be static
|
||||
if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) {
|
||||
// if we don't need to do any blending, the positions/normals can be static
|
||||
if (mesh.blendshapes.isEmpty()) {
|
||||
int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3);
|
||||
int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3);
|
||||
int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3);
|
||||
|
@ -587,8 +587,8 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {
|
|||
networkMesh.vertexBuffer.write(clusterWeightsOffset, mesh.clusterWeights.constData(),
|
||||
mesh.clusterWeights.size() * sizeof(glm::vec4));
|
||||
|
||||
// if there's no springiness, then the cluster indices/weights can be static
|
||||
} else if (mesh.springiness == 0.0f) {
|
||||
// otherwise, at least the cluster indices/weights can be static
|
||||
} else {
|
||||
int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3);
|
||||
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
|
||||
int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
|
||||
|
@ -601,16 +601,7 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {
|
|||
networkMesh.vertexBuffer.write(clusterIndicesOffset, mesh.clusterIndices.constData(),
|
||||
mesh.clusterIndices.size() * sizeof(glm::vec4));
|
||||
networkMesh.vertexBuffer.write(clusterWeightsOffset, mesh.clusterWeights.constData(),
|
||||
mesh.clusterWeights.size() * sizeof(glm::vec4));
|
||||
|
||||
} else {
|
||||
int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3);
|
||||
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
|
||||
networkMesh.vertexBuffer.allocate(texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2));
|
||||
networkMesh.vertexBuffer.write(0, mesh.tangents.constData(), mesh.tangents.size() * sizeof(glm::vec3));
|
||||
networkMesh.vertexBuffer.write(colorsOffset, mesh.colors.constData(), mesh.colors.size() * sizeof(glm::vec3));
|
||||
networkMesh.vertexBuffer.write(texCoordsOffset, mesh.texCoords.constData(),
|
||||
mesh.texCoords.size() * sizeof(glm::vec2));
|
||||
mesh.clusterWeights.size() * sizeof(glm::vec4));
|
||||
}
|
||||
|
||||
networkMesh.vertexBuffer.release();
|
||||
|
|
|
@ -175,7 +175,7 @@ bool Model::render(float alpha) {
|
|||
if (_blendedVertexBufferIDs.isEmpty()) {
|
||||
foreach (const FBXMesh& mesh, geometry.meshes) {
|
||||
GLuint id = 0;
|
||||
if (!mesh.blendshapes.isEmpty() || mesh.springiness > 0.0f) {
|
||||
if (!mesh.blendshapes.isEmpty()) {
|
||||
glGenBuffers(1, &id);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, id);
|
||||
glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3),
|
||||
|
@ -490,11 +490,6 @@ void Model::simulate(float deltaTime, bool fullUpdate, const QVector<JointState>
|
|||
foreach (const FBXMesh& mesh, geometry.meshes) {
|
||||
MeshState state;
|
||||
state.clusterMatrices.resize(mesh.clusters.size());
|
||||
if (mesh.springiness > 0.0f) {
|
||||
state.worldSpaceVertices.resize(mesh.vertices.size());
|
||||
state.vertexVelocities.resize(mesh.vertices.size());
|
||||
state.worldSpaceNormals.resize(mesh.vertices.size());
|
||||
}
|
||||
_meshStates.append(state);
|
||||
}
|
||||
foreach (const FBXAttachment& attachment, geometry.attachments) {
|
||||
|
@ -541,80 +536,6 @@ void Model::simulate(float deltaTime, bool fullUpdate, const QVector<JointState>
|
|||
const FBXCluster& cluster = mesh.clusters.at(j);
|
||||
state.clusterMatrices[j] = _jointStates[cluster.jointIndex].transform * cluster.inverseBindMatrix;
|
||||
}
|
||||
int vertexCount = state.worldSpaceVertices.size();
|
||||
if (vertexCount == 0) {
|
||||
continue;
|
||||
}
|
||||
glm::vec3* destVertices = state.worldSpaceVertices.data();
|
||||
glm::vec3* destVelocities = state.vertexVelocities.data();
|
||||
glm::vec3* destNormals = state.worldSpaceNormals.data();
|
||||
|
||||
const glm::vec3* sourceVertices = mesh.vertices.constData();
|
||||
if (!mesh.blendshapes.isEmpty()) {
|
||||
_blendedVertices.resize(max(_blendedVertices.size(), vertexCount));
|
||||
memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3));
|
||||
|
||||
// blend in each coefficient
|
||||
for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) {
|
||||
float coefficient = _blendshapeCoefficients[j];
|
||||
if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData();
|
||||
for (const int* index = mesh.blendshapes[j].indices.constData(),
|
||||
*end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++) {
|
||||
_blendedVertices[*index] += *vertex * coefficient;
|
||||
}
|
||||
}
|
||||
sourceVertices = _blendedVertices.constData();
|
||||
}
|
||||
glm::mat4 transform = glm::translate(_translation);
|
||||
if (mesh.clusters.size() > 1) {
|
||||
_blendedVertices.resize(max(_blendedVertices.size(), vertexCount));
|
||||
|
||||
// skin each vertex
|
||||
const glm::vec4* clusterIndices = mesh.clusterIndices.constData();
|
||||
const glm::vec4* clusterWeights = mesh.clusterWeights.constData();
|
||||
for (int j = 0; j < vertexCount; j++) {
|
||||
_blendedVertices[j] =
|
||||
glm::vec3(state.clusterMatrices[clusterIndices[j][0]] *
|
||||
glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][0] +
|
||||
glm::vec3(state.clusterMatrices[clusterIndices[j][1]] *
|
||||
glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][1] +
|
||||
glm::vec3(state.clusterMatrices[clusterIndices[j][2]] *
|
||||
glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][2] +
|
||||
glm::vec3(state.clusterMatrices[clusterIndices[j][3]] *
|
||||
glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][3];
|
||||
}
|
||||
sourceVertices = _blendedVertices.constData();
|
||||
|
||||
} else {
|
||||
transform = state.clusterMatrices[0];
|
||||
}
|
||||
if (_resetStates) {
|
||||
for (int j = 0; j < vertexCount; j++) {
|
||||
destVertices[j] = glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f));
|
||||
destVelocities[j] = glm::vec3();
|
||||
}
|
||||
} else {
|
||||
const float SPRINGINESS_MULTIPLIER = 200.0f;
|
||||
const float DAMPING = 5.0f;
|
||||
for (int j = 0; j < vertexCount; j++) {
|
||||
destVelocities[j] += ((glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)) - destVertices[j]) *
|
||||
mesh.springiness * SPRINGINESS_MULTIPLIER - destVelocities[j] * DAMPING) * deltaTime;
|
||||
destVertices[j] += destVelocities[j] * deltaTime;
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < vertexCount; j++) {
|
||||
destNormals[j] = glm::vec3();
|
||||
|
||||
const glm::vec3& middle = destVertices[j];
|
||||
for (QVarLengthArray<QPair<int, int>, 4>::const_iterator connection = mesh.vertexConnections.at(j).constBegin();
|
||||
connection != mesh.vertexConnections.at(j).constEnd(); connection++) {
|
||||
destNormals[j] += glm::normalize(glm::cross(destVertices[connection->second] - middle,
|
||||
destVertices[connection->first] - middle));
|
||||
}
|
||||
}
|
||||
}
|
||||
_resetStates = false;
|
||||
}
|
||||
|
@ -980,34 +901,30 @@ void Model::renderMeshes(float alpha, bool translucent) {
|
|||
const MeshState& state = _meshStates.at(i);
|
||||
ProgramObject* activeProgram = program;
|
||||
int tangentLocation = _normalMapTangentLocation;
|
||||
if (state.worldSpaceVertices.isEmpty()) {
|
||||
glPushMatrix();
|
||||
Application::getInstance()->loadTranslatedViewMatrix(_translation);
|
||||
|
||||
if (state.clusterMatrices.size() > 1) {
|
||||
skinProgram->bind();
|
||||
glUniformMatrix4fvARB(skinLocations->clusterMatrices, state.clusterMatrices.size(), false,
|
||||
(const float*)state.clusterMatrices.constData());
|
||||
int offset = (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3) +
|
||||
mesh.texCoords.size() * sizeof(glm::vec2) +
|
||||
(mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0);
|
||||
skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4);
|
||||
skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT,
|
||||
offset + vertexCount * sizeof(glm::vec4), 4);
|
||||
skinProgram->enableAttributeArray(skinLocations->clusterIndices);
|
||||
skinProgram->enableAttributeArray(skinLocations->clusterWeights);
|
||||
activeProgram = skinProgram;
|
||||
tangentLocation = skinLocations->tangent;
|
||||
|
||||
} else {
|
||||
glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]);
|
||||
program->bind();
|
||||
}
|
||||
} else {
|
||||
glPushMatrix();
|
||||
Application::getInstance()->loadTranslatedViewMatrix(_translation);
|
||||
|
||||
if (state.clusterMatrices.size() > 1) {
|
||||
skinProgram->bind();
|
||||
glUniformMatrix4fvARB(skinLocations->clusterMatrices, state.clusterMatrices.size(), false,
|
||||
(const float*)state.clusterMatrices.constData());
|
||||
int offset = (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3) +
|
||||
mesh.texCoords.size() * sizeof(glm::vec2) +
|
||||
(mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0);
|
||||
skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4);
|
||||
skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT,
|
||||
offset + vertexCount * sizeof(glm::vec4), 4);
|
||||
skinProgram->enableAttributeArray(skinLocations->clusterIndices);
|
||||
skinProgram->enableAttributeArray(skinLocations->clusterWeights);
|
||||
activeProgram = skinProgram;
|
||||
tangentLocation = skinLocations->tangent;
|
||||
|
||||
} else {
|
||||
glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]);
|
||||
program->bind();
|
||||
}
|
||||
|
||||
if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) {
|
||||
if (mesh.blendshapes.isEmpty()) {
|
||||
if (!mesh.tangents.isEmpty()) {
|
||||
activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3);
|
||||
activeProgram->enableAttributeArray(tangentLocation);
|
||||
|
@ -1026,38 +943,31 @@ void Model::renderMeshes(float alpha, bool translucent) {
|
|||
glTexCoordPointer(2, GL_FLOAT, 0, (void*)((mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3)));
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _blendedVertexBufferIDs.at(i));
|
||||
|
||||
if (!state.worldSpaceVertices.isEmpty()) {
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), state.worldSpaceVertices.constData());
|
||||
glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3),
|
||||
vertexCount * sizeof(glm::vec3), state.worldSpaceNormals.constData());
|
||||
|
||||
} else {
|
||||
_blendedVertices.resize(max(_blendedVertices.size(), vertexCount));
|
||||
_blendedNormals.resize(_blendedVertices.size());
|
||||
memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3));
|
||||
memcpy(_blendedNormals.data(), mesh.normals.constData(), vertexCount * sizeof(glm::vec3));
|
||||
|
||||
// blend in each coefficient
|
||||
for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) {
|
||||
float coefficient = _blendshapeCoefficients[j];
|
||||
if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
const float NORMAL_COEFFICIENT_SCALE = 0.01f;
|
||||
float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE;
|
||||
const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData();
|
||||
const glm::vec3* normal = mesh.blendshapes[j].normals.constData();
|
||||
for (const int* index = mesh.blendshapes[j].indices.constData(),
|
||||
*end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++, normal++) {
|
||||
_blendedVertices[*index] += *vertex * coefficient;
|
||||
_blendedNormals[*index] += *normal * normalCoefficient;
|
||||
}
|
||||
_blendedVertices.resize(max(_blendedVertices.size(), vertexCount));
|
||||
_blendedNormals.resize(_blendedVertices.size());
|
||||
memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3));
|
||||
memcpy(_blendedNormals.data(), mesh.normals.constData(), vertexCount * sizeof(glm::vec3));
|
||||
|
||||
// blend in each coefficient
|
||||
for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) {
|
||||
float coefficient = _blendshapeCoefficients[j];
|
||||
if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
const float NORMAL_COEFFICIENT_SCALE = 0.01f;
|
||||
float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE;
|
||||
const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData();
|
||||
const glm::vec3* normal = mesh.blendshapes[j].normals.constData();
|
||||
for (const int* index = mesh.blendshapes[j].indices.constData(),
|
||||
*end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++, normal++) {
|
||||
_blendedVertices[*index] += *vertex * coefficient;
|
||||
_blendedNormals[*index] += *normal * normalCoefficient;
|
||||
}
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData());
|
||||
glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3),
|
||||
vertexCount * sizeof(glm::vec3), _blendedNormals.constData());
|
||||
}
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData());
|
||||
glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3),
|
||||
vertexCount * sizeof(glm::vec3), _blendedNormals.constData());
|
||||
}
|
||||
glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||
glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3)));
|
||||
|
@ -1126,14 +1036,13 @@ void Model::renderMeshes(float alpha, bool translucent) {
|
|||
|
||||
activeProgram->disableAttributeArray(tangentLocation);
|
||||
}
|
||||
|
||||
if (state.worldSpaceVertices.isEmpty()) {
|
||||
if (state.clusterMatrices.size() > 1) {
|
||||
skinProgram->disableAttributeArray(skinLocations->clusterIndices);
|
||||
skinProgram->disableAttributeArray(skinLocations->clusterWeights);
|
||||
}
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
if (state.clusterMatrices.size() > 1) {
|
||||
skinProgram->disableAttributeArray(skinLocations->clusterIndices);
|
||||
skinProgram->disableAttributeArray(skinLocations->clusterWeights);
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
activeProgram->release();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -219,9 +219,6 @@ protected:
|
|||
class MeshState {
|
||||
public:
|
||||
QVector<glm::mat4> clusterMatrices;
|
||||
QVector<glm::vec3> worldSpaceVertices;
|
||||
QVector<glm::vec3> vertexVelocities;
|
||||
QVector<glm::vec3> worldSpaceNormals;
|
||||
};
|
||||
|
||||
QVector<MeshState> _meshStates;
|
||||
|
|
Loading…
Reference in a new issue