185 lines
7.2 KiB
C++
185 lines
7.2 KiB
C++
/*
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#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<Light*> & 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;
|
|
}
|