228 lines
8.1 KiB
C++
228 lines
8.1 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 "glrendererbase.h"
|
|
#include "globject.h"
|
|
#include "qglview.h"
|
|
|
|
|
|
GLRendererBase::GLRendererBase(QGLView * view_): view(*view_) {
|
|
white_image = QImage(1, 1, QImage::Format_ARGB32);
|
|
white_image.fill(0xFFFFFFFF);
|
|
white_image_id = 0;
|
|
violent_image = QImage(1, 1, QImage::Format_ARGB32);
|
|
violent_image.fill(QColor(127, 127, 255));
|
|
violent_image_id = 0;
|
|
}
|
|
|
|
|
|
void GLRendererBase::setupLight(const Light & l, int inpass_index, int gl_index) {
|
|
QVector3D lp = l.worldPos(), ld = (l.itransform_ * QVector4D(l.direction, 0.)).toVector3D().normalized();
|
|
GLfloat pos[] = {0.f, 0.f, 0.f, 0.f};
|
|
GLfloat dir[] = {0.f, 0.f, 0.f};
|
|
GLfloat col[] = {0.f, 0.f, 0.f};
|
|
pos[0] = l.light_type == Light::Directional ? -l.direction.x() : lp.x();
|
|
pos[1] = l.light_type == Light::Directional ? -l.direction.y() : lp.y();
|
|
pos[2] = l.light_type == Light::Directional ? -l.direction.z() : lp.z();
|
|
pos[3] = l.light_type == Light::Directional ? 0. : 1.;
|
|
dir[0] = ld.x();
|
|
dir[1] = ld.y();
|
|
dir[2] = ld.z();
|
|
col[0] = l.visible_ ? l.color().redF() * l.intensity : 0.;
|
|
col[1] = l.visible_ ? l.color().greenF() * l.intensity : 0.;
|
|
col[2] = l.visible_ ? l.color().blueF() * l.intensity : 0.;
|
|
glEnable(gl_index);
|
|
//glLightfv(gl_index, GL_AMBIENT, ambient);
|
|
glLightfv(gl_index, GL_DIFFUSE, col);
|
|
glLightfv(gl_index, GL_SPECULAR, col);
|
|
glLightfv(gl_index, GL_POSITION, pos);
|
|
glLightf(gl_index, GL_CONSTANT_ATTENUATION, l.decay_const);
|
|
glLightf(gl_index, GL_LINEAR_ATTENUATION, l.decay_linear);
|
|
glLightf(gl_index, GL_QUADRATIC_ATTENUATION, l.decay_quadratic);
|
|
if (l.light_type == Light::Cone) {
|
|
glLightfv(gl_index, GL_SPOT_DIRECTION, dir);
|
|
glLightf(gl_index, GL_SPOT_CUTOFF, l.angle_spread);
|
|
glLightf(gl_index, GL_SPOT_EXPONENT, l.angle_decay_exp);
|
|
} else {
|
|
glLightf(gl_index, GL_SPOT_CUTOFF, 180.);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void GLRendererBase::setupAmbientLight(const QColor & a, bool first_pass) {
|
|
GLfloat ambient[] = {0.0f, 0.0f, 0.0f, 1.f};
|
|
if (first_pass) {
|
|
ambient[0] = view.ambientColor_.redF();
|
|
ambient[1] = view.ambientColor_.greenF();
|
|
ambient[2] = view.ambientColor_.blueF();
|
|
}
|
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
|
|
}
|
|
|
|
|
|
void GLRendererBase::setupShadersLights(int lights_count) {
|
|
/*foreach (QGLShaderProgram * i, view.shaders_ppl) {
|
|
i->bind();
|
|
i->setUniformValue("lightsCount", lights_count);
|
|
i->setUniformValue("acc_light", lights_count > 0);
|
|
//i->setUniformValue("mat", mvm);
|
|
}*/
|
|
}
|
|
|
|
|
|
#define BIND_TEXTURE(ch, map) if (rp.prev_tex[ch] != mat.map.bitmap_id) { \
|
|
rp.prev_tex[ch] = mat.map.bitmap_id; \
|
|
glActiveTextureChannel(ch); glBindTexture(GL_TEXTURE_2D, mat.map.bitmap_id); \
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, view.anisotropicLevel_);}
|
|
|
|
void GLRendererBase::setupTextures(GLObjectBase & o, GLRendererBase::RenderingParameters & rp, bool first_object) {
|
|
if (first_object) {
|
|
glReleaseTextures();
|
|
return;
|
|
}
|
|
setupShadersTextures(o, rp);
|
|
Material & mat(o.material_);
|
|
if (rp.light) {
|
|
if (o.accept_light) {if (!rp.prev_light) {glSetLightEnabled(true); rp.prev_light = true;}}
|
|
else {if (rp.prev_light) {glSetLightEnabled(false); rp.prev_light = false;}}
|
|
}
|
|
if (rp.fog) {
|
|
if (o.accept_fog) {if (!rp.prev_fog) {glSetFogEnabled(true); rp.prev_fog = true;}}
|
|
else {if (rp.prev_fog) {glSetFogEnabled(false); rp.prev_fog = false;}}
|
|
}
|
|
if (rp.textures) {
|
|
BIND_TEXTURE(0, map_diffuse);
|
|
BIND_TEXTURE(1, map_normal);
|
|
BIND_TEXTURE(2, map_relief);
|
|
BIND_TEXTURE(3, map_self_illumination);
|
|
BIND_TEXTURE(4, map_specularity);
|
|
BIND_TEXTURE(5, map_specular);
|
|
glActiveTextureChannel(0);
|
|
}
|
|
}
|
|
|
|
#undef BIND_TEXTURE
|
|
|
|
|
|
void GLRendererBase::setupLights(int pass, int lights_per_pass) {
|
|
int light_start, light_end, lmax;
|
|
light_start = pass * lights_per_pass;
|
|
light_end = qMin<int>((pass + 1) * lights_per_pass, view.lights_.size());
|
|
setupAmbientLight(view.ambientColor_, pass == 0);
|
|
if (!view.lights_.isEmpty()) {
|
|
setupShadersLights(light_end - light_start);
|
|
for (int i = light_start; i < light_end; ++i)
|
|
setupLight(*view.lights_[i], i - light_start, GL_LIGHT0 + i - light_start);
|
|
lmax = light_start + 8;
|
|
for (int i = light_end; i < lmax; ++i)
|
|
glDisable(GL_LIGHT0 + i - light_start);
|
|
} else {
|
|
setupShadersLights(0);
|
|
for (int i = 0; i < 8; ++i)
|
|
glDisable(GL_LIGHT0 + i);
|
|
}
|
|
}
|
|
|
|
|
|
void GLRendererBase::applyFilteringParameters() {
|
|
if (view.linearFiltering_) {
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
} else {
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
|
|
}
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, view.anisotropicLevel_);
|
|
}
|
|
|
|
|
|
void GLRendererBase::renderObjects(int pass, int light_pass, void * shaders, bool textures, bool light, bool fog) {
|
|
RenderingParameters rp;
|
|
rp.pass = pass;
|
|
rp.light_pass = light_pass;
|
|
rp.shaders = shaders;
|
|
rp.textures = textures;
|
|
rp.light = rp.prev_light = light;
|
|
rp.fog = rp.prev_fog = fog;
|
|
rp.view_matrix = getGLMatrix(GL_MODELVIEW_MATRIX);
|
|
rp.proj_matrix = getGLMatrix(GL_PROJECTION_MATRIX);
|
|
//qDebug() << "view:" << rp.view_matrix;
|
|
for (int i = 0; i < 32; ++i) rp.prev_tex[i] = 0;
|
|
setupTextures(view.objects_, rp, true);
|
|
glSetLightEnabled(rp.prev_light);
|
|
glSetFogEnabled(rp.prev_fog);
|
|
glSetCapEnabled(GL_TEXTURE_2D, rp.textures);
|
|
glSetCapEnabled(GL_BLEND, pass == GLObjectBase::Transparent);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glDisable(GL_TEXTURE_CUBE_MAP);
|
|
glPushMatrix();
|
|
renderSingleObject(view.objects_, rp);
|
|
glPopMatrix();
|
|
}
|
|
|
|
|
|
void GLRendererBase::renderSingleObject(GLObjectBase & o, RenderingParameters & rp) {
|
|
if (!o.isInit())
|
|
o.init();
|
|
if (!o.isTexturesLoaded())
|
|
o.loadTextures();
|
|
if (!o.visible_) return;
|
|
if (rp.pass == o.pass_) {
|
|
Material & mat(o.material_);
|
|
QMatrix4x4 curview = rp.view_matrix * o.itransform_;
|
|
setupTextures(o, rp, false);
|
|
mat.apply((QGLShaderProgram*)rp.shaders);
|
|
glSetPolygonMode(o.render_mode != GLObjectBase::View ? o.render_mode : (view.rmode != GLObjectBase::View ? view.rmode : GL_FILL));
|
|
glLineWidth(o.line_width > 0. ? o.line_width : view.lineWidth_);
|
|
glPointSize(o.line_width > 0. ? o.line_width : view.lineWidth_);
|
|
o.update();
|
|
if (o.pass_ == GLObjectBase::Transparent) {
|
|
glActiveTextureChannel(3);
|
|
if (mat.reflectivity > 0.) {
|
|
glEnable(GL_TEXTURE_CUBE_MAP);
|
|
if (!mat.map_reflection.isEmpty()) mat.map_reflection.bind();
|
|
else glDisable(GL_TEXTURE_CUBE_MAP);
|
|
} else glDisable(GL_TEXTURE_CUBE_MAP);
|
|
if (rp.light_pass > 0) glDisable(GL_TEXTURE_CUBE_MAP);
|
|
GLfloat gm[16], bc[4] = {mat.reflectivity, mat.reflectivity, mat.reflectivity, mat.reflectivity};
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_CONSTANT);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
|
|
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, bc);
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, gm);
|
|
glMatrixMode(GL_TEXTURE);
|
|
glLoadTransposeMatrixf(gm);
|
|
glScalef(-1., -1., -1.);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glActiveTextureChannel(0);
|
|
}
|
|
if (rp.shaders) {
|
|
//qDebug() << o.name() << curview << curview.determinant();
|
|
setUniformMatrices((QGLShaderProgram*)rp.shaders, rp.proj_matrix, curview);
|
|
} else {
|
|
glMatrixMode(GL_MODELVIEW);
|
|
setGLMatrix(curview);
|
|
}
|
|
o.draw((QGLShaderProgram*)rp.shaders);
|
|
}
|
|
foreach (GLObjectBase * i, o.children_)
|
|
renderSingleObject(*i, rp);
|
|
}
|