/* QGLView Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "gltypes.h" #include "qglview.h" const char qgl_vertex_head[] = //"in vec3 _qgl_Vertex;\n" "in vec3 qgl_Normal;\n" "in vec3 qgl_Tangent;\n" "in vec3 qgl_Bitangent;\n" "in vec2 qgl_Texture;\n" "in vec4 qgl_Color;\n" "out vec2 qgl_FragTexture;\n" "out vec4 qgl_FragColor;\n" //"vec4 qgl_Vertex = vec4(_qgl_Vertex, 1);\n" "in vec3 qgl_Vertex;\n" "vec4 qgl_ftransform() {return qgl_ModelViewProjectionMatrix * vec4(qgl_Vertex, 1);}\n"; const char qgl_fragment_head[] = "in vec2 qgl_FragTexture;\n" "in vec4 qgl_FragColor;\n" "out vec4 qgl_FragData[gl_MaxDrawBuffers];\n"; const char qgl_uniform[] = "uniform mat4 qgl_ModelViewMatrix;\n" "uniform mat4 qgl_ProjectionMatrix;\n" "uniform mat4 qgl_ModelViewProjectionMatrix;\n" "uniform mat3 qgl_NormalMatrix;\n" "uniform mat4 qgl_ModelViewMatrixInverse;\n" "uniform mat4 qgl_ProjectionMatrixInverse;\n" "uniform mat4 qgl_ModelViewProjectionMatrixInverse;\n" "uniform mat4 qgl_ModelViewMatrixTranspose;\n" "uniform mat4 qgl_ProjectionMatrixTranspose;\n" "uniform mat4 qgl_ModelViewProjectionMatrixTranspose;\n" "uniform mat4 qgl_ModelViewMatrixInverseTranspose;\n" "uniform mat4 qgl_ProjectionMatrixInverseTranspose;\n" "uniform mat4 qgl_ModelViewProjectionMatrixInverseTranspose;\n"; const char qgl_structs[] = "const int qgl_MaxLights = 8;\n" "struct QGLLight {\n" " vec4 color;\n" " vec4 position;\n" " vec4 direction;\n" " float intensity;\n" " float startAngle;\n" " float startAngleCos;\n" " float endAngle;\n" " float endAngleCos;\n" " float constantAttenuation;\n" " float linearAttenuation;\n" " float quadraticAttenuation;\n" " sampler2DShadow shadow;\n" //" sampler2D shadowColor\n" " mat4 shadowMatrix;\n" //" vec4 shadowDir0;\n" //" vec4 shadowDir1;\n" "};\n" "struct QGLMap {\n" " float offset;\n" " float amount;\n" " vec2 scale;\n" " sampler2D map;\n" "};\n" "struct QGLMaterial {\n" " float transparency;\n" " float reflectivity;\n" " float iof;\n" " float dispersion;\n" " vec4 color_diffuse;\n" " vec4 color_specular;\n" " vec4 color_self_illumination;\n" " QGLMap map_diffuse;\n" " QGLMap map_normal;\n" " QGLMap map_relief;\n" " QGLMap map_self_illumination;\n" " QGLMap map_specularity;\n" " QGLMap map_specular;\n" "};\n" "uniform QGLLight qgl_AmbientLight;\n" "uniform QGLLight qgl_Light[qgl_MaxLights];\n" "uniform QGLMaterial qgl_Material;\n"; QString loadShaderFile(QOpenGLShaderProgram * prog, QOpenGLShader::ShaderType type, const QString & file) { QFile f(file); if (!f.open(QIODevice::ReadOnly)) return ""; QString all = QString::fromUtf8(f.readAll()); int i = all.indexOf("#version"); QString version = all.mid(i + 8, all.indexOf("\n", i) - i - 8).trimmed(); if (version.toInt() >= 150) { int ip = all.indexOf("\n", i); if (ip < 0) return all; if (type == QOpenGLShader::Vertex) { all.insert(ip + 1, qgl_vertex_head); } if (type == QOpenGLShader::Fragment) { all.insert(ip + 1, qgl_fragment_head); } all.insert(ip + 1, qgl_structs); all.insert(ip + 1, qgl_uniform); } prog->addShaderFromSourceCode(type, all); //qDebug() << "********" << all; return all; } bool loadShaders(QOpenGLShaderProgram * prog, const QString & name, const QString & dir) { prog->removeAllShaders(); QDir d(dir); QFileInfoList sl; //qDebug() << "[QGLView] Shader \"" + name + "\" load shaders from" << d.absolutePath(); sl = d.entryInfoList(QStringList(name + ".geom"), QDir::Files | QDir::NoDotAndDotDot); foreach (const QFileInfo & i, sl) { //qDebug() << "[QGLView] Shader \"" + name + "\" add geometry shader:" << i.fileName(); loadShaderFile(prog, QOpenGLShader::Geometry, i.absoluteFilePath()); } sl = d.entryInfoList(QStringList(name + ".vert"), QDir::Files | QDir::NoDotAndDotDot); foreach (const QFileInfo & i, sl) { //qDebug() << "[QGLView] Shader \"" + name + "\" add vertex shader:" << i.fileName(); loadShaderFile(prog, QOpenGLShader::Vertex, i.absoluteFilePath()); } sl = d.entryInfoList(QStringList(name + ".frag"), QDir::Files | QDir::NoDotAndDotDot); foreach (const QFileInfo & i, sl) { //qDebug() << "[QGLView] Shader \"" + name + "\" add fragment shader:" << i.fileName(); loadShaderFile(prog, QOpenGLShader::Fragment, i.absoluteFilePath()); } if (!prog->link()) { qDebug() << "[QGLView] Shader \"" + name + "\" link error: " + prog->log(); return false; } return true; } void setUniformMatrices(QOpenGLShaderProgram * prog, QMatrix4x4 proj, QMatrix4x4 view, QMatrix4x4 prevproj, QMatrix4x4 prevview) { if (!prog) return; if (!prog->isLinked()) return; QMatrix4x4 mvpm = proj * view; QMatrix4x4 pmvpm = prevproj * prevview; QMatrix3x3 nm = view.normalMatrix(); //nm.in; prog->setUniformValue("qgl_ModelViewMatrix", view); prog->setUniformValue("qgl_ProjectionMatrix", proj); prog->setUniformValue("prev_ModelViewProjectioMatrix", pmvpm); prog->setUniformValue("prev_ModelViewMatrix", prevview); prog->setUniformValue("qgl_ModelViewProjectionMatrix", mvpm); prog->setUniformValue("qgl_NormalMatrix", nm); //prog->setUniformValue("qgl_BumpMatrix", nm.); prog->setUniformValue("qgl_ModelViewMatrixTranspose", view.transposed()); prog->setUniformValue("qgl_ProjectionMatrixTranspose", proj.transposed()); prog->setUniformValue("qgl_ModelViewProjectionMatrixTranspose", mvpm.transposed()); } void setUniformMap(QOpenGLShaderProgram * prog, QString map_name, const Map & map, int channel, int def_channel) { if (!prog) return; if (!prog->isLinked()) return; prog->setUniformValue(("qgl_Material." + map_name + ".offset").toLatin1().constData(), map.color_offset); prog->setUniformValue(("qgl_Material." + map_name + ".amount").toLatin1().constData(), map.color_amount); prog->setUniformValue(("qgl_Material." + map_name + ".scale").toLatin1().constData(), map.bitmap_scale); prog->setUniformValue(("qgl_Material." + map_name + ".map").toLatin1().constData(), map.bitmap_id > 0 ? channel : def_channel); } void setUniformMaterial(QOpenGLShaderProgram * prog, const Material & mat) { if (!prog) return; if (!prog->isLinked()) return; QOpenGLFunctions *glFuncs = QOpenGLContext::currentContext()->functions(); GLfloat mat_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f}; mat_diffuse[0] = mat.color_diffuse.redF(); mat_diffuse[1] = mat.color_diffuse.greenF(); mat_diffuse[2] = mat.color_diffuse.blueF(); mat_diffuse[3] = mat.color_diffuse.alphaF() * (1.f - mat.transparency); glFuncs->glVertexAttrib4f(prog->attributeLocation("qgl_Color"), mat_diffuse[0], mat_diffuse[1], mat_diffuse[2], mat_diffuse[3]); prog->setUniformValue("qgl_Material.transparency", mat.transparency); prog->setUniformValue("qgl_Material.reflectivity", mat.reflectivity); prog->setUniformValue("qgl_Material.iof", mat.iof); prog->setUniformValue("qgl_Material.dispersion", mat.dispersion); prog->setUniformValue("qgl_Material.color_diffuse", mat.color_diffuse); prog->setUniformValue("qgl_Material.color_self_illumination", mat.color_self_illumination); prog->setUniformValue("qgl_Material.color_specular", mat.color_specular); setUniformMap(prog, "map_diffuse", mat.map_diffuse, 0, 6); setUniformMap(prog, "map_normal", mat.map_normal, 1, 7); setUniformMap(prog, "map_relief", mat.map_relief, 2, 6); setUniformMap(prog, "map_self_illumination", mat.map_self_illumination, 3, 6); setUniformMap(prog, "map_specularity", mat.map_specularity, 4, 6); setUniformMap(prog, "map_specular", mat.map_specular, 5, 6); } void setUniformLights(QOpenGLShaderProgram * prog, const QVector & lights, const QMatrix4x4 & mat, int shadow_start) { for (int i = 0; i < lights.size(); ++i) setUniformLight(prog, lights[i], QString("qgl_Light[%1]").arg(i), mat, shadow_start + i); } /* " vec3 position;\n" " vec3 direction;\n" " vec4 color;\n" " float intensity;\n" " float startAngle;\n" " float endAngle;\n" " float constantAttenuation;\n" " float linearAttenuation;\n" " float quadraticAttenuation;\n" " sampler2DShadow shadow;\n" " mat4 shadowMatrix;\n" */ void setUniformLight(QOpenGLShaderProgram * prog, Light * light, QString ulightn, const QMatrix4x4 & mat, int shadow) { if (!prog) return; if (!prog->isLinked()) return; QMatrix4x4 m = mat * light->worldTransform(); QVector4D pos(0, 0, 0, 1.), dir(light->direction, 1);//, dir0(light->dir0), dir1(light->dir1); pos = m * pos; dir = ((m * dir) - pos).normalized(); float ang_start = light->angle_start / 2.f, ang_end = light->angle_end / 2.f; if (light->light_type == Light::Omni) ang_start = ang_end = 180.; //qDebug() << "light" << light->name() << ulightn << pos; prog->setUniformValue((ulightn + ".position").toLatin1().constData(), pos); prog->setUniformValue((ulightn + ".direction").toLatin1().constData(), dir); prog->setUniformValue((ulightn + ".intensity").toLatin1().constData(), GLfloat(light->intensity)); prog->setUniformValue((ulightn + ".startAngle").toLatin1().constData(), GLfloat(ang_start)); prog->setUniformValue((ulightn + ".startAngleCos").toLatin1().constData(), GLfloat(cosf(ang_start * deg2rad))); prog->setUniformValue((ulightn + ".endAngle").toLatin1().constData(), GLfloat(ang_end)); prog->setUniformValue((ulightn + ".endAngleCos").toLatin1().constData(), GLfloat(cosf(ang_end * deg2rad))); prog->setUniformValue((ulightn + ".color").toLatin1().constData(), light->color()); prog->setUniformValue((ulightn + ".constantAttenuation").toLatin1().constData(), GLfloat(light->decay_const)); prog->setUniformValue((ulightn + ".linearAttenuation").toLatin1().constData(), GLfloat(light->decay_linear)); prog->setUniformValue((ulightn + ".quadraticAttenuation").toLatin1().constData(), GLfloat(light->decay_quadratic)); prog->setUniformValue((ulightn + ".shadow").toLatin1().constData(), shadow); prog->setUniformValue((ulightn + ".shadowColor").toLatin1().constData(), shadow); prog->setUniformValue((ulightn + ".shadowMatrix").toLatin1().constData(), light->shadow_matrix); //qDebug() << light->shadow_matrix; //prog->setUniformValue((ulightn + ".shadowDir0").toLatin1().constData(), (mat * dir0)); //prog->setUniformValue((ulightn + ".shadowDir1").toLatin1().constData(), (mat * dir1)); //qDebug() << light->direction << light->dir0 << light->dir1; }