Crossfire Server, Trunk
FaceMakerDialog.cpp
Go to the documentation of this file.
1 #include "FaceMakerDialog.h"
2 #include <QtWidgets>
3 #include <QtCore/qiodevice.h>
4 #include <QtCore/qfile.h>
5 #include <QMap>
6 
7 #include "ResourcesManager.h"
8 #include "CREPixmap.h"
9 
10 extern "C" {
11 #include "global.h"
12 }
13 #include "assets.h"
14 #include "AssetsManager.h"
15 
16 FaceMakerDialog::FaceMakerDialog(QWidget* parent, ResourcesManager* manager) : QDialog(parent), myManager(manager)
17 {
18  QGridLayout* layout = new QGridLayout(this);
19  int line = 0;
20 
21  layout->addWidget(new QLabel(tr("Settings:"), this), line++, 0);
22 
23  mySettings = new QTextEdit(this);
24  layout->addWidget(mySettings, line++, 0);
25  mySettings->setAcceptRichText(false);
26 
27  QDialogButtonBox* box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Close, Qt::Horizontal, this);
28  layout->addWidget(box, line++, 0);
29  connect(box, SIGNAL(rejected()), this, SLOT(reject()));
30  connect(box, SIGNAL(accepted()), this, SLOT(makeFaces()));
31  box->button(QDialogButtonBox::Ok)->setText("Generate");
32 
33  resize(500, 600);
34 
35  setWindowTitle(tr("Face variant maker"));
36 
37  mySettings->setPlainText(tr(R"RaW(dest: %1/arch/wall/light_blue_cave/
38 name: light_blue_cave
39 faces: cave_15.111, cave1.111, cave2.111, cave3.111, cave4.111, cave5.111
40 faces: cave6.111, cave7.111, cave8.111, cave9.111, cave10.111, cave11.111
41 faces: cave12.111, cave13.111, cave14.111, cave15.111, cave16.111, cave17.111
42 faces: cave18.111, cave19.111, cave20.111, cave21.111, cave22.111, cave23.111
43 faces: cave24.111, cave25.111
44 variants: 2
45 68, 68, 68: 4, 5, 65
46 119, 119, 119:14, 229, 197; 67, 151, 229
47 arch
48 name wall
49 anim_speed 4
50 client_anim_random 1
51 blocksview 1
52 move_block all
53 no_pick 1
54 archend
55 face
56 magicmap blue
57 visibility 100
58 faceend
59 )RaW").arg(settings.datadir));
60 }
61 
62 QColor FaceMakerDialog::parse(const QString& color)
63 {
64  auto split = color.trimmed().split(',');
65  if (split.size() != 3) {
66  QMessageBox::critical(this, tr("Error"), tr("Invalid color %1").arg(color));
67  return QColor();
68  }
69  return QColor::fromRgb(split[0].trimmed().toInt(), split[1].trimmed().toInt(), split[2].trimmed().toInt());
70 }
71 
73 {
74  QMap<QRgb, QList<QColor> > colors;
75  QString dest, name, archContent, faceContent;
76  QStringList faces;
77  int variants = 1;
78 
79  bool inArch = false, inFace = false;
80  auto lines = mySettings->toPlainText().split('\n');
81 
82  foreach (QString line, lines) {
83  if (inArch) {
84  if (line == "archend") {
85  inArch = false;
86  } else {
87  archContent += line + "\n";
88  }
89  continue;
90  }
91  if (inFace) {
92  if (line == "faceend") {
93  inFace = false;
94  } else {
95  faceContent += line + "\n";
96  }
97  continue;
98  }
99 
100  if (line.isEmpty()) {
101  continue;
102  }
103 
104  if (line.startsWith("dest:")) {
105  dest = line.mid(5).trimmed();
106  } else if (line.startsWith("name:")) {
107  name = line.mid(5).trimmed();
108  } else if (line.startsWith("faces:")) {
109  QStringList add(line.mid(6).split(','));
110  foreach (QString face, add) {
111  faces.append(face.trimmed());
112  }
113  } else if (line.startsWith("variants:")) {
114  variants = line.mid(9).trimmed().toInt();
115  } else if (line == "arch") {
116  inArch = true;
117  } else if (line == "face") {
118  inFace = true;
119  } else {
120  auto split = line.split(":");
121  if (split.size() != 2) {
122  QMessageBox::critical(this, tr("Error"), tr("Invalid line %1").arg(line));
123  return;
124  }
125  QColor source = parse(split[0]);
126  auto dest = split[1].split(';');
127  foreach (QString d, dest) {
128  colors[source.rgba()].append(parse(d));
129  }
130  }
131  }
132 
133  if (dest.isEmpty())
134  {
135  QMessageBox::critical(this, tr("Error"), tr("Missing 'dest'!"));
136  return;
137  }
138  if (name.isEmpty())
139  {
140  QMessageBox::critical(this, tr("Error"), tr("Missing 'name'!"));
141  return;
142  }
143  if (faces.isEmpty())
144  {
145  QMessageBox::critical(this, tr("Error"), tr("No face to process!"));
146  return;
147  }
148 
149  if (variants <= 0)
150  {
151  QMessageBox::critical(this, tr("Error"), tr("At least one variant required!"));
152  return;
153  }
154 
155  QFile arc(dest + QDir::separator() + name + ".arc");
156  if (!archContent.isEmpty() && !arc.open(QFile::Truncate | QFile::WriteOnly))
157  {
158  QMessageBox::critical(this, tr("Error"), tr("Error while opening the archetype file %1!").arg(arc.fileName()));
159  return;
160  }
161  QFile fface(dest + QDir::separator() + name + ".face");
162  if ((!faceContent.isEmpty() || variants > 1) && !fface.open(QFile::Truncate | QFile::WriteOnly))
163  {
164  QMessageBox::critical(this, tr("Error"), tr("Error while opening the face file %1!").arg(fface.fileName()));
165  return;
166  }
167 
168  int i = 0;
169  foreach(QString face, faces)
170  {
171  QString archName(name + "_" + QString::number(i));
172  if (!archContent.isEmpty()) {
173  QString item(tr("Object %1\nface %1.111\n").arg(archName));
174  if (variants > 1) {
175  item += tr("animation %1\n").arg(archName);
176  }
177  item += archContent;
178  item += "end\n";
179  arc.write(item.toLocal8Bit());
180  }
181 
182  QString anim(tr("animation %1\n").arg(archName));
183 
184  int faceNumber = getManager()->faces()->get(face.toLocal8Bit().data())->number;
185 
186  for (int var = 1; var <= variants; var++) {
187  QImage image;
188 
189  if (faceNumber >= 0 && CREPixmap::faceset->allocated >= static_cast<size_t>(faceNumber) && CREPixmap::faceset->faces[faceNumber].datalen > 0)
190  {
191  QPixmap face;
192  if (face.loadFromData((uchar*)CREPixmap::faceset->faces[faceNumber].data, CREPixmap::faceset->faces[faceNumber].datalen))
193  {
194  image = face.toImage();
195  }
196  }
197 
198  for (int x = 0; x < image.width(); x++) {
199  for (int y = 0; y < image.height(); y++) {
200  auto rgba = image.pixel(x, y);
201  auto subs = colors.find(rgba);
202  if (subs != colors.end()) {
203  image.setPixelColor(x, y, QColor(subs.value()[rndm(0, subs.value().length() - 1)]));
204  }
205  }
206  }
207 
208  QString base = dest + QDir::separator() + name + "_" + QString::number(i) + ".base.11" + QString::number(var) + ".png";
209  image.save(base, "PNG");
210 
211  if (!faceContent.isEmpty()) {
212  QString fc(tr("face %1\n%2end\n").arg(archName + ".11" + QString::number(var), faceContent));
213  fface.write(fc.toLocal8Bit());
214  }
215  anim += tr("%1.11%2\n").arg(archName).arg(var);
216  }
217  anim += "mina\n";
218  if (variants > 1) {
219  fface.write(anim.toLocal8Bit());
220  }
221  i++;
222  }
223 
224  QMessageBox::information(this, tr("Completed"), tr("Generation completed"));
225 }
global.h
uchar
#define uchar
Definition: re-cmp.h:42
layout
Definition: main.c:85
diamondslots.x
x
Definition: diamondslots.py:15
ResourcesManager
Definition: ResourcesManager.h:28
AssetsManager.h
Settings::datadir
const char * datadir
Definition: global.h:244
FaceMakerDialog.h
FaceMakerDialog::makeFaces
void makeFaces()
Definition: FaceMakerDialog.cpp:72
inja::string_view::split
std::pair< nonstd::string_view, nonstd::string_view > split(nonstd::string_view view, char Separator)
Definition: inja.hpp:1886
FaceMakerDialog::parse
QColor parse(const QString &color)
Definition: FaceMakerDialog.cpp:62
smoking_pipe.color
color
Definition: smoking_pipe.py:5
getManager
AssetsManager * getManager()
Definition: assets.cpp:329
settings
struct Settings settings
Definition: init.c:39
FaceMakerDialog::FaceMakerDialog
FaceMakerDialog(QWidget *parent, ResourcesManager *manager)
Definition: FaceMakerDialog.cpp:16
is_valid_types_gen.line
line
Definition: is_valid_types_gen.py:34
CREPixmap::faceset
static face_sets * faceset
Definition: CREPixmap.h:13
Face::number
uint16_t number
Definition: face.h:15
AssetsManager::faces
Faces * faces()
Definition: AssetsManager.h:39
face_info::data
uint8_t * data
Definition: image.h:11
say.box
box
Definition: say.py:152
rndm
int rndm(int min, int max)
Definition: utils.c:162
AssetsCollection::get
T * get(const Key &name)
Definition: AssetsCollection.h:66
animate.anim
string anim
Definition: animate.py:20
ResourcesManager.h
item
Definition: item.py:1
convert.dest
dest
Definition: convert.py:25
diamondslots.y
y
Definition: diamondslots.py:16
assets.h
face_info::datalen
uint16_t datalen
Definition: image.h:12
dragon_attune.faces
dictionary faces
Definition: dragon_attune.py:31
FaceMakerDialog::mySettings
QTextEdit * mySettings
Definition: FaceMakerDialog.h:22
say.item
dictionary item
Definition: say.py:149
connect
Definition: connect.py:1
CREPixmap.h
face_sets::faces
face_info * faces
Definition: image.h:26
manager
static AssetsManager * manager
Definition: assets.cpp:63
give.name
name
Definition: give.py:27