/* QGLView Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "gltypes.h" #include "qglview.h" #include "glshaders.h" #include "glshaders_headers.h" using namespace QGLEngineShaders; bool addShader(QOpenGLShaderProgram * prog, QOpenGLShader::ShaderType type, QString & content, const QString & file, const QString & defs) { if (type == 0 || content.isEmpty()) { content.clear(); return true; } //qDebug() << "[QGLView] Shader" << file << "found" << (QOpenGLShader::ShaderTypeBit)(int)type << "section ..."; switch (type) { case QOpenGLShader::Fragment: content.prepend(qgl_fragment_head); content.prepend(qgl_uniform); content.prepend(qgl_structs); break; case QOpenGLShader::Vertex : content.prepend(qgl_vertex_head ); break; case QOpenGLShader::Geometry: content.prepend(qgl_geometry_head); break; } content.prepend(defs); content.prepend(qgl_common_head); bool ret = prog->addShaderFromSourceCode(type, content.toLatin1()); if (!ret) qDebug() << "[QGLView] Shader" << file << "Compile error:\n" << prog->log(); content.clear(); return ret; } QString prepareDefines(const QStringList & defines) { if (defines.isEmpty()) return QString(); QString ret; foreach (QString s, defines) ret.append("#define " + s + "\n"); return ret; } bool QGLEngineShaders::loadShadersMulti(QOpenGLShaderProgram *& prog, const QString & file, const QStringList & defines) { if (!prog) prog = new QOpenGLShaderProgram(); prog->removeAllShaders(); QFile f(file); if (!f.open(QIODevice::ReadOnly)) { qDebug() << "[QGLView] Shader" << file << "Error: can`t open file!"; return false; } QTextStream ts(&f); QString cur_shader, line, pl, defs = prepareDefines(defines); QOpenGLShader::ShaderType type = 0; while (!ts.atEnd()) { line = ts.readLine(); pl = line.trimmed().remove(' ').remove('\t').mid(2).toLower(); pl.chop(2); if (pl == "vertex" || pl == "vert") { if (!addShader(prog, type, cur_shader, file, defs)) return false; type = QOpenGLShader::Vertex; continue; } if (pl == "fragment" || pl == "frag") { if (!addShader(prog, type, cur_shader, file, defs)) return false; type = QOpenGLShader::Fragment; continue; } if (pl == "geometry" || pl == "geom") { if (!addShader(prog, type, cur_shader, file, defs)) return false; type = QOpenGLShader::Geometry; continue; } if (pl == "tessellation_control") { if (!addShader(prog, type, cur_shader, file, defs)) return false; type = QOpenGLShader::TessellationControl; continue; } if (pl == "tessellation_evaluation") { if (!addShader(prog, type, cur_shader, file, defs)) return false; type = QOpenGLShader::TessellationEvaluation; continue; } cur_shader.append("\n"); cur_shader.append(line); } if (!addShader(prog, type, cur_shader, file, defs)) return false; if (!prog->link()) { qDebug() << "[QGLView] Shader" << file << "Link error:\n" << prog->log(); return false; } qDebug() << "[QGLView] Shader" << file << "ok"; return true; } void QGLEngineShaders::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 QGLEngineShaders::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 QGLEngineShaders::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; }