/* GLObjectBase & Light 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 "globject.h" #include "glcamera.h" #include "qglview.h" GLObjectBase::GLObjectBase() { type_ = glMesh; render_mode = View; pass_ = Solid; geom_prim = Triangles; scale_ = QVector3D(1., 1., 1.); parent_ = 0; is_root = is_init = is_tex_loaded = selected_ = false; visible_ = accept_fog = accept_light = cast_shadow = rec_shadow = select_ = true; line_width = -1.; blend_src = GL_SRC_ALPHA; blend_dest = GL_ONE_MINUS_SRC_ALPHA; type_ = glMesh; raw_matrix = false; mat_.setToIdentity(); view_ = 0; } GLObjectBase::~GLObjectBase() { //qDebug() << "del" << name() << view_; if (parent_) parent_->children_.removeAll(this); if (view_) ((QGLView*)view_)->objectDeleted(this); foreach (GLObjectBase * c, children_) { c->parent_ = 0; delete c; } } GLObjectBase * GLObjectBase::clone(bool withChildren) { GLObjectBase * o = new GLObjectBase(); o->pass_ = pass_; o->is_init = false; o->accept_light = accept_light; o->accept_fog = accept_fog; o->visible_ = visible_; o->type_ = type_; o->raw_matrix = raw_matrix; o->mat_ = mat_; o->pos_ = pos_; o->angles_ = angles_; o->scale_ = scale_; o->itransform_ = itransform_; o->bound = bound; o->name_ = name_ + "_copy"; o->blend_src = blend_src; o->blend_dest = blend_dest; o->material_ = material_; o->pos_h = pos_h; o->points = points; o->puvws = puvws; o->faces = faces; o->uvws = uvws; o->norms = norms; o->normals = normals; o->vbo.vertices_ = vbo.vertices_; o->vbo.normals_ = vbo.normals_; o->vbo.texcoords_ = vbo.texcoords_; o->vbo.colors_ = vbo.colors_; o->view_ = 0; o->children_.clear(); if (withChildren) { for (int i = 0; i < children_.size(); ++i) o->addChild(children_[i]->clone(withChildren)); } return o; } void GLObjectBase::draw(__GLShaderProgram__ * prog, bool simplest) { vbo.draw(geom_prim, prog, simplest); /*if (!d_vertices.isEmpty()) { glBindBuffer(GL_ARRAY_BUFFER, 0); glVertexPointer(3, GL_FLOAT, 0, d_vertices.constData()); glTexCoordPointer(2, GL_FLOAT, 0, d_uvs.constData()); //glColorPointer(4, GL_FLOAT, 0, d_colors.constData()); glNormalPointer(GL_FLOAT, 0, d_normals.constData()); glDrawArrays(geom_prim, 0, d_vertices.size() / 3);*/ /*if (pass_ == Reflection) { glActiveTexture(GL_TEXTURE1); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); }*/ //} } void GLObjectBase::setView(QGLView * v) { view_ = v; foreach (GLObjectBase * c, children_) c->setView(v); } void GLObjectBase::addChild(GLObjectBase * o) { if (o == this) return; if (o->parent_) o->parent_->children_.removeAll(o); children_ << o; o->parent_ = this; o->setView((QGLView*)view_); o->buildTransform(); if (view_) { view_->collectLights(); QList cl = o->children(true); cl << o; foreach (GLObjectBase * i, cl) { emit ((QGLView*)view_)->objectAdded(i); } } } void GLObjectBase::clearChildren(bool deleteAll) { foreach (GLObjectBase * i, children_) { i->view_ = 0; i->parent_ = 0; i->clearChildren(deleteAll); if (deleteAll) { delete i; } i->buildTransform(); } children_.clear(); if (view_) view_->collectLights(); } QList GLObjectBase::children(bool all_) { if (!all_) return children_; QList cl; addChildren(cl, this); return cl; } void GLObjectBase::addChildren(QList & list, GLObjectBase * where) { foreach (GLObjectBase * i, where->children_) { list << i; addChildren(list, i); } } void GLObjectBase::calculateBoundingBox() { bound = vbo.boundingBox(); QVector c = bound.corners(), tc; //QMatrix4x4 mat = itransform_.inverted(); //qDebug() << itransform_ << mat_ << mat; foreach (QVector3D p, c) tc << (itransform_ * QVector4D(p, 1)).toVector3D(); bound = Box3D(tc); foreach (GLObjectBase * i, children_) { i->calculateBoundingBox(); bound |= i->boundingBox(); } } void GLObjectBase::setProperty(const QString & pn, const QVariant & v) { meta[pn] = v; } QVariant GLObjectBase::property(const QString & pn, bool * exists) const { if (exists) *exists = meta.contains(pn); return meta.value(pn); } bool GLObjectBase::hasProperty(const QString & pn) const { return meta.contains(pn); } void GLObjectBase::removeProperty(const QString & pn) { meta.remove(pn); } void GLObjectBase::setTransform(const QMatrix4x4 & t) { raw_matrix = true; mat_ = t; pos_ = mat_.column(3).toVector3D(); mat_.setColumn(3, QVector4D(0., 0., 0., 1.)); buildTransform(); } void GLObjectBase::select() { //qDebug() << "select" << name() << view_; selected_ = true; if (view_) ((QGLView*)view_)->selectObject(this); } void GLObjectBase::buildTransform() { itransform_.setToIdentity(); GLObjectBase * p = parent_; if (p) itransform_ = p->itransform_; if (raw_matrix) { itransform_.translate(pos_); itransform_ *= mat_; //qDebug() << "raw_matrix" << itransform_; } else localTransform(itransform_); //qDebug() << name_ << itransform_; foreach (GLObjectBase * i, children_) i->buildTransform(); } void GLObjectBase::localTransform(QMatrix4x4 & m) { m.translate(pos_); m.rotate(angles_.z(), 0., 0., 1.); m.rotate(angles_.y(), 0., 1., 0.); m.rotate(angles_.x(), 1., 0., 0.); m.scale(scale_); } void GLObjectBase::checkPass() { if (material_.color_diffuse.alphaF() * (1.f - material_.transparency) < 1.f) pass_ = Transparent; else pass_ = Solid; } QMatrix4x4 GLObjectBase::worldMatrix(QMatrix4x4 parent) const { QMatrix4x4 mat; mat.translate(pos_); if (raw_matrix) { mat *= mat_; } else { if (angles_.z() != 0.) mat.rotate(angles_.z(), 0., 0., 1.); if (angles_.y() != 0.) mat.rotate(angles_.y(), 0., 1., 0.); if (angles_.x() != 0.) mat.rotate(angles_.x(), 1., 0., 0.); mat.scale(scale_); } return parent * mat; } void GLObjectBase::render(int * id, QMap * ids, int sh_id_loc) { if (!visible_) return; //glPushMatrix(); ///qglMultMatrix TODO material_.apply(0); if (id != 0) { ++(*id); ids->insert(*id, this); //glVertexAttrib1f(sh_id_loc, (*id) / 255.f); //qDebug() << "assign to" << sh_id_loc << (*id) / 255.f; } draw(0); foreach (GLObjectBase * i, children_) i->render(id, ids, sh_id_loc); //glPopMatrix(); } Light::Light(): GLObjectBase(), shadow_map(0, true, GL_R16F) { type_ = glLight; light_type = Omni; intensity = 1.; angle_start = angle_end = 180.; decay_linear = decay_quadratic = decay_start = 0.; decay_const = decay_end = 1.; direction.setZ(1.); } Light::Light(const QVector3D & p, const QColor & c, GLdouble i): GLObjectBase(), shadow_map(0, true, GL_R16F) { type_ = glLight; light_type = Omni; pos_ = p; intensity = i; /*color_ = c;*/ angle_start = angle_end = 180.; decay_linear = decay_quadratic = decay_start = 0.; decay_const = decay_end = 1.; direction.setZ(1.); } GLObjectBase * Light::clone(bool withChildren) { Light * o = new Light(*this); //GLObjectBase::clone(withChildren); o->is_init = false; o->name_ = name_ + "_copy"; o->view_ = 0; o->children_.clear(); if (withChildren) { for (int i = 0; i < children_.size(); ++i) o->addChild(children_[i]->clone(withChildren)); } o->light_type = light_type; o->direction = direction; o->angle_start = angle_start; o->angle_end = angle_end; o->intensity = intensity; o->decay_const = decay_const; o->decay_linear = decay_linear; o->decay_quadratic = decay_quadratic; return o; } void Light::draw(__GLShaderProgram__ * prog, bool simplest) { bool l = glIsEnabled(GL_LIGHTING); glDisable(GL_LIGHTING); glPointSize(8.); glColor3f(0., 0., 0.); glBegin(GL_POINTS); glVertex3f(0., 0., 0.); glEnd(); double s = 10; if (light_type != Omni) { glBegin(GL_LINES); QVector4D dir = QVector4D(direction); if (raw_matrix) dir = transform().inverted() * dir; glVertex3f(0., 0., 0.); glVertex3f(dir.x() * s, dir.y() * s, dir.z() * s); glEnd(); } if (l) glEnable(GL_LIGHTING); } QDataStream & operator <<(QDataStream & s, const GLObjectBase * p) { ChunkStream cs; //qDebug() << "place" << p->name() << "..."; cs << cs.chunk(1, int(p->type_)) << cs.chunk(2, p->accept_light) << cs.chunk(3, p->accept_fog) << cs.chunk(4, p->visible_) << cs.chunk(5, p->cast_shadow) << cs.chunk(6, p->rec_shadow) << cs.chunk(7, p->raw_matrix) << cs.chunk(8, p->line_width) << cs.chunk(9, int(p->render_mode)) << cs.chunk(10, p->material_) << cs.chunk(11, p->pos_) << cs.chunk(12, p->angles_) << cs.chunk(13, p->scale_) << cs.chunk(14, p->mat_) << cs.chunk(15, p->vbo) << cs.chunk(16, p->children_.size()) << cs.chunk(17, p->name_) << cs.chunk(18, p->meta); //qDebug() << "place self done"; if (p->type_ == GLObjectBase::glLight) { //qDebug() << "place light ..."; Light * l = (Light*)p; cs << cs.chunk(100, l->direction) << cs.chunk(101, l->angle_start) << cs.chunk(102, l->angle_end) << cs.chunk(103, l->intensity) << cs.chunk(104, l->decay_const) << cs.chunk(105, l->decay_linear) << cs.chunk(106, l->decay_quadratic) << cs.chunk(107, l->decay_start) << cs.chunk(108, l->decay_end) << cs.chunk(109, int(l->light_type)); } if (p->type_ == GLObjectBase::glCamera) { //qDebug() << "place camera ..."; Camera * c = (Camera*)p; cs << cs.chunk(200, c->aim_) << cs.chunk(201, c->fov_) << cs.chunk(202, c->depth_start) << cs.chunk(203, c->depth_end) << cs.chunk(204, c->angle_limit_lower_xy) << cs.chunk(205, c->angle_limit_upper_xy) << cs.chunk(206, c->mirror_x) << cs.chunk(207, c->mirror_y); } //qDebug() << "place" << p->name() << cs.data().size() << s.device()->size(); s << cs.data(); foreach (const GLObjectBase * c, p->children_) s << c; return s; } QDataStream & operator >>(QDataStream & s, GLObjectBase *& p) { ChunkStream cs(s); p = 0; int ccnt = 0; Light * l = 0; Camera * c = 0; //qDebug() << "read obj ..."; while (!cs.atEnd()) { switch (cs.read()) { case 1: { GLObjectBase::Type type = (GLObjectBase::Type)cs.getData(); switch (type) { case GLObjectBase::glMesh: p = new GLObjectBase(); break; case GLObjectBase::glLight: p = new Light(); l = (Light*)p; break; case GLObjectBase::glCamera: p = new Camera(); c = (Camera*)p; break; default : break; } if (p) p->type_ = type; } break; case 2: if (p) p->accept_light = cs.getData(); break; case 3: if (p) p->accept_fog = cs.getData(); break; case 4: if (p) p->visible_ = cs.getData(); break; case 5: if (p) p->cast_shadow = cs.getData(); break; case 6: if (p) p->rec_shadow = cs.getData(); break; case 7: if (p) p->raw_matrix = cs.getData(); break; case 8: if (p) p->line_width = cs.getData(); break; case 9: if (p) p->render_mode = (GLObjectBase::RenderMode)cs.getData(); break; case 10: if (p) p->material_ = cs.getData(); break; case 11: if (p) p->pos_ = cs.getData(); break; case 12: if (p) p->angles_ = cs.getData(); break; case 13: if (p) p->scale_ = cs.getData(); break; case 14: if (p) p->mat_ = cs.getData(); break; case 15: if (p) p->vbo = cs.getData(); break; case 16: if (p) ccnt = cs.getData(); break; case 17: if (p) p->name_ = cs.getData(); break; case 18: if (p) p->meta = cs.getData(); break; case 100: if (l) l->direction = cs.getData(); break; case 101: if (l) l->angle_start = cs.getData(); break; case 102: if (l) l->angle_end = cs.getData(); break; case 103: if (l) l->intensity = cs.getData(); break; case 104: if (l) l->decay_const = cs.getData(); break; case 105: if (l) l->decay_linear = cs.getData(); break; case 106: if (l) l->decay_quadratic = cs.getData(); break; case 107: if (l) l->decay_start = cs.getData(); break; case 108: if (l) l->decay_end = cs.getData(); break; case 109: if (l) l->light_type = (Light::Type)cs.getData(); break; case 200: if (c) c->setAim(cs.getData()); break; case 201: if (c) c->setFOV(cs.getData()); break; case 202: if (c) c->setDepthStart(cs.getData()); break; case 203: if (c) c->setDepthEnd(cs.getData()); break; case 204: if (c) c->setAngleLowerLimitXY(cs.getData()); break; case 205: if (c) c->setAngleUpperLimitXY(cs.getData()); break; case 206: if (c) c->mirror_x = cs.getData(); break; case 207: if (c) c->mirror_y = cs.getData(); break; } } //qDebug() << p->name() << ccnt; for (int i = 0; i < ccnt; ++i) { GLObjectBase * c = 0; s >> c; if (!c) continue; c->parent_ = p; p->children_ << c; } return s; }