393 lines
12 KiB
C++
393 lines
12 KiB
C++
/*
|
|
GLObjectBase & Light
|
|
Copyright (C) 2017 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 "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::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::clearChildren(bool deleteAll) {
|
|
foreach (GLObjectBase * i, children_) {
|
|
i->setView(0);
|
|
i->parent_ = 0;
|
|
if (deleteAll) {
|
|
i->clearChildren(true);
|
|
delete i;
|
|
} else {
|
|
i->buildTransform();
|
|
}
|
|
}
|
|
children_.clear();
|
|
if (view_) view_->collectLights();
|
|
}
|
|
|
|
|
|
QList<GLObjectBase * > GLObjectBase::children(bool all_) {
|
|
if (!all_) return children_;
|
|
QList<GLObjectBase * > cl;
|
|
addChildren(cl, this);
|
|
return cl;
|
|
}
|
|
|
|
|
|
void GLObjectBase::addChildren(QList<GLObjectBase * > & list, GLObjectBase * where) {
|
|
foreach (GLObjectBase * i, where->children_) {
|
|
list << i;
|
|
addChildren(list, i);
|
|
}
|
|
}
|
|
|
|
|
|
void GLObjectBase::calculateBoundingBox() {
|
|
bound = vbo.boundingBox();
|
|
}
|
|
|
|
|
|
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 != 0)
|
|
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<int, GLObjectBase * > * 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_);
|
|
//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<int>();
|
|
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<bool>(); break;
|
|
case 3: if (p) p->accept_fog = cs.getData<bool>(); break;
|
|
case 4: if (p) p->visible_ = cs.getData<bool>(); break;
|
|
case 5: if (p) p->cast_shadow = cs.getData<bool>(); break;
|
|
case 6: if (p) p->rec_shadow = cs.getData<bool>(); break;
|
|
case 7: if (p) p->raw_matrix = cs.getData<bool>(); break;
|
|
case 8: if (p) p->line_width = cs.getData<double>(); break;
|
|
case 9: if (p) p->render_mode = (GLObjectBase::RenderMode)cs.getData<int>(); break;
|
|
case 10: if (p) p->material_ = cs.getData<Material>(); break;
|
|
case 11: if (p) p->pos_ = cs.getData<QVector3D>(); break;
|
|
case 12: if (p) p->angles_ = cs.getData<QVector3D>(); break;
|
|
case 13: if (p) p->scale_ = cs.getData<QVector3D>(); break;
|
|
case 14: if (p) p->mat_ = cs.getData<QMatrix4x4>(); break;
|
|
case 15: if (p) p->vbo = cs.getData<GLVBO>(); break;
|
|
case 16: if (p) ccnt = cs.getData<int>(); break;
|
|
case 17: if (p) p->name_ = cs.getData<QString>(); break;
|
|
case 100: if (l) l->direction = cs.getData<QVector3D>(); break;
|
|
case 101: if (l) l->angle_start = cs.getData<GLdouble>(); break;
|
|
case 102: if (l) l->angle_end = cs.getData<GLdouble>(); break;
|
|
case 103: if (l) l->intensity = cs.getData<GLdouble>(); break;
|
|
case 104: if (l) l->decay_const = cs.getData<GLdouble>(); break;
|
|
case 105: if (l) l->decay_linear = cs.getData<GLdouble>(); break;
|
|
case 106: if (l) l->decay_quadratic = cs.getData<GLdouble>(); break;
|
|
case 107: if (l) l->decay_start = cs.getData<GLdouble>(); break;
|
|
case 108: if (l) l->decay_end = cs.getData<GLdouble>(); break;
|
|
case 109: if (l) l->light_type = (Light::Type)cs.getData<int>(); break;
|
|
case 200: if (c) c->setAim(cs.getData<QVector3D>()); break;
|
|
case 201: if (c) c->setFOV(cs.getData<GLdouble>()); break;
|
|
case 202: if (c) c->setDepthStart(cs.getData<GLdouble>()); break;
|
|
case 203: if (c) c->setDepthEnd(cs.getData<GLdouble>()); break;
|
|
case 204: if (c) c->setAngleLowerLimitXY(cs.getData<GLdouble>()); break;
|
|
case 205: if (c) c->setAngleUpperLimitXY(cs.getData<GLdouble>()); break;
|
|
case 206: if (c) c->mirror_x = cs.getData<bool>(); break;
|
|
case 207: if (c) c->mirror_y = cs.getData<bool>(); 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;
|
|
}
|