#include "modeleditor.h"
#include "newvoxeldialog.h"
#include "colorselector.h"
#include <q3popupmenu.h>
#include <qmenubar.h>
#include <q3hbox.h>
#include <qfile.h>
#include <qdatastream.h>
#include <qcolordialog.h>
#include <q3filedialog.h>
#include <q3valuelist.h>
#include <qlabel.h>
#include <q3vbox.h>
#include <QPixmap>
ModelEditor::ModelEditor( QWidget *parent, const char *name, Qt::WFlags f )
: Q3MainWindow( parent, name, f ), currLayer(0), clip(0)
{
Q3HBox *hb = new Q3HBox(this);
setCentralWidget(hb);
Q3VBox *vb = new Q3VBox(hb);
new QLabel("Color Picker:", vb);
ColorSelector *sel = new ColorSelector(vb);
sel->setFixedSize( 280, 280 );
connect( sel, SIGNAL(colorSelected(QColor)), this, SLOT( selectedColor(QColor)) );
new QLabel("Software View:", vb);
view = new VoxelView(vb);
view->setFixedSize( 280, 280 );
Q3VBox *vb2 = new Q3VBox(hb);
new QLabel("Layer Editor", vb2);
ge = new GridEditor(vb2);
ge->setFixedSize( 280, 280 );
connect(ge, SIGNAL(changed()), view, SLOT(updateView()) );
new QLabel("OpenGL View:", vb2);
glview = new GLVoxelView(vb2);
glview->setFixedSize( 280, 280 );
connect(ge, SIGNAL(changed()), glview, SLOT(updateGL()) );
hb->setSpacing(2);
vb->setSpacing(2);
vb2->setSpacing(2);
model = new VoxelData( 20, 20, 20 ); // 20x20x20 on startup, but can be anything
initMenu();
ax = 30;
ay = 0;
az = 0;
ge->setMap( model->layer(currLayer), model->width(), model->height() );
view->setVoxelModel( model );
view->setViewAngles( ax, ay, az );
glview->setVoxelModel( model );
glview->setViewAngles( ax, ay, az );
loadFile("example.vxl"); // for demo purposes, load an example file on start
setMinimumSize( 600, 600 );
}
void ModelEditor::newVoxel()
{
// create a new voxel model dialog, then create a new blank model with the given width, height, depth
NewVoxelDialog *dlg = new NewVoxelDialog(this, 0, true);
if (dlg->exec() == QDialog::Accepted) {
model = new VoxelData(dlg->widthSpin->value(),
dlg->heightSpin->value(),
dlg->depthSpin->value());
ge->setMap( model->layer(currLayer), model->width(), model->height() );
view->setVoxelModel( model );
view->setViewAngles( ax, ay, az );
glview->setVoxelModel( model );
glview->setViewAngles( ax, ay, az );
}
}
void ModelEditor::save()
{
// pick file to save model to and write it out
QString fn = Q3FileDialog::getSaveFileName( QDir::currentDirPath(), "*.vxl", this, 0, tr("Save Voxel") );
if ( fn.isEmpty() )
return;
QFile f( fn );
if ( f.open( QIODevice::WriteOnly ) ) {
QDataStream ds( &f );
model->write( ds );
}
}
void ModelEditor::load()
{
// pick file to load and load it
QString fn = Q3FileDialog::getOpenFileName( QDir::currentDirPath(), "*.vxl", this, 0, tr("Save Voxel") );
if ( fn.isEmpty() )
return;
loadFile(fn);
}
void ModelEditor::loadFile(QString fn)
{
// open and read file
QFile f( fn );
if ( f.open( QIODevice::ReadOnly ) ) {
QDataStream ds( &f );
model->read( ds );
ge->setMap( model->layer(currLayer), model->width(), model->height() );
view->setVoxelModel( model );
view->setViewAngles( ax, ay, az );
glview->setVoxelModel( model );
glview->setViewAngles( ax, ay, az );
}
}
void ModelEditor::initMenu()
{
// Setup the applications menus
Q3PopupMenu *file = new Q3PopupMenu( this );
file->insertItem( tr("&New"), this, SLOT(newVoxel()) );
file->insertItem( tr("&Load"), this, SLOT(load()) );
file->insertItem( tr("&Save"), this, SLOT(save()) );
file->insertItem( tr("&Quit"), qApp, SLOT(quit()) );
menuBar()->insertItem( tr("&File"), file );
Q3PopupMenu *edit = new Q3PopupMenu( this );
edit->insertItem( tr("&Copy"), this, SLOT(copy()), Qt::CTRL + Qt::Key_C );
edit->insertItem( tr("&Paste"), this, SLOT(paste()), Qt::CTRL + Qt::Key_V );
edit->insertSeparator();
edit->insertItem( tr("Layer &up"), this, SLOT(up()), Qt::Key_Up );
edit->insertItem( tr("Layer &down"), this, SLOT(down()), Qt::Key_Down );
edit->insertItem( tr("Rotate &left"), this, SLOT(left()), Qt::Key_Left );
edit->insertItem( tr("Rotate &right"), this, SLOT(right()), Qt::Key_Right );
edit->insertItem( tr("Rotate &up"), this, SLOT(tiltup()), Qt::Key_A );
edit->insertItem( tr("Rotate &down"), this, SLOT(tiltdown()), Qt::Key_Z );
edit->insertItem( tr("Rotate &cw"), this, SLOT(cw()), Qt::Key_W );
edit->insertItem( tr("Rotate &ccw"), this, SLOT(ccw()), Qt::Key_Q );
menuBar()->insertItem( tr("&Edit"), edit );
}
// up key pressed, move edit plane up one voxel
void ModelEditor::up()
{
if ( currLayer > 0 ) {
currLayer--;
ge->setMap( model->layer(currLayer), model->width(), model->height() );
glview->setCurrentLayer( currLayer );
}
}
// down key pressed, move edit plane down one voxel
void ModelEditor::down()
{
if ( currLayer < model->height()-1 ) {
currLayer++;
ge->setMap( model->layer(currLayer), model->width(), model->height() );
glview->setCurrentLayer( currLayer );
}
}
// left key pressed, spin around z-axis
void ModelEditor::left()
{
az += 15;
if ( az >= 360 )
az = 0;
view->setViewAngles( ax, ay, az );
glview->setViewAngles( ax, ay, az );
}
// right key pressed, spin around z-axis
void ModelEditor::right()
{
az -= 15;
if ( az < 0 )
az = 360-15;
view->setViewAngles( ax, ay, az );
glview->setViewAngles( ax, ay, az );
}
// 'a' key pressed, spin around x-axis
void ModelEditor::tiltup()
{
ax += 15;
if ( ax >= 360 )
ax = 0;
view->setViewAngles( ax, ay, az );
glview->setViewAngles( ax, ay, az );
}
// 'z' key pressed, spin around x-axis
void ModelEditor::tiltdown()
{
ax -= 15;
if ( ax < 0 )
ax = 360-15;
view->setViewAngles( ax, ay, az );
glview->setViewAngles( ax, ay, az );
}
// 'q' key pressed, spin around y-axis
void ModelEditor::cw() // clock-wise
{
ay += 15;
if ( ay >= 360 )
ay = 0;
view->setViewAngles( ax, ay, az );
glview->setViewAngles( ax, ay, az );
}
// 'w' key pressed, spin around y-axis
void ModelEditor::ccw() // counter clock-wise
{
ay -= 15;
if ( ay < 0 )
ay = 360-15;
view->setViewAngles( ax, ay, az );
glview->setViewAngles( ax, ay, az );
}
// copies the current plane of voxel data
void ModelEditor::copy()
{
// XXX could use QClipboard, but it seems kind of pointless.
if (!clip || clip->width() != model->width() || clip->height() != model->height()) {
delete clip;
clip = new VoxelData(model->width(), model->height(), 1);
}
for (int x = 0; x < model->width(); x++) {
QRgb *src = model->layer(currLayer)[x];
QRgb *dest = clip->layer(0)[x];
memcpy(dest, src, model->height()*sizeof(QRgb));
}
}
// pastes the last copied voxel data to the current plane
void ModelEditor::paste()
{
if (clip && clip->width() == model->width() && clip->height() == model->height()) {
for (int x = 0; x < model->width(); x++) {
QRgb *src = clip->layer(0)[x];
QRgb *dest = model->layer(currLayer)[x];
memcpy(dest, src, model->height()*sizeof(QRgb));
}
glview->repaint(false);
view->repaint(false);
}
}
// when a color is picked, use that color in the editor
void ModelEditor::selectedColor(QColor c)
{
ge->setColor( c.rgb() );
}