ToolBox widget cleanup. (#17)

This commit is contained in:
Shaun Reed 2025-03-23 22:28:41 +00:00
parent d827d02a15
commit f40366cb8d
12 changed files with 296 additions and 149 deletions

View File

@ -57,7 +57,7 @@ endif()
# Allow add_subdirectory on this project to use target ALIAS if available. # Allow add_subdirectory on this project to use target ALIAS if available.
# If this example project is opened standalone we will use find_package. # If this example project is opened standalone we will use find_package.
if(NOT TARGET Qtk::qtk) if(NOT TARGET Qtk::qtk)
find_package(Qtk 0.2 REQUIRED) find_package(Qtk 0.3 REQUIRED)
endif() endif()
find_package(Qt6 COMPONENTS Core Widgets OpenGLWidgets REQUIRED) find_package(Qt6 COMPONENTS Core Widgets OpenGLWidgets REQUIRED)
@ -100,4 +100,4 @@ if((Qt6_VERSION VERSION_GREATER_EQUAL "6.3.0" AND (WIN32 OR APPLE))
install(SCRIPT ${QTK_EXAMPLE_DEPLOY_SCRIPT} COMPONENT qtk_example) install(SCRIPT ${QTK_EXAMPLE_DEPLOY_SCRIPT} COMPONENT qtk_example)
elseif(NOT Qtk_IS_TOP_LEVEL) elseif(NOT Qtk_IS_TOP_LEVEL)
message(WARNING "[Qtk] Installation is only supported on Qt >=6.5.\n") message(WARNING "[Qtk] Installation is only supported on Qt >=6.5.\n")
endif() endif()

View File

@ -222,6 +222,9 @@
</property> </property>
</action> </action>
<action name="actionLoad_Model"> <action name="actionLoad_Model">
<property name="enabled">
<bool>false</bool>
</property>
<property name="icon"> <property name="icon">
<iconset> <iconset>
<normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/solid/cube.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/solid/cube.svg</iconset> <normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/solid/cube.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/solid/cube.svg</iconset>
@ -234,6 +237,9 @@
</property> </property>
</action> </action>
<action name="actionDelete_Object"> <action name="actionDelete_Object">
<property name="enabled">
<bool>false</bool>
</property>
<property name="icon"> <property name="icon">
<iconset> <iconset>
<normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/trash-can.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/trash-can.svg</iconset> <normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/trash-can.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/trash-can.svg</iconset>

View File

@ -482,21 +482,9 @@ void QtkScene::update()
myCube->getTransform().rotate(-0.75f, 0.0f, 1.0f, 0.0f); myCube->getTransform().rotate(-0.75f, 0.0f, 1.0f, 0.0f);
} }
// Helper lambda to set the light position used by GLSL shaders on the model.
// TODO: This could be a helper function on the Model class.
auto setLightPosition = [](const std::string & lightName, Model * model) {
if (auto light = Model::getInstance(lightName.c_str()); light) {
QVector3D position = light->getTransform().getTranslation();
model->setUniform("uLight.position", position);
} else {
qDebug() << "[QtkScene] Failed to set light position: "
<< lightName.c_str();
}
};
QMatrix4x4 posMatrix; QMatrix4x4 posMatrix;
if (auto alien = getModel("alienTest"); alien) { if (auto alien = getModel("alienTest"); alien) {
setLightPosition("alienTestLight", alien); alien->setLightPosition("alienTestLight");
alien->setUniform("uCameraPosition", cameraPosition); alien->setUniform("uCameraPosition", cameraPosition);
posMatrix = alien->getTransform().toMatrix(); posMatrix = alien->getTransform().toMatrix();
@ -508,7 +496,7 @@ void QtkScene::update()
} }
if (auto spartan = getModel("spartanTest"); spartan) { if (auto spartan = getModel("spartanTest"); spartan) {
setLightPosition("spartanTestLight", spartan); spartan->setLightPosition("spartanTestLight");
spartan->setUniform("uCameraPosition", cameraPosition); spartan->setUniform("uCameraPosition", cameraPosition);
posMatrix = spartan->getTransform().toMatrix(); posMatrix = spartan->getTransform().toMatrix();
@ -520,7 +508,7 @@ void QtkScene::update()
} }
if (auto phong = getModel("testPhong"); phong) { if (auto phong = getModel("testPhong"); phong) {
setLightPosition("testLight", phong); phong->setLightPosition("testLight");
phong->getTransform().rotate(0.75f, 1.0f, 0.5f, 0.0f); phong->getTransform().rotate(0.75f, 1.0f, 0.5f, 0.0f);
phong->bindShaders(); phong->bindShaders();

View File

@ -16,20 +16,94 @@
using namespace Qtk; using namespace Qtk;
ToolBox::ToolBox(QWidget * parent) : QDockWidget(parent), ui(new Ui::ToolBox) ToolBox::ToolBox(QWidget * parent) :
QDockWidget(parent), objectDetails_(this), transformPanel_(this),
scalePanel_(this), vertex_(this, "Vertex Shader:"),
fragment_(this, "Fragment Shader:"), properiesForm_(new QFormLayout),
shaderForm_(new QFormLayout), ui(new Ui::ToolBox)
{ {
ui->setupUi(this); ui->setupUi(this);
setMinimumWidth(350); setMinimumWidth(350);
// Object Properties.
ui->page_properties->setLayout(properiesForm_);
properiesForm_->addRow(objectDetails_.name.label, objectDetails_.name.value);
properiesForm_->addRow(objectDetails_.objectType.label,
objectDetails_.objectType.value);
properiesForm_->addRow(reinterpret_cast<QWidget *>(&transformPanel_));
properiesForm_->addRow(reinterpret_cast<QWidget *>(&scalePanel_));
ui->toolBox->setCurrentWidget(ui->page_properties);
// Shader views.
ui->page_shaders->setLayout(shaderForm_);
shaderForm_->addRow(reinterpret_cast<QWidget *>(&vertex_));
shaderForm_->addRow(reinterpret_cast<QWidget *>(&fragment_));
} }
void ToolBox::updateFocus(const QString & name) void ToolBox::updateFocus(const QString & name)
{ {
auto object = auto object =
Qtk::QtkWidget::mWidgetManager.get_widget()->getScene()->getObject(name); QtkWidget::mWidgetManager.get_widget()->getScene()->getObject(name);
if (object != Q_NULLPTR) { if (object != Q_NULLPTR) {
removePages(); refreshProperties(object);
createPageProperties(object); refreshShaders(object);
createPageShader(object); }
}
ToolBox::SpinBox3D::SpinBox3D(QWidget * parent, const char * l) :
QWidget(parent), layout(new QHBoxLayout(this)), label(new QLabel(tr(l)))
{
// The layout owns the widget and will clean it up on destruction.
layout->addWidget(label);
for (const auto & f : fields) {
layout->addWidget(f->spinBox);
f->spinBox->setMinimum(std::numeric_limits<double>::lowest());
f->spinBox->setSingleStep(0.1);
f->spinBox->setFixedWidth(75);
}
}
void ToolBox::SpinBox::disconnect() const
{
Object::disconnect(connection);
}
void ToolBox::TransformPanel::setObject(const Qtk::Object * object)
{
// Reconnect translation panel controls to the new object.
const std::vector binds = {&Object::setTranslationX,
&Object::setTranslationY,
&Object::setTranslationZ};
for (size_t i = 0; i < spinBox3D.fields.size(); i++) {
auto * f = spinBox3D.fields[i];
// Disconnect before changing spin box value.
f->disconnect();
// Set the values in the spin box to the object's current X,Y,Z
f->spinBox->setValue(object->getTransform().getTranslation()[i]);
// Reconnect to bind spin box value to the new object's position.
f->connection =
connect(f->spinBox, &QDoubleSpinBox::valueChanged, object, binds[i]);
}
}
void ToolBox::ScalePanel::setObject(const Qtk::Object * object)
{
// Reconnect scale panel controls to the new object.
const std::vector binds = {
&Object::setScaleX, &Object::setScaleY, &Object::setScaleZ};
for (size_t i = 0; i < spinBox3D.fields.size(); i++) {
auto * f = spinBox3D.fields[i];
// Disconnect before changing spin box value.
f->disconnect();
// Set the values in the spin box to the object's current X,Y,Z
f->spinBox->setValue(object->getTransform().getScale()[i]);
// Reconnect to bind spin box value to the new object's scale.
f->connection =
connect(f->spinBox, &QDoubleSpinBox::valueChanged, object, binds[i]);
} }
} }
@ -38,110 +112,19 @@ ToolBox::~ToolBox()
delete ui; delete ui;
} }
void ToolBox::removePages() void ToolBox::refreshProperties(const Object * object)
{ {
// Remove all existing pages. // Refresh to show the new object's details.
for (size_t i = 0; i < ui->toolBox->count(); i++) { objectDetails_.setObject(object);
delete ui->toolBox->widget(i); // Reconnect transform panel controls to the new object.
ui->toolBox->removeItem(i); transformPanel_.setObject(object);
} scalePanel_.setObject(object);
} }
void ToolBox::createPageProperties(const Object * object) void ToolBox::refreshShaders(const Object * object)
{ {
auto transform = object->getTransform(); vertex_.path.setValue(object->getVertexShader().c_str());
auto type = object->getType(); vertex_.editor->setText(object->getVertexShaderSourceCode().c_str());
auto * widget = new QWidget; fragment_.path.setValue(object->getFragmentShader().c_str());
ui->toolBox->addItem(widget, "Properties"); fragment_.editor->setText(object->getFragmentShaderSourceCode().c_str());
ui->toolBox->setCurrentWidget(widget);
auto * layout = new QFormLayout;
layout->addRow(new QLabel(tr("Name:")),
new QLabel(object->getName().c_str()));
layout->addRow(new QLabel(tr("Type:")),
new QLabel(type == Object::Type::QTK_MESH ? "Mesh" : "Model"));
auto rowLayout = new QHBoxLayout;
rowLayout->addWidget(new QLabel(tr("Translation:")));
int minWidth = 75;
for (size_t i = 0; i < 3; i++) {
auto spinBox = new QDoubleSpinBox;
spinBox->setMinimum(std::numeric_limits<double>::lowest());
spinBox->setSingleStep(0.1);
spinBox->setValue(transform.getTranslation()[i]);
spinBox->setFixedWidth(minWidth);
rowLayout->addWidget(spinBox);
if (i == 0) {
connect(spinBox,
&QDoubleSpinBox::valueChanged,
object,
&Object::setTranslationX);
} else if (i == 1) {
connect(spinBox,
&QDoubleSpinBox::valueChanged,
object,
&Object::setTranslationY);
} else if (i == 2) {
connect(spinBox,
&QDoubleSpinBox::valueChanged,
object,
&Object::setTranslationZ);
}
}
layout->addRow(rowLayout);
rowLayout = new QHBoxLayout;
rowLayout->addWidget(new QLabel(tr("Scale:")));
for (size_t i = 0; i < 3; i++) {
auto spinBox = new QDoubleSpinBox;
spinBox->setMinimum(std::numeric_limits<double>::lowest());
spinBox->setSingleStep(0.1);
spinBox->setValue(transform.getScale()[i]);
spinBox->setFixedWidth(minWidth);
rowLayout->addWidget(spinBox);
if (i == 0) {
connect(
spinBox, &QDoubleSpinBox::valueChanged, object, &Object::setScaleX);
} else if (i == 1) {
connect(
spinBox, &QDoubleSpinBox::valueChanged, object, &Object::setScaleY);
} else if (i == 2) {
connect(
spinBox, &QDoubleSpinBox::valueChanged, object, &Object::setScaleZ);
}
}
layout->addRow(rowLayout);
widget->setLayout(layout);
}
void ToolBox::createPageShader(const Object * object)
{
// Shaders page.
auto widget = new QWidget;
ui->toolBox->addItem(widget, "Shaders");
auto mainLayout = new QFormLayout;
auto rowLayout = new QHBoxLayout;
rowLayout->addWidget(new QLabel("Vertex Shader:"));
rowLayout->addWidget(new QLabel(object->getVertexShader().c_str()));
mainLayout->addRow(rowLayout);
auto shaderView = new QTextEdit;
shaderView->setReadOnly(true);
shaderView->setText(object->getVertexShaderSourceCode().c_str());
mainLayout->addRow(shaderView);
rowLayout = new QHBoxLayout;
rowLayout->addWidget(new QLabel("Fragment Shader:"));
rowLayout->addWidget(new QLabel(object->getFragmentShader().c_str()));
mainLayout->addRow(rowLayout);
shaderView = new QTextEdit;
shaderView->setReadOnly(true);
shaderView->setText(object->getFragmentShaderSourceCode().c_str());
mainLayout->addRow(shaderView);
widget->setLayout(mainLayout);
} }

