mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
add a simple domain baker to enumerate models.json.gz
This commit is contained in:
parent
074fb08313
commit
177d4d0e07
7 changed files with 391 additions and 2 deletions
111
tools/oven/src/DomainBaker.cpp
Normal file
111
tools/oven/src/DomainBaker.cpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
//
|
||||
// DomainBaker.cpp
|
||||
// tools/oven/src
|
||||
//
|
||||
// Created by Stephen Birarda on 4/12/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
|
||||
#include "Gzip.h"
|
||||
|
||||
#include "DomainBaker.h"
|
||||
|
||||
DomainBaker::DomainBaker(const QUrl& localModelFileURL, QString baseOutputPath) :
|
||||
_localEntitiesFileURL(localModelFileURL),
|
||||
_baseOutputPath(baseOutputPath)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DomainBaker::start() {
|
||||
loadLocalFile();
|
||||
enumerateEntities();
|
||||
}
|
||||
|
||||
void DomainBaker::loadLocalFile() {
|
||||
// load up the local entities file
|
||||
QFile modelsFile { _localEntitiesFileURL.toLocalFile() };
|
||||
|
||||
if (!modelsFile.open(QIODevice::ReadOnly)) {
|
||||
// add an error to our list to specify that the file could not be read
|
||||
|
||||
// return to stop processing
|
||||
return;
|
||||
}
|
||||
|
||||
// grab a byte array from the file
|
||||
auto fileContents = modelsFile.readAll();
|
||||
|
||||
// check if we need to inflate a gzipped models file or if this was already decompressed
|
||||
static const QString GZIPPED_ENTITIES_FILE_SUFFIX = "gz";
|
||||
if (QFileInfo(_localEntitiesFileURL.toLocalFile()).suffix() == "gz") {
|
||||
// this was a gzipped models file that we need to decompress
|
||||
QByteArray uncompressedContents;
|
||||
gunzip(fileContents, uncompressedContents);
|
||||
fileContents = uncompressedContents;
|
||||
}
|
||||
|
||||
// read the file contents to a JSON document
|
||||
auto jsonDocument = QJsonDocument::fromJson(fileContents);
|
||||
|
||||
// grab the entities object from the root JSON object
|
||||
_entities = jsonDocument.object()["Entities"].toArray();
|
||||
|
||||
if (_entities.isEmpty()) {
|
||||
// add an error to our list stating that the models file was empty
|
||||
|
||||
// return to stop processing
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void DomainBaker::enumerateEntities() {
|
||||
qDebug() << "Enumerating" << _entities.size() << "entities from domain";
|
||||
|
||||
foreach(QJsonValue entityValue, _entities) {
|
||||
// make sure this is a JSON object
|
||||
if (entityValue.isObject()) {
|
||||
auto entity = entityValue.toObject();
|
||||
|
||||
// check if this is an entity with a model URL
|
||||
static const QString ENTITY_MODEL_URL_KEY = "modelURL";
|
||||
if (entity.contains(ENTITY_MODEL_URL_KEY)) {
|
||||
// grab a QUrl for the model URL
|
||||
auto modelURL = QUrl(entity[ENTITY_MODEL_URL_KEY].toString());
|
||||
|
||||
// check if the file pointed to by this URL is a bakeable model, by comparing extensions
|
||||
auto modelFileName = modelURL.fileName();
|
||||
|
||||
static const QStringList BAKEABLE_MODEL_EXTENSIONS { ".fbx" };
|
||||
auto completeLowerExtension = modelFileName.mid(modelFileName.indexOf('.')).toLower();
|
||||
|
||||
if (BAKEABLE_MODEL_EXTENSIONS.contains(completeLowerExtension)) {
|
||||
// grab a clean version of the URL without a query or fragment
|
||||
modelURL.setFragment("");
|
||||
modelURL.setQuery("");
|
||||
|
||||
// setup an FBXBaker for this URL, as long as we don't already have one
|
||||
if (!_bakers.contains(modelURL)) {
|
||||
QSharedPointer<FBXBaker> baker { new FBXBaker(modelURL, _baseOutputPath) };
|
||||
|
||||
// start the baker
|
||||
baker->start();
|
||||
|
||||
// insert it into our bakers hash so we hold a strong pointer to it
|
||||
_bakers.insert(modelURL, baker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
tools/oven/src/DomainBaker.h
Normal file
44
tools/oven/src/DomainBaker.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// DomainBaker.h
|
||||
// tools/oven/src
|
||||
//
|
||||
// Created by Stephen Birarda on 4/12/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_DomainBaker_h
|
||||
#define hifi_DomainBaker_h
|
||||
|
||||
#include <QtCore/QJsonArray>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QUrl>
|
||||
|
||||
#include <FBXBaker.h>
|
||||
|
||||
class DomainBaker : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DomainBaker(const QUrl& localEntitiesFileURL, QString baseOutputPath);
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
private:
|
||||
void loadLocalFile();
|
||||
void enumerateEntities();
|
||||
|
||||
QUrl _localEntitiesFileURL;
|
||||
QString _baseOutputPath;
|
||||
QJsonArray _entities;
|
||||
|
||||
|
||||
QHash<QUrl, QSharedPointer<FBXBaker>> _bakers;
|
||||
};
|
||||
|
||||
#endif // hifi_DomainBaker_h
|
177
tools/oven/src/ui/DomainBakeWidget.cpp
Normal file
177
tools/oven/src/ui/DomainBakeWidget.cpp
Normal file
|
@ -0,0 +1,177 @@
|
|||
//
|
||||
// DomainBakeWidget.cpp
|
||||
// tools/oven/src/ui
|
||||
//
|
||||
// Created by Stephen Birarda on 4/12/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QGridLayout>
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QLineEdit>
|
||||
#include <QtWidgets/QPushButton>
|
||||
#include <QtWidgets/QStackedWidget>
|
||||
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "DomainBakeWidget.h"
|
||||
|
||||
static const QString EXPORT_DIR_SETTING_KEY = "domain_export_directory";
|
||||
static const QString BROWSE_START_DIR_SETTING_KEY = "domain_search_directory";
|
||||
|
||||
DomainBakeWidget::DomainBakeWidget(QWidget* parent, Qt::WindowFlags flags) :
|
||||
QWidget(parent, flags),
|
||||
_exportDirectory(EXPORT_DIR_SETTING_KEY),
|
||||
_browseStartDirectory(BROWSE_START_DIR_SETTING_KEY)
|
||||
{
|
||||
setupUI();
|
||||
}
|
||||
|
||||
void DomainBakeWidget::setupUI() {
|
||||
// setup a grid layout to hold everything
|
||||
QGridLayout* gridLayout = new QGridLayout;
|
||||
|
||||
int rowIndex = 0;
|
||||
|
||||
// setup a section to choose the file being baked
|
||||
QLabel* entitiesFileLabel = new QLabel("Entities File");
|
||||
|
||||
_entitiesFileLineEdit = new QLineEdit;
|
||||
_entitiesFileLineEdit->setPlaceholderText("File or URL");
|
||||
|
||||
QPushButton* chooseFileButton = new QPushButton("Browse...");
|
||||
connect(chooseFileButton, &QPushButton::clicked, this, &DomainBakeWidget::chooseFileButtonClicked);
|
||||
|
||||
// add the components for the entities file picker to the layout
|
||||
gridLayout->addWidget(entitiesFileLabel, rowIndex, 0);
|
||||
gridLayout->addWidget(_entitiesFileLineEdit, rowIndex, 1, 1, 3);
|
||||
gridLayout->addWidget(chooseFileButton, rowIndex, 4);
|
||||
|
||||
// start a new row for next component
|
||||
++rowIndex;
|
||||
|
||||
// setup a section to choose the output directory
|
||||
QLabel* outputDirectoryLabel = new QLabel("Output Directory");
|
||||
|
||||
_outputDirLineEdit = new QLineEdit;
|
||||
|
||||
// set the current export directory to whatever was last used
|
||||
_outputDirLineEdit->setText(_exportDirectory.get());
|
||||
|
||||
// whenever the output directory line edit changes, update the value in settings
|
||||
connect(_outputDirLineEdit, &QLineEdit::textChanged, this, &DomainBakeWidget::outputDirectoryChanged);
|
||||
|
||||
QPushButton* chooseOutputDirectoryButton = new QPushButton("Browse...");
|
||||
connect(chooseOutputDirectoryButton, &QPushButton::clicked, this, &DomainBakeWidget::chooseOutputDirButtonClicked);
|
||||
|
||||
// add the components for the output directory picker to the layout
|
||||
gridLayout->addWidget(outputDirectoryLabel, rowIndex, 0);
|
||||
gridLayout->addWidget(_outputDirLineEdit, rowIndex, 1, 1, 3);
|
||||
gridLayout->addWidget(chooseOutputDirectoryButton, rowIndex, 4);
|
||||
|
||||
// start a new row for the next component
|
||||
++rowIndex;
|
||||
|
||||
// add a horizontal line to split the bake/cancel buttons off
|
||||
QFrame* lineFrame = new QFrame;
|
||||
lineFrame->setFrameShape(QFrame::HLine);
|
||||
lineFrame->setFrameShadow(QFrame::Sunken);
|
||||
gridLayout->addWidget(lineFrame, rowIndex, 0, 1, -1);
|
||||
|
||||
// start a new row for the next component
|
||||
++rowIndex;
|
||||
|
||||
// add a button that will kickoff the bake
|
||||
QPushButton* bakeButton = new QPushButton("Bake");
|
||||
connect(bakeButton, &QPushButton::clicked, this, &DomainBakeWidget::bakeButtonClicked);
|
||||
gridLayout->addWidget(bakeButton, rowIndex, 3);
|
||||
|
||||
// add a cancel button to go back to the modes page
|
||||
QPushButton* cancelButton = new QPushButton("Cancel");
|
||||
connect(cancelButton, &QPushButton::clicked, this, &DomainBakeWidget::cancelButtonClicked);
|
||||
gridLayout->addWidget(cancelButton, rowIndex, 4);
|
||||
|
||||
setLayout(gridLayout);
|
||||
}
|
||||
|
||||
void DomainBakeWidget::chooseFileButtonClicked() {
|
||||
// pop a file dialog so the user can select the entities file
|
||||
|
||||
// if we have picked an FBX before, start in the folder that matches the last path
|
||||
// otherwise start in the home directory
|
||||
auto startDir = _browseStartDirectory.get();
|
||||
if (startDir.isEmpty()) {
|
||||
startDir = QDir::homePath();
|
||||
}
|
||||
|
||||
auto selectedFile = QFileDialog::getOpenFileName(this, "Choose Entities File", startDir);
|
||||
|
||||
if (!selectedFile.isEmpty()) {
|
||||
// set the contents of the entities file text box to be the path to the selected file
|
||||
_entitiesFileLineEdit->setText(selectedFile);
|
||||
|
||||
auto directoryOfEntitiesFile = QFileInfo(selectedFile).absolutePath();
|
||||
|
||||
// save the directory containing this entities file so we can default to it next time we show the file dialog
|
||||
_browseStartDirectory.set(directoryOfEntitiesFile);
|
||||
|
||||
// if our output directory is not yet set, set it to the directory of this entities file
|
||||
_outputDirLineEdit->setText(directoryOfEntitiesFile);
|
||||
}
|
||||
}
|
||||
|
||||
void DomainBakeWidget::chooseOutputDirButtonClicked() {
|
||||
// pop a file dialog so the user can select the output directory
|
||||
|
||||
// if we have a previously selected output directory, use that as the initial path in the choose dialog
|
||||
// otherwise use the user's home directory
|
||||
auto startDir = _exportDirectory.get();
|
||||
if (startDir.isEmpty()) {
|
||||
startDir = QDir::homePath();
|
||||
}
|
||||
|
||||
auto selectedDir = QFileDialog::getExistingDirectory(this, "Choose Output Directory", startDir);
|
||||
|
||||
if (!selectedDir.isEmpty()) {
|
||||
// set the contents of the output directory text box to be the path to the directory
|
||||
_outputDirLineEdit->setText(selectedDir);
|
||||
}
|
||||
}
|
||||
|
||||
void DomainBakeWidget::outputDirectoryChanged(const QString& newDirectory) {
|
||||
// update the export directory setting so we can re-use it next time
|
||||
_exportDirectory.set(newDirectory);
|
||||
}
|
||||
|
||||
void DomainBakeWidget::bakeButtonClicked() {
|
||||
// make sure we have a valid output directory
|
||||
QDir outputDirectory(_outputDirLineEdit->text());
|
||||
|
||||
if (!outputDirectory.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure we have a non empty URL to an entities file to bake
|
||||
if (!_entitiesFileLineEdit->text().isEmpty()) {
|
||||
// everything seems to be in place, kick off a bake for this entities file now
|
||||
auto fileToBakeURL = QUrl::fromLocalFile(_entitiesFileLineEdit->text());
|
||||
_baker = std::unique_ptr<DomainBaker> { new DomainBaker(fileToBakeURL, outputDirectory.absolutePath()) };
|
||||
_baker->start();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void DomainBakeWidget::cancelButtonClicked() {
|
||||
// the user wants to go back to the mode selection screen
|
||||
// remove ourselves from the stacked widget and call delete later so we'll be cleaned up
|
||||
auto stackedWidget = qobject_cast<QStackedWidget*>(parentWidget());
|
||||
stackedWidget->removeWidget(this);
|
||||
|
||||
this->deleteLater();
|
||||
}
|
49
tools/oven/src/ui/DomainBakeWidget.h
Normal file
49
tools/oven/src/ui/DomainBakeWidget.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// DomainBakeWidget.h
|
||||
// tools/oven/src/ui
|
||||
//
|
||||
// Created by Stephen Birarda on 4/12/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_DomainBakeWidget_h
|
||||
#define hifi_DomainBakeWidget_h
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
#include <SettingHandle.h>
|
||||
|
||||
#include "../DomainBaker.h"
|
||||
|
||||
class QLineEdit;
|
||||
|
||||
class DomainBakeWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DomainBakeWidget(QWidget* parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
|
||||
|
||||
private slots:
|
||||
void chooseFileButtonClicked();
|
||||
void chooseOutputDirButtonClicked();
|
||||
void bakeButtonClicked();
|
||||
void cancelButtonClicked();
|
||||
|
||||
void outputDirectoryChanged(const QString& newDirectory);
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
|
||||
std::unique_ptr<DomainBaker> _baker;
|
||||
|
||||
QLineEdit* _entitiesFileLineEdit;
|
||||
QLineEdit* _outputDirLineEdit;
|
||||
|
||||
Setting::Handle<QString> _exportDirectory;
|
||||
Setting::Handle<QString> _browseStartDirectory;
|
||||
};
|
||||
|
||||
#endif // hifi_ModelBakeWidget_h
|
|
@ -42,8 +42,6 @@ private:
|
|||
QLineEdit* _modelLineEdit;
|
||||
QLineEdit* _outputDirLineEdit;
|
||||
|
||||
QUrl modelToBakeURL;
|
||||
|
||||
Setting::Handle<QString> _exportDirectory;
|
||||
Setting::Handle<QString> _modelStartDirectory;
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <QtWidgets/QPushButton>
|
||||
#include <QtWidgets/QStackedWidget>
|
||||
|
||||
#include "DomainBakeWidget.h"
|
||||
#include "ModelBakeWidget.h"
|
||||
|
||||
#include "ModesWidget.h"
|
||||
|
@ -34,6 +35,7 @@ void ModesWidget::setupUI() {
|
|||
|
||||
// add a button for domain baking
|
||||
QPushButton* domainButton = new QPushButton("Bake Domain");
|
||||
connect(domainButton, &QPushButton::clicked, this, &ModesWidget::showDomainBakingWidget);
|
||||
horizontalLayout->addWidget(domainButton);
|
||||
|
||||
// add a button for texture baking
|
||||
|
@ -49,3 +51,10 @@ void ModesWidget::showModelBakingWidget() {
|
|||
// add a new widget for making baking to the stack, and switch to it
|
||||
stackedWidget->setCurrentIndex(stackedWidget->addWidget(new ModelBakeWidget));
|
||||
}
|
||||
|
||||
void ModesWidget::showDomainBakingWidget() {
|
||||
auto stackedWidget = qobject_cast<QStackedWidget*>(parentWidget());
|
||||
|
||||
// add a new widget for making baking to the stack, and switch to it
|
||||
stackedWidget->setCurrentIndex(stackedWidget->addWidget(new DomainBakeWidget));
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ public:
|
|||
|
||||
private slots:
|
||||
void showModelBakingWidget();
|
||||
void showDomainBakingWidget();
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
|
|
Loading…
Reference in a new issue