diff --git a/application/application.pro b/application/application.pro index d44db070..36844107 100644 --- a/application/application.pro +++ b/application/application.pro @@ -155,17 +155,24 @@ HEADERS += sources/mesh_generator.h SOURCES += sources/mesh_generator.cc HEADERS += sources/mesh_result_post_processor.h SOURCES += sources/mesh_result_post_processor.cc -HEADERS += sources/model.h -SOURCES += sources/model.cc +HEADERS += sources/model_mesh.h +SOURCES += sources/model_mesh.cc HEADERS += sources/model_offscreen_render.h SOURCES += sources/model_offscreen_render.cc HEADERS += sources/model_opengl_program.h SOURCES += sources/model_opengl_program.cc HEADERS += sources/model_opengl_object.h SOURCES += sources/model_opengl_object.cc -HEADERS += sources/model_shader_vertex.h +HEADERS += sources/model_opengl_vertex.h HEADERS += sources/model_widget.h SOURCES += sources/model_widget.cc +HEADERS += sources/monochrome_mesh.h +SOURCES += sources/monochrome_mesh.cc +HEADERS += sources/monochrome_opengl_program.h +SOURCES += sources/monochrome_opengl_program.cc +HEADERS += sources/monochrome_opengl_object.h +SOURCES += sources/monochrome_opengl_object.cc +HEADERS += sources/monochrome_opengl_vertex.h HEADERS += sources/part_preview_images_generator.h SOURCES += sources/part_preview_images_generator.cc HEADERS += sources/part_tree_widget.h diff --git a/application/resources.qrc b/application/resources.qrc index b596c8f9..7c35e22a 100644 --- a/application/resources.qrc +++ b/application/resources.qrc @@ -8,6 +8,10 @@ shaders/model.frag shaders/model_core.vert shaders/model_core.frag + shaders/monochrome.vert + shaders/monochrome.frag + shaders/monochrome_core.vert + shaders/monochrome_core.frag resources/cedar_bridge_irradiance.dds resources/cedar_bridge_specular.dds resources/dust3d-vertical.png diff --git a/application/shaders/monochrome.frag b/application/shaders/monochrome.frag new file mode 100644 index 00000000..9be65eb8 --- /dev/null +++ b/application/shaders/monochrome.frag @@ -0,0 +1,9 @@ +#version 110 +varying vec3 pointPosition; +varying vec3 pointColor; +varying float pointAlpha; + +void main() +{ + gl_FragColor = vec4(pointColor, pointAlpha); +} diff --git a/application/shaders/monochrome.vert b/application/shaders/monochrome.vert new file mode 100644 index 00000000..123122fc --- /dev/null +++ b/application/shaders/monochrome.vert @@ -0,0 +1,19 @@ +#version 110 +attribute vec4 vertex; +attribute vec3 color; +attribute float alpha; +uniform mat4 modelMatrix; +uniform mat4 viewMatrix; +uniform mat4 projectionMatrix; +varying vec3 pointPosition; +varying vec3 pointColor; +varying float pointAlpha; + +void main() +{ + pointPosition = (modelMatrix * vertex).xyz; + pointColor = color; + pointAlpha = alpha; + + gl_Position = projectionMatrix * viewMatrix * vec4(pointPosition, 1.0); +} diff --git a/application/shaders/monochrome_core.frag b/application/shaders/monochrome_core.frag new file mode 100644 index 00000000..aba2a57f --- /dev/null +++ b/application/shaders/monochrome_core.frag @@ -0,0 +1,8 @@ +#version 330 +in vec3 pointColor; +in float pointAlpha; +out vec4 fragColor; +void main() +{ + fragColor = vec4(pointColor, pointAlpha); +} \ No newline at end of file diff --git a/application/shaders/monochrome_core.vert b/application/shaders/monochrome_core.vert new file mode 100644 index 00000000..ea3620f1 --- /dev/null +++ b/application/shaders/monochrome_core.vert @@ -0,0 +1,19 @@ +#version 330 +layout(location = 0) in vec4 vertex; +layout(location = 1) in vec3 color; +layout(location = 2) in float alpha; +uniform mat4 modelMatrix; +uniform mat4 viewMatrix; +uniform mat4 projectionMatrix; +out vec3 pointPosition; +out vec3 pointColor; +out float pointAlpha; + +void main() +{ + pointPosition = (modelMatrix * vertex).xyz; + pointColor = color; + pointAlpha = alpha; + + gl_Position = projectionMatrix * viewMatrix * vec4(pointPosition, 1.0); +} \ No newline at end of file diff --git a/application/sources/document.cc b/application/sources/document.cc index 58528b6c..47c48d83 100644 --- a/application/sources/document.cc +++ b/application/sources/document.cc @@ -729,30 +729,38 @@ void Document::fromSnapshot(const dust3d::Snapshot &snapshot) emit uncheckAll(); } -Model *Document::takeResultMesh() +ModelMesh *Document::takeResultMesh() { if (nullptr == m_resultMesh) return nullptr; - Model *resultMesh = new Model(*m_resultMesh); + ModelMesh *resultMesh = new ModelMesh(*m_resultMesh); return resultMesh; } +MonochromeMesh *Document::takeWireframeMesh() +{ + if (nullptr == m_wireframeMesh) + return nullptr; + return new MonochromeMesh(*m_wireframeMesh); +} + bool Document::isMeshGenerationSucceed() { return m_isMeshGenerationSucceed; } -Model *Document::takeResultTextureMesh() +ModelMesh *Document::takeResultTextureMesh() { if (nullptr == m_resultTextureMesh) return nullptr; - Model *resultTextureMesh = new Model(*m_resultTextureMesh); + ModelMesh *resultTextureMesh = new ModelMesh(*m_resultTextureMesh); return resultTextureMesh; } void Document::meshReady() { - Model *resultMesh = m_meshGenerator->takeResultMesh(); + ModelMesh *resultMesh = m_meshGenerator->takeResultMesh(); + m_wireframeMesh.reset(m_meshGenerator->takeWireframeMesh()); dust3d::Object *object = m_meshGenerator->takeObject(); bool isSuccessful = m_meshGenerator->isSuccessful(); @@ -772,7 +780,7 @@ void Document::meshReady() for (auto &partId: m_meshGenerator->generatedPreviewPartIds()) { auto part = partMap.find(partId); if (part != partMap.end()) { - Model *resultPartPreviewMesh = m_meshGenerator->takePartPreviewMesh(partId); + ModelMesh *resultPartPreviewMesh = m_meshGenerator->takePartPreviewMesh(partId); part->second.updatePreviewMesh(resultPartPreviewMesh); partPreviewsChanged = true; } @@ -1591,7 +1599,7 @@ void Document::materialPreviewsReady() for (const auto &materialId: m_materialPreviewsGenerator->generatedPreviewMaterialIds()) { auto material = materialMap.find(materialId); if (material != materialMap.end()) { - Model *resultPartPreviewMesh = m_materialPreviewsGenerator->takePreview(materialId); + ModelMesh *resultPartPreviewMesh = m_materialPreviewsGenerator->takePreview(materialId); material->second.updatePreviewMesh(resultPartPreviewMesh); emit materialPreviewChanged(materialId); } diff --git a/application/sources/document.h b/application/sources/document.h index 1244b1af..2cda209e 100644 --- a/application/sources/document.h +++ b/application/sources/document.h @@ -14,7 +14,8 @@ #include #include #include -#include "model.h" +#include "model_mesh.h" +#include "monochrome_mesh.h" #include "theme.h" #include "skeleton_document.h" #include "material_layer.h" @@ -44,20 +45,20 @@ public: QString name; bool dirty = true; std::vector layers; - void updatePreviewMesh(Model *previewMesh) + void updatePreviewMesh(ModelMesh *previewMesh) { delete m_previewMesh; m_previewMesh = previewMesh; } - Model *takePreviewMesh() const + ModelMesh *takePreviewMesh() const { if (nullptr == m_previewMesh) return nullptr; - return new Model(*m_previewMesh); + return new ModelMesh(*m_previewMesh); } private: Q_DISABLE_COPY(Material); - Model *m_previewMesh = nullptr; + ModelMesh *m_previewMesh = nullptr; }; enum class DocumentToSnapshotFor @@ -133,8 +134,8 @@ public: // need initialize QImage *textureAmbientOcclusionImage = nullptr; QByteArray *textureAmbientOcclusionImageByteArray = nullptr; bool weldEnabled = true; - float brushMetalness = Model::m_defaultMetalness; - float brushRoughness = Model::m_defaultRoughness; + float brushMetalness = ModelMesh::m_defaultMetalness; + float brushRoughness = ModelMesh::m_defaultRoughness; public: Document(); ~Document(); @@ -160,11 +161,12 @@ public: }; void addFromSnapshot(const dust3d::Snapshot &snapshot, enum SnapshotSource source=SnapshotSource::Paste); const Material *findMaterial(dust3d::Uuid materialId) const; - Model *takeResultMesh(); - Model *takePaintedMesh(); + ModelMesh *takeResultMesh(); + MonochromeMesh *takeWireframeMesh(); + ModelMesh *takePaintedMesh(); bool isMeshGenerationSucceed(); - Model *takeResultTextureMesh(); - Model *takeResultRigWeightMesh(); + ModelMesh *takeResultTextureMesh(); + ModelMesh *takeResultRigWeightMesh(); void updateTurnaround(const QImage &image); void clearTurnaround(); void updateTextureImage(QImage *image); @@ -239,7 +241,8 @@ private: bool m_isResultMeshObsolete = false; MeshGenerator *m_meshGenerator = nullptr; - Model *m_resultMesh = nullptr; + ModelMesh *m_resultMesh = nullptr; + std::unique_ptr m_wireframeMesh; bool m_isMeshGenerationSucceed = true; int m_batchChangeRefCount = 0; dust3d::Object *m_currentObject = nullptr; @@ -248,7 +251,7 @@ private: bool m_isPostProcessResultObsolete = false; MeshResultPostProcessor *m_postProcessor = nullptr; dust3d::Object *m_postProcessedObject = new dust3d::Object; - Model *m_resultTextureMesh = nullptr; + ModelMesh *m_resultTextureMesh = nullptr; unsigned long long m_textureImageUpdateVersion = 0; bool m_smoothNormal = false; MaterialPreviewsGenerator *m_materialPreviewsGenerator = nullptr; diff --git a/application/sources/document_window.cc b/application/sources/document_window.cc index 952bb70c..c54c8e74 100644 --- a/application/sources/document_window.cc +++ b/application/sources/document_window.cc @@ -423,7 +423,7 @@ DocumentWindow::DocumentWindow() m_toggleColorAction = new QAction(tr("Toggle Color"), this); connect(m_toggleColorAction, &QAction::triggered, [&]() { m_modelRemoveColor = !m_modelRemoveColor; - Model *mesh = nullptr; + ModelMesh *mesh = nullptr; if (m_document->isMeshGenerating() || m_document->isPostProcessing() || m_document->isTextureGenerating()) { @@ -738,6 +738,7 @@ DocumentWindow::DocumentWindow() if (m_modelRemoveColor && resultMesh) resultMesh->removeColor(); m_modelRenderWidget->updateMesh(resultMesh); + m_modelRenderWidget->updateWireframeMesh(m_document->takeWireframeMesh()); }); connect(canvasGraphicsWidget, &SkeletonGraphicsWidget::cursorChanged, [=]() { @@ -1027,7 +1028,7 @@ void DocumentWindow::openPathAs(const QString &path, const QString &asName) QByteArray fileData = file.readAll(); dust3d::Ds3FileReader ds3Reader((const std::uint8_t *)fileData.data(), fileData.size()); - for (int i = 0; i < ds3Reader.items().size(); ++i) { + for (int i = 0; i < (int)ds3Reader.items().size(); ++i) { const dust3d::Ds3ReaderItem &item = ds3Reader.items()[i]; qDebug() << "[" << i << "]item.name:" << item.name << "item.type:" << item.type; if (item.type == "asset") { @@ -1045,7 +1046,7 @@ void DocumentWindow::openPathAs(const QString &path, const QString &asName) } } - for (int i = 0; i < ds3Reader.items().size(); ++i) { + for (int i = 0; i < (int)ds3Reader.items().size(); ++i) { const dust3d::Ds3ReaderItem &item = ds3Reader.items()[i]; if (item.type == "model") { std::vector data; @@ -1124,7 +1125,7 @@ void DocumentWindow::exportObjResult() void DocumentWindow::exportObjToFilename(const QString &filename) { QApplication::setOverrideCursor(Qt::WaitCursor); - Model *resultMesh = m_document->takeResultMesh(); + ModelMesh *resultMesh = m_document->takeResultMesh(); if (nullptr != resultMesh) { resultMesh->exportAsObj(filename); delete resultMesh; @@ -1534,13 +1535,13 @@ void DocumentWindow::updateRecentFileActions() { QStringList files = Preferences::instance().recentFileList(); - for (int i = 0; i < files.size() && i < m_recentFileActions.size(); ++i) { + for (int i = 0; i < (int)files.size() && i < (int)m_recentFileActions.size(); ++i) { QString text = tr("&%1 %2").arg(i + 1).arg(strippedName(files[i])); m_recentFileActions[i]->setText(text); m_recentFileActions[i]->setData(files[i]); m_recentFileActions[i]->setVisible(true); } - for (int j = files.size(); j < m_recentFileActions.size(); ++j) + for (int j = files.size(); j < (int)m_recentFileActions.size(); ++j) m_recentFileActions[j]->setVisible(false); m_recentFileSeparatorAction->setVisible(files.size() > 0); diff --git a/application/sources/glb_file.cc b/application/sources/glb_file.cc index 00998384..a02a55f0 100644 --- a/application/sources/glb_file.cc +++ b/application/sources/glb_file.cc @@ -7,7 +7,7 @@ #include #include "glb_file.h" #include "version.h" -#include "model.h" +#include "model_mesh.h" bool GlbFileWriter::m_enableComment = false; @@ -79,8 +79,8 @@ GlbFileWriter::GlbFileWriter(dust3d::Object &object, m_json["meshes"][0]["primitives"][primitiveIndex]["attributes"]["TEXCOORD_0"] = bufferViewIndex + (++attributeIndex); int textureIndex = 0; m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["baseColorTexture"]["index"] = textureIndex++; - m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["metallicFactor"] = Model::m_defaultMetalness; - m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["roughnessFactor"] = Model::m_defaultRoughness; + m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["metallicFactor"] = ModelMesh::m_defaultMetalness; + m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["roughnessFactor"] = ModelMesh::m_defaultRoughness; if (object.alphaEnabled) m_json["materials"][primitiveIndex]["alphaMode"] = "BLEND"; if (normalImage) { diff --git a/application/sources/material_previews_generator.cc b/application/sources/material_previews_generator.cc index dd1949fe..0cdf2e51 100644 --- a/application/sources/material_previews_generator.cc +++ b/application/sources/material_previews_generator.cc @@ -31,9 +31,9 @@ const std::set &MaterialPreviewsGenerator::generatedPreviewMateria return m_generatedMaterialIds; } -Model *MaterialPreviewsGenerator::takePreview(dust3d::Uuid materialId) +ModelMesh *MaterialPreviewsGenerator::takePreview(dust3d::Uuid materialId) { - Model *resultMesh = m_previews[materialId]; + ModelMesh *resultMesh = m_previews[materialId]; m_previews[materialId] = nullptr; return resultMesh; } @@ -102,9 +102,9 @@ void MaterialPreviewsGenerator::generate() } } textureGenerator->generate(); - Model *texturedResultMesh = textureGenerator->takeResultMesh(); + ModelMesh *texturedResultMesh = textureGenerator->takeResultMesh(); if (nullptr != texturedResultMesh) { - m_previews[material.first] = new Model(*texturedResultMesh); + m_previews[material.first] = new ModelMesh(*texturedResultMesh); m_generatedMaterialIds.insert(material.first); delete texturedResultMesh; } diff --git a/application/sources/material_previews_generator.h b/application/sources/material_previews_generator.h index df156002..b6161694 100644 --- a/application/sources/material_previews_generator.h +++ b/application/sources/material_previews_generator.h @@ -4,7 +4,7 @@ #include #include #include -#include "model.h" +#include "model_mesh.h" #include "material_layer.h" class MaterialPreviewsGenerator : public QObject @@ -15,7 +15,7 @@ public: ~MaterialPreviewsGenerator(); void addMaterial(dust3d::Uuid materialId, const std::vector &layers); const std::set &generatedPreviewMaterialIds(); - Model *takePreview(dust3d::Uuid materialId); + ModelMesh *takePreview(dust3d::Uuid materialId); void generate(); signals: void finished(); @@ -23,7 +23,7 @@ public slots: void process(); private: std::vector>> m_materials; - std::map m_previews; + std::map m_previews; std::set m_generatedMaterialIds; }; diff --git a/application/sources/material_widget.cc b/application/sources/material_widget.cc index 33fd544c..54a1c185 100644 --- a/application/sources/material_widget.cc +++ b/application/sources/material_widget.cc @@ -63,7 +63,7 @@ void MaterialWidget::updatePreview(dust3d::Uuid materialId) qDebug() << "Material not found:" << m_materialId; return; } - Model *previewMesh = material->takePreviewMesh(); + ModelMesh *previewMesh = material->takePreviewMesh(); m_previewWidget->updateMesh(previewMesh); } diff --git a/application/sources/mesh_generator.cc b/application/sources/mesh_generator.cc index a4481165..56606419 100644 --- a/application/sources/mesh_generator.cc +++ b/application/sources/mesh_generator.cc @@ -17,9 +17,9 @@ MeshGenerator::~MeshGenerator() delete m_resultMesh; } -Model *MeshGenerator::takePartPreviewMesh(const dust3d::Uuid &partId) +ModelMesh *MeshGenerator::takePartPreviewMesh(const dust3d::Uuid &partId) { - Model *resultMesh = m_partPreviewMeshes[partId]; + ModelMesh *resultMesh = m_partPreviewMeshes[partId]; m_partPreviewMeshes[partId] = nullptr; return resultMesh; } @@ -31,6 +31,11 @@ QImage *MeshGenerator::takePartPreviewImage(const dust3d::Uuid &partId) return image; } +MonochromeMesh *MeshGenerator::takeWireframeMesh() +{ + return m_wireframeMesh.release(); +} + void MeshGenerator::process() { QElapsedTimer countTimeConsumed; @@ -39,7 +44,7 @@ void MeshGenerator::process() generate(); if (nullptr != m_object) - m_resultMesh = new Model(*m_object); + m_resultMesh = new ModelMesh(*m_object); for (const auto &partId: m_generatedPreviewImagePartIds) { auto it = m_generatedPartPreviews.find(partId); @@ -51,22 +56,25 @@ void MeshGenerator::process() auto it = m_generatedPartPreviews.find(partId); if (it == m_generatedPartPreviews.end()) continue; - m_partPreviewMeshes[partId] = new Model(it->second.vertices, + m_partPreviewMeshes[partId] = new ModelMesh(it->second.vertices, it->second.triangles, it->second.vertexNormals, it->second.color, it->second.metalness, it->second.roughness); } + + if (nullptr != m_object) + m_wireframeMesh = std::make_unique(*m_object); qDebug() << "The mesh generation took" << countTimeConsumed.elapsed() << "milliseconds"; emit finished(); } -Model *MeshGenerator::takeResultMesh() +ModelMesh *MeshGenerator::takeResultMesh() { - Model *resultMesh = m_resultMesh; + ModelMesh *resultMesh = m_resultMesh; m_resultMesh = nullptr; return resultMesh; } diff --git a/application/sources/mesh_generator.h b/application/sources/mesh_generator.h index 78d66fca..dcd97de3 100644 --- a/application/sources/mesh_generator.h +++ b/application/sources/mesh_generator.h @@ -1,10 +1,12 @@ #ifndef DUST3D_APPLICATION_MESH_GENERATOR_H_ #define DUST3D_APPLICATION_MESH_GENERATOR_H_ +#include #include #include #include -#include "model.h" +#include "model_mesh.h" +#include "monochrome_mesh.h" class MeshGenerator : public QObject, public dust3d::MeshGenerator { @@ -12,17 +14,19 @@ class MeshGenerator : public QObject, public dust3d::MeshGenerator public: MeshGenerator(dust3d::Snapshot *snapshot); ~MeshGenerator(); - Model *takeResultMesh(); - Model *takePartPreviewMesh(const dust3d::Uuid &partId); + ModelMesh *takeResultMesh(); + ModelMesh *takePartPreviewMesh(const dust3d::Uuid &partId); QImage *takePartPreviewImage(const dust3d::Uuid &partId); + MonochromeMesh *takeWireframeMesh(); public slots: void process(); signals: void finished(); private: - Model *m_resultMesh = nullptr; - std::map m_partPreviewMeshes; + ModelMesh *m_resultMesh = nullptr; + std::map m_partPreviewMeshes; std::map m_partPreviewImages; + std::unique_ptr m_wireframeMesh; }; #endif diff --git a/application/sources/model.cc b/application/sources/model_mesh.cc similarity index 79% rename from application/sources/model.cc rename to application/sources/model_mesh.cc index 174a1db7..70efe16e 100644 --- a/application/sources/model.cc +++ b/application/sources/model_mesh.cc @@ -2,13 +2,13 @@ #include #include #include -#include "model.h" +#include "model_mesh.h" #include "version.h" -float Model::m_defaultMetalness = 0.0; -float Model::m_defaultRoughness = 1.0; +float ModelMesh::m_defaultMetalness = 0.0; +float ModelMesh::m_defaultRoughness = 1.0; -Model::Model(const Model &mesh) : +ModelMesh::ModelMesh(const ModelMesh &mesh) : m_triangleVertices(nullptr), m_triangleVertexCount(0), m_edgeVertices(nullptr), @@ -17,21 +17,21 @@ Model::Model(const Model &mesh) : { if (nullptr != mesh.m_triangleVertices && mesh.m_triangleVertexCount > 0) { - this->m_triangleVertices = new ModelShaderVertex[mesh.m_triangleVertexCount]; + this->m_triangleVertices = new ModelOpenGLVertex[mesh.m_triangleVertexCount]; this->m_triangleVertexCount = mesh.m_triangleVertexCount; for (int i = 0; i < mesh.m_triangleVertexCount; i++) this->m_triangleVertices[i] = mesh.m_triangleVertices[i]; } if (nullptr != mesh.m_edgeVertices && mesh.m_edgeVertexCount > 0) { - this->m_edgeVertices = new ModelShaderVertex[mesh.m_edgeVertexCount]; + this->m_edgeVertices = new ModelOpenGLVertex[mesh.m_edgeVertexCount]; this->m_edgeVertexCount = mesh.m_edgeVertexCount; for (int i = 0; i < mesh.m_edgeVertexCount; i++) this->m_edgeVertices[i] = mesh.m_edgeVertices[i]; } if (nullptr != mesh.m_toolVertices && mesh.m_toolVertexCount > 0) { - this->m_toolVertices = new ModelShaderVertex[mesh.m_toolVertexCount]; + this->m_toolVertices = new ModelOpenGLVertex[mesh.m_toolVertexCount]; this->m_toolVertexCount = mesh.m_toolVertexCount; for (int i = 0; i < mesh.m_toolVertexCount; i++) this->m_toolVertices[i] = mesh.m_toolVertices[i]; @@ -54,7 +54,7 @@ Model::Model(const Model &mesh) : this->m_meshId = mesh.meshId(); } -void Model::removeColor() +void ModelMesh::removeColor() { delete this->m_textureImage; this->m_textureImage = nullptr; @@ -77,7 +77,7 @@ void Model::removeColor() } } -Model::Model(ModelShaderVertex *triangleVertices, int vertexNum, ModelShaderVertex *edgeVertices, int edgeVertexCount) : +ModelMesh::ModelMesh(ModelOpenGLVertex *triangleVertices, int vertexNum, ModelOpenGLVertex *edgeVertices, int edgeVertexCount) : m_triangleVertices(triangleVertices), m_triangleVertexCount(vertexNum), m_edgeVertices(edgeVertices), @@ -86,21 +86,21 @@ Model::Model(ModelShaderVertex *triangleVertices, int vertexNum, ModelShaderVert { } -Model::Model(const std::vector &vertices, const std::vector> &triangles, +ModelMesh::ModelMesh(const std::vector &vertices, const std::vector> &triangles, const std::vector> &triangleVertexNormals, const dust3d::Color &color, float metalness, float roughness) { m_triangleVertexCount = (int)triangles.size() * 3; - m_triangleVertices = new ModelShaderVertex[m_triangleVertexCount]; + m_triangleVertices = new ModelOpenGLVertex[m_triangleVertexCount]; int destIndex = 0; for (size_t i = 0; i < triangles.size(); ++i) { for (auto j = 0; j < 3; j++) { int vertexIndex = (int)triangles[i][j]; const dust3d::Vector3 *srcVert = &vertices[vertexIndex]; const dust3d::Vector3 *srcNormal = &(triangleVertexNormals)[i][j]; - ModelShaderVertex *dest = &m_triangleVertices[destIndex]; + ModelOpenGLVertex *dest = &m_triangleVertices[destIndex]; dest->colorR = color.r(); dest->colorG = color.g(); dest->colorB = color.b(); @@ -123,7 +123,7 @@ Model::Model(const std::vector &vertices, const std::vectorcolorR = triangleColor->r(); dest->colorG = triangleColor->g(); dest->colorB = triangleColor->b(); @@ -196,7 +196,7 @@ Model::Model(dust3d::Object &object) : edgeCount += face.size(); } m_edgeVertexCount = (int)edgeCount * 2; - m_edgeVertices = new ModelShaderVertex[m_edgeVertexCount]; + m_edgeVertices = new ModelOpenGLVertex[m_edgeVertexCount]; size_t edgeVertexIndex = 0; for (size_t faceIndex = 0; faceIndex < object.triangleAndQuads.size(); ++faceIndex) { const auto &face = object.triangleAndQuads[faceIndex]; @@ -204,8 +204,8 @@ Model::Model(dust3d::Object &object) : for (size_t x = 0; x < 2; ++x) { size_t sourceIndex = face[(i + x) % face.size()]; const dust3d::Vector3 *srcVert = &object.vertices[sourceIndex]; - ModelShaderVertex *dest = &m_edgeVertices[edgeVertexIndex]; - memset(dest, 0, sizeof(ModelShaderVertex)); + ModelOpenGLVertex *dest = &m_edgeVertices[edgeVertexIndex]; + memset(dest, 0, sizeof(ModelOpenGLVertex)); dest->colorR = 0.0; dest->colorG = 0.0; dest->colorB = 0.0; @@ -221,7 +221,7 @@ Model::Model(dust3d::Object &object) : } } -Model::Model() : +ModelMesh::ModelMesh() : m_triangleVertices(nullptr), m_triangleVertexCount(0), m_edgeVertices(nullptr), @@ -230,7 +230,7 @@ Model::Model() : { } -Model::~Model() +ModelMesh::~ModelMesh() { delete[] m_triangleVertices; m_triangleVertexCount = 0; @@ -243,112 +243,112 @@ Model::~Model() delete m_metalnessRoughnessAmbientOcclusionImage; } -const std::vector &Model::vertices() +const std::vector &ModelMesh::vertices() { return m_vertices; } -const std::vector> &Model::faces() +const std::vector> &ModelMesh::faces() { return m_faces; } -const std::vector &Model::triangulatedVertices() +const std::vector &ModelMesh::triangulatedVertices() { return m_triangulatedVertices; } -ModelShaderVertex *Model::triangleVertices() +ModelOpenGLVertex *ModelMesh::triangleVertices() { return m_triangleVertices; } -int Model::triangleVertexCount() +int ModelMesh::triangleVertexCount() { return m_triangleVertexCount; } -ModelShaderVertex *Model::edgeVertices() +ModelOpenGLVertex *ModelMesh::edgeVertices() { return m_edgeVertices; } -int Model::edgeVertexCount() +int ModelMesh::edgeVertexCount() { return m_edgeVertexCount; } -ModelShaderVertex *Model::toolVertices() +ModelOpenGLVertex *ModelMesh::toolVertices() { return m_toolVertices; } -int Model::toolVertexCount() +int ModelMesh::toolVertexCount() { return m_toolVertexCount; } -void Model::setTextureImage(QImage *textureImage) +void ModelMesh::setTextureImage(QImage *textureImage) { m_textureImage = textureImage; } -const QImage *Model::textureImage() +const QImage *ModelMesh::textureImage() { return m_textureImage; } -void Model::setNormalMapImage(QImage *normalMapImage) +void ModelMesh::setNormalMapImage(QImage *normalMapImage) { m_normalMapImage = normalMapImage; } -const QImage *Model::normalMapImage() +const QImage *ModelMesh::normalMapImage() { return m_normalMapImage; } -const QImage *Model::metalnessRoughnessAmbientOcclusionImage() +const QImage *ModelMesh::metalnessRoughnessAmbientOcclusionImage() { return m_metalnessRoughnessAmbientOcclusionImage; } -void Model::setMetalnessRoughnessAmbientOcclusionImage(QImage *image) +void ModelMesh::setMetalnessRoughnessAmbientOcclusionImage(QImage *image) { m_metalnessRoughnessAmbientOcclusionImage = image; } -bool Model::hasMetalnessInImage() +bool ModelMesh::hasMetalnessInImage() { return m_hasMetalnessInImage; } -void Model::setHasMetalnessInImage(bool hasInImage) +void ModelMesh::setHasMetalnessInImage(bool hasInImage) { m_hasMetalnessInImage = hasInImage; } -bool Model::hasRoughnessInImage() +bool ModelMesh::hasRoughnessInImage() { return m_hasRoughnessInImage; } -void Model::setHasRoughnessInImage(bool hasInImage) +void ModelMesh::setHasRoughnessInImage(bool hasInImage) { m_hasRoughnessInImage = hasInImage; } -bool Model::hasAmbientOcclusionInImage() +bool ModelMesh::hasAmbientOcclusionInImage() { return m_hasAmbientOcclusionInImage; } -void Model::setHasAmbientOcclusionInImage(bool hasInImage) +void ModelMesh::setHasAmbientOcclusionInImage(bool hasInImage) { m_hasAmbientOcclusionInImage = hasInImage; } -void Model::exportAsObj(QTextStream *textStream) +void ModelMesh::exportAsObj(QTextStream *textStream) { auto &stream = *textStream; stream << "# " << APP_NAME << " " << APP_HUMAN_VER << endl; @@ -365,7 +365,7 @@ void Model::exportAsObj(QTextStream *textStream) } } -void Model::exportAsObj(const QString &filename) +void ModelMesh::exportAsObj(const QString &filename) { QFile file(filename); if (file.open(QIODevice::WriteOnly)) { @@ -374,7 +374,7 @@ void Model::exportAsObj(const QString &filename) } } -void Model::updateTool(ModelShaderVertex *toolVertices, int vertexNum) +void ModelMesh::updateTool(ModelOpenGLVertex *toolVertices, int vertexNum) { delete[] m_toolVertices; m_toolVertices = nullptr; @@ -384,7 +384,7 @@ void Model::updateTool(ModelShaderVertex *toolVertices, int vertexNum) m_toolVertexCount = vertexNum; } -void Model::updateEdges(ModelShaderVertex *edgeVertices, int edgeVertexCount) +void ModelMesh::updateEdges(ModelOpenGLVertex *edgeVertices, int edgeVertexCount) { delete[] m_edgeVertices; m_edgeVertices = nullptr; @@ -394,7 +394,7 @@ void Model::updateEdges(ModelShaderVertex *edgeVertices, int edgeVertexCount) m_edgeVertexCount = edgeVertexCount; } -void Model::updateTriangleVertices(ModelShaderVertex *triangleVertices, int triangleVertexCount) +void ModelMesh::updateTriangleVertices(ModelOpenGLVertex *triangleVertices, int triangleVertexCount) { delete[] m_triangleVertices; m_triangleVertices = 0; @@ -404,12 +404,12 @@ void Model::updateTriangleVertices(ModelShaderVertex *triangleVertices, int tria m_triangleVertexCount = triangleVertexCount; } -quint64 Model::meshId() const +quint64 ModelMesh::meshId() const { return m_meshId; } -void Model::setMeshId(quint64 id) +void ModelMesh::setMeshId(quint64 id) { m_meshId = id; } diff --git a/application/sources/model.h b/application/sources/model_mesh.h similarity index 68% rename from application/sources/model.h rename to application/sources/model_mesh.h index 6977a791..dfe1680f 100644 --- a/application/sources/model.h +++ b/application/sources/model_mesh.h @@ -1,5 +1,5 @@ -#ifndef DUST3D_APPLICATION_MODEL_H_ -#define DUST3D_APPLICATION_MODEL_H_ +#ifndef DUST3D_APPLICATION_MODEL_MESH_H_ +#define DUST3D_APPLICATION_MODEL_MESH_H_ #include #include @@ -8,26 +8,26 @@ #include #include #include -#include "model_shader_vertex.h" +#include "model_opengl_vertex.h" -class Model +class ModelMesh { public: - Model(const std::vector &vertices, const std::vector> &triangles, + ModelMesh(const std::vector &vertices, const std::vector> &triangles, const std::vector> &triangleVertexNormals, const dust3d::Color &color=dust3d::Color::createWhite(), float metalness=0.0, float roughness=0.0); - Model(dust3d::Object &object); - Model(ModelShaderVertex *triangleVertices, int vertexNum, ModelShaderVertex *edgeVertices=nullptr, int edgeVertexCount=0); - Model(const Model &mesh); - Model(); - ~Model(); - ModelShaderVertex *triangleVertices(); + ModelMesh(dust3d::Object &object); + ModelMesh(ModelOpenGLVertex *triangleVertices, int vertexNum, ModelOpenGLVertex *edgeVertices=nullptr, int edgeVertexCount=0); + ModelMesh(const ModelMesh &mesh); + ModelMesh(); + ~ModelMesh(); + ModelOpenGLVertex *triangleVertices(); int triangleVertexCount(); - ModelShaderVertex *edgeVertices(); + ModelOpenGLVertex *edgeVertices(); int edgeVertexCount(); - ModelShaderVertex *toolVertices(); + ModelOpenGLVertex *toolVertices(); int toolVertexCount(); const std::vector &vertices(); const std::vector> &faces(); @@ -48,18 +48,18 @@ public: static float m_defaultRoughness; void exportAsObj(const QString &filename); void exportAsObj(QTextStream *textStream); - void updateTool(ModelShaderVertex *toolVertices, int vertexNum); - void updateEdges(ModelShaderVertex *edgeVertices, int edgeVertexCount); - void updateTriangleVertices(ModelShaderVertex *triangleVertices, int triangleVertexCount); + void updateTool(ModelOpenGLVertex *toolVertices, int vertexNum); + void updateEdges(ModelOpenGLVertex *edgeVertices, int edgeVertexCount); + void updateTriangleVertices(ModelOpenGLVertex *triangleVertices, int triangleVertexCount); quint64 meshId() const; void setMeshId(quint64 id); void removeColor(); private: - ModelShaderVertex *m_triangleVertices = nullptr; + ModelOpenGLVertex *m_triangleVertices = nullptr; int m_triangleVertexCount = 0; - ModelShaderVertex *m_edgeVertices = nullptr; + ModelOpenGLVertex *m_edgeVertices = nullptr; int m_edgeVertexCount = 0; - ModelShaderVertex *m_toolVertices = nullptr; + ModelOpenGLVertex *m_toolVertices = nullptr; int m_toolVertexCount = 0; std::vector m_vertices; std::vector> m_faces; diff --git a/application/sources/model_offscreen_render.cc b/application/sources/model_offscreen_render.cc index 299e38eb..1b93eee3 100644 --- a/application/sources/model_offscreen_render.cc +++ b/application/sources/model_offscreen_render.cc @@ -40,7 +40,7 @@ void ModelOffscreenRender::setRenderThread(QThread *thread) // TODO } -void ModelOffscreenRender::updateMesh(Model *mesh) +void ModelOffscreenRender::updateMesh(ModelMesh *mesh) { // TODO } diff --git a/application/sources/model_offscreen_render.h b/application/sources/model_offscreen_render.h index 17c6502d..85f3670c 100644 --- a/application/sources/model_offscreen_render.h +++ b/application/sources/model_offscreen_render.h @@ -4,7 +4,7 @@ #include #include #include -#include "model.h" +#include "model_mesh.h" class ModelOffscreenRender: public QOffscreenSurface { @@ -17,7 +17,7 @@ public: void setEyePosition(const QVector3D &eyePosition); void setMoveToPosition(const QVector3D &moveToPosition); void setRenderThread(QThread *thread); - void updateMesh(Model *mesh); + void updateMesh(ModelMesh *mesh); QImage toImage(const QSize &size); }; diff --git a/application/sources/model_opengl_object.cc b/application/sources/model_opengl_object.cc index 14b1f4c3..3cf116c6 100644 --- a/application/sources/model_opengl_object.cc +++ b/application/sources/model_opengl_object.cc @@ -3,7 +3,7 @@ #include #include "model_opengl_object.h" -void ModelOpenGLObject::update(std::unique_ptr mesh) +void ModelOpenGLObject::update(std::unique_ptr mesh) { QMutexLocker lock(&m_meshMutex); m_mesh = std::move(mesh); @@ -22,7 +22,7 @@ void ModelOpenGLObject::draw() void ModelOpenGLObject::copyMeshToOpenGL() { - std::unique_ptr mesh; + std::unique_ptr mesh; bool meshChanged = false; if (m_meshIsDirty) { QMutexLocker lock(&m_meshMutex); @@ -41,7 +41,7 @@ void ModelOpenGLObject::copyMeshToOpenGL() m_buffer.destroy(); m_buffer.create(); m_buffer.bind(); - m_buffer.allocate(mesh->triangleVertices(), mesh->triangleVertexCount() * sizeof(ModelShaderVertex)); + m_buffer.allocate(mesh->triangleVertices(), mesh->triangleVertexCount() * sizeof(ModelOpenGLVertex)); m_meshTriangleVertexCount = mesh->triangleVertexCount(); QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); f->glEnableVertexAttribArray(0); @@ -52,14 +52,14 @@ void ModelOpenGLObject::copyMeshToOpenGL() f->glEnableVertexAttribArray(5); f->glEnableVertexAttribArray(6); f->glEnableVertexAttribArray(7); - f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), 0); - f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(3 * sizeof(GLfloat))); - f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(6 * sizeof(GLfloat))); - f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(9 * sizeof(GLfloat))); - f->glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(11 * sizeof(GLfloat))); - f->glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(12 * sizeof(GLfloat))); - f->glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(13 * sizeof(GLfloat))); - f->glVertexAttribPointer(7, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(16 * sizeof(GLfloat))); + f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(ModelOpenGLVertex), 0); + f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(ModelOpenGLVertex), reinterpret_cast(3 * sizeof(GLfloat))); + f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(ModelOpenGLVertex), reinterpret_cast(6 * sizeof(GLfloat))); + f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(ModelOpenGLVertex), reinterpret_cast(9 * sizeof(GLfloat))); + f->glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(ModelOpenGLVertex), reinterpret_cast(11 * sizeof(GLfloat))); + f->glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(ModelOpenGLVertex), reinterpret_cast(12 * sizeof(GLfloat))); + f->glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, sizeof(ModelOpenGLVertex), reinterpret_cast(13 * sizeof(GLfloat))); + f->glVertexAttribPointer(7, 1, GL_FLOAT, GL_FALSE, sizeof(ModelOpenGLVertex), reinterpret_cast(16 * sizeof(GLfloat))); m_buffer.release(); } } \ No newline at end of file diff --git a/application/sources/model_opengl_object.h b/application/sources/model_opengl_object.h index 4ac8279b..2a0a2455 100644 --- a/application/sources/model_opengl_object.h +++ b/application/sources/model_opengl_object.h @@ -5,18 +5,18 @@ #include #include #include -#include "model.h" +#include "model_mesh.h" class ModelOpenGLObject { public: - void update(std::unique_ptr mesh); + void update(std::unique_ptr mesh); void draw(); private: void copyMeshToOpenGL(); QOpenGLVertexArrayObject m_vertexArrayObject; QOpenGLBuffer m_buffer; - std::unique_ptr m_mesh; + std::unique_ptr m_mesh; bool m_meshIsDirty = false; QMutex m_meshMutex; int m_meshTriangleVertexCount = 0; diff --git a/application/sources/model_shader_vertex.h b/application/sources/model_opengl_vertex.h similarity index 78% rename from application/sources/model_shader_vertex.h rename to application/sources/model_opengl_vertex.h index 2f925bd4..dae56b17 100644 --- a/application/sources/model_shader_vertex.h +++ b/application/sources/model_opengl_vertex.h @@ -1,5 +1,5 @@ -#ifndef DUST3D_APPLICATION_MODEL_SHADER_VERTEX_H_ -#define DUST3D_APPLICATION_MODEL_SHADER_VERTEX_H_ +#ifndef DUST3D_APPLICATION_MODEL_OPENGL_VERTEX_H_ +#define DUST3D_APPLICATION_MODEL_OPENGL_VERTEX_H_ #include @@ -24,7 +24,7 @@ typedef struct GLfloat tangentY; GLfloat tangentZ; GLfloat alpha = 1.0; -} ModelShaderVertex; +} ModelOpenGLVertex; #pragma pack(pop) #endif diff --git a/application/sources/model_widget.cc b/application/sources/model_widget.cc index 937975ec..04548336 100644 --- a/application/sources/model_widget.cc +++ b/application/sources/model_widget.cc @@ -115,11 +115,11 @@ void ModelWidget::setZRotation(int angle) void ModelWidget::cleanup() { - if (!m_openGLProgram) + if (!m_modelOpenGLProgram) return; makeCurrent(); - m_openGLObject.reset(); - m_openGLProgram.reset(); + m_modelOpenGLObject.reset(); + m_modelOpenGLProgram.reset(); doneCurrent(); } @@ -163,13 +163,13 @@ std::pair ModelWidget::screenPositionToMouseRay(const QPoi void ModelWidget::toggleWireframe() { - // TODO + m_isWireframeVisible = !m_isWireframeVisible; + update(); } bool ModelWidget::isWireframeVisible() { - // TODO - return false; + return m_isWireframeVisible; } void ModelWidget::enableEnvironmentLight() @@ -367,11 +367,20 @@ void ModelWidget::setMousePickRadius(float radius) update(); } -void ModelWidget::updateMesh(Model *mesh) +void ModelWidget::updateMesh(ModelMesh *mesh) { - if (!m_openGLObject) - m_openGLObject = std::make_unique(); - m_openGLObject->update(std::unique_ptr(mesh)); + if (!m_modelOpenGLObject) + m_modelOpenGLObject = std::make_unique(); + m_modelOpenGLObject->update(std::unique_ptr(mesh)); + emit renderParametersChanged(); + update(); +} + +void ModelWidget::updateWireframeMesh(MonochromeMesh *mesh) +{ + if (!m_wireframeOpenGLObject) + m_wireframeOpenGLObject = std::make_unique(); + m_wireframeOpenGLObject->update(std::unique_ptr(mesh)); emit renderParametersChanged(); update(); } @@ -481,20 +490,48 @@ void ModelWidget::paintGL() m_camera.setToIdentity(); m_camera.translate(m_eyePosition.x(), m_eyePosition.y(), m_eyePosition.z()); - if (!m_openGLProgram) { - m_openGLProgram = std::make_unique(); - m_openGLProgram->load(format().profile() == QSurfaceFormat::CoreProfile); + if (!m_modelOpenGLProgram) { + m_modelOpenGLProgram = std::make_unique(); + m_modelOpenGLProgram->load(format().profile() == QSurfaceFormat::CoreProfile); } - m_openGLProgram->bind(); + if (m_isWireframeVisible) { + if (!m_monochromeOpenGLProgram) { + m_monochromeOpenGLProgram = std::make_unique(); + m_monochromeOpenGLProgram->load(format().profile() == QSurfaceFormat::CoreProfile); + } + } - m_openGLProgram->setUniformValue(m_openGLProgram->getUniformLocationByName("eyePosition"), m_eyePosition); - m_openGLProgram->setUniformValue(m_openGLProgram->getUniformLocationByName("projectionMatrix"), m_projection); - m_openGLProgram->setUniformValue(m_openGLProgram->getUniformLocationByName("modelMatrix"), m_world); - m_openGLProgram->setUniformValue(m_openGLProgram->getUniformLocationByName("viewMatrix"), m_camera); + drawModel(); + if (m_isWireframeVisible) + drawWireframe(); +} + +void ModelWidget::drawWireframe() +{ + m_monochromeOpenGLProgram->bind(); + + m_monochromeOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("projectionMatrix"), m_projection); + m_monochromeOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("modelMatrix"), m_world); + m_monochromeOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("viewMatrix"), m_camera); + + if (m_wireframeOpenGLObject) + m_wireframeOpenGLObject->draw(); + + m_monochromeOpenGLProgram->release(); +} + +void ModelWidget::drawModel() +{ + m_modelOpenGLProgram->bind(); + + m_modelOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("eyePosition"), m_eyePosition); + m_modelOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("projectionMatrix"), m_projection); + m_modelOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("modelMatrix"), m_world); + m_modelOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("viewMatrix"), m_camera); if (m_isEnvironmentLightEnabled) { - if (m_openGLProgram->isCoreProfile()) { + if (m_modelOpenGLProgram->isCoreProfile()) { if (!m_environmentIrradianceMap) { DdsFileReader irradianceFile(":/resources/cedar_bridge_irradiance.dds"); m_environmentIrradianceMap.reset(irradianceFile.createOpenGLTexture()); @@ -505,10 +542,10 @@ void ModelWidget::paintGL() } m_environmentIrradianceMap->bind(0); - m_openGLProgram->setUniformValue(m_openGLProgram->getUniformLocationByName("environmentIrradianceMapId"), 0); + m_modelOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("environmentIrradianceMapId"), 0); m_environmentSpecularMap->bind(1); - m_openGLProgram->setUniformValue(m_openGLProgram->getUniformLocationByName("environmentSpecularMapId"), 1); + m_modelOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("environmentSpecularMapId"), 1); } else { if (!m_environmentIrradianceMaps) { DdsFileReader irradianceFile(":/resources/cedar_bridge_irradiance.dds"); @@ -529,14 +566,14 @@ void ModelWidget::paintGL() bindPosition = 0; for (size_t i = 0; i < m_environmentIrradianceMaps->size(); ++i) - m_openGLProgram->setUniformValue(m_openGLProgram->getUniformLocationByName("environmentIrradianceMapId[" + std::to_string(i) + "]"), (int)(bindPosition++)); + m_modelOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("environmentIrradianceMapId[" + std::to_string(i) + "]"), (int)(bindPosition++)); for (size_t i = 0; i < m_environmentSpecularMaps->size(); ++i) - m_openGLProgram->setUniformValue(m_openGLProgram->getUniformLocationByName("environmentSpecularMapId[" + std::to_string(i) + "]"), (int)(bindPosition++)); + m_modelOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("environmentSpecularMapId[" + std::to_string(i) + "]"), (int)(bindPosition++)); } } - if (m_openGLObject) - m_openGLObject->draw(); + if (m_modelOpenGLObject) + m_modelOpenGLObject->draw(); - m_openGLProgram->release(); + m_modelOpenGLProgram->release(); } diff --git a/application/sources/model_widget.h b/application/sources/model_widget.h index 2bc94b68..446a2460 100644 --- a/application/sources/model_widget.h +++ b/application/sources/model_widget.h @@ -10,9 +10,12 @@ #include #include #include -#include "model.h" +#include "model_mesh.h" #include "model_opengl_program.h" #include "model_opengl_object.h" +#include "monochrome_mesh.h" +#include "monochrome_opengl_program.h" +#include "monochrome_opengl_object.h" class ModelWidget : public QOpenGLWidget { @@ -31,7 +34,8 @@ signals: public: ModelWidget(QWidget *parent = 0); ~ModelWidget(); - void updateMesh(Model *mesh); + void updateMesh(ModelMesh *mesh); + void updateWireframeMesh(MonochromeMesh *mesh); void updateColorTexture(QImage *colorTextureImage); void toggleWireframe(); bool isWireframeVisible(); @@ -82,8 +86,10 @@ private: int m_yRot = m_defaultYRotation; int m_zRot = m_defaultZRotation; int m_directionOnMoveStart = 0; - std::unique_ptr m_openGLProgram; - std::unique_ptr m_openGLObject; + std::unique_ptr m_modelOpenGLProgram; + std::unique_ptr m_modelOpenGLObject; + std::unique_ptr m_monochromeOpenGLProgram; + std::unique_ptr m_wireframeOpenGLObject; bool m_moveStarted = false; bool m_moveEnabled = true; bool m_zoomEnabled = true; @@ -108,6 +114,7 @@ private: bool m_enableCullFace = true; bool m_notGraphics = false; bool m_isEnvironmentLightEnabled = false; + bool m_isWireframeVisible = false; std::unique_ptr m_environmentIrradianceMap; std::unique_ptr m_environmentSpecularMap; std::unique_ptr>> m_environmentIrradianceMaps; @@ -116,6 +123,8 @@ private: std::pair screenPositionToMouseRay(const QPoint &screenPosition); void updateProjectionMatrix(); void normalizeAngle(int &angle); + void drawModel(); + void drawWireframe(); public: static int m_defaultXRotation; static int m_defaultYRotation; diff --git a/application/sources/monochrome_mesh.cc b/application/sources/monochrome_mesh.cc new file mode 100644 index 00000000..7e45e8ff --- /dev/null +++ b/application/sources/monochrome_mesh.cc @@ -0,0 +1,58 @@ +#include +#include "monochrome_mesh.h" + +MonochromeMesh::MonochromeMesh(const MonochromeMesh &mesh) +{ + m_lineVertices = mesh.m_lineVertices; +} + +MonochromeMesh::MonochromeMesh(MonochromeMesh &&mesh) +{ + m_lineVertices = std::move(mesh.m_lineVertices); +} + +MonochromeMesh::MonochromeMesh(const dust3d::Object &object) +{ + std::set> halfEdges; + for (const auto &face: object.triangleAndQuads) { + if (3 == face.size()) { + halfEdges.insert({face[0], face[1]}); + halfEdges.insert({face[1], face[0]}); + halfEdges.insert({face[1], face[2]}); + halfEdges.insert({face[2], face[1]}); + halfEdges.insert({face[2], face[0]}); + halfEdges.insert({face[0], face[2]}); + continue; + } + halfEdges.insert({face[0], face[1]}); + halfEdges.insert({face[1], face[0]}); + halfEdges.insert({face[1], face[2]}); + halfEdges.insert({face[2], face[1]}); + halfEdges.insert({face[2], face[3]}); + halfEdges.insert({face[3], face[2]}); + halfEdges.insert({face[3], face[0]}); + halfEdges.insert({face[0], face[3]}); + } + m_lineVertices.reserve(halfEdges.size() * 2); + for (const auto &halfEdge: halfEdges) { + // For two halfedges shared one edge, only output one line + if (halfEdge.first > halfEdge.second) + continue; + const auto &from = object.vertices[halfEdge.first]; + const auto &to = object.vertices[halfEdge.second]; + m_lineVertices.emplace_back(MonochromeOpenGLVertex {(GLfloat)from.x(), (GLfloat)from.y(), (GLfloat)from.z()}); + m_lineVertices.emplace_back(MonochromeOpenGLVertex {(GLfloat)to.x(), (GLfloat)to.y(), (GLfloat)to.z()}); + } +} + +const MonochromeOpenGLVertex *MonochromeMesh::lineVertices() +{ + if (m_lineVertices.empty()) + return nullptr; + return &m_lineVertices[0]; +} + +int MonochromeMesh::lineVertexCount() +{ + return (int)m_lineVertices.size(); +} diff --git a/application/sources/monochrome_mesh.h b/application/sources/monochrome_mesh.h new file mode 100644 index 00000000..bc046bff --- /dev/null +++ b/application/sources/monochrome_mesh.h @@ -0,0 +1,21 @@ +#ifndef DUST3D_APPLICATION_MONOCHROME_MESH_H_ +#define DUST3D_APPLICATION_MONOCHROME_MESH_H_ + +#include +#include +#include "monochrome_opengl_vertex.h" + +class MonochromeMesh +{ +public: + MonochromeMesh(const MonochromeMesh &mesh); + MonochromeMesh(MonochromeMesh &&mesh); + MonochromeMesh(const dust3d::Object &object); + const MonochromeOpenGLVertex *lineVertices(); + int lineVertexCount(); +private: + std::vector m_lineVertices; +}; + +#endif + diff --git a/application/sources/monochrome_opengl_object.cc b/application/sources/monochrome_opengl_object.cc new file mode 100644 index 00000000..2d693e14 --- /dev/null +++ b/application/sources/monochrome_opengl_object.cc @@ -0,0 +1,55 @@ +#include +#include +#include +#include "monochrome_opengl_object.h" + +void MonochromeOpenGLObject::update(std::unique_ptr mesh) +{ + QMutexLocker lock(&m_meshMutex); + m_mesh = std::move(mesh); + m_meshIsDirty = true; +} + +void MonochromeOpenGLObject::draw() +{ + copyMeshToOpenGL(); + if (0 == m_meshLineVertexCount) + return; + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + QOpenGLVertexArrayObject::Binder binder(&m_vertexArrayObject); + f->glDrawArrays(GL_LINES, 0, m_meshLineVertexCount); +} + +void MonochromeOpenGLObject::copyMeshToOpenGL() +{ + std::unique_ptr mesh; + bool meshChanged = false; + if (m_meshIsDirty) { + QMutexLocker lock(&m_meshMutex); + if (m_meshIsDirty) { + m_meshIsDirty = false; + meshChanged = true; + mesh = std::move(m_mesh); + } + } + if (!meshChanged) + return; + m_meshLineVertexCount = 0; + if (mesh) { + QOpenGLVertexArrayObject::Binder binder(&m_vertexArrayObject); + if (m_buffer.isCreated()) + m_buffer.destroy(); + m_buffer.create(); + m_buffer.bind(); + m_buffer.allocate(mesh->lineVertices(), mesh->lineVertexCount() * sizeof(MonochromeOpenGLVertex)); + m_meshLineVertexCount = mesh->lineVertexCount(); + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glEnableVertexAttribArray(0); + f->glEnableVertexAttribArray(1); + f->glEnableVertexAttribArray(2); + f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(MonochromeOpenGLVertex), 0); + f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(MonochromeOpenGLVertex), reinterpret_cast(3 * sizeof(GLfloat))); + f->glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(MonochromeOpenGLVertex), reinterpret_cast(6 * sizeof(GLfloat))); + m_buffer.release(); + } +} \ No newline at end of file diff --git a/application/sources/monochrome_opengl_object.h b/application/sources/monochrome_opengl_object.h new file mode 100644 index 00000000..856799e7 --- /dev/null +++ b/application/sources/monochrome_opengl_object.h @@ -0,0 +1,25 @@ +#ifndef DUST3D_APPLICATION_MONOCHROME_OPENGL_OBJECT_H_ +#define DUST3D_APPLICATION_MONOCHROME_OPENGL_OBJECT_H_ + +#include +#include +#include +#include +#include "monochrome_mesh.h" + +class MonochromeOpenGLObject +{ +public: + void update(std::unique_ptr mesh); + void draw(); +private: + void copyMeshToOpenGL(); + QOpenGLVertexArrayObject m_vertexArrayObject; + QOpenGLBuffer m_buffer; + std::unique_ptr m_mesh; + bool m_meshIsDirty = false; + QMutex m_meshMutex; + int m_meshLineVertexCount = 0; +}; + +#endif diff --git a/application/sources/monochrome_opengl_program.cc b/application/sources/monochrome_opengl_program.cc new file mode 100644 index 00000000..25417d29 --- /dev/null +++ b/application/sources/monochrome_opengl_program.cc @@ -0,0 +1,60 @@ +#include +#include +#include +#include "monochrome_opengl_program.h" + +static const QString &loadShaderSource(const QString &name) +{ + static std::map s_shaderSources; + auto findShader = s_shaderSources.find(name); + if (findShader != s_shaderSources.end()) { + return findShader->second; + } + QFile file(name); + file.open(QFile::ReadOnly | QFile::Text); + QTextStream stream(&file); + auto insertResult = s_shaderSources.insert({name, stream.readAll()}); + return insertResult.first->second; +} + +void MonochromeOpenGLProgram::addShaderFromResource(QOpenGLShader::ShaderType type, const char *resourceName) +{ + if (!addShaderFromSourceCode(type, loadShaderSource(resourceName))) + dust3dDebug << "Failed to addShaderFromResource, resource:" << resourceName << ", " << log().toStdString(); +} + +bool MonochromeOpenGLProgram::isCoreProfile() const +{ + return m_isCoreProfile; +} + +void MonochromeOpenGLProgram::load(bool isCoreProfile) +{ + if (m_isLoaded) + return; + + m_isCoreProfile = isCoreProfile; + if (m_isCoreProfile) { + addShaderFromResource(QOpenGLShader::Vertex, ":/shaders/monochrome_core.vert"); + addShaderFromResource(QOpenGLShader::Fragment, ":/shaders/monochrome_core.frag"); + } else { + addShaderFromResource(QOpenGLShader::Vertex, ":/shaders/monochrome.vert"); + addShaderFromResource(QOpenGLShader::Fragment, ":/shaders/monochrome.frag"); + } + bindAttributeLocation("vertex", 0); + bindAttributeLocation("color", 1); + bindAttributeLocation("alpha", 2); + link(); + bind(); + m_isLoaded = true; +} + +int MonochromeOpenGLProgram::getUniformLocationByName(const std::string &name) +{ + auto findLocation = m_uniformLocationMap.find(name); + if (findLocation != m_uniformLocationMap.end()) + return findLocation->second; + int location = uniformLocation(name.c_str()); + m_uniformLocationMap.insert({name, location}); + return location; +} diff --git a/application/sources/monochrome_opengl_program.h b/application/sources/monochrome_opengl_program.h new file mode 100644 index 00000000..6f6460d4 --- /dev/null +++ b/application/sources/monochrome_opengl_program.h @@ -0,0 +1,22 @@ +#ifndef DUST3D_APPLICATION_MONOCHROME_OPENGL_PROGRAM_H_ +#define DUST3D_APPLICATION_MONOCHROME_OPENGL_PROGRAM_H_ + +#include +#include + +class MonochromeOpenGLProgram: public QOpenGLShaderProgram +{ +public: + void load(bool isCoreProfile=false); + int getUniformLocationByName(const std::string &name); + bool isCoreProfile() const; + +private: + void addShaderFromResource(QOpenGLShader::ShaderType type, const char *resourceName); + + bool m_isLoaded = false; + bool m_isCoreProfile = false; + std::map m_uniformLocationMap; +}; + +#endif diff --git a/application/sources/monochrome_opengl_vertex.h b/application/sources/monochrome_opengl_vertex.h new file mode 100644 index 00000000..50ba04e2 --- /dev/null +++ b/application/sources/monochrome_opengl_vertex.h @@ -0,0 +1,20 @@ +#ifndef DUST3D_APPLICATION_MONOCHROME_OPENGL_VERTEX_H_ +#define DUST3D_APPLICATION_MONOCHROME_OPENGL_VERTEX_H_ + +#include + +#pragma pack(push) +#pragma pack(1) +typedef struct +{ + GLfloat posX; + GLfloat posY; + GLfloat posZ; + GLfloat colorR = 1.0; + GLfloat colorG = 1.0; + GLfloat colorB = 1.0; + GLfloat alpha = 1.0; +} MonochromeOpenGLVertex; +#pragma pack(pop) + +#endif diff --git a/application/sources/part_preview_images_generator.cc b/application/sources/part_preview_images_generator.cc index 7de9a921..c9276f46 100644 --- a/application/sources/part_preview_images_generator.cc +++ b/application/sources/part_preview_images_generator.cc @@ -2,7 +2,7 @@ #include "part_preview_images_generator.h" #include "theme.h" -void PartPreviewImagesGenerator::addPart(const dust3d::Uuid &partId, Model *previewMesh, bool isCutFace) +void PartPreviewImagesGenerator::addPart(const dust3d::Uuid &partId, ModelMesh *previewMesh, bool isCutFace) { m_partPreviews.insert({partId, {previewMesh, isCutFace}}); } diff --git a/application/sources/part_preview_images_generator.h b/application/sources/part_preview_images_generator.h index e281f5bf..3ef16b94 100644 --- a/application/sources/part_preview_images_generator.h +++ b/application/sources/part_preview_images_generator.h @@ -18,7 +18,7 @@ public: struct PreviewInput { - Model *mesh = nullptr; + ModelMesh *mesh = nullptr; bool isCutFace = false; }; @@ -32,7 +32,7 @@ public: delete m_offscreenRender; } - void addPart(const dust3d::Uuid &partId, Model *previewMesh, bool isCutFace); + void addPart(const dust3d::Uuid &partId, ModelMesh *previewMesh, bool isCutFace); void generate(); std::map *takePartImages(); signals: diff --git a/application/sources/skeleton_document.h b/application/sources/skeleton_document.h index 2963ba83..b91a80c1 100644 --- a/application/sources/skeleton_document.h +++ b/application/sources/skeleton_document.h @@ -15,7 +15,7 @@ #include #include #include "theme.h" -#include "model.h" +#include "model_mesh.h" #include "debug.h" class SkeletonNode @@ -388,21 +388,21 @@ public: smooth = other.smooth; hollowThickness = other.hollowThickness; } - void updatePreviewMesh(Model *previewMesh) + void updatePreviewMesh(ModelMesh *previewMesh) { delete m_previewMesh; m_previewMesh = previewMesh; isPreviewMeshObsolete = true; } - Model *takePreviewMesh() const + ModelMesh *takePreviewMesh() const { if (nullptr == m_previewMesh) return nullptr; - return new Model(*m_previewMesh); + return new ModelMesh(*m_previewMesh); } private: Q_DISABLE_COPY(SkeletonPart); - Model *m_previewMesh = nullptr; + ModelMesh *m_previewMesh = nullptr; }; enum class SkeletonDocumentEditMode diff --git a/application/sources/texture_generator.cc b/application/sources/texture_generator.cc index 10cea0fe..4ccaa648 100644 --- a/application/sources/texture_generator.cc +++ b/application/sources/texture_generator.cc @@ -73,9 +73,9 @@ dust3d::Object *TextureGenerator::takeObject() return object; } -Model *TextureGenerator::takeResultMesh() +ModelMesh *TextureGenerator::takeResultMesh() { - Model *resultMesh = m_resultMesh; + ModelMesh *resultMesh = m_resultMesh; m_resultMesh = nullptr; return resultMesh; } @@ -174,7 +174,7 @@ bool TextureGenerator::hasTransparencySettings() void TextureGenerator::generate() { - m_resultMesh = new Model(*m_object); + m_resultMesh = new ModelMesh(*m_object); if (nullptr == m_object->triangleVertexUvs()) return; diff --git a/application/sources/texture_generator.h b/application/sources/texture_generator.h index e84e0933..1c6b1145 100644 --- a/application/sources/texture_generator.h +++ b/application/sources/texture_generator.h @@ -8,7 +8,7 @@ #include #include #include -#include "model.h" +#include "model_mesh.h" class TextureGenerator : public QObject { @@ -22,7 +22,7 @@ public: QImage *takeResultTextureMetalnessImage(); QImage *takeResultTextureAmbientOcclusionImage(); dust3d::Object *takeObject(); - Model *takeResultMesh(); + ModelMesh *takeResultMesh(); bool hasTransparencySettings(); void addPartColorMap(dust3d::Uuid partId, const QImage *image, float tileScale); void addPartNormalMap(dust3d::Uuid partId, const QImage *image, float tileScale); @@ -48,7 +48,7 @@ private: QImage *m_resultTextureRoughnessImage = nullptr; QImage *m_resultTextureMetalnessImage = nullptr; QImage *m_resultTextureAmbientOcclusionImage = nullptr; - Model *m_resultMesh = nullptr; + ModelMesh *m_resultMesh = nullptr; std::map> m_partColorTextureMap; std::map> m_partNormalTextureMap; std::map> m_partMetalnessTextureMap;