View File

@ -13,7 +13,10 @@
#include <QDesignerExportWidget> #include <QDesignerExportWidget>
#include <QDockWidget> #include <QDockWidget>
#include <QDoubleSpinBox> #include <QDoubleSpinBox>
#include <QGroupBox> #include <QFormLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QTextEdit>
#include "qtk/scene.h" #include "qtk/scene.h"
@ -25,7 +28,7 @@ namespace Ui
namespace Qtk namespace Qtk
{ {
class ToolBox : public QDockWidget class ToolBox final : public QDockWidget
{ {
Q_OBJECT Q_OBJECT
@ -38,11 +41,9 @@ namespace Qtk
~ToolBox(); ~ToolBox();
void removePages(); void refreshProperties(const Object * object);
void createPageProperties(const Object * object); void refreshShaders(const Object * object);
void createPageShader(const Object * object);
void updateFocus(const QString & name); void updateFocus(const QString & name);
@ -52,6 +53,143 @@ namespace Qtk
* Private Members * Private Members
************************************************************************/ ************************************************************************/
/// Displays details on the object.
struct ObjectDetails {
/// Single item containing a label and value.
struct Item {
explicit Item(QWidget * parent,
const char * l = "Item:",
const char * v = "") :
label(new QLabel(tr(l), parent)),
value(new QLabel(tr(v), parent))
{
}
void setValue(const char * v) { value->setText(tr(v)); }
void setItem(const char * l, const char * v)
{
label->setText(tr(l));
value->setText(tr(v));
}
QLabel * label;
QLabel * value;
};
/// We pass the parent widget so that Qt handles releasing memory.
explicit ObjectDetails(QWidget * parent) :
name(parent, "Name:"), objectType(parent, "Object Type:")
{
}
/// Refresh to display the new object's details
void setObject(const Qtk::Object * object)
{
name.setItem("Name:", object->getName().toStdString().c_str());
objectType.setItem(
"Type:",
object->getType() == Object::QTK_MESH ? "Mesh" : "Model");
}
Item name, objectType;
};
ObjectDetails objectDetails_;
/// Structure to associate a QSpinBox with a connection.
struct SpinBox {
/**
* Default constructor passes no parent to the QSpinBox.
* It must be added to a layout for Qt to clean up the resources.
*/
SpinBox() : spinBox(new QDoubleSpinBox) {}
/// Disconnect the associated connection.
void disconnect() const;
QDoubleSpinBox * spinBox;
QMetaObject::Connection connection;
};
/// Spinbox with 3 fields and a single label.
class SpinBox3D final : QWidget
{
public:
/// We pass a parent to ensure Qt will clean up resources.
/// Assigning a QWidget to a QLayout also ensures Qt will clean up.
explicit SpinBox3D(QWidget * parent, const char * l = "SpinBox3D:");
/// The main layout for the SpinBox3D widget.
QHBoxLayout * layout;
/// Label for the SpinBox3D.
QLabel * label;
/// SpinBox and a connection for each field.
SpinBox x, y, z;
/// Array for iterating over fields.
std::array<SpinBox *, 3> fields {&x, &y, &z};
};
/// Initialize the transform panel and configure QObject connections.
struct TransformPanel {
explicit TransformPanel(QWidget * parent) :
spinBox3D(parent, "Transform:")
{
}
/// Reconnect QObject connections and spin box values in UI.
void setObject(const Qtk::Object * object);
SpinBox3D spinBox3D;
};
TransformPanel transformPanel_;
/// Initialize the scale panel and configure QObject connections.
struct ScalePanel {
explicit ScalePanel(QWidget * parent) : spinBox3D(parent, "Scale:") {}
/// Reconnect QObject connections and spin box values in UI.
void setObject(const Qtk::Object * object);
SpinBox3D spinBox3D;
};
ScalePanel scalePanel_;
/// Displays shader name, path, and read-only text view.
class ShaderView final : QWidget
{
public:
explicit ShaderView(QWidget * parent,
const char * l = "ShaderView:") :
layout(new QVBoxLayout(this)), path(parent, l),
editor(new QTextEdit(parent))
{
// Create a child horizontal layout for shader name and file path.
auto * pathLayout = new QHBoxLayout;
pathLayout->addWidget(path.label);
pathLayout->addWidget(path.value);
layout->addLayout(pathLayout);
// Add the read-only text editor widget to the main layout.
editor->setReadOnly(true);
layout->addWidget(editor);
}
/// The main layout for the ShaderView widget.
QVBoxLayout * layout;
/// Shader name and path on disk.
ObjectDetails::Item path;
/// Read-only (for now) display of the shader source code.
QTextEdit * editor;
};
ShaderView vertex_, fragment_;
QFormLayout * properiesForm_;
QFormLayout * shaderForm_;
Ui::ToolBox * ui; Ui::ToolBox * ui;
}; };
} // namespace Qtk } // namespace Qtk

View File

@ -43,7 +43,7 @@ void Qtk::TreeView::updateView(const Qtk::Scene * scene)
mSceneName = scene->getSceneName(); mSceneName = scene->getSceneName();
auto objects = scene->getObjects(); auto objects = scene->getObjects();
for (const auto & object : objects) { for (const auto & object : objects) {
QStringList list(QStringList(QString(object->getName().c_str()))); QStringList list(QStringList(QString(object->getName())));
ui->treeWidget->insertTopLevelItem(0, new QTreeWidgetItem(list)); ui->treeWidget->insertTopLevelItem(0, new QTreeWidgetItem(list));
} }
} }

