Qt 4.8
generator.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtOpenGL module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <QFile>
43 #include <QList>
44 #include <QMap>
45 #include <QPair>
46 #include <QSet>
47 #include <QString>
48 #include <QTextStream>
49 
50 #include <QtDebug>
51 #include <cstdlib>
52 
54 
56 
57 #define TAB " "
58 
60 
61 QString readSourceFile(const QString &sourceFile, bool fragmentProgram = false)
62 {
63  QFile file(sourceFile);
64 
66  qDebug() << "Missing source file" << sourceFile;
67  exit(0);
68  }
69 
70  QString source;
71 
72  QTextStream in(&file);
73  while (!in.atEnd()) {
74  QString line = in.readLine();
75 
76  if (fragmentProgram && line[0] == '#' && !line.startsWith("#var"))
77  continue;
78 
79  if (fragmentProgram)
80  source.append(" \"");
81 
82  source.append(line);
83 
84  if (fragmentProgram)
85  source.append("\\n\"");
86 
87  source.append('\n');
88  }
89 
90  if (fragmentProgram)
91  source.append(" ;\n");
92 
93  return source;
94 }
95 
97 {
98  QFile file(confFile);
99 
101  qDebug() << "Missing file" << confFile;
102  exit(0);
103  }
104 
105  QList<QStringPair> result;
106 
107  QTextStream in(&file);
108  while (!in.atEnd()) {
109  QString line = in.readLine();
110 
111  if (line.startsWith('#'))
112  continue;
113 
114  QTextStream lineStream(&line);
115 
116  QString enumerator;
117  QString sourceFile;
118 
119  lineStream >> enumerator;
120 
121  if (lineStream.atEnd()) {
122  qDebug() << "Error in file" << confFile << '(' << enumerator << ')';
123  exit(0);
124  }
125 
126  lineStream >> sourceFile;
127 
128  result << QStringPair(enumerator, readSourceFile(sourceFile));
129  }
130 
131  return result;
132 }
133 
135 {
136  {
137  QFile tempSourceFile("__tmp__.glsl");
138  if (!tempSourceFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
139  qDebug() << "Failed opening __tmp__.glsl";
140  exit(0);
141  }
142 
143  QTextStream out(&tempSourceFile);
144  out << source;
145  }
146 
147  if (std::system("cgc -quiet -oglsl -profile arbfp1 __tmp__.glsl >__tmp__.frag") == -1) {
148  qDebug() << "Failed running cgc";
149  exit(0);
150  }
151 
152  return readSourceFile("__tmp__.frag", true);
153 }
154 
155 QString getWord(QString line, int word)
156 {
157  QTextStream in(&line);
158 
159  QString result;
160 
161  for (int i = 0; i < word; ++i)
162  in >> result;
163 
164  return result;
165 }
166 
167 static int toInt(const QByteArray &str)
168 {
169  int value = 0;
170 
171  for (int i = 0; i < str.size(); ++i) {
172  if (str[i] < '0' || str[i] > '9')
173  break;
174 
175  value *= 10;
176  value += (str[i] - '0');
177  }
178 
179  return value;
180 }
181 QList<int> getLocations(const QSet<QString> &variables, QString source)
182 {
183  QTextStream in(&source);
184 
185  QMap<QString, int> locations;
186 
187  foreach (QString variable, variables)
188  locations[variable] = -1;
189 
190  while (!in.atEnd()) {
191  QString line = in.readLine().trimmed();
192 
193  line = line.right(line.size() - 1);
194 
195  if (line.startsWith("#var")) {
196  QByteArray temp;
198 
199  QTextStream lineStream(&line);
200 
201  lineStream >> temp >> temp >> name;
202 
203  int location = -1;
204 
205  while (!lineStream.atEnd()) {
206  lineStream >> temp;
207 
208  if (temp.startsWith("c[")) {
209  location = toInt(temp.right(temp.size() - 2));
210  break;
211  }
212 
213  if (temp == "texunit") {
214  lineStream >> temp;
215  location = toInt(temp);
216  break;
217  }
218  }
219 
220  locations[name] = location;
221  }
222  }
223 
224  QList<int> result;
225 
226  foreach (QString variable, variables)
227  result << locations[variable];
228 
229  return result;
230 }
231 
232 // remove #var statements
234 {
235  QTextStream in(&source);
236 
237  QString result;
238 
239  while (!in.atEnd()) {
240  QString line = in.readLine();
241  if (!line.trimmed().startsWith("\"#"))
242  result += line + '\n';
243  }
244 
245  return result;
246 }
247 
248 void writeVariablesEnum(QTextStream &out, const char *name, const QSet<QString> &s)
249 {
250  out << "enum " << name << " {";
252  if (it != s.end()) {
253  out << "\n" TAB "VAR_" << it->toUpper();
254  for (++it; it != s.end(); ++it)
255  out << ",\n" TAB "VAR_" << it->toUpper();
256  }
257  out << "\n};\n\n";
258 }
259 
260 void writeTypesEnum(QTextStream &out, const char *name, const QList<QStringPair> &s)
261 {
262  out << "enum " << name << " {";
264  if (it != s.end()) {
265  out << "\n" TAB << it->first;
266  for (++it; it != s.end(); ++it)
267  out << ",\n" TAB << it->first;
268  }
269  out << "\n};\n\n";
270 }
271 
272 void writeIncludeFile(const QSet<QString> &variables,
273  const QList<QStringPair> &brushes,
274  const QList<QStringPair> &compositionModes,
275  const QList<QStringPair> &masks,
276  const QMap<QString, QMap<QString, QString> > &compiled)
277 {
278  QFile includeFile("fragmentprograms_p.h");
279  if (!includeFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
280  qDebug() << "Failed opening fragmentprograms_p.h";
281  exit(0);
282  }
283 
284  QTextStream out(&includeFile);
285 
286  QLatin1String tab(TAB);
287 
288  out << "/****************************************************************************\n"
289  "**\n"
290  "** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).\n"
291  "** Contact: http://www.qt-project.org/legal\n"
292  "**\n"
293  "** This file is part of the QtOpenGL module of the Qt Toolkit.\n"
294  "**\n"
295  "** $QT_BEGIN_LICENSE:LGPL$\n"
296  "** Commercial License Usage\n"
297  "** Licensees holding valid commercial Qt licenses may use this file in\n"
298  "** accordance with the commercial license agreement provided with the\n"
299  "** Software or, alternatively, in accordance with the terms contained in\n"
300  "** a written agreement between you and Digia. For licensing terms and\n"
301  "** conditions see http://qt.digia.com/licensing. For further information\n"
302  "** use the contact form at http://qt.digia.com/contact-us.\n"
303  "**\n"
304  "** GNU Lesser General Public License Usage\n"
305  "** Alternatively, this file may be used under the terms of the GNU Lesser\n"
306  "** General Public License version 2.1 as published by the Free Software\n"
307  "** Foundation and appearing in the file LICENSE.LGPL included in the\n"
308  "** packaging of this file. Please review the following information to\n"
309  "** ensure the GNU Lesser General Public License version 2.1 requirements\n"
310  "** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\n"
311  "**\n"
312  "** In addition, as a special exception, Digia gives you certain additional\n"
313  "** rights. These rights are described in the Digia Qt LGPL Exception\n"
314  "** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.\n"
315  "**\n"
316  "** GNU General Public License Usage\n"
317  "** Alternatively, this file may be used under the terms of the GNU\n"
318  "** General Public License version 3.0 as published by the Free Software\n"
319  "** Foundation and appearing in the file LICENSE.GPL included in the\n"
320  "** packaging of this file. Please review the following information to\n"
321  "** ensure the GNU General Public License version 3.0 requirements will be\n"
322  "** met: http://www.gnu.org/copyleft/gpl.html.\n"
323  "**\n"
324  "**\n"
325  "** $QT_END_LICENSE$\n"
326  "**\n"
327  "****************************************************************************/\n"
328  "\n"
329  "#ifndef FRAGMENTPROGRAMS_P_H\n"
330  "#define FRAGMENTPROGRAMS_P_H\n"
331  "\n"
332  "//\n"
333  "// W A R N I N G\n"
334  "// -------------\n"
335  "//\n"
336  "// This file is not part of the Qt API. It exists purely as an\n"
337  "// implementation detail. This header file may change from version to\n"
338  "// version without notice, or even be removed.\n"
339  "//\n"
340  "// We mean it.\n"
341  "//\n"
342  "\n";
343 
344  writeVariablesEnum(out, "FragmentVariable", variables);
345  writeTypesEnum(out, "FragmentBrushType", brushes);
346  writeTypesEnum(out, "FragmentCompositionModeType", compositionModes);
347  writeTypesEnum(out, "FragmentMaskType", masks);
348 
349  out << "static const unsigned int num_fragment_variables = " << variables.size() << ";\n\n";
350  out << "static const unsigned int num_fragment_brushes = " << brushes.size() << ";\n";
351  out << "static const unsigned int num_fragment_composition_modes = " << compositionModes.size() << ";\n";
352  out << "static const unsigned int num_fragment_masks = " << masks.size() << ";\n\n";
353 
354  foreach (QStringPair mask, masks) {
355  const QString compiledSource = compiled[mask.first]["MASK__"];
356 
357  out << "static const char *FragmentProgram_" << mask.first << " =\n"
358  << trimmed(compiledSource)
359  << '\n';
360  }
361 
362  foreach (QStringPair brush, brushes) {
363  foreach (QStringPair mode, compositionModes) {
364  const QString compiledSource = compiled[brush.first][mode.first];
365 
366  out << "static const char *FragmentProgram_" << brush.first << '_' << mode.first << " =\n"
367  << trimmed(compiledSource)
368  << '\n';
369  }
370  }
371 
372  out << "static const char *mask_fragment_program_sources[num_fragment_masks] = {\n";
373  foreach (QStringPair mask, masks)
374  out << tab << "FragmentProgram_" << mask.first << ",\n";
375  out << "};\n\n";
376 
377  out << "static const char *painter_fragment_program_sources[num_fragment_brushes][num_fragment_composition_modes] = {\n";
378  foreach (QStringPair brush, brushes) {
379  out << tab << "{\n";
380 
381  foreach (QStringPair mode, compositionModes)
382  out << tab << tab << "FragmentProgram_" << brush.first << '_' << mode.first << ",\n";
383 
384  out << tab << "},\n";
385  }
386  out << "};\n\n";
387 
388  out << "static int painter_variable_locations[num_fragment_brushes][num_fragment_composition_modes][num_fragment_variables] = {\n";
389  foreach (QStringPair brush, brushes) {
390  out << tab << "{\n";
391 
392  foreach (QStringPair mode, compositionModes) {
393  out << tab << tab << "{ ";
394 
395  QList<int> locations = getLocations(variables, compiled[brush.first][mode.first]);
396 
397  foreach (int location, locations)
398  out << location << ", ";
399 
400  out << "},\n";
401  }
402 
403  out << tab << "},\n";
404  }
405  out << "};\n\n";
406 
407  out << "static int mask_variable_locations[num_fragment_masks][num_fragment_variables] = {\n";
408  foreach (QStringPair mask, masks) {
409  out << tab << "{ ";
410 
411  QList<int> locations = getLocations(variables, compiled[mask.first]["MASK__"]);
412 
413  foreach (int location, locations)
414  out << location << ", ";
415 
416  out << "},\n";
417  }
418  out << "};\n\n";
419  out << "#endif\n";
420 }
421 
423 {
424  QList<QString> result;
425 
426  QTextStream in(&program);
427  while (!in.atEnd()) {
428  QString line = in.readLine();
429 
430  if (line.startsWith("uniform")) {
431  QString word = getWord(line, 3);
432  result << word.left(word.size() - 1);
433  } else if (line.startsWith("#include")) {
434  QString file = getWord(line, 2);
435  result << getVariables(readSourceFile(file.mid(1, file.size() - 2)));
436  }
437  }
438 
439  return result;
440 }
441 
442 int main()
443 {
444  QList<QStringPair> brushes = readConf(QLatin1String("brushes.conf"));
445  QList<QStringPair> compositionModes = readConf(QLatin1String("composition_modes.conf"));
446  QList<QStringPair> masks = readConf(QLatin1String("masks.conf"));
447 
448  QString painterSource = readSourceFile("painter.glsl");
449  QString painterNoMaskSource = readSourceFile("painter_nomask.glsl");
450  QString fastPainterSource = readSourceFile("fast_painter.glsl");
451  QString brushPainterSource = readSourceFile("brush_painter.glsl");
452 
453  QSet<QString> variables;
454 
455  QList<QStringPair> programs[3] = { brushes, compositionModes, masks };
456 
457  for (int i = 0; i < 3; ++i)
458  foreach (QStringPair value, programs[i])
459  variables += QSet<QString>::fromList(getVariables(value.second));
460 
461  variables += QSet<QString>::fromList(getVariables(painterSource));
462  variables += QSet<QString>::fromList(getVariables(fastPainterSource));
463 
465 
466  foreach (QStringPair brush, brushes) {
467  foreach (QStringPair mode, compositionModes) {
468  QString combinedSource = brush.second + mode.second + painterSource;
469  compiled[brush.first][mode.first] = compileSource(combinedSource);
470 
471  combinedSource = brush.second + mode.second + painterNoMaskSource;
472  compiled[brush.first][mode.first + "_NOMASK"] = compileSource(combinedSource);
473  }
474 
475  QString fastSource = brush.second + fastPainterSource;
476  QString brushSource = brush.second + brushPainterSource;
477 
478  compiled[brush.first]["COMPOSITION_MODE_BLEND_MODE_MASK"] = compileSource(fastSource);
479  compiled[brush.first]["COMPOSITION_MODE_BLEND_MODE_NOMASK"] = compileSource(brushSource);
480  }
481 
482  QList<QStringPair> temp;
483 
484  foreach (QStringPair mode, compositionModes)
485  temp << QStringPair(mode.first + "_NOMASK", mode.second);
486 
487  compositionModes += temp;
488 
489  compositionModes << QStringPair("COMPOSITION_MODE_BLEND_MODE_MASK", "")
490  << QStringPair("COMPOSITION_MODE_BLEND_MODE_NOMASK", "");
491 
492  foreach (QStringPair mask, masks)
493  compiled[mask.first]["MASK__"] = compileSource(mask.second);
494 
495  writeIncludeFile(variables, brushes, compositionModes, masks, compiled);
496 
497  return 0;
498 }
499 
QString compileSource(const QString &source)
Definition: generator.cpp:134
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QString readLine(qint64 maxlen=0)
Reads one line of text from the stream, and returns it as a QString.
#define it(className, varName)
bool open(OpenMode flags)
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition: qfile.cpp:1064
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
QString getWord(QString line, int word)
Definition: generator.cpp:155
T1 first
Definition: qpair.h:65
T2 second
Definition: qpair.h:66
iterator begin()
Returns an STL-style iterator pointing to the first item in the list.
Definition: qlist.h:267
int main()
Definition: generator.cpp:442
The QList::const_iterator class provides an STL-style const iterator for QList and QQueue...
Definition: qlist.h:228
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition: qstring.cpp:3734
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
QString readSourceFile(const QString &sourceFile, bool fragmentProgram=false)
Definition: generator.cpp:61
The QString class provides a Unicode character string.
Definition: qstring.h:83
#define TAB
Definition: generator.cpp:57
iterator begin()
Definition: qset.h:166
QPair< QString, QString > QStringPair
Definition: generator.cpp:59
void writeIncludeFile(const QSet< QString > &variables, const QList< QStringPair > &brushes, const QList< QStringPair > &compositionModes, const QList< QStringPair > &masks, const QMap< QString, QMap< QString, QString > > &compiled)
Definition: generator.cpp:272
int size() const
Definition: qset.h:75
Q_CORE_EXPORT void qDebug(const char *,...)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QString left(int n) const Q_REQUIRED_RESULT
Returns a substring that contains the n leftmost characters of the string.
Definition: qstring.cpp:3664
QString trimmed() const Q_REQUIRED_RESULT
Returns a string that has whitespace removed from the start and the end.
Definition: qstring.cpp:4506
int size() const
Returns the number of characters in this string.
Definition: qstring.h:102
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the list...
Definition: qlist.h:270
const char * name
static int toInt(const QByteArray &str)
Definition: generator.cpp:167
iterator end()
Definition: qset.h:169
QList< QString > getVariables(QString program)
Definition: generator.cpp:422
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal...
Definition: qstring.h:654
QString right(int n) const Q_REQUIRED_RESULT
Returns a substring that contains the n rightmost characters of the string.
Definition: qstring.cpp:3682
QString mid(int position, int n=-1) const Q_REQUIRED_RESULT
Returns a string that contains n characters of this string, starting at the specified position index...
Definition: qstring.cpp:3706
QString & append(QChar c)
Definition: qstring.cpp:1777
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:65
QString trimmed(QString source)
Definition: generator.cpp:233
The QTextStream class provides a convenient interface for reading and writing text.
Definition: qtextstream.h:73
static QTestResult::TestLocation location
Definition: qtestresult.cpp:63
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
QList< QStringPair > readConf(const QString &confFile)
Definition: generator.cpp:96
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
void writeTypesEnum(QTextStream &out, const char *name, const QList< QStringPair > &s)
Definition: generator.cpp:260
#define QT_USE_NAMESPACE
This macro expands to using QT_NAMESPACE if QT_NAMESPACE is defined and nothing otherwise.
Definition: qglobal.h:88
QList< int > getLocations(const QSet< QString > &variables, QString source)
Definition: generator.cpp:181
bool atEnd() const
Returns true if there is no more data to be read from the QTextStream; otherwise returns false...
void writeVariablesEnum(QTextStream &out, const char *name, const QSet< QString > &s)
Definition: generator.cpp:248
static QSet< T > fromList(const QList< T > &list)
Definition: qset.h:319
The QList class is a template class that provides lists.
Definition: qdatastream.h:62