diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index adc5bb1b71..dbb2170150 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -81,6 +81,8 @@ const int STARTUP_JITTER_SAMPLES = PACKET_LENGTH_SAMPLES_PER_CHANNEL / 2; // Startup optimistically with small jitter buffer that // will start playback on the second received audio packet. +static const float CLIPBOARD_TREE_SCALE = 1.0f; + void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message) { fprintf(stdout, "%s", message.toLocal8Bit().constData()); LogDisplay::instance.addMessage(message.toLocal8Bit().constData()); @@ -94,6 +96,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _frameCount(0), _fps(120.0f), _justStarted(true), + _clipboard(CLIPBOARD_TREE_SCALE), + _voxelImporter(_window), _wantToKillLocalVoxels(false), _audioScope(256, 200, true), _mouseX(0), @@ -125,7 +129,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _packetsPerSecond(0), _bytesPerSecond(0), _bytesCount(0), - _swatch(NULL) + _swatch(NULL), + _pasteMode(false) { _applicationStartupTime = startup_time; _window->setWindowTitle("Interface"); @@ -810,6 +815,10 @@ void Application::mousePressEvent(QMouseEvent* event) { _pieMenu.mousePressEvent(_mouseX, _mouseY); } + if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode) && _pasteMode) { + pasteVoxels(); + } + if (MAKE_SOUND_ON_VOXEL_CLICK && _isHoverVoxel && !_isHoverVoxelSounding) { _hoverVoxelOriginalColor[0] = _hoverVoxel.red; _hoverVoxelOriginalColor[1] = _hoverVoxel.green; @@ -1187,185 +1196,27 @@ void Application::exportVoxels() { _window->activateWindow(); } -const char* IMPORT_FILE_TYPES = "Sparse Voxel Octree Files, Square PNG, Schematic Files (*.svo *.png *.schematic)"; -void Application::importVoxelsToClipboard() { - QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); - QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels to Clipboard"), desktopLocation, - tr(IMPORT_FILE_TYPES)); - - QByteArray fileNameAscii = fileNameString.toLocal8Bit(); - const char* fileName = fileNameAscii.data(); - - _clipboardTree.eraseAllVoxels(); - if (fileNameString.endsWith(".png", Qt::CaseInsensitive)) { - QImage pngImage = QImage(fileName); - if (pngImage.height() != pngImage.width()) { - qDebug("ERROR: Bad PNG size: height != width.\n"); - return; - } - - const uint32_t* pixels; - if (pngImage.format() == QImage::Format_ARGB32) { - pixels = reinterpret_cast(pngImage.constBits()); - } else { - QImage tmp = pngImage.convertToFormat(QImage::Format_ARGB32); - pixels = reinterpret_cast(tmp.constBits()); - } - _clipboardTree.readFromSquareARGB32Pixels(pixels, pngImage.height()); - } else if (fileNameString.endsWith(".svo", Qt::CaseInsensitive)) { - _clipboardTree.readFromSVOFile(fileName); - } else if (fileNameString.endsWith(".schematic", Qt::CaseInsensitive)) { - _clipboardTree.readFromSchematicFile(fileName); - } - - // restore the main window's active state - _window->activateWindow(); -} - void Application::importVoxels() { - QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); + _pasteMode = false; - QStringList fileNameStringList = QFileDialog::getOpenFileNames(_glWidget, tr("Import Voxels"), desktopLocation, - tr(IMPORT_FILE_TYPES)); + if (_voxelImporter.exec()) { + qDebug("[DEBUG] Import succedded.\n"); - - // remember the "selected" voxel point before we do any importing... - float originalX = _mouseVoxel.x; - float originalZ = _mouseVoxel.z; - - const int PNG_TYPE_NAME_LENGTH = 4; - const int SVO_TYPE_NAME_LENGTH = 4; - const int SCH_TYPE_NAME_LENGTH = 10; - - // assume this is where we'll place it if filename doesn't have tiling - int unspecifiedColumnNum = 1; - int unspecifiedRowNum = 1; - - // if they select multiple files, but they don't specify the tiling, we - // will tile them to this size - int unspecifiedSquare = (sqrt(fileNameStringList.size()) + 0.5); - qDebug("unspecifiedSquare: %d\n", unspecifiedSquare); - - for (int i = 0; i < fileNameStringList.size(); i++) { - QString fileNameString = fileNameStringList.at(i); - QString extension; - QByteArray fileNameAscii = fileNameString.toLocal8Bit(); - const char* fileName = fileNameAscii.data(); - - int fileTypeNameLength = 0; - VoxelTree importVoxels; - if (fileNameString.endsWith(".png", Qt::CaseInsensitive)) { - extension = QString(".png"); - QImage pngImage = QImage(fileName); - fileTypeNameLength = PNG_TYPE_NAME_LENGTH; - if (pngImage.height() != pngImage.width()) { - qDebug("ERROR: Bad PNG size: height != width.\n"); - return; - } - - const uint32_t* pixels; - if (pngImage.format() == QImage::Format_ARGB32) { - pixels = reinterpret_cast(pngImage.constBits()); - } else { - QImage tmp = pngImage.convertToFormat(QImage::Format_ARGB32); - pixels = reinterpret_cast(tmp.constBits()); - } - - importVoxels.readFromSquareARGB32Pixels(pixels, pngImage.height()); - } else if (fileNameString.endsWith(".svo", Qt::CaseInsensitive)) { - extension = QString(".svo"); - importVoxels.readFromSVOFile(fileName); - fileTypeNameLength = SVO_TYPE_NAME_LENGTH; - } else if (fileNameString.endsWith(".schematic", Qt::CaseInsensitive)) { - extension = QString(".schematic"); - importVoxels.readFromSchematicFile(fileName); - fileTypeNameLength = SCH_TYPE_NAME_LENGTH; - } - - // Where we plan to place this - int columnNum = 1; - int rowNum = 1; - bool isTileLocationUnspecified = false; - - // If we're in multi-file mode, then look for tiling specification in the file name - if (fileNameStringList.size() > 1) { - int indexOfFirstPeriod = fileNameString.indexOf('.'); - - //qDebug("indexOfFirstPeriod: %d\n", indexOfFirstPeriod); - - // If the first period, is the extension, then this is not a grid name; - if (fileNameString.mid(indexOfFirstPeriod, fileNameString.length() - indexOfFirstPeriod) == extension) { - qDebug("not a valid grid name... treat like tile Location Unspecified\n"); - isTileLocationUnspecified = true; - } else { - QString fileCoord = fileNameString.mid(indexOfFirstPeriod + 1, - fileNameString.length() - indexOfFirstPeriod - fileTypeNameLength - 1); - - //qDebug() << "fileCoord: " << fileCoord << "\n"; - indexOfFirstPeriod = fileCoord.indexOf('.'); - - //qDebug("indexOfFirstPeriod: %d\n", indexOfFirstPeriod); - - QString columnNumString = fileCoord.right(fileCoord.length() - indexOfFirstPeriod - 1); - QString rowNumString = fileCoord.left(indexOfFirstPeriod); - - //qDebug() << "columnNumString: " << columnNumString << "\n"; - //qDebug() << "rowNumString: " << rowNumString << "\n"; - - columnNum = columnNumString.toFloat(); - rowNum = rowNumString.toFloat(); - - // If there are no "grid sections" in the filename, then we're going to get - if (columnNum < 1 || rowNum < 1) { - qDebug("not a valid grid name... treat like tile Location Unspecified\n"); - isTileLocationUnspecified = true; - } - } - } - - if (isTileLocationUnspecified) { - qDebug("tile Location is Unspecified... \n"); - columnNum = unspecifiedColumnNum; - rowNum = unspecifiedRowNum; - - unspecifiedColumnNum++; - if (unspecifiedColumnNum > unspecifiedSquare) { - unspecifiedColumnNum = 1; - unspecifiedRowNum++; - } - } - qDebug("columnNum: %d\t rowNum: %d\n", columnNum, rowNum); - - _mouseVoxel.x = originalX + (columnNum - 1) * _mouseVoxel.s; - _mouseVoxel.z = originalZ + (rowNum - 1) * _mouseVoxel.s; - - VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - - // Recurse the Import Voxels tree, where everything is root relative, and send all the colored voxels to - // the server as an set voxel message, this will also rebase the voxels to the new location - unsigned char* calculatedOctCode = NULL; - SendVoxelsOperationArgs args; - - // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the - // voxel size/position details. - if (selectedNode) { - args.newBaseOctCode = selectedNode->getOctalCode(); + if (_voxelImporter.getimportIntoClipboard()) { + _clipboard.killLocalVoxels(); + _voxelImporter.getVoxelSystem()->copySubTreeIntoNewTree( + _voxelImporter.getVoxelSystem()->getVoxelAt(0, 0, 0, 1), + &_clipboard, + true); } else { - args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - } - - qDebug("column:%d, row:%d, voxel:%f,%f,%f,%f\n", columnNum, rowNum, _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s ); - - // send the insert/paste of these voxels - importVoxels.recurseTreeWithOperation(sendVoxelsOperation, &args); - _voxelEditSender.flushQueue(); - - if (calculatedOctCode) { - delete[] calculatedOctCode; + _pasteMode = true; } + + } else { + qDebug("[DEBUG] Import failed.\n"); } - + // restore the main window's active state _window->activateWindow(); } @@ -1379,11 +1230,17 @@ void Application::copyVoxels() { VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode) { // clear the clipboard first... - _clipboardTree.eraseAllVoxels(); + _clipboard.killLocalVoxels(); // then copy onto it - _voxels.copySubTreeIntoNewTree(selectedNode, &_clipboardTree, true); + _voxels.copySubTreeIntoNewTree(selectedNode, &_clipboard, true); } + + _pasteMode = false; +} + +void Application::togglePasteMode() { + _pasteMode = !_pasteMode; } void Application::pasteVoxels() { @@ -1403,7 +1260,12 @@ void Application::pasteVoxels() { args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); } - _clipboardTree.recurseTreeWithOperation(sendVoxelsOperation, &args); + if (_voxelImporter.getImportWaiting()) { + _voxelImporter.getVoxelSystem()->recurseTreeWithOperation(sendVoxelsOperation, &args); + _voxelImporter.reset(); + } else { + _clipboard.recurseTreeWithOperation(sendVoxelsOperation, &args); + } _voxelEditSender.flushQueue(); if (calculatedOctCode) { @@ -1445,6 +1307,10 @@ void Application::initDisplay() { void Application::init() { _voxels.init(); + _clipboard.init(); + _clipboardViewFrustum.setKeyholeRadius(1000.0f); + _clipboardViewFrustum.calculate(); + _clipboard.setViewFrustum(&_clipboardViewFrustum); _environment.init(); @@ -2331,6 +2197,23 @@ void Application::displaySide(Camera& whichCamera) { glEnable(GL_LIGHTING); } + if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode) && _pasteMode) { + glPushMatrix(); + glTranslatef(_mouseVoxel.x * TREE_SCALE, + _mouseVoxel.y * TREE_SCALE, + _mouseVoxel.z * TREE_SCALE); + glScalef(_mouseVoxel.s * TREE_SCALE, + _mouseVoxel.s * TREE_SCALE, + _mouseVoxel.s * TREE_SCALE); + + if (_voxelImporter.getImportWaiting()) { + _voxelImporter.getVoxelSystem()->render(true); + } else { + _clipboard.render(true); + } + glPopMatrix(); + } + _myAvatar.renderScreenTint(SCREEN_TINT_BEFORE_AVATARS, whichCamera); if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) { @@ -2399,7 +2282,7 @@ void Application::displaySide(Camera& whichCamera) { } renderFollowIndicator(); - + // render the glow effect _glowEffect.render(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 51606ce75a..a4ae01b730 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -42,6 +42,7 @@ #include "VoxelEditPacketSender.h" #include "VoxelPacketProcessor.h" #include "VoxelSystem.h" +#include "VoxelImporter.h" #include "Webcam.h" #include "avatar/Avatar.h" #include "avatar/HandControl.h" @@ -138,9 +139,9 @@ public slots: void sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data); void exportVoxels(); void importVoxels(); - void importVoxelsToClipboard(); void cutVoxels(); void copyVoxels(); + void togglePasteMode(); void pasteVoxels(); void setRenderVoxels(bool renderVoxels); @@ -238,8 +239,10 @@ private: Stars _stars; - VoxelSystem _voxels; - VoxelTree _clipboardTree; // if I copy/paste + VoxelSystem _voxels; + VoxelSystem _clipboard; // if I copy/paste + ViewFrustum _clipboardViewFrustum; + VoxelImporter _voxelImporter; QByteArray _voxelsFilename; bool _wantToKillLocalVoxels; @@ -341,6 +344,8 @@ private: ToolsPalette _palette; Swatch _swatch; + bool _pasteMode; + PieMenu _pieMenu; VoxelSceneStats _voxelSceneStats; diff --git a/interface/src/ImportDialog.cpp b/interface/src/ImportDialog.cpp new file mode 100644 index 0000000000..9c6653cc8a --- /dev/null +++ b/interface/src/ImportDialog.cpp @@ -0,0 +1,260 @@ +// +// ImportDialog.cpp +// hifi +// +// Created by Clement Brisset on 8/12/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +#include "ImportDialog.h" +#include "Application.h" + +#include +#include +#include + +const QString WINDOW_NAME = QObject::tr("Import Voxels"); +const QString IMPORT_BUTTON_NAME = QObject::tr("Import"); +const QString IMPORT_TO_CLIPBOARD_CHECKBOX_STRING = QObject::tr("Import into clipboard"); +const QString PREVIEW_CHECKBOX_STRING = QObject::tr("Load preview"); +const QString IMPORT_FILE_TYPES = QObject::tr("Sparse Voxel Octree Files, " + "Square PNG, " + "Schematic Files " + "(*.svo *.png *.schematic)"); + +const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); + + +const glm::vec3 UP_VECT = glm::vec3(0, 1, 0); +const float ANGULAR_RATE = 0.02f; +const float VERTICAL_ANGLE = M_PI_4 / 2.0f; +const float RETURN_RATE = 0.02f; +const float NEAR_CLIP = 0.5f; +const float FAR_CLIP = 10.0f; +const float FIELD_OF_VIEW = 60.0f; + +class GLWidget : public QGLWidget { +public: + GLWidget(QWidget* parent = NULL, VoxelSystem* voxelSystem = NULL); + void setDraw(bool draw) {_draw = draw;} + void setTargetCenter(glm::vec3 targetCenter) {_targetCenter = targetCenter;} + +protected: + virtual void initializeGL(); + virtual void resizeGL(int width, int height); + virtual void paintGL(); + + void mousePressEvent(QMouseEvent* event); + void mouseMoveEvent(QMouseEvent* event); + void mouseReleaseEvent(QMouseEvent* event); + +private: + VoxelSystem* _voxelSystem; + + bool _draw; + + double _a; // horizontal angle of the camera to the center of the object + double _h; // vertical angle of the camera to the center of the object + glm::vec3 _targetCenter; + + bool _pressed; + int _mouseX; + int _mouseY; +}; + +GLWidget::GLWidget(QWidget *parent, VoxelSystem *voxelSystem) + : QGLWidget(parent, Application::getInstance()->getGLWidget()), + _voxelSystem(voxelSystem), + _draw(false), + _a(0.0f), + _h(VERTICAL_ANGLE), + _targetCenter(0.5f, 0.5f, 0.5f), + _pressed(false), + _mouseX(0), + _mouseY(0) { +} + +void GLWidget::initializeGL() { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glShadeModel (GL_SMOOTH); + glEnable(GL_DEPTH_TEST); +} + +void GLWidget::resizeGL(int width, int height) { + glViewport(0, 0, width, height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(FIELD_OF_VIEW, + (float) width / height, + NEAR_CLIP, + FAR_CLIP); +} + +void GLWidget::paintGL() { + glEnable(GL_LINE_SMOOTH); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + if (!_pressed) { + _a += ANGULAR_RATE; + _h = (1.0f - RETURN_RATE) * _h + RETURN_RATE * VERTICAL_ANGLE; + } + + gluLookAt(_targetCenter.x + (glm::length(_targetCenter) + NEAR_CLIP) * cos(_a), + _targetCenter.y + (glm::length(_targetCenter) + NEAR_CLIP) * sin(_h), + _targetCenter.z + (glm::length(_targetCenter) + NEAR_CLIP) * sin(_a), + _targetCenter.x, _targetCenter.y, _targetCenter.z, + UP_VECT.x, UP_VECT.y, UP_VECT.z); + + + if (_draw && _voxelSystem) { + glBegin(GL_LINES); + glColor3d(1, 1 ,1); + glVertex3d(0, 0, 0); + glVertex3d(1, 0, 0); + + glVertex3d(0, 0, 0); + glVertex3d(0, 1, 0); + + glVertex3d(0, 0, 0); + glVertex3d(0, 0, 1); + + + glColor3d(0.4f, 0.4f ,0.4f); + glVertex3d(2 * _targetCenter.x, 2 * _targetCenter.y, 2 * _targetCenter.z); + glVertex3d(0 , 2 * _targetCenter.y, 2 * _targetCenter.z); + + glVertex3d(2 * _targetCenter.x, 2 * _targetCenter.y, 2 * _targetCenter.z); + glVertex3d(2 * _targetCenter.x, 0 , 2 * _targetCenter.z); + + glVertex3d(2 * _targetCenter.x, 2 * _targetCenter.y, 2 * _targetCenter.z); + glVertex3d(2 * _targetCenter.x, 2 * _targetCenter.y, 0 ); + glEnd(); + + _voxelSystem->render(false); + } +} + + +void GLWidget::mousePressEvent(QMouseEvent* event) { + _pressed = true; + _mouseX = event->globalX(); + _mouseY = event->globalY(); +} + +void GLWidget::mouseMoveEvent(QMouseEvent* event) { + _a += (M_PI * (event->globalX() - _mouseX)) / height(); + _h += (M_PI * (event->globalY() - _mouseY)) / height(); + _h = glm::clamp(_h, -M_PI_4, M_PI_4); + + _mouseX = event->globalX(); + _mouseY = event->globalY(); +} + +void GLWidget::mouseReleaseEvent(QMouseEvent* event) { + _pressed = false; +} + +ImportDialog::ImportDialog(QWidget *parent, VoxelSystem* voxelSystem) + : QFileDialog(parent, WINDOW_NAME, DESKTOP_LOCATION, IMPORT_FILE_TYPES), + _importButton (IMPORT_BUTTON_NAME, this), + _clipboardImportBox(IMPORT_TO_CLIPBOARD_CHECKBOX_STRING, this), + _previewBox (PREVIEW_CHECKBOX_STRING, this), + _previewBar (this), + _glPreview (new GLWidget(this, voxelSystem)) { + + setOption(QFileDialog::DontUseNativeDialog, true); + setFileMode(QFileDialog::ExistingFile); + setViewMode(QFileDialog::Detail); + + QGridLayout* gridLayout = (QGridLayout*) layout(); + gridLayout->addWidget(&_importButton , 2, 2); + gridLayout->addWidget(&_clipboardImportBox, 2, 3); + gridLayout->addWidget(&_previewBox , 3, 3); + gridLayout->addWidget(&_previewBar , 0, 3); + gridLayout->addWidget(_glPreview , 1, 3); + gridLayout->setColumnStretch(3, 1); + + _previewBar.setVisible(false); + _previewBar.setRange(0, 100); + _previewBar.setValue(0); + + connect(&_importButton, SIGNAL(pressed()), SLOT(import())); + connect(&_previewBox, SIGNAL(toggled(bool)), SIGNAL(previewToggled(bool))); + connect(&_previewBox, SIGNAL(toggled(bool)), SLOT(preview(bool))); + + connect(this, SIGNAL(currentChanged(QString)), SLOT(saveCurrentFile(QString))); + connect(&_glTimer, SIGNAL(timeout()), SLOT(timer())); + + connect(voxelSystem, SIGNAL(importSize(float,float,float)), SLOT(setGLCamera(float, float, float))); + connect(voxelSystem, SIGNAL(importProgress(int)), &_previewBar, SLOT(setValue(int))); +} + +ImportDialog::~ImportDialog() { + delete _glPreview; +} + +void ImportDialog::import() { + _importButton.setDisabled(true); + _clipboardImportBox.setDisabled(true); + _previewBox.setDisabled(true); + + _previewBar.setValue(0); + _previewBar.setVisible(true); + + emit accepted(); +} + +void ImportDialog::accept() { + QFileDialog::accept(); +} + +void ImportDialog::reject() { + QFileDialog::reject(); +} + +int ImportDialog::exec() { + return QFileDialog::exec(); +} + +void ImportDialog::setGLCamera(float x, float y, float z) { + _glPreview->setTargetCenter(glm::vec3(x, y, z) / 2.0f); +} + +void ImportDialog::reset() { + _previewBox.setChecked(false); + _previewBar.setVisible(false); + _previewBar.setValue(0); + _importButton.setEnabled(true); + _clipboardImportBox.setEnabled(true); + _previewBox.setEnabled(true); + + _glTimer.stop(); + _glPreview->setDraw(false); + _glPreview->updateGL(); +} + +void ImportDialog::preview(bool wantPreview) { + _previewBar.setValue(0); + _previewBar.setVisible(wantPreview); + _glPreview->setDraw(wantPreview); + + if (wantPreview) { + _glTimer.start(); + } else { + _glTimer.stop(); + _glPreview->updateGL(); + } +} + +void ImportDialog::saveCurrentFile(QString filename) { + _currentFile = filename; +} + +void ImportDialog::timer() { + _glPreview->updateGL(); + _glTimer.start(16); +} diff --git a/interface/src/ImportDialog.h b/interface/src/ImportDialog.h new file mode 100644 index 0000000000..f3c1934760 --- /dev/null +++ b/interface/src/ImportDialog.h @@ -0,0 +1,61 @@ +// +// ImportDialog.h +// hifi +// +// Created by Clement Brisset on 8/12/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __hifi__ImportDialog__ +#define __hifi__ImportDialog__ + +#include + +#include +#include +#include +#include +#include +#include + +class GLWidget; + +class ImportDialog : public QFileDialog { + Q_OBJECT +public: + ImportDialog(QWidget* parent = NULL, VoxelSystem* voxelSystem = NULL); + ~ImportDialog(); + + bool getWantPreview() const { return _previewBox.isChecked(); } + QString getCurrentFile() const { return _currentFile; } + bool getImportIntoClipboard() const { return _clipboardImportBox.isChecked(); } + + void reset(); + +signals: + void previewToggled(bool); + void accepted(); + +public slots: + int exec(); + void setGLCamera(float x, float y, float z); + void import(); + void accept(); + void reject(); + +private slots: + void preview(bool preview); + void saveCurrentFile(QString); + void timer(); + +private: + QString _currentFile; + QPushButton _importButton; + QCheckBox _clipboardImportBox; + QCheckBox _previewBox; + QProgressBar _previewBar; + GLWidget* _glPreview; + QTimer _glTimer; +}; + +#endif /* defined(__hifi__ImportDialog__) */ diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index b435604d3f..434ecbdf58 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -246,14 +246,9 @@ Menu::Menu() : addActionToQMenuAndActionHash(voxelMenu, MenuOption::ExportVoxels, Qt::CTRL | Qt::Key_E, appInstance, SLOT(exportVoxels())); addActionToQMenuAndActionHash(voxelMenu, MenuOption::ImportVoxels, Qt::CTRL | Qt::Key_I, appInstance, SLOT(importVoxels())); - addActionToQMenuAndActionHash(voxelMenu, - MenuOption::ImportVoxelsClipboard, - Qt::SHIFT | Qt::CTRL | Qt::Key_I, - appInstance, - SLOT(importVoxelsToClipboard())); addActionToQMenuAndActionHash(voxelMenu, MenuOption::CutVoxels, Qt::CTRL | Qt::Key_X, appInstance, SLOT(cutVoxels())); addActionToQMenuAndActionHash(voxelMenu, MenuOption::CopyVoxels, Qt::CTRL | Qt::Key_C, appInstance, SLOT(copyVoxels())); - addActionToQMenuAndActionHash(voxelMenu, MenuOption::PasteVoxels, Qt::CTRL | Qt::Key_V, appInstance, SLOT(pasteVoxels())); + addActionToQMenuAndActionHash(voxelMenu, MenuOption::PasteVoxels, Qt::CTRL | Qt::Key_V, appInstance, SLOT(togglePasteMode())); QMenu* debugMenu = addMenu("Debug"); diff --git a/interface/src/VoxelImporter.cpp b/interface/src/VoxelImporter.cpp new file mode 100644 index 0000000000..ef4eeafc4b --- /dev/null +++ b/interface/src/VoxelImporter.cpp @@ -0,0 +1,180 @@ +// +// VoxelImporter.cpp +// hifi +// +// Created by Clement Brisset on 8/9/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include + +#include +#include + +static const int IMPORT_SYSTEM_SCALE = 1.0f; +static const int MAX_VOXELS_PER_IMPORT = 2000000; + +class ImportTask : public QObject, public QRunnable { +public: + ImportTask(VoxelSystem* voxelSystem, const QString &filename); + void run(); + +private: + VoxelSystem* _voxelSystem; + QString _filename; +}; + +VoxelImporter::VoxelImporter(QWidget* parent) + : QObject(parent), + _voxelSystem(IMPORT_SYSTEM_SCALE, MAX_VOXELS_PER_IMPORT), + _initialized(false), + _importWaiting(false), + _importDialog(parent, &_voxelSystem), + _currentTask(NULL), + _nextTask(NULL) { + + connect(&_importDialog, SIGNAL(previewToggled(bool)), SLOT(preImport())); + connect(&_importDialog, SIGNAL(currentChanged(QString)), SLOT(preImport())); + connect(&_importDialog, SIGNAL(accepted()), SLOT(import())); +} + +VoxelImporter::~VoxelImporter() { + if (_nextTask) { + delete _nextTask; + _nextTask = NULL; + } + + if (_currentTask) { + disconnect(_currentTask, 0, 0, 0); + _voxelSystem.cancelImport(); + _currentTask = NULL; + } +} + +void VoxelImporter::reset() { + _voxelSystem.killLocalVoxels(); + _importDialog.reset(); + _filename = ""; + _importWaiting = false; + + if (_nextTask) { + delete _nextTask; + _nextTask = NULL; + } + + if (_currentTask) { + _voxelSystem.cancelImport(); + } +} + +int VoxelImporter::exec() { + if (!_initialized) { + _voxelSystem.init(); + _importViewFrustum.calculate(); + _voxelSystem.setViewFrustum(&_importViewFrustum); + _initialized = true; + } + reset(); + + int ret = _importDialog.exec(); + + if (!ret) { + reset(); + } else { + _importDialog.reset(); + _importWaiting = true; + } + + return ret; +} + +int VoxelImporter::preImport() { + QString filename = _importDialog.getCurrentFile(); + + if (!QFileInfo(filename).isFile()) { + return 0; + } + + if (_importDialog.getWantPreview()) { + _filename = filename; + + if (_nextTask) { + delete _nextTask; + } + + _nextTask = new ImportTask(&_voxelSystem, _filename); + connect(_nextTask, SIGNAL(destroyed()), SLOT(launchTask())); + + if (_currentTask != NULL) { + _voxelSystem.cancelImport(); + } else { + launchTask(); + } + } + + return 1; +} + +int VoxelImporter::import() { + QString filename = _importDialog.getCurrentFile(); + + if (!QFileInfo(filename).isFile()) { + _importDialog.reject(); + return 0; + } + + if (_filename == filename) { + if (_currentTask) { + connect(_currentTask, SIGNAL(destroyed()), &_importDialog, SLOT(accept())); + } else { + _importDialog.accept(); + } + return 1; + } + + _filename = filename; + + if (_nextTask) { + delete _nextTask; + } + + _nextTask = new ImportTask(&_voxelSystem, _filename); + connect(_nextTask, SIGNAL(destroyed()), SLOT(launchTask())); + connect(_nextTask, SIGNAL(destroyed()), &_importDialog, SLOT(accept())); + + if (_currentTask != NULL) { + _voxelSystem.cancelImport(); + } else { + launchTask(); + } + + return 1; +} + +void VoxelImporter::launchTask() { + if (_nextTask != NULL) { + _voxelSystem.killLocalVoxels(); + _currentTask = _nextTask; + _nextTask = NULL; + QThreadPool::globalInstance()->start(_currentTask); + } else { + _currentTask = NULL; + } +} + +ImportTask::ImportTask(VoxelSystem* voxelSystem, const QString &filename) + : _voxelSystem(voxelSystem), + _filename(filename) { +} + +void ImportTask::run() { + if (_filename.endsWith(".png", Qt::CaseInsensitive)) { + _voxelSystem->readFromSquareARGB32Pixels(_filename.toLocal8Bit().data()); + } else if (_filename.endsWith(".svo", Qt::CaseInsensitive)) { + _voxelSystem->readFromSVOFile(_filename.toLocal8Bit().data()); + } else if (_filename.endsWith(".schematic", Qt::CaseInsensitive)) { + _voxelSystem->readFromSchematicFile(_filename.toLocal8Bit().data()); + } else { + qDebug("[ERROR] Invalid file extension.\n"); + } +} diff --git a/interface/src/VoxelImporter.h b/interface/src/VoxelImporter.h new file mode 100644 index 0000000000..4ab230d6fb --- /dev/null +++ b/interface/src/VoxelImporter.h @@ -0,0 +1,53 @@ +// +// VoxelImporter.h +// hifi +// +// Created by Clement Brisset on 8/9/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __hifi__VoxelImporter__ +#define __hifi__VoxelImporter__ + +#include +#include + +#include +#include + +class ImportTask; + +class VoxelImporter : public QObject { + Q_OBJECT +public: + VoxelImporter(QWidget* parent = NULL); + ~VoxelImporter(); + void reset(); + + bool getImportWaiting() const { return _importWaiting; } + VoxelSystem* getVoxelSystem() { return &_voxelSystem; } + bool getimportIntoClipboard() const { return _importDialog.getImportIntoClipboard(); } + +public slots: + int exec(); + int preImport(); + int import(); + +private slots: + void launchTask(); + +private: + VoxelSystem _voxelSystem; + ViewFrustum _importViewFrustum; + bool _initialized; + bool _importWaiting; + + ImportDialog _importDialog; + + QString _filename; + + ImportTask* _currentTask; + ImportTask* _nextTask; +}; + +#endif /* defined(__hifi__VoxelImporter__) */ diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 59f55cf4b6..b0cbcf02c3 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -67,6 +67,9 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) : _voxelServerCount = 0; _viewFrustum = Application::getInstance()->getViewFrustum(); + + connect(_tree, SIGNAL(importSize(float,float,float)), SIGNAL(importSize(float,float,float))); + connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int))); } void VoxelSystem::nodeDeleted(VoxelNode* node) { @@ -142,6 +145,22 @@ bool VoxelSystem::readFromSVOFile(const char* filename) { return result; } +bool VoxelSystem::readFromSquareARGB32Pixels(const char *filename) { + bool result = _tree->readFromSquareARGB32Pixels(filename); + if (result) { + setupNewVoxelsForDrawing(); + } + return result; +} + +bool VoxelSystem::readFromSchematicFile(const char* filename) { + bool result = _tree->readFromSchematicFile(filename); + if (result) { + setupNewVoxelsForDrawing(); + } + return result; +} + long int VoxelSystem::getVoxelsCreated() { return _tree->voxelsCreated; } @@ -638,7 +657,7 @@ void VoxelSystem::updatePartialVBOs() { } // if we got to the end of the array, and we're in an active dirty segment... - if (inSegment) { + if (inSegment) { updateVBOSegment(segmentStart, _voxelsInReadArrays - 1); inSegment = false; } @@ -978,6 +997,10 @@ public: { } }; +void VoxelSystem::cancelImport() { + _tree->cancelImport(); +} + // "Remove" voxels from the tree that are not in view. We don't actually delete them, // we remove them from the tree and place them into a holding area for later deletion bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { @@ -1289,14 +1312,23 @@ void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bo setupNewVoxelsForDrawing(); }; -void VoxelSystem::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinationTree, bool rebaseToRoot) { - _tree->copySubTreeIntoNewTree(startNode, destinationTree, rebaseToRoot); +void VoxelSystem::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelSystem* destination, bool rebaseToRoot) { + _tree->copySubTreeIntoNewTree(startNode, destination->_tree, rebaseToRoot); + destination->setupNewVoxelsForDrawing(); +} + +void VoxelSystem::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destination, bool rebaseToRoot) { + _tree->copySubTreeIntoNewTree(startNode, destination, rebaseToRoot); } void VoxelSystem::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destinationNode) { _tree->copyFromTreeIntoSubTree(sourceTree, destinationNode); } +void VoxelSystem::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData) { + _tree->recurseTreeWithOperation(operation, extraData); +} + struct FalseColorizeOccludedArgs { ViewFrustum* viewFrustum; CoverageMap* map; diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 240d12f0f1..7b6c001e8a 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -51,6 +51,8 @@ public: void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); void writeToSVOFile(const char* filename, VoxelNode* node) const; bool readFromSVOFile(const char* filename); + bool readFromSquareARGB32Pixels(const char* filename); + bool readFromSchematicFile(const char* filename); long int getVoxelsCreated(); long int getVoxelsColored(); @@ -79,9 +81,12 @@ public: void createSphere(float r,float xc, float yc, float zc, float s, bool solid, creationMode mode, bool destructive = false, bool debug = false); + void copySubTreeIntoNewTree(VoxelNode* startNode, VoxelSystem* destinationTree, bool rebaseToRoot); void copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinationTree, bool rebaseToRoot); void copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destinationNode); + void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); + CoverageMapV2 myCoverageMapV2; CoverageMap myCoverageMap; @@ -89,6 +94,10 @@ public: virtual void nodeAdded(Node* node); virtual void nodeKilled(Node* node); +signals: + void importSize(float x, float y, float z); + void importProgress(int progress); + public slots: void collectStatsForTreesAndVBOs(); @@ -102,6 +111,8 @@ public slots: void falseColorizeOccluded(); void falseColorizeOccludedV2(); void falseColorizeBySource(); + + void cancelImport(); protected: float _treeScale; diff --git a/libraries/voxels/src/Tags.cpp b/libraries/voxels/src/Tags.cpp index 7df6f227ad..32d717cc6b 100644 --- a/libraries/voxels/src/Tags.cpp +++ b/libraries/voxels/src/Tags.cpp @@ -163,10 +163,13 @@ int retrieveData(std::string filename, std::stringstream &ss) { ss << file; return 0; } + if (type == 0x1F) { - return ungzip(file, ss); + int ret = ungzip(file, ss); + return ret; } + std::cerr << "[DEBUG] Schematic compression type not recognize : " << type << std::endl; return 1; } @@ -242,3 +245,156 @@ int ungzip(std::ifstream &file, std::stringstream &ss) { } +void computeBlockColor(int id, int data, int& red, int& green, int& blue, int& create) { + + switch (id) { + case 1: + case 14: + case 15: + case 16: + case 21: + case 56: + case 73: + case 74: + case 97: + case 129: red = 128; green = 128; blue = 128; break; + case 2: red = 77; green = 117; blue = 66; break; + case 3: + case 60: red = 116; green = 83; blue = 56; break; + case 4: red = 71; green = 71; blue = 71; break; + case 5: + case 125: red = 133; green = 94; blue = 62; break; + case 7: red = 35; green = 35; blue = 35; break; + case 8: + case 9: red = 100; green = 109; blue = 185; break; + case 10: + case 11: red = 192; green = 64; blue = 8; break; + case 12: red = 209; green = 199; blue = 155; break; + case 13: red = 96; green = 94; blue = 93; break; + case 17: red = 71; green = 56; blue = 35; break; + case 18: red = 76; green = 104; blue = 64; break; + case 19: red = 119; green = 119; blue = 37; break; + case 22: red = 22; green = 44; blue = 86; break; + case 23: + case 29: + case 33: + case 61: + case 62: + case 158: red = 61; green = 61; blue = 61; break; + case 24: red = 209; green = 202; blue = 156; break; + case 25: + case 58: + case 84: + case 137: red = 57; green = 38; blue = 25; break; + case 35: + switch (data) { + case 0: red = 234; green = 234; blue = 234; break; + case 1: red = 224; green = 140; blue = 84; break; + case 2: red = 185; green = 90; blue = 194; break; + case 3: red = 124; green = 152; blue = 208; break; + case 4: red = 165; green = 154; blue = 35; break; + case 5: red = 70; green = 187; blue = 61; break; + case 6: red = 206; green = 124; blue = 145; break; + case 7: red = 66; green = 66; blue = 66; break; + case 8: red = 170; green = 176; blue = 176; break; + case 9: red = 45; green = 108; blue = 35; break; + case 10: red = 130; green = 62; blue = 8; break; + case 11: red = 43; green = 51; blue = 29; break; + case 12: red = 73; green = 47; blue = 29; break; + case 13: red = 57; green = 76; blue = 36; break; + case 14: red = 165; green = 58; blue = 53; break; + case 15: red = 24; green = 24; blue = 24; break; + default: + create = 0; + break; + } + break; + case 41: red = 239; green = 238; blue = 105; break; + case 42: red = 146; green = 146; blue = 146; break; + case 43: + case 98: red = 161; green = 161; blue = 161; break; + case 44: + create = 3; + + switch (data) { + case 0: red = 161; green = 161; blue = 161; break; + case 1: red = 209; green = 202; blue = 156; break; + case 2: red = 133; green = 94; blue = 62; break; + case 3: red = 71; green = 71; blue = 71; break; + case 4: red = 121; green = 67; blue = 53; break; + case 5: red = 161; green = 161; blue = 161; break; + case 6: red = 45; green = 22; blue = 26; break; + case 7: red = 195; green = 192; blue = 185; break; + default: + create = 0; + break; + } + break; + case 45: red = 121; green = 67; blue = 53; break; + case 46: red = 118; green = 36; blue = 13; break; + case 47: red = 155; green = 127; blue = 76; break; + case 48: red = 61; green = 79; blue = 61; break; + case 49: red = 52; green = 41; blue = 74; break; + case 52: red = 12; green = 66; blue = 71; break; + case 53: + case 67: + case 108: + case 109: + case 114: + case 128: + case 134: + case 135: + case 136: + case 156: + create = 2; + + switch (id) { + case 53: + case 134: + case 135: + case 136: red = 133; green = 94; blue = 62; break; + case 67: red = 71; green = 71; blue = 71; break; + case 108: red = 121; green = 67; blue = 53; break; + case 109: red = 161; green = 161; blue = 161; break; + case 114: red = 45; green = 22; blue = 26; break; + case 128: red = 209; green = 202; blue = 156; break; + case 156: red = 195; green = 192; blue = 185; break; + default: + create = 0; + break; + } + break; + case 54: + case 95: + case 146: red = 155; green = 105; blue = 32; break; + case 57: red = 145; green = 219; blue = 215; break; + case 79: red = 142; green = 162; blue = 195; break; + case 80: red = 255; green = 255; blue = 255; break; + case 81: red = 8; green = 64; blue = 15; break; + case 82: red = 150; green = 155; blue = 166; break; + case 86: + case 91: red = 179; green = 108; blue = 17; break; + case 87: + case 153: red = 91; green = 31; blue = 30; break; + case 88: red = 68; green = 49; blue = 38; break; + case 89: red = 180; green = 134; blue = 65; break; + case 103: red = 141; green = 143; blue = 36; break; + case 110: red = 103; green = 92; blue = 95; break; + case 112: red = 45; green = 22; blue = 26; break; + case 121: red = 183; green = 178; blue = 129; break; + case 123: red = 101; green = 59; blue = 31; break; + case 124: red = 213; green = 178; blue = 123; break; + case 130: red = 38; green = 54; blue = 56; break; + case 133: red = 53; green = 84; blue = 85; break; + case 152: red = 131; green = 22; blue = 7; break; + case 155: red = 195; green = 192; blue = 185; break; + case 159: red = 195; green = 165; blue = 150; break; + case 170: red = 168; green = 139; blue = 15; break; + case 172: red = 140; green = 86; blue = 61; break; + case 173: red = 9; green = 9; blue = 9; break; + default: + create = 0; + break; + } +} + diff --git a/libraries/voxels/src/Tags.h b/libraries/voxels/src/Tags.h index a005095142..9888190b14 100644 --- a/libraries/voxels/src/Tags.h +++ b/libraries/voxels/src/Tags.h @@ -29,8 +29,9 @@ #define TAG_Compound 10 #define TAG_Int_Array 11 -int retrieveData(std::string filename, std::stringstream &ss); -int ungzip(std::ifstream &file, std::stringstream &ss); +int retrieveData(std::string filename, std::stringstream &ss); +int ungzip(std::ifstream &file, std::stringstream &ss); +void computeBlockColor(int id, int data, int& r, int& g, int& b, int& create); class Tag { public: diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index c0fcee02dd..124d2f7fa6 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -18,6 +18,7 @@ #include #include +#include #include "CoverageMap.h" #include "GeometryUtil.h" @@ -48,7 +49,8 @@ VoxelTree::VoxelTree(bool shouldReaverage) : voxelsColoredStats(100), voxelsBytesReadStats(100), _isDirty(true), - _shouldReaverage(shouldReaverage) { + _shouldReaverage(shouldReaverage), + _stopImport(false) { rootNode = new VoxelNode(); } @@ -359,6 +361,8 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int // skip bitstream to new startPoint bitstreamAt += theseBytesRead; bytesRead += theseBytesRead; + + emit importProgress((100 * (bitstreamAt - bitstream)) / bufferSizeBytes); } this->voxelsBytesRead += bufferSizeBytes; @@ -1557,6 +1561,10 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp bool VoxelTree::readFromSVOFile(const char* fileName) { std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate); if(file.is_open()) { + + emit importSize(1.0f, 1.0f, 1.0f); + emit importProgress(0); + qDebug("loading file %s...\n", fileName); // get file length.... @@ -1570,21 +1578,45 @@ bool VoxelTree::readFromSVOFile(const char* fileName) { readBitstreamToTree(entireFile, fileLength, args); delete[] entireFile; + emit importProgress(100); + file.close(); return true; } return false; } -bool VoxelTree::readFromSquareARGB32Pixels(const uint32_t* pixels, int dimension) { - SquarePixelMap pixelMap = SquarePixelMap(pixels, dimension); +bool VoxelTree::readFromSquareARGB32Pixels(const char* filename) { + QImage pngImage = QImage(filename); + if (pngImage.height() != pngImage.width()) { + qDebug("ERROR: Bad PNG size: height != width.\n"); + return false; + } + + emit importSize(1.0f, 1.0f, 1.0f); + emit importProgress(0); + + const uint32_t* pixels; + if (pngImage.format() == QImage::Format_ARGB32) { + pixels = reinterpret_cast(pngImage.constBits()); + } else { + QImage tmp = pngImage.convertToFormat(QImage::Format_ARGB32); + pixels = reinterpret_cast(tmp.constBits()); + } + + SquarePixelMap pixelMap = SquarePixelMap(pixels, pngImage.height()); pixelMap.addVoxelsToVoxelTree(this); + + emit importProgress(100); return true; } bool VoxelTree::readFromSchematicFile(const char *fileName) { + _stopImport = false; + emit importProgress(0); + std::stringstream ss; - int err = retrieveData(fileName, ss); + int err = retrieveData(std::string(fileName), ss); if (err && ss.get() != TAG_Compound) { qDebug("[ERROR] Invalid schematic file.\n"); return false; @@ -1593,7 +1625,7 @@ bool VoxelTree::readFromSchematicFile(const char *fileName) { ss.get(); TagCompound schematics(ss); if (!schematics.getBlocksId() || !schematics.getBlocksData()) { - qDebug("[ERROR] Invalid schematic file.\n"); + qDebug("[ERROR] Invalid schematic data.\n"); return false; } @@ -1608,9 +1640,22 @@ bool VoxelTree::readFromSchematicFile(const char *fileName) { int red = 128, green = 128, blue = 128; int count = 0; + emit importSize(size * schematics.getWidth(), + size * schematics.getHeight(), + size * schematics.getLength()); + emit importProgress(0); + for (int y = 0; y < schematics.getHeight(); ++y) { for (int z = 0; z < schematics.getLength(); ++z) { + emit importProgress((int) 100 * (y * schematics.getLength() + z) / (schematics.getHeight() * schematics.getLength())); + for (int x = 0; x < schematics.getWidth(); ++x) { + if (_stopImport) { + qDebug("[DEBUG] Canceled import at %d voxels.\n", count); + _stopImport = false; + return true; + } + int pos = ((y * schematics.getLength()) + z) * schematics.getWidth() + x; int id = schematics.getBlocksId()[pos]; int data = schematics.getBlocksData()[pos]; @@ -1656,6 +1701,7 @@ bool VoxelTree::readFromSchematicFile(const char *fileName) { } } + emit importProgress(100); qDebug("Created %d voxels from minecraft import.\n", count); return true; @@ -1747,155 +1793,6 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin } } -void VoxelTree::computeBlockColor(int id, int data, int& red, int& green, int& blue, int& create) { - - switch (id) { - case 1: - case 14: - case 15: - case 16: - case 21: - case 56: - case 73: - case 74: - case 97: - case 129: red = 128; green = 128; blue = 128; break; - case 2: red = 77; green = 117; blue = 66; break; - case 3: - case 60: red = 116; green = 83; blue = 56; break; - case 4: red = 71; green = 71; blue = 71; break; - case 5: - case 125: red = 133; green = 94; blue = 62; break; - case 7: red = 35; green = 35; blue = 35; break; - case 8: - case 9: red = 100; green = 109; blue = 185; break; - case 10: - case 11: red = 192; green = 64; blue = 8; break; - case 12: red = 209; green = 199; blue = 155; break; - case 13: red = 96; green = 94; blue = 93; break; - case 17: red = 71; green = 56; blue = 35; break; - case 18: red = 76; green = 104; blue = 64; break; - case 19: red = 119; green = 119; blue = 37; break; - case 22: red = 22; green = 44; blue = 86; break; - case 23: - case 29: - case 33: - case 61: - case 62: - case 158: red = 61; green = 61; blue = 61; break; - case 24: red = 209; green = 202; blue = 156; break; - case 25: - case 58: - case 84: - case 137: red = 57; green = 38; blue = 25; break; - case 35: - switch (data) { - case 0: red = 234; green = 234; blue = 234; break; - case 1: red = 224; green = 140; blue = 84; break; - case 2: red = 185; green = 90; blue = 194; break; - case 3: red = 124; green = 152; blue = 208; break; - case 4: red = 165; green = 154; blue = 35; break; - case 5: red = 70; green = 187; blue = 61; break; - case 6: red = 206; green = 124; blue = 145; break; - case 7: red = 66; green = 66; blue = 66; break; - case 8: red = 170; green = 176; blue = 176; break; - case 9: red = 45; green = 108; blue = 35; break; - case 10: red = 130; green = 62; blue = 8; break; - case 11: red = 43; green = 51; blue = 29; break; - case 12: red = 73; green = 47; blue = 29; break; - case 13: red = 57; green = 76; blue = 36; break; - case 14: red = 165; green = 58; blue = 53; break; - case 15: red = 24; green = 24; blue = 24; break; - default: - create = 0; - break; - } - break; - case 41: red = 239; green = 238; blue = 105; break; - case 42: red = 146; green = 146; blue = 146; break; - case 43: - case 98: red = 161; green = 161; blue = 161; break; - case 44: - create = 3; - - switch (data) { - case 0: red = 161; green = 161; blue = 161; break; - case 1: red = 209; green = 202; blue = 156; break; - case 2: red = 133; green = 94; blue = 62; break; - case 3: red = 71; green = 71; blue = 71; break; - case 4: red = 121; green = 67; blue = 53; break; - case 5: red = 161; green = 161; blue = 161; break; - case 6: red = 45; green = 22; blue = 26; break; - case 7: red = 195; green = 192; blue = 185; break; - default: - create = 0; - break; - } - break; - case 45: red = 121; green = 67; blue = 53; break; - case 46: red = 118; green = 36; blue = 13; break; - case 47: red = 155; green = 127; blue = 76; break; - case 48: red = 61; green = 79; blue = 61; break; - case 49: red = 52; green = 41; blue = 74; break; - case 52: red = 12; green = 66; blue = 71; break; - case 53: - case 67: - case 108: - case 109: - case 114: - case 128: - case 134: - case 135: - case 136: - case 156: - create = 2; - - switch (id) { - case 53: - case 134: - case 135: - case 136: red = 133; green = 94; blue = 62; break; - case 67: red = 71; green = 71; blue = 71; break; - case 108: red = 121; green = 67; blue = 53; break; - case 109: red = 161; green = 161; blue = 161; break; - case 114: red = 45; green = 22; blue = 26; break; - case 128: red = 209; green = 202; blue = 156; break; - case 156: red = 195; green = 192; blue = 185; break; - default: - create = 0; - break; - } - break; - case 54: - case 95: - case 146: red = 155; green = 105; blue = 32; break; - case 57: red = 145; green = 219; blue = 215; break; - case 79: red = 142; green = 162; blue = 195; break; - case 80: red = 255; green = 255; blue = 255; break; - case 81: red = 8; green = 64; blue = 15; break; - case 82: red = 150; green = 155; blue = 166; break; - case 86: - case 91: red = 179; green = 108; blue = 17; break; - case 87: - case 153: red = 91; green = 31; blue = 30; break; - case 88: red = 68; green = 49; blue = 38; break; - case 89: red = 180; green = 134; blue = 65; break; - case 103: red = 141; green = 143; blue = 36; break; - case 110: red = 103; green = 92; blue = 95; break; - case 112: red = 45; green = 22; blue = 26; break; - case 121: red = 183; green = 178; blue = 129; break; - case 123: red = 101; green = 59; blue = 31; break; - case 124: red = 213; green = 178; blue = 123; break; - case 130: red = 38; green = 54; blue = 56; break; - case 133: red = 53; green = 84; blue = 85; break; - case 152: red = 131; green = 22; blue = 7; break; - case 155: red = 195; green = 192; blue = 185; break; - case 159: red = 195; green = 165; blue = 150; break; - case 170: red = 168; green = 139; blue = 15; break; - case 172: red = 140; green = 86; blue = 61; break; - case 173: red = 9; green = 9; blue = 9; break; - default: - create = 0; - break; - } -} \ No newline at end of file +void VoxelTree::cancelImport() { + _stopImport = true; +} diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index f27543caa8..e988b3f3e0 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -19,6 +19,8 @@ #include "VoxelNodeBag.h" #include "VoxelSceneStats.h" +#include + // Callback function, for recuseTreeWithOperation typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData); typedef enum {GRADIENT, RANDOM, NATURAL} creationMode; @@ -112,7 +114,8 @@ public: {} }; -class VoxelTree { +class VoxelTree : public QObject { + Q_OBJECT public: // when a voxel is created in the tree (object new'd) long voxelsCreated; @@ -172,9 +175,8 @@ public: void writeToSVOFile(const char* filename, VoxelNode* node = NULL) const; bool readFromSVOFile(const char* filename); // reads voxels from square image with alpha as a Y-axis - bool readFromSquareARGB32Pixels(const uint32_t* pixels, int dimension); + bool readFromSquareARGB32Pixels(const char *filename); bool readFromSchematicFile(const char* filename); - void computeBlockColor(int id, int data, int& r, int& g, int& b, int& create); unsigned long getVoxelCount(); @@ -192,6 +194,13 @@ public: RecurseVoxelTreeOperation operation, const glm::vec3& point, void* extraData); +signals: + void importSize(float x, float y, float z); + void importProgress(int progress); + +public slots: + void cancelImport(); + private: void deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraData); @@ -209,6 +218,7 @@ private: bool _isDirty; unsigned long int _nodesChangedFromBitstream; bool _shouldReaverage; + bool _stopImport; }; float boundaryDistanceForRenderLevel(unsigned int renderLevel);