source: trunk/src/opengl/gl2paintengineex/qglshader.cpp@ 353

Last change on this file since 353 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 13.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtOpenGL module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qglshader_p.h"
43
44
45// Windows needs to resolve OpenGL 2.0 function pointers for each context. The
46// QGL OpenGL 2.0 functions are actually macros, which take a "ctx" parameter.
47#define Q_CTX QGLContext* ctx = d->ctx; \
48 if (!ctx) \
49 return false; \
50 ctx->makeCurrent(); \
51
52
53
54
55class QGLShaderPrivate
56{
57public:
58 QGLShaderPrivate() : shaderId(0), valid(false), ctx(0) {}
59
60 GLuint shaderId;
61 QString source;
62 bool valid;
63 QGLShader::ShaderType type;
64 QGLContext* ctx;
65};
66
67
68QGLShader::QGLShader(QGLShader::ShaderType type, const QGLContext* ctx)
69 : d_ptr(new QGLShaderPrivate)
70{
71 Q_D(QGLShader);
72
73 if (!ctx)
74 ctx = QGLContext::currentContext();
75
76 if (!ctx) {
77 qWarning("QGLShader being created without a context");
78 return;
79 }
80
81 d->ctx = const_cast<QGLContext*>(ctx);
82 d->ctx->makeCurrent();
83
84 if (type == QGLShader::FragmentShader)
85 d->shaderId = glCreateShader(GL_FRAGMENT_SHADER);
86 else
87 d->shaderId = glCreateShader(GL_VERTEX_SHADER);
88
89 if (d->shaderId == 0) {
90 qWarning("Error creating shader object");
91 return;
92 }
93
94 d->type = type;
95}
96
97GLuint QGLShader::id()
98{
99 Q_D(QGLShader);
100 return d->shaderId;
101}
102
103const QGLContext* QGLShader::context()
104{
105 Q_D(QGLShader);
106 return d->ctx;
107}
108
109void QGLShader::clearSource()
110{
111 Q_D(QGLShader);
112 d->source.clear();
113 d->valid = false;
114}
115
116void QGLShader::addSource(const QLatin1String& newSource)
117{
118 Q_D(QGLShader);
119 d->source += newSource;
120 d->valid = false;
121}
122
123
124bool QGLShader::compile()
125{
126 Q_D(QGLShader);
127
128 d->valid = false;
129
130 if (d->source.size() == 0)
131 return false;
132
133 const QByteArray src_ba = d->source.toAscii();
134 const char* src = src_ba.constData();
135
136 glShaderSource(d->shaderId, 1, &src, 0);
137
138 glCompileShader(d->shaderId);
139
140 GLint shaderCompiled;
141 glGetShaderiv(d->shaderId, GL_COMPILE_STATUS, &shaderCompiled);
142 if (!shaderCompiled)
143 return false;
144
145 d->valid = true;
146 return true;
147}
148
149bool QGLShader::isValid()
150{
151 Q_D(QGLShader);
152 return d->valid;
153}
154
155QString QGLShader::log()
156{
157 Q_D(QGLShader);
158
159 char* logData;
160 GLint logSize;
161 GLint logLength;
162
163 glGetShaderiv(d->shaderId, GL_INFO_LOG_LENGTH, &logSize);
164
165 if (!logSize)
166 return QString();
167
168 logData = new char[logSize];
169 glGetShaderInfoLog(d->shaderId, logSize, &logLength, logData);
170 QString result = QString::fromAscii(logData);
171 delete [] logData;
172
173 return result;
174}
175
176
177
178
179
180
181
182
183
184
185
186
187class QGLShaderProgramPrivate
188{
189public:
190 QGLShaderProgramPrivate() : valid(false), programId(0), ctx(0) {}
191 void populateVariableLists();
192
193 QVector<QGLShader*> shaders;
194 QGLUniformList uniforms;
195 QGLVertexAttributeList attributeArrays;
196 bool valid;
197 GLuint programId;
198 QGLContext* ctx;
199};
200
201
202
203void QGLShaderProgramPrivate::populateVariableLists()
204{
205 attributeArrays.clear();
206 uniforms.clear();
207
208 int count;
209 int sizeOfNameBuff;
210 char* name;
211 GLint nameLength;
212 GLenum type;
213 GLint size;
214 GLint location;
215
216 glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &count);
217 glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &sizeOfNameBuff);
218 name = new char[sizeOfNameBuff];
219
220 for (int i = 0; i < count; ++i) {
221 nameLength = -1;
222 glGetActiveAttrib(programId, i, sizeOfNameBuff, &nameLength, &size, &type, name);
223 if (nameLength == -1)
224 continue;
225
226 location = glGetAttribLocation(programId, name);
227 attributeArrays.insert(QString::fromAscii(name), QGLVertexAttribute(type, location, ctx));
228 }
229
230 delete [] name;
231
232
233 glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &count);
234 glGetProgramiv(programId, GL_ACTIVE_UNIFORM_MAX_LENGTH, &sizeOfNameBuff);
235
236 name = new char[sizeOfNameBuff];
237
238 for (int i = 0; i < count; ++i) {
239 nameLength = -1;
240 glGetActiveUniform(programId, i, sizeOfNameBuff, &nameLength, &size, &type, name);
241 if (nameLength == -1)
242 continue;
243
244 location = glGetUniformLocation(programId, name);
245 uniforms.insert(QString::fromAscii(name), QGLUniform(type, location, ctx));
246 }
247}
248
249
250QGLShaderProgram::QGLShaderProgram(const QGLContext* ctx)
251 : d_ptr(new QGLShaderProgramPrivate)
252{
253 Q_D(QGLShaderProgram);
254 if (!ctx)
255 ctx = QGLContext::currentContext();
256
257 if (!ctx) {
258 qWarning("QGLShaderProgram being created without a context");
259 return;
260 }
261
262 d->ctx = const_cast<QGLContext*>(ctx);
263 d->ctx->makeCurrent();
264
265 d->programId = glCreateProgram();
266
267 d->valid = false;
268}
269
270
271const QGLUniformList & QGLShaderProgram::uniforms()
272{
273 Q_D(QGLShaderProgram);
274 return const_cast<const QGLUniformList&>(d->uniforms);
275}
276
277
278const QGLVertexAttributeList& QGLShaderProgram::vertexAttributes()
279{
280 Q_D(QGLShaderProgram);
281 return const_cast<const QGLVertexAttributeList&>(d->attributeArrays);
282}
283
284
285bool QGLShaderProgram::addShader(QGLShader* newShader)
286{
287 Q_D(QGLShaderProgram);
288 if (!newShader || !d->ctx)
289 return false;
290
291 if (newShader->context() != d->ctx) {
292 qWarning("Shader object's context does not match program's context");
293 return false;
294 }
295
296 if (!newShader->isValid())
297 return false;
298
299 QGLContext* ctx = d->ctx;
300 if (!ctx)
301 return false;
302 ctx->makeCurrent();
303
304 glAttachShader(d->programId, newShader->id());
305
306 d->shaders.append(newShader);
307 return true;
308}
309
310
311bool QGLShaderProgram::removeShader(QGLShader* oldShader)
312{
313 Q_D(QGLShaderProgram);
314
315 int idx = d->shaders.indexOf(oldShader);
316
317 if (idx == -1)
318 return false;
319
320 d->shaders.remove(idx);
321
322 QGLContext* ctx = d->ctx;
323 if (!ctx)
324 return false;
325 ctx->makeCurrent();
326
327 glDetachShader(d->programId, oldShader->id());
328 return true;
329}
330
331
332bool QGLShaderProgram::removeAllShaders()
333{
334 Q_D(QGLShaderProgram);
335
336 QGLContext* ctx = d->ctx;
337 if (!ctx)
338 return false;
339 ctx->makeCurrent();
340
341 foreach (QGLShader* shader, d->shaders)
342 glDetachShader(d->programId, shader->id());
343
344 d->shaders.clear();
345 return true;
346}
347
348#include <stdio.h>
349
350bool QGLShaderProgram::link()
351{
352 Q_D(QGLShaderProgram);
353
354 QGLContext* ctx = d->ctx;
355 if (!ctx)
356 return false;
357 ctx->makeCurrent();
358
359 glLinkProgram(d->programId);
360
361
362 GLint linked;
363 glGetProgramiv(d->programId, GL_LINK_STATUS, &linked);
364
365 if (!linked)
366 return false;
367
368 d->populateVariableLists();
369
370 d->valid = true;
371 return true;
372}
373
374void QGLShaderProgram::use()
375{
376 Q_D(QGLShaderProgram);
377 if (!d->valid)
378 return;
379
380 glUseProgram(d->programId);
381}
382
383
384QString QGLShaderProgram::log()
385{
386 Q_D(QGLShaderProgram);
387
388 QGLContext* ctx = d->ctx;
389 if (!ctx)
390 return QString();
391 ctx->makeCurrent();
392
393 GLint logSize = -666;
394 glGetProgramiv(d->programId, GL_INFO_LOG_LENGTH, &logSize);
395
396 char* logData = new char[logSize];
397 GLint logLength;
398
399 glGetProgramInfoLog(d->programId, logSize, &logLength, logData);
400
401 QString result = QString::fromAscii(logData);
402 delete [] logData;
403
404 return result;
405}
406
407GLuint QGLShaderProgram::id()
408{
409 Q_D(QGLShaderProgram);
410 return d->programId;
411}
412
413/////////////////////////////////////////////////////////////////////////
414
415
416
417
418QGLUniform::QGLUniform()
419 : m_id(0), m_type(QGLInvalidType), ctx(0)
420{
421 qWarning("Unknown uniform! Either the uniform doesn't exist or it was removed at shader link");
422}
423
424const QGLUniform& QGLUniform::operator=(const GLfloat& rhs) const
425{
426 if (m_type != QGLFloatType)
427 return *this;
428
429 glUniform1f(m_id, rhs);
430
431 return *this;
432}
433
434const QGLUniform& QGLUniform::operator=(const QGLVec2& rhs) const
435{
436 if (m_type != QGLVec2Type)
437 return *this;
438
439 glUniform2fv(m_id, 1, (const GLfloat*)&rhs);
440
441 return *this;
442}
443
444const QGLUniform& QGLUniform::operator=(const QSizeF& rhs) const
445{
446 if (m_type != QGLVec2Type)
447 return *this;
448
449 glUniform2f(m_id, rhs.width(), rhs.height());
450
451 return *this;
452}
453
454const QGLUniform& QGLUniform::operator=(const QPointF& rhs) const
455{
456 if (m_type != QGLVec2Type)
457 return *this;
458
459 glUniform2f(m_id, rhs.x(), rhs.y());
460
461 return *this;
462}
463
464const QGLUniform& QGLUniform::operator=(const QGLVec3& rhs) const
465{
466 if (m_type != QGLVec3Type)
467 return *this;
468
469 glUniform3fv(m_id, 1, (const GLfloat*)&rhs);
470
471 return *this;
472}
473
474const QGLUniform& QGLUniform::operator=(const QGLVec4& rhs) const
475{
476 if (m_type != QGLVec4Type)
477 return *this;
478
479 glUniform4fv(m_id, 1, (const GLfloat*)&rhs);
480
481 return *this;
482}
483
484const QGLUniform& QGLUniform::operator=(const QColor& rhs) const
485{
486 if (m_type != QGLVec4Type)
487 return *this;
488
489 glUniform4f(m_id, rhs.redF(), rhs.greenF(), rhs.blueF(), rhs.alphaF());
490
491 return *this;
492}
493
494const QGLUniform& QGLUniform::operator=(const GLfloat rhs[2][2]) const
495{
496 if (m_type != QGLMat2Type)
497 return *this;
498
499 glUniformMatrix2fv(m_id, 1, GL_FALSE, (GLfloat*)rhs);
500
501 return *this;
502}
503
504const QGLUniform& QGLUniform::operator=(const GLfloat rhs[3][3]) const
505{
506 if (m_type != QGLMat3Type)
507 return *this;
508
509 glUniformMatrix3fv(m_id, 1, GL_FALSE, (GLfloat*)rhs);
510
511 return *this;
512}
513
514// Transposes ready for GL
515const QGLUniform& QGLUniform::operator=(const QTransform& rhs) const
516{
517 if (m_type != QGLMat3Type)
518 return *this;
519
520 GLfloat mat3[3][3] = {
521 {rhs.m11(), rhs.m12(), rhs.m13()},
522 {rhs.m21(), rhs.m22(), rhs.m23()},
523 {rhs.m31(), rhs.m32(), rhs.m33()}
524 };
525
526 glUniformMatrix3fv(m_id, 1, GL_FALSE, (GLfloat*)mat3);
527
528 return *this;
529}
530
531const QGLUniform& QGLUniform::operator=(const GLfloat rhs[4][4]) const
532{
533 if (m_type != QGLMat4Type)
534 return *this;
535
536 glUniformMatrix4fv(m_id, 1, GL_FALSE, (GLfloat*)rhs);
537
538 return *this;
539}
540
541const QGLUniform& QGLUniform::operator=(const GLuint& rhs) const
542{
543 if ((m_type != QGLSampler2DType) || (m_type != QGLSamplerCubeType))
544 return *this;
545
546 glUniform1i(m_id, rhs);
547
548 return *this;
549}
550
551
552
553
554/////////////////////////////////////////////////////////////////////////
555
556QGLVertexAttribute::QGLVertexAttribute()
557 : m_id(0), m_type(QGLInvalidType), ctx(0)
558{
559 qWarning("Unknown vertex attribute!");
560}
561
562void QGLVertexAttribute::enable() const
563{
564 glEnableVertexAttribArray(m_id);
565}
566
567void QGLVertexAttribute::disable() const
568{
569 glDisableVertexAttribArray(m_id);
570}
571
572// NOTE: Under PC emulation, QGLVec4Type is _always_ returned as the type, so this
573// method isn't very useful. I.e. The datatypes are needed to distinguish the different
574// sizes for the function signatures.
575const QGLVertexAttribute& QGLVertexAttribute::operator=(const GLfloat* rhs) const
576{
577 int size = -1;
578 if (m_type == QGLFloatType)
579 size = 1;
580 else if (m_type == QGLVec2Type)
581 size = 2;
582 else if (m_type == QGLVec3Type)
583 size = 3;
584 else if (m_type == QGLVec4Type)
585 size = 4;
586 else if (m_type == QGLMat2Type) //### Not sure if this is right for matrix attributes...
587 size = 4;
588 else if (m_type == QGLMat3Type) //### Not sure if this is right for matrix attributes...
589 size = 9;
590 else if (m_type == QGLMat4Type) //### Not sure if this is right for matrix attributes...
591 size = 16;
592 else
593 return *this;
594
595 glVertexAttribPointer(m_id, size, GL_FLOAT, GL_FALSE, 0, rhs);
596
597 return *this;
598}
599
600const QGLVertexAttribute& QGLVertexAttribute::operator=(const QGLVec3* rhs) const
601{
602 glVertexAttribPointer(m_id, 3, GL_FLOAT, GL_FALSE, 0, (GLfloat*)rhs);
603
604 return *this;
605}
Note: See TracBrowser for help on using the repository browser.