|
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 |