232 lines
9.4 KiB
C++
232 lines
9.4 KiB
C++
/*
|
|
QGLView
|
|
Copyright (C) 2012 Ivan Pelipenko peri4ko@gmail.com
|
|
|
|
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"
|
|
|
|
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"
|
|
"vec4 qgl_ftransform() {return qgl_ModelViewProjectionMatrix * qgl_Vertex;}\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 = 16;\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"
|
|
"};\n"
|
|
"struct QGLMap {\n"
|
|
" float offset;\n"
|
|
" float amount;\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(QGLShaderProgram * prog, QGLShader::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 == QGLShader::Vertex) {
|
|
all.insert(ip + 1, qgl_vertex_head);
|
|
}
|
|
if (type == QGLShader::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(QGLShaderProgram * prog, const QString & name, const QString & dir) {
|
|
prog->removeAllShaders();
|
|
QDir d(dir);
|
|
QFileInfoList sl;
|
|
//qDebug() << "[QGLView] Shader \"" + name + "\" load shaders from" << d.absolutePath();
|
|
#if QT_VERSION >= 0x040700
|
|
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, QGLShader::Geometry, i.absoluteFilePath());
|
|
}
|
|
#endif
|
|
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, QGLShader::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, QGLShader::Fragment, i.absoluteFilePath());
|
|
}
|
|
if (!prog->link()) {
|
|
qDebug() << "[QGLView] Shader \"" + name + "\" link error: " + prog->log();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void setUniformMatrices(QGLShaderProgram * prog, QMatrix4x4 proj, QMatrix4x4 view, QMatrix4x4 prevproj, QMatrix4x4 prevview) {
|
|
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("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(QGLShaderProgram * prog, QString map_name, const Map & map, int channel, int def_channel) {
|
|
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 + ".map").toLatin1().constData(), map.bitmap_id > 0 ? channel : def_channel);
|
|
}
|
|
|
|
|
|
void setUniformMaterial(QGLShaderProgram * prog, const Material & mat) {
|
|
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);
|
|
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(QGLShaderProgram * prog, const QVector<Light*> & lights, const QMatrix4x4 & mat, const QVector4D & dp) {
|
|
for (int i = 0; i < lights.size(); ++i)
|
|
setUniformLight(prog, lights[i], QString("qgl_Light[%1]").arg(i), mat, dp);
|
|
}
|
|
/*
|
|
" 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"
|
|
*/
|
|
void setUniformLight(QGLShaderProgram * prog, Light * light, QString ulightn, const QMatrix4x4 & mat, const QVector4D & dp) {
|
|
QMatrix4x4 m = mat * light->worldTransform();
|
|
QVector4D pos(0, 0, 0, 1.), dir(light->direction);
|
|
pos = m * pos;
|
|
dir = (m * dir).normalized();
|
|
double ang_start = light->angle_start / 2., ang_end = light->angle_end / 2.;
|
|
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(cos(ang_start * deg2rad)));
|
|
prog->setUniformValue((ulightn + ".endAngle").toLatin1().constData(), GLfloat(ang_end));
|
|
prog->setUniformValue((ulightn + ".endAngleCos").toLatin1().constData(), GLfloat(cos(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));
|
|
}
|