src/opengl/util/generator.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    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 
       
    53 QT_BEGIN_NAMESPACE
       
    54 
       
    55 QT_USE_NAMESPACE
       
    56 
       
    57 #define TAB "    "
       
    58 
       
    59 typedef QPair<QString, QString> QStringPair;
       
    60 
       
    61 QString readSourceFile(const QString &sourceFile, bool fragmentProgram = false)
       
    62 {
       
    63     QFile file(sourceFile);
       
    64 
       
    65     if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
       
    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 
       
    96 QList<QStringPair> readConf(const QString &confFile)
       
    97 {
       
    98     QFile file(confFile);
       
    99 
       
   100     if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
       
   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 
       
   134 QString compileSource(const QString &source)
       
   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;
       
   197             QByteArray name;
       
   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
       
   233 QString trimmed(QString source)
       
   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 << " {";
       
   251     QSet<QString>::const_iterator it = s.begin();
       
   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 << " {";
       
   263     QList<QStringPair>::const_iterator it = s.begin();
       
   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) 2009 Nokia Corporation and/or its subsidiary(-ies).\n"
       
   291            "** All rights reserved.\n"
       
   292            "** Contact: Nokia Corporation (qt-info@nokia.com)\n"
       
   293            "**\n"
       
   294            "** This file is part of the QtOpenGL module of the Qt Toolkit.\n"
       
   295            "**\n"
       
   296            "** $QT_BEGIN_LICENSE:LGPL$\n"
       
   297            "** No Commercial Usage\n"
       
   298            "** This file contains pre-release code and may not be distributed.\n"
       
   299            "** You may use this file in accordance with the terms and conditions\n"
       
   300            "** contained in the Technology Preview License Agreement accompanying\n"
       
   301            "** this package.\n"
       
   302            "**\n"
       
   303            "** GNU Lesser General Public License Usage\n"
       
   304            "** Alternatively, this file may be used under the terms of the GNU Lesser\n"
       
   305            "** General Public License version 2.1 as published by the Free Software\n"
       
   306            "** Foundation and appearing in the file LICENSE.LGPL included in the\n"
       
   307            "** packaging of this file.  Please review the following information to\n"
       
   308            "** ensure the GNU Lesser General Public License version 2.1 requirements\n"
       
   309            "** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\n"
       
   310            "**\n"
       
   311            "** In addition, as a special exception, Nokia gives you certain additional\n"
       
   312            "** rights.  These rights are described in the Nokia Qt LGPL Exception\n"
       
   313            "** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.\n"
       
   314            "**\n"
       
   315            "** If you have questions regarding the use of this file, please contact\n"
       
   316            "** Nokia at qt-info@nokia.com.\n"
       
   317            "**\n"
       
   318            "**\n"
       
   319            "**\n"
       
   320            "**\n"
       
   321            "**\n"
       
   322            "**\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 
       
   422 QList<QString> getVariables(QString program)
       
   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 
       
   464     QMap<QString, QMap<QString, QString> > compiled;
       
   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 
       
   500 QT_END_NAMESPACE