View File

@ -45,7 +45,7 @@ MeshRenderer::MeshRenderer(const char * name, const ShapeBase & shape) :
MeshRenderer::~MeshRenderer() MeshRenderer::~MeshRenderer()
{ {
sInstances.remove(mName.c_str()); sInstances.remove(mName);
} }
/******************************************************************************* /*******************************************************************************

View File

@ -56,8 +56,19 @@ void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY)
} }
} }
void Model::setLightPosition(const QString & lightName, const char * uniform)
{
if (auto light = MeshRenderer::getInstance(lightName); light) {
QVector3D position = light->getTransform().getTranslation();
setUniform(uniform, position);
} else {
qDebug() << "[QtkScene] Failed to set " << mName
<< "light position: " << lightName;
}
}
// Static function to access ModelManager for getting Models by name // Static function to access ModelManager for getting Models by name
Model * Qtk::Model::getInstance(const char * name) Model * Model::getInstance(const char * name)
{ {
return mManager[name]; return mManager[name];
} }
@ -102,7 +113,7 @@ void Model::loadModel(const std::string & path)
sortModelMeshes(); sortModelMeshes();
// Object finished loading, insert it into ModelManager // Object finished loading, insert it into ModelManager
mManager.insert(getName().c_str(), this); mManager.insert(getName(), this);
} }
void Model::processNode(aiNode * node, const aiScene * scene) void Model::processNode(aiNode * node, const aiScene * scene)
@ -261,13 +272,11 @@ ModelMesh::Textures Model::loadMaterialTextures(aiMaterial * mat,
void Model::sortModelMeshes() void Model::sortModelMeshes()
{ {
auto cameraPos = Scene::getCamera().getTransform(); auto cameraPos = Scene::getCamera().getTransform().getTranslation();
auto cameraDistance = [&cameraPos](const ModelMesh & a, const ModelMesh & b) { auto cameraDistance = [&cameraPos](const ModelMesh & a, const ModelMesh & b) {
// Sort by the first vertex position in the model // Sort by the first vertex position in the model
return (cameraPos.getTranslation().distanceToPoint( return cameraPos.distanceToPoint(a.mVertices[0].mPosition)
a.mVertices[0].mPosition)) < cameraPos.distanceToPoint(b.mVertices[0].mPosition);
< (cameraPos.getTranslation().distanceToPoint(
b.mVertices[0].mPosition));
}; };
std::sort(mMeshes.begin(), mMeshes.end(), cameraDistance); std::sort(mMeshes.begin(), mMeshes.end(), cameraDistance);
} }

View File

@ -63,7 +63,7 @@ namespace Qtk
loadModel(mModelPath); loadModel(mModelPath);
} }
inline ~Model() override { mManager.remove(getName().c_str()); } inline ~Model() override { mManager.remove(getName()); }
/************************************************************************* /*************************************************************************
* Public Methods * Public Methods
@ -113,6 +113,14 @@ namespace Qtk
} }
} }
/**
* Sets the position of a light used in GLSL unfiroms.
*
* @param lightName Object name of the light
*/
void setLightPosition(const QString & lightName,
const char * uniform = "uLight.position");
/************************************************************************* /*************************************************************************
* Accessors * Accessors
************************************************************************/ ************************************************************************/

