ToolBox widget cleanup. (#17)
This commit is contained in:
		
							parent
							
								
									d827d02a15
								
							
						
					
					
						commit
						f40366cb8d
					
				@ -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)
 | 
				
			||||||
 | 
				
			|||||||
@ -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>
 | 
				
			||||||
 | 
				
			|||||||
@ -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();
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
				
			||||||
 | 
				
			|||||||
@ -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));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -45,7 +45,7 @@ MeshRenderer::MeshRenderer(const char * name, const ShapeBase & shape) :
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
MeshRenderer::~MeshRenderer()
 | 
					MeshRenderer::~MeshRenderer()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  sInstances.remove(mName.c_str());
 | 
					  sInstances.remove(mName);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*******************************************************************************
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
				
			||||||
       ************************************************************************/
 | 
					       ************************************************************************/
 | 
				
			||||||
 | 
				
			|||||||
@ -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;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
				
			|||||||
@ -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) + ")");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user