This commit is contained in:
Vladislav Khorev 2013-06-22 18:18:33 +00:00
parent 3f6d43ec7b
commit 0583acb7aa
7 changed files with 686 additions and 0 deletions

View File

@ -0,0 +1,140 @@
#include "TextureSheet.h"
bool pixmapSortFunc(const std::pair<QString, boost::shared_ptr<QPixmap>>& pixmap1, const std::pair<QString, boost::shared_ptr<QPixmap>>& pixmap2)
{
return pixmap1.second->width() * pixmap1.second->height() > pixmap2.second->width() * pixmap2.second->height();
}
bool resultTexturePositionsSortFunc(const std::pair<QString, TexCoordRect>& result1, const std::pair<QString, TexCoordRect>& result2)
{
return result1.first < result2.first;
}
void TextureSheet::Calculate(int width, int height)
{
spaceAreaArr.clear();
resultTexturePositions.clear();
std::sort(pixmapArray.begin(), pixmapArray.end(), &pixmapSortFunc);
resultPixmap = boost::shared_ptr<QPixmap>(new QPixmap(width, height));
QColor transparentColor(0,0,0,0);
resultPixmap->fill(transparentColor);
spaceAreaArr.push_back(SpaceArea(0,0,width,height));
QPainter p;
p.begin(&(*resultPixmap));
for (std::vector<std::pair<QString, boost::shared_ptr<QPixmap>>>::iterator pixmapItr = pixmapArray.begin(); pixmapItr != pixmapArray.end(); pixmapItr++)
{
boost::shared_ptr<QPixmap> selectedPixmap = pixmapItr->second;
int foundIndex = -1;
for (size_t i = 0; i < spaceAreaArr.size(); i++)
{
if (spaceAreaArr[i].Width >= selectedPixmap->width()
&& spaceAreaArr[i].Height >= selectedPixmap->height()
&& (foundIndex == -1 ||
spaceAreaArr[i].Width*spaceAreaArr[i].Height < spaceAreaArr[foundIndex].Width*spaceAreaArr[foundIndex].Height))
{
foundIndex = i;
}
}
if (foundIndex != -1)
{
//split space
SpaceArea rightSpaceArea(spaceAreaArr[foundIndex].posX + selectedPixmap->width(),
spaceAreaArr[foundIndex].posY,
spaceAreaArr[foundIndex].Width - selectedPixmap->width(),
selectedPixmap->height());
SpaceArea topSpaceArea(spaceAreaArr[foundIndex].posX,
spaceAreaArr[foundIndex].posY + selectedPixmap->height(),
spaceAreaArr[foundIndex].Width,
spaceAreaArr[foundIndex].Height - selectedPixmap->height());
p.drawPixmap(spaceAreaArr[foundIndex].posX, spaceAreaArr[foundIndex].posY, *selectedPixmap);
TexCoordRect texCoordRect(spaceAreaArr[foundIndex].posX / static_cast<float>(width),
spaceAreaArr[foundIndex].posY / static_cast<float>(height),
(spaceAreaArr[foundIndex].posX + selectedPixmap->width()) / static_cast<float>(width),
(spaceAreaArr[foundIndex].posY + selectedPixmap->height()) / static_cast<float>(height));
texCoordRect.texCoordFromY = 1.f - texCoordRect.texCoordFromY;
texCoordRect.texCoordToY = 1.f - texCoordRect.texCoordToY;
float temp = texCoordRect.texCoordFromY;
texCoordRect.texCoordFromY = texCoordRect.texCoordToY;
texCoordRect.texCoordToY = temp;
resultTexturePositions.push_back(std::pair<QString, TexCoordRect>(pixmapItr->first, texCoordRect));
spaceAreaArr.erase(spaceAreaArr.begin() + foundIndex);
spaceAreaArr.push_back(rightSpaceArea);
spaceAreaArr.push_back(topSpaceArea);
}
else
{
throw std::runtime_error("Not enough space");
}
}
}
QString TextureSheet::GetCalculatedXml()
{
QString result;
result = "<TextureSheet>\n\t<TextureElements>\n";
std::sort(imageNamesArray.begin(), imageNamesArray.end());
std::sort(resultTexturePositions.begin(), resultTexturePositions.end(), &resultTexturePositionsSortFunc);
for (size_t i = 0; i < imageNamesArray.size(); i++)
{
result += QString("\t\t<Texture><Name>%1</Name><TexCoordFrom x='%2' y='%3'/><TexCoordTo x='%4' y='%5'/></Texture>\n")
.arg(imageNamesArray[i])
.arg(QString::number(resultTexturePositions[i].second.texCoordFromX))
.arg(QString::number(resultTexturePositions[i].second.texCoordFromY))
.arg(QString::number(resultTexturePositions[i].second.texCoordToX))
.arg(QString::number(resultTexturePositions[i].second.texCoordToY));
}
result += "\t</TextureElements>\n</TextureSheet>";
return result;
}
void TextureSheet::Clear()
{
spaceAreaArr.clear();
resultTexturePositions.clear();
pixmapArray.clear();
imageNamesArray.clear();
resultPixmap = boost::shared_ptr<QPixmap>(new QPixmap(4,4));
QColor transparentColor(0,0,0,0);
resultPixmap->fill(transparentColor);
}