View File

@ -100,7 +100,7 @@ namespace Qtk
return mShape.mVertices; return mShape.mVertices;
} }
[[nodiscard]] inline std::string getName() const { return mName; } [[nodiscard]] inline QString getName() const { return mName; }
[[nodiscard]] inline const Type & getType() const { return mType; } [[nodiscard]] inline const Type & getType() const { return mType; }
@ -143,7 +143,7 @@ namespace Qtk
* Setters * Setters
************************************************************************/ ************************************************************************/
virtual inline void setName(const std::string & name) { mName = name; } virtual inline void setName(const QString & name) { mName = name; }
virtual inline void setColors(const Colors & value) virtual inline void setColors(const Colors & value)
{ {
@ -244,6 +244,23 @@ namespace Qtk
mProgram.release(); mProgram.release();
} }
/*************************************************************************
* Public Static Methods
************************************************************************/
/**
* Helper to disconnect a QObject connection, only if it's valid.
* If the connection is valid and we fail to disconnect log a message.
*
* @param con QObject connection handle to disconnect.
*/
static void disconnect(const QMetaObject::Connection & con)
{
if (con && !QObject::disconnect(con)) {
qDebug() << "[Qtk] Failed to disconnect valid connection: " << con;
}
}
private: private:
/************************************************************************* /*************************************************************************
* Private Members * Private Members
@ -255,7 +272,7 @@ namespace Qtk
Transform3D mTransform; Transform3D mTransform;
Shape mShape; Shape mShape;
Texture mTexture; Texture mTexture;
std::string mName; QString mName;
bool mBound; bool mBound;
Type mType = QTK_OBJECT; Type mType = QTK_OBJECT;
}; };

View File

@ -103,7 +103,7 @@ std::vector<Object *> Scene::getObjects() const
Object * Scene::getObject(const QString & name) const Object * Scene::getObject(const QString & name) const
{ {
for (const auto & object : getObjects()) { for (const auto & object : getObjects()) {
if (object->getName() == name.toStdString()) { if (object->getName() == name) {
return object; return object;
} }
} }
@ -121,6 +121,6 @@ void Scene::initSceneObjectName(Object * object)
// If the object name exists make it unique. // If the object name exists make it unique.
auto count = ++mObjectCount[object->getName()]; auto count = ++mObjectCount[object->getName()];
if (count > 1) { if (count > 1) {
object->setName(object->getName() + " (" + std::to_string(count) + ")"); object->setName(object->getName() + " (" + QString::number(count) + ")");
} }
} }

View File

@ -120,9 +120,7 @@ namespace Qtk
*/ */
[[nodiscard]] uint64_t getObjectCount(const QString & name) [[nodiscard]] uint64_t getObjectCount(const QString & name)
{ {
return mObjectCount.count(name.toStdString()) return mObjectCount.count(name) ? mObjectCount[name] : 0;
? mObjectCount[name.toStdString()]
: 0;
} }
/** /**
@ -248,7 +246,7 @@ namespace Qtk
/* MeshRenderers used simple geometry. */ /* MeshRenderers used simple geometry. */
std::vector<MeshRenderer *> mMeshes {}; std::vector<MeshRenderer *> mMeshes {};
/* Track count of objects with same initial name. */ /* Track count of objects with same initial name. */
std::unordered_map<std::string, uint64_t> mObjectCount; std::unordered_map<QString, uint64_t> mObjectCount;
}; };
} // namespace Qtk } // namespace Qtk