1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt3D 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 The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/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 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qshaderprogram.h" |
41 | #include "qshaderprogram_p.h" |
42 | #include <Qt3DCore/qpropertyupdatedchange.h> |
43 | #include <Qt3DRender/private/qurlhelper_p.h> |
44 | #include <QDebug> |
45 | #include <QFile> |
46 | #include <QFileInfo> |
47 | #include <QUrl> |
48 | |
49 | /*! |
50 | \class Qt3DRender::QShaderProgram |
51 | \inmodule Qt3DRender |
52 | \brief Encapsulates a Shader Program. |
53 | \inherits Qt3DCore::QNode |
54 | \since 5.5 |
55 | |
56 | A shader program consists of several different shaders, such as vertex and fragment shaders. |
57 | |
58 | Qt3D will automatically populate a set of default uniforms if they are |
59 | encountered during the shader instrospection phase. |
60 | |
61 | \table |
62 | \header |
63 | \li {1, 1} Default Uniform |
64 | \li {2, 1} Associated Qt3D Parameter name |
65 | \li {3, 1} GLSL declaration |
66 | |
67 | \row |
68 | \li {1, 1} ModelMatrix |
69 | \li {2, 1} modelMatrix |
70 | \li {3, 1} uniform mat4 modelMatrix; |
71 | |
72 | \row |
73 | \li {1, 1} ViewMatrix |
74 | \li {2, 1} viewMatrix |
75 | \li {3, 1} uniform mat4 viewMatrix; |
76 | |
77 | \row |
78 | \li {1, 1} ProjectionMatrix |
79 | \li {2, 1} projectionMatrix |
80 | \li {3, 1} uniform mat4 projectionMatrix; |
81 | |
82 | \row |
83 | \li {1, 1} ModelViewMatrix |
84 | \li {2, 1} modelView |
85 | \li {3, 1} uniform mat4 modelView; |
86 | |
87 | \row |
88 | \li {1, 1} ViewProjectionMatrix |
89 | \li {2, 1} viewProjectionMatrix |
90 | \li {3, 1} uniform mat4 viewProjectionMatrix; |
91 | |
92 | \row |
93 | \li {1, 1} ModelViewProjectionMatrix |
94 | \li {2, 1} modelViewProjection \br mvp |
95 | \li {3, 1} uniform mat4 modelViewProjection; \br uniform mat4 mvp; |
96 | |
97 | \row |
98 | \li {1, 1} InverseModelMatrix |
99 | \li {2, 1} inverseModelMatrix |
100 | \li {3, 1} uniform mat4 inverseModelMatrix; |
101 | |
102 | \row |
103 | \li {1, 1} InverseViewMatrix |
104 | \li {2, 1} inverseViewMatrix |
105 | \li {3, 1} uniform mat4 inverseViewMatrix; |
106 | |
107 | \row |
108 | \li {1, 1} InverseProjectionMatrix |
109 | \li {2, 1} inverseProjectionMatrix |
110 | \li {3, 1} uniform mat4 inverseProjectionMatrix; |
111 | |
112 | \row |
113 | \li {1, 1} InverseModelViewMatrix |
114 | \li {2, 1} inverseModelView |
115 | \li {3, 1} uniform mat4 inverseModelView; |
116 | |
117 | \row |
118 | \li {1, 1} InverseViewProjectionMatrix |
119 | \li {2, 1} inverseViewProjectionMatrix |
120 | \li {3, 1} uniform mat4 inverseViewProjectionMatrix; |
121 | |
122 | \row |
123 | \li {1, 1} InverseModelViewProjectionMatrix |
124 | \li {2, 1} inverseModelViewProjection |
125 | \li {3, 1} uniform mat4 inverseModelViewProjection; |
126 | |
127 | \row |
128 | \li {1, 1} ModelNormalMatrix |
129 | \li {2, 1} modelNormalMatrix |
130 | \li {3, 1} uniform mat3 modelNormalMatrix; |
131 | |
132 | \row |
133 | \li {1, 1} ModelViewNormalMatrix |
134 | \li {2, 1} modelViewNormal |
135 | \li {3, 1} uniform mat3 modelViewNormal; |
136 | |
137 | \row |
138 | \li {1, 1} ViewportMatrix |
139 | \li {2, 1} viewportMatrix |
140 | \li {3, 1} uniform mat4 viewportMatrix; |
141 | |
142 | \row |
143 | \li {1, 1} InverseViewportMatrix |
144 | \li {2, 1} inverseViewportMatrix |
145 | \li {3, 1} uniform mat4 inverseViewportMatrix; |
146 | |
147 | \row |
148 | \li {1, 1} AspectRatio \br (surface width / surface height) |
149 | \li {2, 1} aspectRatio |
150 | \li {3, 1} uniform float aspectRatio; |
151 | |
152 | \row |
153 | \li {1, 1} Exposure |
154 | \li {2, 1} exposure |
155 | \li {3, 1} uniform float exposure; |
156 | |
157 | \row |
158 | \li {1, 1} Gamma |
159 | \li {2, 1} gamma |
160 | \li {3, 1} uniform float gamma; |
161 | |
162 | \row |
163 | \li {1, 1} Time \br (in nano seconds) |
164 | \li {2, 1} time |
165 | \li {3, 1} uniform float time; |
166 | |
167 | \row |
168 | \li {1, 1} EyePosition |
169 | \li {2, 1} eyePosition |
170 | \li {3, 1} uniform vec3 eyePosition; |
171 | |
172 | \row |
173 | \li {1, 1} SkinningPalette |
174 | \li {2, 1} skinningPalette[0] |
175 | \li {3, 1} const int maxJoints = 100; \br uniform mat4 skinningPalette[maxJoints]; |
176 | |
177 | \endtable |
178 | */ |
179 | |
180 | /*! |
181 | \qmltype ShaderProgram |
182 | \instantiates Qt3DRender::QShaderProgram |
183 | \inqmlmodule Qt3D.Render |
184 | \brief Encapsulates a Shader Program. |
185 | \since 5.5 |
186 | |
187 | ShaderProgram class encapsulates a shader program. A shader program consists of several |
188 | different shaders, such as vertex and fragment shaders. |
189 | |
190 | Qt3D will automatically populate a set of default uniforms if they are |
191 | encountered during the shader instrospection phase. |
192 | |
193 | \table |
194 | \header |
195 | \li {1, 1} Default Uniform |
196 | \li {2, 1} Associated Qt3D Parameter name |
197 | \li {3, 1} GLSL declaration |
198 | |
199 | \row |
200 | \li {1, 1} ModelMatrix |
201 | \li {2, 1} modelMatrix |
202 | \li {3, 1} uniform mat4 modelMatrix; |
203 | |
204 | \row |
205 | \li {1, 1} ViewMatrix |
206 | \li {2, 1} viewMatrix |
207 | \li {3, 1} uniform mat4 viewMatrix; |
208 | |
209 | \row |
210 | \li {1, 1} ProjectionMatrix |
211 | \li {2, 1} projectionMatrix |
212 | \li {3, 1} uniform mat4 projectionMatrix; |
213 | |
214 | \row |
215 | \li {1, 1} ModelViewMatrix |
216 | \li {2, 1} modelView |
217 | \li {3, 1} uniform mat4 modelView; |
218 | |
219 | \row |
220 | \li {1, 1} ViewProjectionMatrix |
221 | \li {2, 1} viewProjectionMatrix |
222 | \li {3, 1} uniform mat4 viewProjectionMatrix; |
223 | |
224 | \row |
225 | \li {1, 1} ModelViewProjectionMatrix |
226 | \li {2, 1} modelViewProjection \br mvp |
227 | \li {3, 1} uniform mat4 modelViewProjection; \br uniform mat4 mvp; |
228 | |
229 | \row |
230 | \li {1, 1} InverseModelMatrix |
231 | \li {2, 1} inverseModelMatrix |
232 | \li {3, 1} uniform mat4 inverseModelMatrix; |
233 | |
234 | \row |
235 | \li {1, 1} InverseViewMatrix |
236 | \li {2, 1} inverseViewMatrix |
237 | \li {3, 1} uniform mat4 inverseViewMatrix; |
238 | |
239 | \row |
240 | \li {1, 1} InverseProjectionMatrix |
241 | \li {2, 1} inverseProjectionMatrix |
242 | \li {3, 1} uniform mat4 inverseProjectionMatrix; |
243 | |
244 | \row |
245 | \li {1, 1} InverseModelViewMatrix |
246 | \li {2, 1} inverseModelView |
247 | \li {3, 1} uniform mat4 inverseModelView; |
248 | |
249 | \row |
250 | \li {1, 1} InverseViewProjectionMatrix |
251 | \li {2, 1} inverseViewProjectionMatrix |
252 | \li {3, 1} uniform mat4 inverseViewProjectionMatrix; |
253 | |
254 | \row |
255 | \li {1, 1} InverseModelViewProjectionMatrix |
256 | \li {2, 1} inverseModelViewProjection |
257 | \li {3, 1} uniform mat4 inverseModelViewProjection; |
258 | |
259 | \row |
260 | \li {1, 1} ModelNormalMatrix |
261 | \li {2, 1} modelNormalMatrix |
262 | \li {3, 1} uniform mat3 modelNormalMatrix; |
263 | |
264 | \row |
265 | \li {1, 1} ModelViewNormalMatrix |
266 | \li {2, 1} modelViewNormal |
267 | \li {3, 1} uniform mat3 modelViewNormal; |
268 | |
269 | \row |
270 | \li {1, 1} ViewportMatrix |
271 | \li {2, 1} viewportMatrix |
272 | \li {3, 1} uniform mat4 viewportMatrix; |
273 | |
274 | \row |
275 | \li {1, 1} InverseViewportMatrix |
276 | \li {2, 1} inverseViewportMatrix |
277 | \li {3, 1} uniform mat4 inverseViewportMatrix; |
278 | |
279 | \row |
280 | \li {1, 1} AspectRatio \br (surface width / surface height) |
281 | \li {2, 1} aspectRatio |
282 | \li {3, 1} uniform float aspectRatio; |
283 | |
284 | \row |
285 | \li {1, 1} Exposure |
286 | \li {2, 1} exposure |
287 | \li {3, 1} uniform float exposure; |
288 | |
289 | \row |
290 | \li {1, 1} Gamma |
291 | \li {2, 1} gamma |
292 | \li {3, 1} uniform float gamma; |
293 | |
294 | \row |
295 | \li {1, 1} Time \br (in nano seconds) |
296 | \li {2, 1} time |
297 | \li {3, 1} uniform float time; |
298 | |
299 | \row |
300 | \li {1, 1} EyePosition |
301 | \li {2, 1} eyePosition |
302 | \li {3, 1} uniform vec3 eyePosition; |
303 | |
304 | \row |
305 | \li {1, 1} SkinningPalette |
306 | \li {2, 1} skinningPalette[0] |
307 | \li {3, 1} const int maxJoints = 100; \br uniform mat4 skinningPalette[maxJoints]; |
308 | |
309 | \endtable |
310 | */ |
311 | |
312 | /*! |
313 | \enum QShaderProgram::ShaderType |
314 | |
315 | This enum identifies the type of shader used. |
316 | |
317 | \value Vertex Vertex shader |
318 | \value Fragment Fragment shader |
319 | \value TessellationControl Tesselation control shader |
320 | \value TessellationEvaluation Tesselation evaluation shader |
321 | \value Geometry Geometry shader |
322 | \value Compute Compute shader |
323 | */ |
324 | |
325 | /*! |
326 | \enum QShaderProgram::Status |
327 | |
328 | This enum identifies the status of shader used. |
329 | |
330 | \value NotReady The shader hasn't been compiled and linked yet |
331 | \value Ready The shader was successfully compiled |
332 | \value Error An error occurred while compiling the shader |
333 | */ |
334 | |
335 | QT_BEGIN_NAMESPACE |
336 | |
337 | namespace Qt3DRender { |
338 | |
339 | QShaderProgramPrivate::QShaderProgramPrivate() |
340 | : QNodePrivate() |
341 | , m_status(QShaderProgram::NotReady) |
342 | { |
343 | } |
344 | |
345 | void QShaderProgramPrivate::setLog(const QString &log) |
346 | { |
347 | Q_Q(QShaderProgram); |
348 | if (log != m_log) { |
349 | m_log = log; |
350 | const bool blocked = q->blockNotifications(true); |
351 | emit q->logChanged(m_log); |
352 | q->blockNotifications(blocked); |
353 | } |
354 | } |
355 | |
356 | void QShaderProgramPrivate::setStatus(QShaderProgram::Status status) |
357 | { |
358 | Q_Q(QShaderProgram); |
359 | if (status != m_status) { |
360 | m_status = status; |
361 | const bool blocked = q->blockNotifications(true); |
362 | emit q->statusChanged(m_status); |
363 | q->blockNotifications(blocked); |
364 | } |
365 | } |
366 | |
367 | QShaderProgram::QShaderProgram(QNode *parent) |
368 | : QNode(*new QShaderProgramPrivate, parent) |
369 | { |
370 | } |
371 | |
372 | QShaderProgram::~QShaderProgram() |
373 | { |
374 | } |
375 | |
376 | /*! \internal */ |
377 | QShaderProgram::QShaderProgram(QShaderProgramPrivate &dd, QNode *parent) |
378 | : QNode(dd, parent) |
379 | { |
380 | } |
381 | |
382 | /*! |
383 | Posts a scene change with parameter \a change. |
384 | */ |
385 | void QShaderProgram::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) |
386 | { |
387 | Q_D(QShaderProgram); |
388 | if (change->type() == Qt3DCore::PropertyUpdated) { |
389 | const Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change); |
390 | if (e->propertyName() == QByteArrayLiteral("log" )) |
391 | d->setLog(e->value().toString()); |
392 | else if (e->propertyName() == QByteArrayLiteral("status" )) |
393 | d->setStatus(static_cast<QShaderProgram::Status>(e->value().toInt())); |
394 | } |
395 | } |
396 | |
397 | /*! |
398 | \qmlproperty string ShaderProgram::vertexShaderCode |
399 | |
400 | Holds the vertex shader code used by this shader program. |
401 | */ |
402 | /*! |
403 | \property QShaderProgram::vertexShaderCode |
404 | |
405 | Holds the vertex shader code used by this shader program. |
406 | */ |
407 | void QShaderProgram::setVertexShaderCode(const QByteArray &vertexShaderCode) |
408 | { |
409 | Q_D(QShaderProgram); |
410 | if (vertexShaderCode != d->m_vertexShaderCode) { |
411 | d->m_vertexShaderCode = vertexShaderCode; |
412 | emit vertexShaderCodeChanged(vertexShaderCode); |
413 | } |
414 | } |
415 | |
416 | QByteArray QShaderProgram::vertexShaderCode() const |
417 | { |
418 | Q_D(const QShaderProgram); |
419 | return d->m_vertexShaderCode; |
420 | } |
421 | |
422 | /*! |
423 | \qmlproperty string ShaderProgram::tessellationControlShaderCode |
424 | |
425 | Holds the tesselation control shader code used by this shader program. |
426 | */ |
427 | /*! |
428 | \property QShaderProgram::tessellationControlShaderCode |
429 | |
430 | Holds the tesselation control shader code used by this shader program. |
431 | */ |
432 | void QShaderProgram::setTessellationControlShaderCode(const QByteArray &tessellationControlShaderCode) |
433 | { |
434 | Q_D(QShaderProgram); |
435 | if (tessellationControlShaderCode != d->m_tessControlShaderCode) { |
436 | d->m_tessControlShaderCode = tessellationControlShaderCode; |
437 | emit tessellationControlShaderCodeChanged(tessellationControlShaderCode); |
438 | } |
439 | } |
440 | |
441 | QByteArray QShaderProgram::tessellationControlShaderCode() const |
442 | { |
443 | Q_D(const QShaderProgram); |
444 | return d->m_tessControlShaderCode; |
445 | } |
446 | |
447 | /*! |
448 | \qmlproperty string ShaderProgram::tessellationEvaluationShaderCode |
449 | |
450 | Holds the tesselation evaluation shader code used by this shader program. |
451 | */ |
452 | /*! |
453 | \property QShaderProgram::tessellationEvaluationShaderCode |
454 | |
455 | Holds the tesselation evaluation shader code used by this shader program. |
456 | */ |
457 | void QShaderProgram::setTessellationEvaluationShaderCode(const QByteArray &tessellationEvaluationShaderCode) |
458 | { |
459 | Q_D(QShaderProgram); |
460 | if (tessellationEvaluationShaderCode != d->m_tessEvalShaderCode) { |
461 | d->m_tessEvalShaderCode = tessellationEvaluationShaderCode; |
462 | emit tessellationEvaluationShaderCodeChanged(tessellationEvaluationShaderCode); |
463 | } |
464 | } |
465 | |
466 | QByteArray QShaderProgram::tessellationEvaluationShaderCode() const |
467 | { |
468 | Q_D(const QShaderProgram); |
469 | return d->m_tessEvalShaderCode; |
470 | } |
471 | |
472 | /*! |
473 | \qmlproperty string ShaderProgram::geometryShaderCode |
474 | |
475 | Holds the geometry shader code used by this shader program. |
476 | */ |
477 | /*! |
478 | \property QShaderProgram::geometryShaderCode |
479 | |
480 | Holds the geometry shader code used by this shader program. |
481 | */ |
482 | void QShaderProgram::setGeometryShaderCode(const QByteArray &geometryShaderCode) |
483 | { |
484 | Q_D(QShaderProgram); |
485 | if (geometryShaderCode != d->m_geometryShaderCode) { |
486 | d->m_geometryShaderCode = geometryShaderCode; |
487 | emit geometryShaderCodeChanged(geometryShaderCode); |
488 | } |
489 | } |
490 | |
491 | QByteArray QShaderProgram::geometryShaderCode() const |
492 | { |
493 | Q_D(const QShaderProgram); |
494 | return d->m_geometryShaderCode; |
495 | } |
496 | |
497 | /*! |
498 | \qmlproperty string ShaderProgram::fragmentShaderCode |
499 | |
500 | Holds the fragment shader code used by this shader program. |
501 | */ |
502 | /*! |
503 | \property QShaderProgram::fragmentShaderCode |
504 | |
505 | Holds the fragment shader code used by this shader program. |
506 | */ |
507 | void QShaderProgram::setFragmentShaderCode(const QByteArray &fragmentShaderCode) |
508 | { |
509 | Q_D(QShaderProgram); |
510 | if (fragmentShaderCode != d->m_fragmentShaderCode) { |
511 | d->m_fragmentShaderCode = fragmentShaderCode; |
512 | emit fragmentShaderCodeChanged(fragmentShaderCode); |
513 | } |
514 | } |
515 | |
516 | QByteArray QShaderProgram::fragmentShaderCode() const |
517 | { |
518 | Q_D(const QShaderProgram); |
519 | return d->m_fragmentShaderCode; |
520 | } |
521 | |
522 | /*! |
523 | \qmlproperty string ShaderProgram::computeShaderCode |
524 | |
525 | Holds the compute shader code used by this shader program. |
526 | */ |
527 | /*! |
528 | \property QShaderProgram::computeShaderCode |
529 | |
530 | Holds the compute shader code used by this shader program. |
531 | */ |
532 | void QShaderProgram::setComputeShaderCode(const QByteArray &computeShaderCode) |
533 | { |
534 | Q_D(QShaderProgram); |
535 | if (computeShaderCode != d->m_computeShaderCode) { |
536 | d->m_computeShaderCode = computeShaderCode; |
537 | emit computeShaderCodeChanged(computeShaderCode); |
538 | } |
539 | } |
540 | |
541 | QByteArray QShaderProgram::computeShaderCode() const |
542 | { |
543 | Q_D(const QShaderProgram); |
544 | return d->m_computeShaderCode; |
545 | } |
546 | |
547 | |
548 | /*! |
549 | Sets the shader code for \a type of shader to the \a shaderCode. |
550 | */ |
551 | void QShaderProgram::setShaderCode(ShaderType type, const QByteArray &shaderCode) |
552 | { |
553 | switch (type) { |
554 | case Vertex: |
555 | setVertexShaderCode(shaderCode); |
556 | break; |
557 | case TessellationControl: |
558 | setTessellationControlShaderCode(shaderCode); |
559 | break; |
560 | case TessellationEvaluation: |
561 | setTessellationEvaluationShaderCode(shaderCode); |
562 | break; |
563 | case Geometry: |
564 | setGeometryShaderCode(shaderCode); |
565 | break; |
566 | case Fragment: |
567 | setFragmentShaderCode(shaderCode); |
568 | break; |
569 | case Compute: |
570 | setComputeShaderCode(shaderCode); |
571 | break; |
572 | default: |
573 | Q_UNREACHABLE(); |
574 | } |
575 | } |
576 | |
577 | /*! |
578 | Returns the shader code for \a type. |
579 | */ |
580 | QByteArray QShaderProgram::shaderCode(ShaderType type) const |
581 | { |
582 | Q_D(const QShaderProgram); |
583 | switch (type) { |
584 | case Vertex: |
585 | return d->m_vertexShaderCode; |
586 | case TessellationControl: |
587 | return d->m_tessControlShaderCode; |
588 | case TessellationEvaluation: |
589 | return d->m_tessEvalShaderCode; |
590 | case Geometry: |
591 | return d->m_geometryShaderCode; |
592 | case Fragment: |
593 | return d->m_fragmentShaderCode; |
594 | case Compute: |
595 | return d->m_computeShaderCode; |
596 | default: |
597 | Q_UNREACHABLE(); |
598 | } |
599 | } |
600 | |
601 | /*! |
602 | \qmlproperty string ShaderProgram::log |
603 | |
604 | Holds the log of the current shader program. This is useful to diagnose a |
605 | compilation failure of the shader program. |
606 | */ |
607 | /*! |
608 | \property QShaderProgram::log |
609 | |
610 | Holds the log of the current shader program. This is useful to diagnose a |
611 | compilation failure of the shader program. |
612 | */ |
613 | QString QShaderProgram::log() const |
614 | { |
615 | Q_D(const QShaderProgram); |
616 | return d->m_log; |
617 | } |
618 | |
619 | /*! |
620 | \qmlproperty string ShaderProgram::status |
621 | |
622 | Holds the status of the current shader program. |
623 | */ |
624 | /*! |
625 | \property QShaderProgram::status |
626 | |
627 | Holds the status of the current shader program. |
628 | */ |
629 | /*! |
630 | Returns the status of the current shader program. |
631 | */ |
632 | QShaderProgram::Status QShaderProgram::status() const |
633 | { |
634 | Q_D(const QShaderProgram); |
635 | return d->m_status; |
636 | } |
637 | |
638 | QByteArray QShaderProgramPrivate::deincludify(const QString &filePath) |
639 | { |
640 | QFile f(filePath); |
641 | if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) { |
642 | qWarning() << "Could not read shader source file:" << f.fileName(); |
643 | return QByteArray(); |
644 | } |
645 | |
646 | QByteArray contents = f.readAll(); |
647 | return deincludify(contents, filePath); |
648 | } |
649 | |
650 | QByteArray QShaderProgramPrivate::deincludify(const QByteArray &contents, const QString &filePath) |
651 | { |
652 | QByteArrayList lines = contents.split('\n'); |
653 | const QByteArray includeDirective = QByteArrayLiteral("#pragma include" ); |
654 | for (int i = 0; i < lines.count(); ++i) { |
655 | const auto line = lines[i].simplified(); |
656 | if (line.startsWith(includeDirective)) { |
657 | const QString includePartialPath = QString::fromUtf8(line.mid(includeDirective.count() + 1)); |
658 | |
659 | QString includePath = QFileInfo(includePartialPath).isAbsolute() ? includePartialPath |
660 | : QFileInfo(filePath).absolutePath() + QLatin1Char('/') + includePartialPath; |
661 | if (qEnvironmentVariableIsSet("QT3D_GLSL100_WORKAROUND" )) { |
662 | QString candidate = includePath + QLatin1String("100" ); |
663 | if (QFile::exists(candidate)) |
664 | includePath = candidate; |
665 | } |
666 | lines.removeAt(i); |
667 | QByteArray includedContents = deincludify(includePath); |
668 | lines.insert(i, includedContents); |
669 | QString lineDirective = QString(QStringLiteral("#line %1" )).arg(i + 2); |
670 | lines.insert(i + 1, lineDirective.toUtf8()); |
671 | } |
672 | } |
673 | |
674 | return lines.join('\n'); |
675 | } |
676 | |
677 | /*! |
678 | \qmlmethod string ShaderProgram::loadSource(url sourceUrl) |
679 | |
680 | Returns the shader code loaded from \a sourceUrl. |
681 | */ |
682 | /*! |
683 | Returns the shader code loaded from \a sourceUrl. |
684 | */ |
685 | QByteArray QShaderProgram::loadSource(const QUrl &sourceUrl) |
686 | { |
687 | // TO DO: Handle remote path |
688 | return QShaderProgramPrivate::deincludify(Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(sourceUrl)); |
689 | } |
690 | |
691 | Qt3DCore::QNodeCreatedChangeBasePtr QShaderProgram::createNodeCreationChange() const |
692 | { |
693 | auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QShaderProgramData>::create(this); |
694 | auto &data = creationChange->data; |
695 | Q_D(const QShaderProgram); |
696 | data.vertexShaderCode = d->m_vertexShaderCode; |
697 | data.tessellationControlShaderCode = d->m_tessControlShaderCode; |
698 | data.tessellationEvaluationShaderCode = d->m_tessEvalShaderCode; |
699 | data.geometryShaderCode = d->m_geometryShaderCode; |
700 | data.fragmentShaderCode = d->m_fragmentShaderCode; |
701 | data.computeShaderCode = d->m_computeShaderCode; |
702 | return creationChange; |
703 | } |
704 | |
705 | } // of namespace Qt3DRender |
706 | |
707 | QT_END_NAMESPACE |
708 | |