45 #include "qglabstracteffect.h"
46 #include <QOpenGLShaderProgram>
48 #include "qglscenenode.h"
50 #include <QWeakPointer>
52 #include <QQmlContext>
57 #include <boost/math/special_functions/spherical_harmonic.hpp>
221 , shadersSupported(true)
242 this->parent = parent;
254 QList<QGLTexture2D*> textures = texture2Ds.values();
255 QGLTexture2D* texture;
256 foreach (texture, textures)
270 (
const QString& vertexShader,
const QString& fragmentShader)
272 if (!QOpenGLShaderProgram::hasOpenGLShaderPrograms())
275 setVertexShader(vertexShader.toLatin1());
276 setFragmentShader(fragmentShader.toLatin1());
291 m_texture3DuniformValue = program()->uniformLocation(
"myTexture3D");
292 m_eyePositionUniformLocation = program()->uniformLocation(
"ve_eyePosition");
301 GLuint *
data = parent.data()->texture3Ddata().data;
302 GLuint w = parent.data()->texture3Ddata().width;
303 GLuint h = parent.data()->texture3Ddata().height;
304 GLuint d = parent.data()->texture3Ddata().depth;
307 glGenTextures(1, &g_volTexObj);
309 glBindTexture(GL_TEXTURE_3D, g_volTexObj);
310 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
311 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
312 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
313 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
314 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
316 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
317 glTexImage3D(GL_TEXTURE_3D, 0, GL_INTENSITY, w, h, d, 0, GL_LUMINANCE, GL_UNSIGNED_INT, data);
319 program()->setUniformValue(m_texture3DuniformValue, g_volTexObj);
322 propertyIdsToUniformLocations.clear();
323 uniformLocationsToTextureUnits.clear();
325 propertyListener->disconnect();
326 if (parent.data() == 0)
330 QObject::connect(propertyListener, SIGNAL(propertyChanged()), parent.data(), SIGNAL(effectChanged()));
332 const QMetaObject* parentMetaObject = parent.data()->metaObject();
333 int parentMethodCount = parentMetaObject->methodCount();
335 for (
int i = parentMetaObject->propertyOffset();
336 i < parentMetaObject->propertyCount(); i++)
338 QMetaProperty metaProperty = parentMetaObject->property(i);
339 QByteArray propertyName = metaProperty.name();
340 int location = program()->uniformLocation(propertyName);
345 dirtyProperties.append(i);
346 propertyIdsToUniformLocations[i] = location;
347 if (metaProperty.hasNotifySignal())
349 QMetaMethod notifySignal = metaProperty.notifySignal();
351 int signalIndex = notifySignal.methodIndex();
361 QMetaObject::connect(parent.data(), signalIndex,
362 propertyListener, parentMethodCount + i);
364 qWarning() <<
"Warning: No notification signal found for property: " << propertyName;
365 propertiesWithoutNotificationSignal.append(i);
371 this->setPropertiesDirty();
384 static inline void setUniformFromFloatList(QOpenGLShaderProgram *program,
int uniformLocation, QList<QVariant> list)
386 switch(list.length())
389 program->setUniformValue(uniformLocation, list.at(0).toFloat());
392 program->setUniformValue(uniformLocation,
393 list.at(0).toFloat(),
394 list.at(1).toFloat());
397 program->setUniformValue(uniformLocation,
398 list.at(0).toFloat(),
399 list.at(1).toFloat(),
400 list.at(2).toFloat());
403 program->setUniformValue(uniformLocation,
404 list.at(0).toFloat(),
405 list.at(1).toFloat(),
406 list.at(2).toFloat(),
407 list.at(3).toFloat());
412 for (
int i = 0; i < 9; i++)
414 matrix(i / 3, i % 3) = list.at(i).toFloat();
416 program->setUniformValue(uniformLocation, matrix);
422 for (
int i = 0; i < 16; i++)
424 matrix( i / 4, i % 4) = list.at(i).toFloat();
426 program->setUniformValue(uniformLocation, matrix);
431 qWarning() <<
"Warning: unexpected list size: " << list.size() <<
", only 1-4, 9 and 16 supported";
441 (QGLPainter *painter, QGLPainter::Updates updates)
446 if (changedTextures.count() > 0)
448 foreach (
int i, changedTextures)
450 if (!images.contains(i))
452 changedTextures.remove(i);
456 if (!images[i].isNull())
458 setUniform(i, images[i], painter);
461 qWarning() <<
"Warning: VolumeShaderProgramEffect failed to apply texture for uniform" << i << (urls.contains(i) ? QLatin1String(
" url: ") + urls[i] : QString());
463 changedTextures.remove(i);
468 QGLShaderProgramEffect::update(painter, updates);
471 if (!parent.data() || !(propertyIdsToUniformLocations.count() > 0))
476 QList<int> propertiesNotUpdated;
477 foreach (propertyIndex, dirtyProperties)
479 if (!setUniformForPropertyIndex(propertyIndex, painter))
481 propertiesNotUpdated.append(propertyIndex);
484 dirtyProperties.clear();
485 dirtyProperties.append(propertiesNotUpdated);
488 foreach (propertyIndex, propertiesWithoutNotificationSignal)
490 setUniformForPropertyIndex(propertyIndex, painter);
500 QVector4D inverseColumn3 = painter->modelViewMatrix().top().inverted().column(3);
501 program()->setUniformValue(m_eyePositionUniformLocation, inverseColumn3);
504 inline QGLTexture2D* VolumeShaderProgramEffect::textureForUniformValue(
int uniformLocation)
506 QGLTexture2D* result = texture2Ds.value(uniformLocation);
509 result =
new QGLTexture2D();
510 texture2Ds[uniformLocation] = result;
517 QOpenGLShaderProgram *program = this->program();
518 int uniformLocation = propertyIdsToUniformLocations[propertyIndex];
521 parent.data()->metaObject()->property(propertyIndex).read(parent.data());
523 switch(
int(value.type()))
525 case QVariant::Double:
527 case QMetaType::Float:
528 program->setUniformValue(uniformLocation, value.toFloat());
531 program->setUniformValue(uniformLocation, value.toInt());
534 program->setUniformValue(uniformLocation, value.toUInt());
537 program->setUniformValue(uniformLocation, value.toBool());
539 case QVariant::Color:
540 program->setUniformValue(uniformLocation, value.value<QColor>());
543 setUniformFromFloatList(program, uniformLocation, value.toList());
545 case QVariant::Point:
546 program->setUniformValue(uniformLocation, value.toPoint());
548 case QVariant::PointF:
549 program->setUniformValue(uniformLocation, value.toPointF());
552 program->setUniformValue(uniformLocation, value.toSize());
554 case QVariant::SizeF:
555 program->setUniformValue(uniformLocation, value.toSizeF());
557 case QVariant::Matrix4x4:
558 program->setUniformValue(uniformLocation, value.value<QMatrix4x4>());
560 case QVariant::Vector2D:
561 program->setUniformValue(uniformLocation, value.value<QVector2D>());
563 case QVariant::Vector3D:
564 program->setUniformValue(uniformLocation, value.value<QVector3D>());
566 case QVariant::Vector4D:
567 program->setUniformValue(uniformLocation, value.value<QVector4D>());
569 case QVariant::String:
572 QString urlString = value.toString();
573 processTextureUrl(uniformLocation, urlString);
576 case QVariant::Image:
578 QImage image(value.toString());
579 setUniform(uniformLocation, image, painter);
583 qWarning() <<
"Unrecognized variant for property " << parent.data()->metaObject()->property(propertyIndex).name() <<
" of type " << value.typeName() <<
", could not set corresponding shader variable";
591 void VolumeShaderProgramEffect::setUniform
592 (
int uniformLocation,
const QPixmap pixmap, QGLPainter* painter)
595 QGLTexture2D* texture = textureForUniformValue(uniformLocation);
596 int unit = textureUnitForUniformValue(uniformLocation);
599 texture->setPixmap(pixmap);
600 painter->glActiveTexture(GL_TEXTURE0 + unit);
602 program()->setUniformValue(uniformLocation, unit);
609 void VolumeShaderProgramEffect::setUniform
610 (
int uniformLocation,
const QImage& image, QGLPainter* painter)
613 QGLTexture2D* texture = textureForUniformValue(uniformLocation);
614 int unit = textureUnitForUniformValue(uniformLocation);
617 texture->setImage(image);
618 painter->glActiveTexture(GL_TEXTURE0 + unit);
620 program()->setUniformValue(uniformLocation, unit);
627 int VolumeShaderProgramEffect::textureUnitForUniformValue(
int uniformLocation)
629 int unit = uniformLocationsToTextureUnits.value(uniformLocation, -1);
631 unit = nextTextureUnit++;
632 uniformLocationsToTextureUnits[uniformLocation] = unit;
643 dirtyProperties = this->propertyIdsToUniformLocations.keys();
652 if (dirtyProperties.indexOf(property) == -1)
654 dirtyProperties.append(property);
668 if (urlString.isEmpty() &&
669 urls.contains(uniformLocation) &&
670 !urls[uniformLocation].isNull())
672 if (images.contains(uniformLocation) && !images[uniformLocation].isNull())
674 images[uniformLocation] = QImage();
675 urls.remove(uniformLocation);
676 changedTextures.insert(uniformLocation);
682 if (url.isRelative())
685 QQmlContext *context =
686 QQmlEngine::contextForObject(parent.data());
690 QUrl baseurl = context->baseUrl();
691 QUrl absolute = baseurl.resolved(urlString);
693 if (absolute.isValid())
696 urlString = absolute.toString();
698 qWarning() <<
"Warning: failed to resolve relative path " <<
704 if (urlString != urls[uniformLocation])
706 if (url.scheme() != QLatin1String(
"file"))
713 qWarning(
"Network URL's not yet supported - %s", qPrintable(urlString));
717 QString localFile = url.toLocalFile();
718 if (localFile.endsWith(QLatin1String(
".dds")))
720 qWarning(
"Shader effects with compressed textures not supported: %s",
721 qPrintable(urlString));
725 QImage im(localFile);
728 qWarning(
"Could not load image from local file path - %s", qPrintable(localFile));
732 images[uniformLocation] = im;
733 changedTextures.insert(uniformLocation);
745 : QQuickEffect(parent),
780 emit effectChanged();
801 emit effectChanged();
813 QQuickEffect::enableEffect(painter);
823 QQuickEffect::enableEffect(painter);
833 QQuickEffect::enableEffect(painter);
841 painter->setUserEffect(d->
effect);
859 node->setUserEffect(d->
effect);
869 return m_vertexShaderSource;
874 return m_fragmentShaderSource;
930 return m_texture3Ddata;
935 if (m_vertexShaderSource != arg) {
936 m_vertexShaderSource = arg;
937 QFile file(arg.path());
938 QString vertexShaderFileContents;
939 if (file.open(QIODevice::ReadOnly)) {
940 vertexShaderFileContents = file.readAll();
942 qWarning() <<
"VolumeShaderProgram::setVertexShaderSource: could not open " << arg;
951 if (m_fragmentShaderSource != arg) {
952 m_fragmentShaderSource = arg;
953 QFile file(arg.path());
954 QString fragmentShaderFileContents;
955 if (file.open(QIODevice::ReadOnly)) {
956 fragmentShaderFileContents = file.readAll();
958 qWarning() <<
"VolumeShaderProgram::setFragmentShaderSource: could not open " << arg;
967 if (m_positionReader != arg) {
968 m_positionReader = arg;
969 connect(m_positionReader, SIGNAL(dataChanged()),
this, SLOT(
forceUpdate()));
982 emit effectChanged();
1001 VolumeshaderProgramMethodCount = parent->metaObject()->methodCount();
1018 if (c == QMetaObject::InvokeMetaMethod )
1020 if (
id >= VolumeshaderProgramMethodCount) {
1028 return VolumeShaderProgramPropertyListener::qt_metacall(c,
id, a);