/**************************************************************************** ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtOpenGL module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this ** file. Please review the following information to ensure the GNU Lesser ** General Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE QT_USE_NAMESPACE #define TAB " " typedef QPair QStringPair; QString readSourceFile(const QString &sourceFile, bool fragmentProgram = false) { QFile file(sourceFile); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Missing source file" << sourceFile; exit(0); } QString source; QTextStream in(&file); while (!in.atEnd()) { QString line = in.readLine(); if (fragmentProgram && line[0] == '#' && !line.startsWith("#var")) continue; if (fragmentProgram) source.append(" \""); source.append(line); if (fragmentProgram) source.append("\\n\""); source.append('\n'); } if (fragmentProgram) source.append(" ;\n"); return source; } QList readConf(const QString &confFile) { QFile file(confFile); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Missing file" << confFile; exit(0); } QList result; QTextStream in(&file); while (!in.atEnd()) { QString line = in.readLine(); if (line.startsWith('#')) continue; QTextStream lineStream(&line); QString enumerator; QString sourceFile; lineStream >> enumerator; if (lineStream.atEnd()) { qDebug() << "Error in file" << confFile << '(' << enumerator << ')'; exit(0); } lineStream >> sourceFile; result << QStringPair(enumerator, readSourceFile(sourceFile)); } return result; } QString compileSource(const QString &source) { { QFile tempSourceFile("__tmp__.glsl"); if (!tempSourceFile.open(QIODevice::WriteOnly | QIODevice::Text)) { qDebug() << "Failed opening __tmp__.glsl"; exit(0); } QTextStream out(&tempSourceFile); out << source; } if (std::system("cgc -quiet -oglsl -profile arbfp1 __tmp__.glsl >__tmp__.frag") == -1) { qDebug() << "Failed running cgc"; exit(0); } return readSourceFile("__tmp__.frag", true); } QString getWord(QString line, int word) { QTextStream in(&line); QString result; for (int i = 0; i < word; ++i) in >> result; return result; } static int toInt(const QByteArray &str) { int value = 0; for (int i = 0; i < str.size(); ++i) { if (str[i] < '0' || str[i] > '9') break; value *= 10; value += (str[i] - '0'); } return value; } QList getLocations(const QSet &variables, QString source) { QTextStream in(&source); QMap locations; foreach (QString variable, variables) locations[variable] = -1; while (!in.atEnd()) { QString line = in.readLine().trimmed(); line = line.right(line.size() - 1); if (line.startsWith("#var")) { QByteArray temp; QByteArray name; QTextStream lineStream(&line); lineStream >> temp >> temp >> name; int location = -1; while (!lineStream.atEnd()) { lineStream >> temp; if (temp.startsWith("c[")) { location = toInt(temp.right(temp.size() - 2)); break; } if (temp == "texunit") { lineStream >> temp; location = toInt(temp); break; } } locations[name] = location; } } QList result; foreach (QString variable, variables) result << locations[variable]; return result; } // remove #var statements QString trimmed(QString source) { QTextStream in(&source); QString result; while (!in.atEnd()) { QString line = in.readLine(); if (!line.trimmed().startsWith("\"#")) result += line + '\n'; } return result; } void writeVariablesEnum(QTextStream &out, const char *name, const QSet &s) { out << "enum " << name << " {"; QSet::const_iterator it = s.begin(); if (it != s.end()) { out << "\n" TAB "VAR_" << it->toUpper(); for (++it; it != s.end(); ++it) out << ",\n" TAB "VAR_" << it->toUpper(); } out << "\n};\n\n"; } void writeTypesEnum(QTextStream &out, const char *name, const QList &s) { out << "enum " << name << " {"; QList::const_iterator it = s.begin(); if (it != s.end()) { out << "\n" TAB << it->first; for (++it; it != s.end(); ++it) out << ",\n" TAB << it->first; } out << "\n};\n\n"; } void writeIncludeFile(const QSet &variables, const QList &brushes, const QList &compositionModes, const QList &masks, const QMap > &compiled) { QFile includeFile("fragmentprograms_p.h"); if (!includeFile.open(QIODevice::WriteOnly | QIODevice::Text)) { qDebug() << "Failed opening fragmentprograms_p.h"; exit(0); } QTextStream out(&includeFile); QLatin1String tab(TAB); out << "/****************************************************************************\n" "**\n" "** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).\n" "** All rights reserved.\n" "** Contact: Nokia Corporation (qt-info@nokia.com)\n" "**\n" "** This file is part of the QtOpenGL module of the Qt Toolkit.\n" "**\n" "** $QT_BEGIN_LICENSE:LGPL$\n" "** GNU Lesser General Public License Usage\n" "** This file may be used under the terms of the GNU Lesser General Public\n" "** License version 2.1 as published by the Free Software Foundation and\n" "** appearing in the file LICENSE.LGPL included in the packaging of this\n" "** file. Please review the following information to ensure the GNU Lesser\n" "** General Public License version 2.1 requirements will be met:\n" "** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\n" "**\n" "** In addition, as a special exception, Nokia gives you certain additional\n" "** rights. These rights are described in the Nokia Qt LGPL Exception\n" "** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.\n" "**\n" "** GNU General Public License Usage\n" "** Alternatively, this file may be used under the terms of the GNU General\n" "** Public License version 3.0 as published by the Free Software Foundation\n" "** and appearing in the file LICENSE.GPL included in the packaging of this\n" "** file. Please review the following information to ensure the GNU General\n" "** Public License version 3.0 requirements will be met:\n" "** http://www.gnu.org/copyleft/gpl.html.\n" "**\n" "** Other Usage\n" "** Alternatively, this file may be used in accordance with the terms and\n" "** conditions contained in a signed written agreement between you and Nokia.\n" "**\n" "**\n" "**\n" "**\n" "**\n" "** $QT_END_LICENSE$\n" "**\n" "****************************************************************************/\n" "\n" "#ifndef FRAGMENTPROGRAMS_P_H\n" "#define FRAGMENTPROGRAMS_P_H\n" "\n" "//\n" "// W A R N I N G\n" "// -------------\n" "//\n" "// This file is not part of the Qt API. It exists purely as an\n" "// implementation detail. This header file may change from version to\n" "// version without notice, or even be removed.\n" "//\n" "// We mean it.\n" "//\n" "\n"; writeVariablesEnum(out, "FragmentVariable", variables); writeTypesEnum(out, "FragmentBrushType", brushes); writeTypesEnum(out, "FragmentCompositionModeType", compositionModes); writeTypesEnum(out, "FragmentMaskType", masks); out << "static const unsigned int num_fragment_variables = " << variables.size() << ";\n\n"; out << "static const unsigned int num_fragment_brushes = " << brushes.size() << ";\n"; out << "static const unsigned int num_fragment_composition_modes = " << compositionModes.size() << ";\n"; out << "static const unsigned int num_fragment_masks = " << masks.size() << ";\n\n"; foreach (QStringPair mask, masks) { const QString compiledSource = compiled[mask.first]["MASK__"]; out << "static const char *FragmentProgram_" << mask.first << " =\n" << trimmed(compiledSource) << '\n'; } foreach (QStringPair brush, brushes) { foreach (QStringPair mode, compositionModes) { const QString compiledSource = compiled[brush.first][mode.first]; out << "static const char *FragmentProgram_" << brush.first << '_' << mode.first << " =\n" << trimmed(compiledSource) << '\n'; } } out << "static const char *mask_fragment_program_sources[num_fragment_masks] = {\n"; foreach (QStringPair mask, masks) out << tab << "FragmentProgram_" << mask.first << ",\n"; out << "};\n\n"; out << "static const char *painter_fragment_program_sources[num_fragment_brushes][num_fragment_composition_modes] = {\n"; foreach (QStringPair brush, brushes) { out << tab << "{\n"; foreach (QStringPair mode, compositionModes) out << tab << tab << "FragmentProgram_" << brush.first << '_' << mode.first << ",\n"; out << tab << "},\n"; } out << "};\n\n"; out << "static int painter_variable_locations[num_fragment_brushes][num_fragment_composition_modes][num_fragment_variables] = {\n"; foreach (QStringPair brush, brushes) { out << tab << "{\n"; foreach (QStringPair mode, compositionModes) { out << tab << tab << "{ "; QList locations = getLocations(variables, compiled[brush.first][mode.first]); foreach (int location, locations) out << location << ", "; out << "},\n"; } out << tab << "},\n"; } out << "};\n\n"; out << "static int mask_variable_locations[num_fragment_masks][num_fragment_variables] = {\n"; foreach (QStringPair mask, masks) { out << tab << "{ "; QList locations = getLocations(variables, compiled[mask.first]["MASK__"]); foreach (int location, locations) out << location << ", "; out << "},\n"; } out << "};\n\n"; out << "#endif\n"; } QList getVariables(QString program) { QList result; QTextStream in(&program); while (!in.atEnd()) { QString line = in.readLine(); if (line.startsWith("uniform")) { QString word = getWord(line, 3); result << word.left(word.size() - 1); } else if (line.startsWith("#include")) { QString file = getWord(line, 2); result << getVariables(readSourceFile(file.mid(1, file.size() - 2))); } } return result; } int main() { QList brushes = readConf(QLatin1String("brushes.conf")); QList compositionModes = readConf(QLatin1String("composition_modes.conf")); QList masks = readConf(QLatin1String("masks.conf")); QString painterSource = readSourceFile("painter.glsl"); QString painterNoMaskSource = readSourceFile("painter_nomask.glsl"); QString fastPainterSource = readSourceFile("fast_painter.glsl"); QString brushPainterSource = readSourceFile("brush_painter.glsl"); QSet variables; QList programs[3] = { brushes, compositionModes, masks }; for (int i = 0; i < 3; ++i) foreach (QStringPair value, programs[i]) variables += QSet::fromList(getVariables(value.second)); variables += QSet::fromList(getVariables(painterSource)); variables += QSet::fromList(getVariables(fastPainterSource)); QMap > compiled; foreach (QStringPair brush, brushes) { foreach (QStringPair mode, compositionModes) { QString combinedSource = brush.second + mode.second + painterSource; compiled[brush.first][mode.first] = compileSource(combinedSource); combinedSource = brush.second + mode.second + painterNoMaskSource; compiled[brush.first][mode.first + "_NOMASK"] = compileSource(combinedSource); } QString fastSource = brush.second + fastPainterSource; QString brushSource = brush.second + brushPainterSource; compiled[brush.first]["COMPOSITION_MODE_BLEND_MODE_MASK"] = compileSource(fastSource); compiled[brush.first]["COMPOSITION_MODE_BLEND_MODE_NOMASK"] = compileSource(brushSource); } QList temp; foreach (QStringPair mode, compositionModes) temp << QStringPair(mode.first + "_NOMASK", mode.second); compositionModes += temp; compositionModes << QStringPair("COMPOSITION_MODE_BLEND_MODE_MASK", "") << QStringPair("COMPOSITION_MODE_BLEND_MODE_NOMASK", ""); foreach (QStringPair mask, masks) compiled[mask.first]["MASK__"] = compileSource(mask.second); writeIncludeFile(variables, brushes, compositionModes, masks, compiled); return 0; } QT_END_NAMESPACE