/* QGL GLRendererBase 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 "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.f; //col[1] = l.visible_ ? l.color().greenF() * l.intensity : 0.f; //col[2] = l.visible_ ? l.color().blueF() * l.intensity : 0.f; 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_end / 2.f); glLightf(gl_index, GL_SPOT_EXPONENT, (1.f - piClamp((l.angle_end - l.angle_start) / (l.angle_end + 0.001f), 0., 1.f)) * 128.f); } 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 (QOpenGLShaderProgram * 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; \ glActiveTexture(GL_TEXTURE0 + ch); glBindTexture(GL_TEXTURE_2D, mat.map.bitmap_id); \ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, view->feature(QGLView::qglAnisotropicLevel).toInt());} void GLRendererBase::setupTextures(ObjectBase & o, GLRendererBase::RenderingParameters & rp, bool first_object) { } #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((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->isFeatureEnabled(QGLView::qglLinearFiltering)) { 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->feature(QGLView::qglAnisotropicLevel).toInt()); } void GLRendererBase::renderObjects(int pass, int light_pass, void * shaders, bool textures, bool light, bool fog) { /*RenderingParameters rpl; rpl.pass = pass; rpl.light_pass = light_pass; rpl.shaders = shaders; rpl.textures = textures; rpl.light = rpl.prev_light = light; rpl.fog = rpl.prev_fog = fog; rpl.view_matrix = rp.view_matrix; rpl.prev_view_matrix = rp.prev_view_matrix; rpl.proj_matrix = rp.proj_matrix; rpl.prev_proj_matrix = rp.prev_proj_matrix; rpl.cam_offset_matrix = view->camera()->offsetMatrix(); //qDebug() << "view:" << rp.view_matrix; for (int i = 0; i < 32; ++i) rpl.prev_tex[i] = 0; setupTextures(view->objects_, rpl, true); glSetCapEnabled(GL_TEXTURE_2D, rpl.textures); glSetCapEnabled(GL_BLEND, pass == ObjectBase::Transparent); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_TEXTURE_CUBE_MAP); glPushMatrix(); renderSingleObject(view->objects_, rpl); glPopMatrix();*/ } void GLRendererBase::renderSingleObject(ObjectBase & o, RenderingParameters & rpl) { // if (!o.isInit()) // o.init(); // if (!o.isTexturesLoaded()) // o.loadTextures(); // if (!o.visible_) return; // if (rpl.pass == o.pass_) { // //Material & mat(o.material_); // QMatrix4x4 curview = rpl.view_matrix * rpl.cam_offset_matrix * o.itransform_, prevview = rpl.prev_view_matrix * rpl.cam_offset_matrix * o.itransform_; // //setupTextures(o, rpl, false); // //mat.apply((QOpenGLShaderProgram*)rpl.shaders); // glSetPolygonMode(o.render_mode != ObjectBase::View ? o.render_mode : (view->rmode != ObjectBase::View ? view->rmode : GL_FILL)); // glLineWidth(o.line_width > 0.f ? o.line_width : view->lineWidth_); // glPointSize(o.line_width > 0.f ? o.line_width : view->lineWidth_); // o.update(); // /*if (o.pass_ == GLObjectBase::Transparent) { // glActiveTexture(GL_TEXTURE0 + 3); // if (mat.reflectivity > 0.f) { // 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 (rpl.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); // glActiveTexture(GL_TEXTURE0); // }*/ // if (rpl.shaders) { // //qDebug() << o.name() << curview << curview->determinant(); // //setUniformMatrices((QOpenGLShaderProgram*)rpl.shaders, rpl.proj_matrix, curview, rpl.prev_proj_matrix, prevview); // } else { // glMatrixMode(GL_MODELVIEW); // //setGLMatrix(curview); // } // o.draw((QOpenGLShaderProgram*)rpl.shaders); // } // foreach (ObjectBase * i, o.children_) // renderSingleObject(*i, rpl); } void GLRendererBase::renderShadow(Light * l, QOpenGLShaderProgram * prog, QMatrix4x4 mat) { Camera cam; QVector3D wp = l->worldPos(); cam.setPos(wp); cam.setAim(wp + (l->worldTransform() * QVector4D(l->direction())).toVector3D()); cam.setDepthStart(view->camera()->depthStart()); cam.setFOV(l->angle_end); //cam.apply(1.); /*cam.rotateXY(l->angle_end); QVector3D rdir = l->direction * cos(l->angle_end / 2. * deg2rad); l->dir0 = cam.direction() - rdir; cam.rotateXY(-l->angle_end); cam.rotateZ(l->angle_end); l->dir1 = cam.direction() - rdir;*/ //qDebug() << rdir << l->dir0 << l->dir1; RenderingParameters rpl; rpl.shaders = prog; rpl.textures = rpl.light = rpl.fog = false; //rpl.view_matrix = getGLMatrix(GL_MODELVIEW_MATRIX); //rpl.proj_matrix = getGLMatrix(GL_PROJECTION_MATRIX); rpl.cam_offset_matrix = cam.offsetMatrix(); QMatrix4x4 mbias; mbias.scale(0.5, 0.5, 0.5); mbias.translate(1., 1., 1.); l->shadow_matrix = mbias*rpl.proj_matrix*rpl.view_matrix*rpl.cam_offset_matrix*mat;//;// * mbias; //qDebug() << mbias; //glPushMatrix(); //renderSingleShadow(view->objects_, rpl); //glPopMatrix(); } void GLRendererBase::renderSingleShadow(ObjectBase & o, RenderingParameters & rpl) { // if (!o.isInit()) // o.init(); // if (!o.visible_) return; // if (rpl.shaders) { // //qDebug() << o.name() << curview << curview->determinant(); // //setUniformMatrices((QOpenGLShaderProgram*)rpl.shaders, rpl.proj_matrix, rpl.view_matrix * rpl.cam_offset_matrix * o.itransform_); // } else { // glMatrixMode(GL_MODELVIEW); // //setGLMatrix(rpl.view_matrix * rpl.cam_offset_matrix * o.itransform_); // } // glPolygonMode(GL_FRONT_AND_BACK, o.render_mode != ObjectBase::View ? o.render_mode : (view->rmode != ObjectBase::View ? view->rmode : GL_FILL)); // glLineWidth(o.line_width > 0.f ? o.line_width : view->lineWidth_); // glPointSize(o.line_width > 0.f ? o.line_width : view->lineWidth_); // o.draw((QOpenGLShaderProgram*)rpl.shaders, true); // foreach (ObjectBase * i, o.children_) // renderSingleShadow(*i, rpl); } GLRendererBase::RenderingParameters::RenderingParameters() { shaders = nullptr; cur_shader = nullptr; } void GLRendererBase::RenderingParameters::prepare() { //proj_matrix = getGLMatrix(GL_PROJECTION_MATRIX); //view_matrix = getGLMatrix(GL_MODELVIEW_MATRIX); viewproj_matrix = proj_matrix * view_matrix; normal_matrix = view_matrix.normalMatrix(); proj_matrix_i = proj_matrix.inverted(); view_matrix_i = view_matrix.inverted(); viewproj_matrix_i = viewproj_matrix.inverted(); } void GLRendererBase::RenderingParameters::setUniform(QOpenGLShaderProgram * prog) { if (!prog) return; prog->setUniformValue("qgl_ModelViewMatrix", view_matrix); prog->setUniformValue("qgl_ProjectionMatrix", proj_matrix); prog->setUniformValue("qgl_ModelViewProjectionMatrix", viewproj_matrix); prog->setUniformValue("qgl_NormalMatrix", normal_matrix); prog->setUniformValue("qgl_ModelViewMatrixInverse", view_matrix_i); prog->setUniformValue("qgl_ProjectionMatrixInverse", proj_matrix_i); prog->setUniformValue("qgl_ModelViewProjectionMatrixInverse", viewproj_matrix_i); prog->setUniformValue("qgl_ModelViewMatrixTranspose", view_matrix.transposed()); prog->setUniformValue("qgl_ProjectionMatrixTranspose", proj_matrix.transposed()); prog->setUniformValue("qgl_ModelViewProjectionMatrixTranspose", viewproj_matrix.transposed()); prog->setUniformValue("qgl_ModelViewMatrixInverseTranspose", view_matrix_i.transposed()); prog->setUniformValue("qgl_ProjectionMatrixInverseTranspose", proj_matrix_i.transposed()); prog->setUniformValue("qgl_ModelViewProjectionMatrixInverseTranspose", viewproj_matrix_i.transposed()); }