View File

@ -0,0 +1,88 @@
#ifndef TEXTURESHEET_H
#define TEXTURESHEET_H
#include <QObject>
#include <QGraphicsScene>
#include <QPicture>
#include <QPainter>
#include <QMainWindow>
#include <QFileDialog>
#include <QMessageBox>
#include "boost/shared_ptr.hpp"
#include <map>
struct TexCoordRect
{
float texCoordFromX;
float texCoordFromY;
float texCoordToX;
float texCoordToY;
TexCoordRect()
: texCoordFromX(0)
, texCoordFromY(0)
, texCoordToX(0)
, texCoordToY(0)
{
}
TexCoordRect(float itexCoordFromX, float itexCoordFromY, float itexCoordToX, float itexCoordToY)
: texCoordFromX(itexCoordFromX)
, texCoordFromY(itexCoordFromY)
, texCoordToX(itexCoordToX)
, texCoordToY(itexCoordToY)
{
}
};
struct SpaceArea
{
int posX;
int posY;
int Width;
int Height;
SpaceArea()
: posX(0)
, posY(0)
, Width(0)
, Height(0)
{
}
SpaceArea(int iposX, int iposY, int iWidth, int iHeight)
: posX(iposX)
, posY(iposY)
, Width(iWidth)
, Height(iHeight)
{
}
};
class TextureSheet
{
protected:
public:
std::vector<std::pair<QString, boost::shared_ptr<QPixmap>>> pixmapArray;
std::vector<QString> imageNamesArray;
boost::shared_ptr<QPixmap> resultPixmap;
std::vector<std::pair<QString, TexCoordRect>> resultTexturePositions;
std::vector<SpaceArea> spaceAreaArr;
void Calculate(int width, int height);
QString GetCalculatedXml();
void Clear();
};
#endif // TEXTURESHEET_H

View File

@ -0,0 +1,24 @@
#-------------------------------------------------
#
# Project created by QtCreator 2013-06-20T22:38:10
#
#-------------------------------------------------
QT += core gui
TARGET = TextureSheetMaker
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp \
TextureSheet.cpp
HEADERS += mainwindow.h \
TextureSheet.h
INCLUDEPATH += $$(LibsPath)/boost_1_52_0
DEPENDPATH += $$(LibsPath)/boost_1_52_0
FORMS += mainwindow.ui

View File

@ -0,0 +1,16 @@
#include <QtGui/QApplication>
#include "mainwindow.h"
#include "ui_mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
w.RegisterSignals();
return a.exec();
}

View File

@ -0,0 +1,144 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTextStream.h>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
Ui::MainWindow* MainWindow::GetUi()
{
return ui;
}
void MainWindow::RegisterSignals()
{
QObject::connect(ui->AddTexturesButton, SIGNAL(pressed()), this, SLOT(OnAddTexturesPressed()));
QObject::connect(ui->GenerateButton, SIGNAL(pressed()), this, SLOT(OnGeneratePressed()));
QObject::connect(ui->ClearButton, SIGNAL(pressed()), this, SLOT(OnClearPressed()));
QObject::connect(ui->SaveTextureButton, SIGNAL(pressed()), this, SLOT(OnSaveTexturePressed()));
QObject::connect(ui->SaveParamsButton, SIGNAL(pressed()), this, SLOT(OnSaveSheetParamsPressed()));
}
void MainWindow::OnAddTexturesPressed()
{
QFileDialog dialog(this);
dialog.setFileMode(QFileDialog::ExistingFiles);
dialog.setNameFilter("PNG images (*.png)");
if (dialog.exec())
{
QStringList fileNames = dialog.selectedFiles();
for (int i = 0; i < fileNames.count(); i++)
{
boost::shared_ptr<QPixmap> pixmap(new QPixmap(fileNames[i], "PNG"));
QFileInfo q;
q.setFile(fileNames[i]);
QString fn = q.fileName();
//std::string fileName = fn.toUtf8().constData();
ui->textureList->addItem(fn);
textureSheet.pixmapArray.push_back(std::pair<QString, boost::shared_ptr<QPixmap>>(fn, pixmap));
textureSheet.imageNamesArray.push_back(fn);
}
}
}
void MainWindow::OnGeneratePressed()
{
int width = ui->widthSpinBox->value();
int height = ui->heightSpinBox->value();
try
{
textureSheet.Calculate(width, height);
QString xml = textureSheet.GetCalculatedXml();
ui->textureParamsEdit->clear();
ui->textureParamsEdit->appendPlainText(xml);
}
catch (std::runtime_error& error)
{
QMessageBox msgBox;
msgBox.setText("Not enough space");
msgBox.exec();
}
ui->PixmapSheet->setPixmap(*(textureSheet.resultPixmap));
}
void MainWindow::OnClearPressed()
{
textureSheet.Clear();
ui->PixmapSheet->setPixmap(*(textureSheet.resultPixmap));
ui->textureList->clear();
}
void MainWindow::OnSaveTexturePressed()
{
QFileDialog dialog(this);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilter("PNG images (*.png)");
dialog.setDefaultSuffix("png");
if (dialog.exec())
{
QString fileName = *(dialog.selectedFiles().begin());
textureSheet.resultPixmap->save(fileName, "PNG");
}
}
void MainWindow::OnSaveSheetParamsPressed()
{
QFileDialog dialog(this);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilter("XML files (*.xml)");
dialog.setDefaultSuffix("xml");
if (dialog.exec())
{
QString fileName = *(dialog.selectedFiles().begin());
QFile file(fileName);
if (file.open(QIODevice::WriteOnly | QIODevice::Text))
{
QTextStream outStream(&file);
outStream << ui->textureParamsEdit->toPlainText();
}
}
}

View File

@ -0,0 +1,40 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <vector>
#include "boost/shared_ptr.hpp"
#include "TextureSheet.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
TextureSheet textureSheet;
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Ui::MainWindow* GetUi();
void RegisterSignals();
public slots:
void OnAddTexturesPressed();
void OnGeneratePressed();
void OnClearPressed();
void OnSaveTexturePressed();
void OnSaveSheetParamsPressed();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

View File

@ -0,0 +1,234 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>844</width>
<height>688</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QListWidget" name="textureList">
<property name="geometry">
<rect>
<x>10</x>
<y>50</y>
<width>191</width>
<height>251</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="AddTexturesButton">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>91</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Add textures...</string>
</property>
</widget>
<widget class="QPushButton" name="ClearButton">
<property name="geometry">
<rect>
<x>110</x>
<y>20</y>
<width>91</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Clear</string>
</property>
</widget>
<widget class="QSpinBox" name="widthSpinBox">
<property name="geometry">
<rect>
<x>310</x>
<y>40</y>
<width>61</width>
<height>22</height>
</rect>
</property>
<property name="minimum">
<number>4</number>
</property>
<property name="maximum">
<number>4096</number>
</property>
<property name="value">
<number>512</number>
</property>
</widget>
<widget class="QSpinBox" name="heightSpinBox">
<property name="geometry">
<rect>
<x>311</x>
<y>70</y>
<width>61</width>
<height>22</height>
</rect>
</property>
<property name="minimum">
<number>4</number>
</property>
<property name="maximum">
<number>4096</number>
</property>
<property name="value">
<number>512</number>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>260</x>
<y>50</y>
<width>46</width>
<height>13</height>
</rect>
</property>
<property name="text">
<string>Width:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>260</x>
<y>70</y>
<width>46</width>
<height>13</height>
</rect>
</property>
<property name="text">
<string>Height:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QPlainTextEdit" name="textureParamsEdit">
<property name="geometry">
<rect>
<x>10</x>
<y>340</y>
<width>191</width>
<height>131</height>
</rect>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
</widget>
<widget class="QPushButton" name="GenerateButton">
<property name="geometry">
<rect>
<x>10</x>
<y>310</y>
<width>121</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Generate</string>
</property>
</widget>
<widget class="QPushButton" name="SaveTextureButton">
<property name="geometry">
<rect>
<x>10</x>
<y>480</y>
<width>121</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Save texture...</string>
</property>
</widget>
<widget class="QPushButton" name="SaveParamsButton">
<property name="geometry">
<rect>
<x>10</x>
<y>510</y>
<width>121</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Save params...</string>
</property>
</widget>
<widget class="QFrame" name="frame">
<property name="geometry">
<rect>
<x>220</x>
<y>110</y>
<width>512</width>
<height>512</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<widget class="QLabel" name="PixmapSheet">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>512</width>
<height>512</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>844</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>