source-tree refactoring

This commit is contained in:
2023-02-03 21:22:25 +03:00
parent b20068165f
commit 7d30802cbd
153 changed files with 606 additions and 278 deletions

View File

@@ -0,0 +1,91 @@
/*
QGL Camera
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 <http://www.gnu.org/licenses/>.
*/
#include "gltypes.h"
#include "qglview.h"
Camera::Camera() {
type_ = glCamera;
fov_ = 60.;
roll_ = 0.;
depth_start = 0.1f;
mirror_x = mirror_y = false;
}
QMatrix4x4 Camera::offsetMatrix() const {
QMatrix4x4 ret;
ret.translate(parent_ ? -offset_ : -aim());
return ret;
}
void Camera::assign(const Camera & c) {
trans = c.trans;
aim_dist = c.aim_dist;
fov_ = c.fov_;
mirror_x = c.mirror_x;
mirror_y = c.mirror_y;
depth_start = c.depth_start;
buildTransform();
}
ObjectBase * Camera::clone(bool withChildren) {
Camera * o = new Camera(*this);
o->is_init = false;
o->name_ = name_;
o->scene_ = nullptr;
o->children_.clear();
if (withChildren) {
for (int i = 0; i < children_.size(); ++i)
o->addChild(children_[i]->clone(withChildren));
}
o->trans = trans;
o->aim_dist = aim_dist;
o->fov_ = fov_;
o->roll_ = roll_;
o->mirror_x = mirror_x;
o->mirror_y = mirror_y;
o->depth_start = depth_start;
o->meta = meta;
return o;
}
QMatrix4x4 Camera::viewMatrix() const {
QMatrix4x4 ret;
// qDebug() << pos() << aim();
ret.translate(0., 0., -distance());
ret.rotate(-roll_, 0., 0., 1.);
ret *= trans.matrixRotateScale().inverted();
if (parent_) {
QMatrix4x4 pmat = parent_->worldTransform();
offset_ = pmat.column(3).toVector3D();
pmat(0, 3) = pmat(1, 3) = pmat(2, 3) = 0.;
pmat.translate(aim());
ret *= pmat.inverted();
}
return ret;
}
QMatrix4x4 Camera::projectionMatrix(double aspect) const {
return glMatrixPerspective(fov_, aspect, depth_start);
}

65
src/core/scene/glcamera.h Normal file
View File

@@ -0,0 +1,65 @@
/*
QGL Camera
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 <http://www.gnu.org/licenses/>.
*/
#ifndef GLCAMERA_H
#define GLCAMERA_H
#include "globject.h"
class QGLENGINE_CORE_EXPORT Camera: public AimedObject {
friend QGLENGINE_CORE_EXPORT QDataStream & operator<<(QDataStream & s, const ObjectBase * p);
friend QGLENGINE_CORE_EXPORT QDataStream & operator>>(QDataStream & s, ObjectBase *& p);
public:
Camera();
void setFOV(const float & f) { fov_ = f; }
void setAngles(const QVector3D & a) { setRotation(a); }
void setAngleZ(const float & a) { setRotationZ(a); }
void setAngleXY(const float & a) { setRotationX(a); }
void setAngleRoll(const float & a) { roll_ = a; }
void setDepthStart(const float & d) { depth_start = d; }
void setMirrorX(bool yes) { mirror_x = yes; }
void setMirrorY(bool yes) { mirror_y = yes; }
float FOV() const { return fov_; }
float angleZ() const { return rotationZ(); }
float angleXY() const { return rotationX(); }
float angleRoll() const { return roll_; }
float depthStart() const { return depth_start; }
bool isMirrorX() const { return mirror_x; }
bool isMirrorY() const { return mirror_y; }
void assign(const Camera & c);
virtual ObjectBase * clone(bool withChildren = true);
QMatrix4x4 viewMatrix() const;
QMatrix4x4 projectionMatrix(double aspect) const;
QMatrix4x4 offsetMatrix() const;
QMatrix4x4 fullViewMatrix() const { return viewMatrix() * offsetMatrix(); }
private:
mutable QVector3D offset_;
GLfloat fov_, roll_;
GLfloat depth_start;
bool mirror_x;
bool mirror_y;
};
#endif // GLCAMERA_H

803
src/core/scene/globject.cpp Normal file
View File

@@ -0,0 +1,803 @@
/*
QGL ObjectBase & Light
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 <http://www.gnu.org/licenses/>.
*/
#include "globject.h"
#include "glcamera.h"
#include "glmesh.h"
#include "glscene.h"
#include <chunkstream.h>
// static int _count = 0;
ObjectBase::ObjectBase(Mesh * geom, Material * mat) {
type_ = glMesh;
render_mode = View;
prev_pass = rpSolid;
parent_ = nullptr;
color_ = Qt::white;
is_root = is_init = selected_ = false;
visible_ = accept_fog = accept_light = cast_shadow = rec_shadow = select_ = true;
line_width = -1.;
id_ = 0;
blend_src = GL_SRC_ALPHA;
blend_dest = GL_ONE_MINUS_SRC_ALPHA;
type_ = glMesh;
raw_matrix = selected_aim = false;
mat_.setToIdentity();
scene_ = nullptr;
mesh_ = geom;
material_ = mat;
// qDebug() << "ObjectBase, now" << ++_count;
}
ObjectBase::~ObjectBase() {
// qDebug() << "~ObjectBase, now" << --_count;
if (parent_) parent_->children_.removeAll(this);
if (scene_) {
scene_->__objectDeleted(this);
scene_->setTreeChanged();
scene_->setTreeStructChanged();
}
foreach(ObjectBase * c, children_) {
c->parent_ = nullptr;
delete c;
}
}
ObjectBase * ObjectBase::clone(bool withChildren) {
ObjectBase * o = new ObjectBase();
o->prev_pass = prev_pass;
o->is_init = false;
o->accept_light = accept_light;
o->accept_fog = accept_fog;
o->visible_ = visible_;
o->color_ = color_;
o->type_ = type_;
o->raw_matrix = raw_matrix;
o->mat_ = mat_;
o->trans = trans;
o->itransform_ = itransform_;
o->bound = bound;
o->name_ = name_; // + "_copy";
o->blend_src = blend_src;
o->blend_dest = blend_dest;
o->pos_h = pos_h;
o->material_ = material_;
o->mesh_ = mesh_;
o->meta = meta;
o->scene_ = nullptr;
if (withChildren) {
for (int i = 0; i < children_.size(); ++i)
o->addChild(children_[i]->clone(withChildren));
}
return o;
}
void ObjectBase::destroy() {
if (mesh_) delete mesh_;
}
void ObjectBase::init() {
calculateBoundingBox();
// material_.reflection.create();
// qDebug() << "init" << vbo.buffer_;
is_init = true;
}
RenderPass ObjectBase::pass() const {
RenderPass ret = rpSolid;
if (material_)
if (material_->hasTransparency()) ret = rpTransparent;
return ret;
}
void ObjectBase::setScene(Scene * v) {
scene_ = v;
foreach(ObjectBase * c, children_)
c->setScene(v);
}
void ObjectBase::addChild(ObjectBase * o) {
if (o == this) return;
if (o->parent_) o->parent_->children_.removeAll(o);
children_ << o;
o->parent_ = this;
o->setScene(scene_);
o->buildTransform();
/*if (scene_) {
ObjectBaseList cl = o->children(true);
cl << o;
//foreach (ObjectBase * i, cl) {
// emit view_->objectAdded(i);
//}
}*/
setSceneTreeChanged();
}
void ObjectBase::removeChild(ObjectBase * o) {
if (o == this) return;
children_.removeAll(o);
o->parent_ = nullptr;
o->buildTransform();
setSceneTreeChanged();
}
void ObjectBase::removeChild(int index) {
children_[index]->parent_ = nullptr;
children_[index]->buildTransform();
children_.removeAt(index);
setSceneTreeChanged();
}
void ObjectBase::clearChildren(bool deleteAll) {
foreach(ObjectBase * i, children_) {
i->scene_ = nullptr;
i->parent_ = nullptr;
i->clearChildren(deleteAll);
if (deleteAll) {
delete i;
} else {
i->buildTransform();
}
}
children_.clear();
setSceneTreeChanged();
}
ObjectBase * ObjectBase::child(int index) {
if (index < 0 || index >= children_.size()) return nullptr;
return children_[index];
}
ObjectBase * ObjectBase::child(const QString & name) {
foreach(ObjectBase * i, children_)
if (i->name_ == name) return i;
return nullptr;
}
const ObjectBase * ObjectBase::child(int index) const {
if (index < 0 || index >= children_.size()) return nullptr;
return children_[index];
}
const ObjectBase * ObjectBase::child(const QString & name) const {
foreach(ObjectBase * i, children_)
if (i->name_ == name) return i;
return nullptr;
}
ObjectBaseList ObjectBase::children(bool all_) {
if (!all_) return children_;
ObjectBaseList cl;
addChildren(cl, this);
return cl;
}
bool ObjectBase::isVisible(bool check_parents) const {
if (!check_parents) return visible_;
if (!visible_) return false;
ObjectBase * p = parent_;
while (p) {
if (!p->visible_) return false;
p = p->parent_;
}
return true;
}
void ObjectBase::setVisible(bool v) {
visible_ = v;
setSceneTreeChanged();
}
void ObjectBase::rotateZ(GLfloat a) {
raw_matrix = false;
trans.setRotationZ(trans.rotationZ() + a);
// angles_.setZ(angles_.z() + a);
// while (angles_.z() < -360.f) angles_.setZ(angles_.z() + 360.f);
// while (angles_.z() > 360.f) angles_.setZ(angles_.z() - 360.f);
buildTransform();
}
void ObjectBase::setRotationZ(GLfloat a) {
raw_matrix = false;
trans.setRotationZ(a);
// angles_.setZ(a);
// while (angles_.z() < -360.f) angles_.setZ(angles_.z() + 360.f);
// while (angles_.z() > 360.f) angles_.setZ(angles_.z() - 360.f);
buildTransform();
}
void ObjectBase::setTransform(const Transform & t) {
trans = t;
buildTransform();
}
void ObjectBase::addChildren(ObjectBaseList & list, ObjectBase * where) {
foreach(ObjectBase * i, where->children_) {
list << i;
addChildren(list, i);
}
}
void ObjectBase::calculateBoundingBox() {
bound = Box3D();
if (mesh_) {
bound = mesh_->boundingBox();
QVector<QVector3D> c = bound.corners(), tc;
foreach(QVector3D p, c)
tc << (itransform_ * QVector4D(p, 1)).toVector3D();
bound = Box3D(tc);
}
foreach(ObjectBase * i, children_) {
i->calculateBoundingBox();
bound |= i->boundingBox();
}
}
void ObjectBase::updateTransform() {
buildTransform(true);
}
void ObjectBase::setProperty(const QString & pn, const QVariant & v) {
meta[pn] = v;
}
QVariant ObjectBase::property(const QString & pn, bool * exists) const {
if (exists) *exists = meta.contains(pn);
return meta.value(pn);
}
bool ObjectBase::hasProperty(const QString & pn) const {
return meta.contains(pn);
}
void ObjectBase::removeProperty(const QString & pn) {
meta.remove(pn);
}
void ObjectBase::setMatrix(const QMatrix4x4 & t) {
// raw_matrix = true;
// mat_ = t;
// pos_ = mat_.column(3).toVector3D();
// mat_.setColumn(3, QVector4D(0., 0., 0., 1.));
raw_matrix = false;
trans.setMatrix(t);
buildTransform();
}
QMatrix4x4 ObjectBase::matrix() const {
return trans.matrix();
}
QVector3D ObjectBase::inParentSpace(const QVector3D & v) const {
if (!parent_) return v;
return (parent_->matrix() * QVector4D(v, 1)).toVector3D();
}
void ObjectBase::transferTransformToChildren(bool only_scale) {
QMatrix4x4 m = trans.matrix();
if (only_scale) m = trans.matrixScale();
foreach(ObjectBase * i, children_)
i->trans.setMatrix(m * i->trans.matrix());
if (only_scale)
resetScale();
else
setMatrix(QMatrix4x4());
}
void ObjectBase::cleanTree() {
for (int i = 0; i < children_.size(); ++i) {
ObjectBase * o = children_[i];
if (!o->hasChildren() && !o->mesh() && (o->type() == glMesh)) {
delete o;
--i;
}
o->cleanTree();
}
}
bool ObjectBase::isSelected(bool check_parents) const {
if (!check_parents) return selected_;
if (selected_) return true;
ObjectBase * p = parent_;
while (p) {
if (p->selected_) return true;
p = p->parent_;
}
return false;
}
void ObjectBase::setSelected(bool yes) {
// qDebug() << "select" << name() << view_;
if (select_) selected_ = yes;
if (!selected_) selected_aim = false;
}
ObjectBase * ObjectBase::selectedParent() const {
ObjectBase * p = parent_;
while (p) {
if (p->selected_) return p;
p = p->parent_;
}
return 0;
}
void ObjectBase::setMaterial(Material * m, bool with_children) {
material_ = m;
if (with_children)
foreach(ObjectBase * i, children_)
i->setMaterial(m, true);
setObjectsChanged();
if (scene_) scene_->mat_changed = scene_->tree_changed = true;
}
void ObjectBase::setColor(QColor c, bool with_children) {
color_ = c;
if (with_children)
foreach(ObjectBase * i, children_)
i->setColor(c, true);
setObjectsChanged();
}
void ObjectBase::setMesh(Mesh * v) {
if (scene_) v = scene_->attachMesh(v);
mesh_ = v;
setSceneTreeChanged();
setObjectsChanged();
}
void ObjectBase::buildTransform(bool force) {
if (force) trans.setDirty();
itransform_.setToIdentity();
ObjectBase * 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(ObjectBase * i, children_)
i->buildTransform(force);
setObjectsChanged();
}
void ObjectBase::initInternal() {
init();
foreach(ObjectBase * i, children_)
i->initInternal();
}
void ObjectBase::localTransform(QMatrix4x4 & m) {
m *= trans.matrix();
}
void ObjectBase::setSceneTreeChanged() {
if (scene_) {
scene_->setTreeChanged();
scene_->setTreeStructChanged();
}
setObjectsChanged();
}
void ObjectBase::setObjectsChanged() {
int p = pass();
if (mesh_) {
mesh_->setObjectsChanged(p, true);
mesh_->setSelectionChanged(p, true);
if (prev_pass != p) {
mesh_->setObjectsChanged(prev_pass, true);
mesh_->setSelectionChanged(prev_pass, true);
}
}
prev_pass = p;
}
QMatrix4x4 ObjectBase::worldMatrix(QMatrix4x4 parent) const {
QMatrix4x4 mat;
// mat.translate(pos_);
// if (raw_matrix) {
// mat *= mat_;
// } else {
// if (angles_.z() != 0.f) mat.rotate(angles_.z(), 0., 0., 1.);
// if (angles_.y() != 0.f) mat.rotate(angles_.y(), 0., 1., 0.);
// if (angles_.x() != 0.f) mat.rotate(angles_.x(), 1., 0., 0.);
// mat.scale(scale_);
// }
mat = trans.matrix();
return parent * mat;
}
AimedObject::AimedObject() {
aim_dist = 1.;
}
QVector3D AimedObject::worldAim() const {
QVector3D ret = worldPos() + worldDirection() * aim_dist;
return ret;
}
void AimedObject::setAim(const QVector3D & p) {
QVector3D dir = p - pos();
trans.setRotation(Transform::fromDirection(dir, trans.rotationY()));
aim_dist = dir.length();
buildTransform();
// if (!p.isNull())
// qDebug() << "setAim" << p << aim() << worldAim();
}
QVector3D AimedObject::direction() const {
return trans.direction();
}
void AimedObject::setDirection(const QVector3D & d) {
// double len = qMax(aim_.length(), 0.001f);
// aim_ = d.normalized() * len;
buildTransform();
}
void AimedObject::flyCloser(double s) {
double tl = 1. / (1. + s);
move(direction() * aim_dist * (1. - tl));
aim_dist *= tl;
}
void AimedObject::flyFarer(double s) {
double tl = 1. * (1. + s);
move(direction() * aim_dist * (1. - tl));
aim_dist *= tl;
}
void AimedObject::flyToDistance(double d) {
move(direction() * (aim_dist - d));
aim_dist = d;
// qDebug() << d << (aim() - pos()).length() << aim();
}
void AimedObject::moveForward(const float & x, bool withZ) {
QVector3D dv = itransform_.mapVector(QVector3D(0, 0, -x));
if (!withZ) dv[2] = 0.;
move(dv);
}
void AimedObject::moveLeft(const float & x, bool withZ) {
QVector3D dv = itransform_.mapVector(QVector3D(-x, 0, 0));
if (!withZ) dv[2] = 0.;
move(dv);
}
void AimedObject::moveUp(const float & x, bool onlyZ) {
QVector3D dv = itransform_.mapVector(QVector3D(0, x, 0));
if (onlyZ) dv[0] = dv[1] = 0.;
move(dv);
}
void AimedObject::orbitZ(const float & a) {
QVector3D pa = aim();
rotateZ(-a);
move(pa - aim());
}
void AimedObject::orbitXY(const float & a) {
QVector3D pa = aim();
rotateX(-a);
move(pa - aim());
}
void AimedObject::transformChanged() {}
Light::Light(): AimedObject(), 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.;
setDirection(0, 0, -1.);
}
Light::Light(const QVector3D & p, const QColor & c, float i): AimedObject(), shadow_map(0, true, GL_R16F) {
type_ = glLight;
light_type = Omni;
intensity = i;
color_ = c;
angle_start = angle_end = 180.;
decay_linear = decay_quadratic = decay_start = 0.;
decay_const = decay_end = 1.;
setPos(p);
setDirection(0, 0, -1.);
}
ObjectBase * Light::clone(bool withChildren) {
Light * o = new Light(*this);
// GLObjectBase::clone(withChildren);
o->is_init = false;
o->name_ = name_; // + "_copy";
o->scene_ = nullptr;
o->children_.clear();
if (withChildren) {
for (int i = 0; i < children_.size(); ++i)
o->addChild(children_[i]->clone(withChildren));
}
o->color_ = color_;
o->light_type = light_type;
o->trans = trans;
o->aim_dist = aim_dist;
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;
o->meta = meta;
return o;
}
void Light::apply() {
if (scene_) scene_->setLightsChanged();
}
QDataStream & operator<<(QDataStream & s, const ObjectBase * p) {
ChunkStream cs;
// qDebug() << "place" << p->name() << "...";
cs.add(1, int(p->type_))
.add(2, p->accept_light)
.add(3, p->accept_fog)
.add(4, p->visible_)
.add(5, p->cast_shadow)
.add(6, p->rec_shadow)
.add(7, p->raw_matrix)
.add(8, p->line_width)
.add(9, int(p->render_mode))
.add(14, p->mat_)
.add(16, p->children_.size())
.add(17, p->name_)
.add(18, p->meta)
.add(19, p->color_)
.add(20, p->trans);
// qDebug() << "place self done";
if (p->type_ == ObjectBase::glLight) {
// qDebug() << "place light ...";
const Light * l = (const Light *)p;
cs.add(101, l->angle_start)
.add(102, l->angle_end)
.add(103, l->intensity)
.add(104, l->decay_const)
.add(105, l->decay_linear)
.add(106, l->decay_quadratic)
.add(107, l->decay_start)
.add(108, l->decay_end)
.add(109, int(l->light_type))
.add(111, l->distance());
}
if (p->type_ == ObjectBase::glCamera) {
// qDebug() << "place camera ...";
const Camera * c = (const Camera *)p;
cs.add(200, c->aim())
.add(201, c->fov_)
.add(202, c->depth_start)
.add(206, c->mirror_x)
.add(207, c->mirror_y)
.add(208, c->distance())
.add(209, c->roll_);
}
// qDebug() << "place" << p->name() << cs.data().size() << s.device()->size();
s << cs.data();
foreach(const ObjectBase * c, p->children_)
s << c;
return s;
}
QDataStream & operator>>(QDataStream & s, ObjectBase *& p) {
ChunkStream cs(s);
p = nullptr;
int ccnt = 0;
Light * l = nullptr;
Camera * c = nullptr;
// qDebug() << "read obj ...";
while (!cs.atEnd()) {
switch (cs.read()) {
case 1: {
ObjectBase::Type type = (ObjectBase::Type)cs.getData<int>();
switch (type) {
case ObjectBase::glMesh: p = new ObjectBase(); break;
case ObjectBase::glLight:
p = new Light();
l = (Light *)p;
break;
case ObjectBase::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<float>();
break;
case 9:
if (p) p->render_mode = (ObjectBase::RenderMode)cs.getData<int>();
break;
case 14:
if (p) p->mat_ = cs.getData<QMatrix4x4>();
break;
case 16:
if (p) ccnt = cs.getData<int>();
break;
case 17:
if (p) p->name_ = cs.getData<QString>();
break;
case 18:
if (p) p->meta = cs.getData<QVariantMap>();
break;
case 19:
if (p) p->color_ = cs.getData<QColor>();
break;
case 20:
if (p) p->trans = cs.getData<Transform>();
break;
case 100:
if (l) l->setAim(cs.getData<QVector3D>());
break;
case 101:
if (l) l->angle_start = cs.getData<GLfloat>();
break;
case 102:
if (l) l->angle_end = cs.getData<GLfloat>();
break;
case 103:
if (l) l->intensity = cs.getData<GLfloat>();
break;
case 104:
if (l) l->decay_const = cs.getData<GLfloat>();
break;
case 105:
if (l) l->decay_linear = cs.getData<GLfloat>();
break;
case 106:
if (l) l->decay_quadratic = cs.getData<GLfloat>();
break;
case 107:
if (l) l->decay_start = cs.getData<GLfloat>();
break;
case 108:
if (l) l->decay_end = cs.getData<GLfloat>();
break;
case 109:
if (l) l->light_type = (Light::Type)cs.getData<int>();
break;
case 111:
if (l) l->setDistance(cs.getData<double>());
break;
case 200:
if (c) c->setAim(cs.getData<QVector3D>());
break;
case 201:
if (c) c->setFOV(cs.getData<GLfloat>());
break;
case 202:
if (c) c->setDepthStart(cs.getData<GLfloat>());
break;
case 206:
if (c) c->mirror_x = cs.getData<bool>();
break;
case 207:
if (c) c->mirror_y = cs.getData<bool>();
break;
case 208:
if (c) c->setDistance(cs.getData<double>());
break;
case 209:
if (c) c->roll_ = cs.getData<GLfloat>();
break;
}
}
// qDebug() << p->name() << ccnt;
for (int i = 0; i < ccnt; ++i) {
ObjectBase * c = nullptr;
s >> c;
if (!c) continue;
c->parent_ = p;
p->children_ << c;
}
p->buildTransform();
return s;
}

453
src/core/scene/globject.h Normal file
View File

@@ -0,0 +1,453 @@
/*
QGL ObjectBase & Light
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 <http://www.gnu.org/licenses/>.
*/
#ifndef GLOBJECT_H
#define GLOBJECT_H
#include "glframebuffer.h"
#include "glmaterial.h"
#include "gltransform.h"
#include "gltypes.h"
class QGLENGINE_CORE_EXPORT ObjectBase {
friend class Scene;
friend class RendererSelection;
friend QGLENGINE_CORE_EXPORT QDataStream & operator<<(QDataStream & s, const ObjectBase * p);
friend QGLENGINE_CORE_EXPORT QDataStream & operator>>(QDataStream & s, ObjectBase *& p);
friend QGLENGINE_CORE_EXPORT QDataStream & operator>>(QDataStream & s, Scene *& p);
public:
enum Type {
glMesh,
glLight,
glCamera,
glParticlesSystem
};
enum RenderMode {
View = 0,
Point = GL_POINT,
Line = GL_LINE,
Fill = GL_FILL
};
explicit ObjectBase(Mesh * geom = 0, Material * mat = 0);
virtual ~ObjectBase();
virtual ObjectBase * clone(bool withChildren = true);
void destroy();
QString name() const { return name_; }
void setName(const QString & name) { name_ = name; }
virtual void init();
virtual void update() {}
bool isInit() const { return is_init; }
Type type() const { return type_; }
RenderPass pass() const;
uint id() const { return id_; }
RenderMode renderMode() const { return render_mode; }
void setRenderMode(RenderMode mode) { render_mode = mode; }
float lineWidth() const { return line_width; }
void setLineWidth(const float & width) { line_width = width; }
ObjectBase * parent() { return parent_; }
void setParent(ObjectBase * o) { parent_ = o; }
bool hasParent() const { return parent_ != nullptr; }
bool hasChildren() const { return !children_.isEmpty(); }
void setScene(Scene * v);
void addChild(ObjectBase * o);
void removeChild(ObjectBase * o);
void removeChild(int index);
void clearChildren(bool deleteAll = false);
int childCount() const { return children_.size(); }
ObjectBase * child(int index);
ObjectBase * child(const QString & name);
const ObjectBase * child(int index) const;
const ObjectBase * child(const QString & name) const;
ObjectBaseList children(bool all_ = false);
bool isVisible(bool check_parents = false) const;
bool isHidden(bool check_parents = false) const { return !isVisible(check_parents); }
void setVisible(bool v);
void setHidden(bool v) { setVisible(!v); }
void show() { setVisible(true); }
void hide() { setVisible(false); }
bool isReceiveShadows() const { return rec_shadow; }
bool isCastShadows() const { return cast_shadow; }
void setReceiveShadows(bool on) { rec_shadow = on; }
void setCastShadows(bool on) { cast_shadow = on; }
void move(const QVector3D & dv) {
trans.setTranslation(pos() + dv);
buildTransform();
}
void moveTo(const QVector3D & dv) {
trans.setTranslation(dv);
buildTransform();
}
void move(GLfloat dx, GLfloat dy, GLfloat dz = 0.) {
move(QVector3D(dx, dy, dz));
buildTransform();
}
void moveTo(GLfloat dx, GLfloat dy, GLfloat dz = 0.) {
moveTo(QVector3D(dx, dy, dz));
buildTransform();
}
void moveX(GLfloat o) {
trans.setTranslationX(posX() + o);
buildTransform();
}
void moveY(GLfloat o) {
trans.setTranslationY(posY() + o);
buildTransform();
}
void moveZ(GLfloat o) {
trans.setTranslationZ(posZ() + o);
buildTransform();
}
void setPosX(GLfloat o) {
trans.setTranslationX(o);
buildTransform();
}
void setPosY(GLfloat o) {
trans.setTranslationY(o);
buildTransform();
}
void setPosZ(GLfloat o) {
trans.setTranslationZ(o);
buildTransform();
}
void setPos(GLfloat x, GLfloat y, GLfloat z) {
trans.setTranslation(QVector3D(x, y, z));
buildTransform();
}
void setPos(const QVector3D & p) {
trans.setTranslation(p);
buildTransform();
}
void resetPos() {
trans.setTranslation(QVector3D());
buildTransform();
}
QVector3D pos() const { return trans.translation(); }
float posX() const { return trans.translation().x(); }
float posY() const { return trans.translation().y(); }
float posZ() const { return trans.translation().z(); }
QVector3D worldPos() const { return (itransform_ * QVector4D(0, 0, 0, 1.)).toVector3D(); }
QMatrix4x4 worldTransform() const { return itransform_; }
QVector3D rotation() const { return trans.rotation(); }
float rotationX() const { return rotation().x(); }
float rotationY() const { return rotation().y(); }
float rotationZ() const { return rotation().z(); }
void rotateX(GLfloat a) {
raw_matrix = false;
trans.setRotationX(trans.rotationX() + a);
buildTransform();
}
void rotateY(GLfloat a) {
raw_matrix = false;
trans.setRotationY(trans.rotationY() + a);
buildTransform();
}
void rotateZ(GLfloat a);
void setRotationX(GLfloat a) {
raw_matrix = false;
trans.setRotationX(a);
buildTransform();
}
void setRotationY(GLfloat a) {
raw_matrix = false;
trans.setRotationY(a);
buildTransform();
}
void setRotationZ(GLfloat a);
void setRotation(const QVector3D & a) {
raw_matrix = false;
trans.setRotation(a);
buildTransform();
}
void resetRotation() {
raw_matrix = false;
trans.setRotation(QVector3D());
buildTransform();
}
QVector3D scale() { return trans.scale3D(); }
float scaleX() { return trans.scale3D().x(); }
float scaleY() { return trans.scale3D().y(); }
float scaleZ() { return trans.scale3D().z(); }
void scale(const QVector3D & sv) {
raw_matrix = false;
trans.setScale(trans.scale3D() * sv);
buildTransform();
}
void scale(GLfloat sx, GLfloat sy, GLfloat sz) {
raw_matrix = false;
scale(QVector3D(sx, sy, sz));
buildTransform();
}
void scale(GLfloat sx, GLfloat sy) {
raw_matrix = false;
scale(QVector3D(sx, sy, sy));
buildTransform();
}
void scale(GLfloat sx) {
raw_matrix = false;
scale(QVector3D(sx, sx, sx));
buildTransform();
}
void scaleX(GLfloat a) {
raw_matrix = false;
trans.setScaleX(trans.scale3D().x() + a);
buildTransform();
}
void scaleY(GLfloat a) {
raw_matrix = false;
trans.setScaleY(trans.scale3D().y() + a);
buildTransform();
}
void scaleZ(GLfloat a) {
raw_matrix = false;
trans.setScaleZ(trans.scale3D().z() + a);
buildTransform();
}
void setScale(const QVector3D & a) {
raw_matrix = false;
trans.setScale(a);
buildTransform();
}
void setScale(GLfloat a) {
raw_matrix = false;
trans.setScale(a);
buildTransform();
}
void setScaleX(GLfloat a) {
raw_matrix = false;
trans.setScaleX(a);
buildTransform();
}
void setScaleY(GLfloat a) {
raw_matrix = false;
trans.setScaleY(a);
buildTransform();
}
void setScaleZ(GLfloat a) {
raw_matrix = false;
trans.setScaleZ(a);
buildTransform();
}
void resetScale() {
raw_matrix = false;
trans.setScale(1.f);
buildTransform();
}
Transform transform() { return trans; }
void setTransform(const Transform & t);
void setMatrix(const QMatrix4x4 & t);
QMatrix4x4 matrix() const;
bool isRawMatrix() { return raw_matrix; }
QVector3D inParentSpace(const QVector3D & v) const;
void transferTransformToChildren(bool only_scale = false);
void cleanTree();
bool isAcceptLight() const { return accept_light; }
void setAcceptLight(bool yes) { accept_light = yes; }
bool isAcceptFog() const { return accept_fog; }
void setAcceptFog(bool yes) { accept_fog = yes; }
bool isSelected(bool check_parents = false) const;
void setSelected(bool yes);
void select() { setSelected(true); }
void deselect() { setSelected(false); }
ObjectBase * selectedParent() const;
void setAimSelected(bool yes) { selected_aim = yes; }
bool isAimSelected() const { return selected_aim; }
bool isSelectable() const { return select_; }
void setSelectable(bool yes) { select_ = yes; }
GLenum srcAlpha() const { return blend_src; }
GLenum destAlpha() const { return blend_dest; }
void setSrcAlpha(GLenum mode) { blend_src = mode; }
void setDestAlpha(GLenum mode) { blend_dest = mode; }
void setMaterial(Material * m, bool with_children = false);
Material * material() { return material_; }
void setColor(QColor c, bool with_children = false);
QColor color() { return color_; }
const Box3D & boundingBox() const { return bound; }
void setMesh(Mesh * v);
Mesh * mesh() { return mesh_; }
void calculateBoundingBox();
void updateTransform();
void setProperty(const QString & pn, const QVariant & v);
QVariant property(const QString & pn, bool * exists = 0) const;
bool hasProperty(const QString & pn) const;
void removeProperty(const QString & pn);
QVector3D pos_h;
protected:
virtual void transformChanged() {}
void addChildren(ObjectBaseList & list, ObjectBase * where);
void buildTransform(bool force = false);
void initInternal();
void setSceneTreeChanged();
void setObjectsChanged();
void localTransform(QMatrix4x4 & m);
QMatrix4x4 worldMatrix(QMatrix4x4 parent) const;
int prev_pass; // Pass
bool is_init, accept_light, accept_fog, visible_, cast_shadow, rec_shadow, select_, selected_, raw_matrix;
bool is_root, selected_aim;
float line_width;
QColor color_;
uint id_;
Type type_;
RenderMode render_mode;
Box3D bound;
Transform trans;
ObjectBaseList children_;
QMatrix4x4 itransform_, mat_;
QString name_;
GLenum blend_src, blend_dest;
ObjectBase * parent_;
Scene * scene_;
Material * material_;
Mesh * mesh_;
QVariantMap meta;
};
inline bool operator<(const ObjectBase & f, const ObjectBase & s) {
return f.pos_h.z() < s.pos_h.z();
}
class QGLENGINE_CORE_EXPORT AimedObject: public ObjectBase {
friend class QGLView;
friend class GLRendererBase;
friend class Light;
friend class Camera;
public:
AimedObject();
~AimedObject() {}
QVector3D aim() const { return pos() + (direction() * aim_dist); }
QVector3D worldAim() const;
void setAim(const QVector3D & p);
QVector3D direction() const;
QVector3D worldDirection() const { return (itransform_ * QVector4D(QVector3D(0, 0, -1), 0.)).toVector3D().normalized(); }
void setDirection(const QVector3D & d);
void setDirection(double x, double y, double z) { setDirection(QVector3D(x, y, z)); }
double distance() const { return aim_dist; }
void setDistance(double d) { aim_dist = d; }
void flyCloser(double s);
void flyFarer(double s);
void flyToDistance(double d);
void moveForward(const float & x, bool withZ = true);
void moveBackward(const float & x, bool withZ = true) { moveForward(-x, withZ); }
void moveLeft(const float & x, bool withZ = true);
void moveRight(const float & x, bool withZ = true) { moveLeft(-x, withZ); }
void moveUp(const float & x, bool onlyZ = false);
void moveDown(const float & x, bool onlyZ = false) { moveUp(-x, onlyZ); }
void rotateRoll(const float & a) { rotateY(a); }
void orbitZ(const float & a);
void orbitXY(const float & a);
protected:
void transformChanged() override;
double aim_dist;
};
class QGLENGINE_CORE_EXPORT Light: public AimedObject {
friend class QGLView;
friend class RendererBase;
public:
enum Type {
Omni,
Cone,
Directional
};
Light();
Light(const QVector3D & p, const QColor & c = Qt::white, float i = 1.);
virtual ObjectBase * clone(bool withChildren = true);
virtual void init() {
shadow_map.resize(512, 512);
is_init = true;
}
void apply();
float angle_start;
float angle_end;
float intensity;
float decay_const;
float decay_linear;
float decay_quadratic;
float decay_start;
float decay_end;
Type light_type;
Framebuffer shadow_map;
QMatrix4x4 shadow_matrix;
};
template<class T>
inline T globject_cast(ObjectBase * object) {
return reinterpret_cast<T>(object);
}
template<class T>
inline T globject_cast(const ObjectBase * object) {
return reinterpret_cast<T>(object);
}
QGLENGINE_CORE_EXPORT QDataStream & operator<<(QDataStream & s, const ObjectBase * p);
QGLENGINE_CORE_EXPORT QDataStream & operator>>(QDataStream & s, ObjectBase *& p);
inline ObjectBaseList lights2objectList(const QList<Light *> & v) {
ObjectBaseList ret;
foreach(Light * i, v)
ret << (ObjectBase *)i;
return ret;
}
inline ObjectBaseList cameras2objectList(const QList<Camera *> & v) {
ObjectBaseList ret;
foreach(Camera * i, v)
ret << (ObjectBase *)i;
return ret;
}
#endif // GLOBJECT_H

543
src/core/scene/glscene.cpp Normal file
View File

@@ -0,0 +1,543 @@
/*
QGL Scene
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 <http://www.gnu.org/licenses/>.
*/
#include "glscene.h"
#include "glcamera.h"
#include "glmesh.h"
#include "qglview.h"
#include <chunkstream.h>
Scene::Scene() {
root_ = new ObjectBase();
root_->setScene(this);
tree_changed = mat_changed = lights_changed = true;
destroying = false;
need_reload_materials = tree_struct_changed = true;
sel_mode_ = smSingleSelection;
}
Scene::~Scene() {
destroying = true;
clear();
delete root_;
}
Scene * Scene::clone() {
Scene * ret = new Scene();
ObjectBase * o = root_->clone();
foreach(ObjectBase * co, o->children())
ret->addObject(co);
o->clearChildren();
delete o;
return ret;
}
void Scene::addObject(ObjectBase * o) {
ObjectBaseList aol = o->children(true);
attachObject(o);
foreach(ObjectBase * c, aol)
attachObject(c);
root_->addChild(o);
tree_changed = tree_struct_changed = true;
}
void Scene::addScene(const Scene * s) {
if (!s) return;
// qDebug() << "addScene clone ...";
ObjectBase * o = s->root_->clone();
o->setName(s->name());
// qDebug() << "addScene clone ok" << o << o->children(true).size();
addObject(o);
makeMaterialsUniqueNames();
// qDebug() << "addScene add ok" << o;
}
void Scene::assignFrom(const Scene * s) {
clear();
if (!s) return;
setName(s->name());
foreach(Material * m, s->materials) {
Material * nm = new Material();
*nm = *m;
nm->_changed = true;
nm->setMapsChanged();
materials << nm;
}
for (int i = 0; i < s->root_->childCount(); ++i) {
addObject(s->root_->child(i)->clone());
// qDebug() << i << o->child(i)->pos();
}
tree_changed = mat_changed = lights_changed = need_reload_materials = tree_struct_changed = true;
}
void Scene::clear() {
selected_.clear();
selected_top.clear();
emitSelectionChanged();
root_->clearChildren(true);
td_geometries << geometries;
qDeleteAll(materials);
geometries.clear();
materials.clear();
emit __destroyed();
emit treeChanged();
}
void Scene::reinitAll() {
for (auto * i: geometries)
i->reinit();
for (auto * i: td_geometries)
i->reinit();
setTreeChanged();
mat_changed = lights_changed = true;
need_reload_materials = true;
tree_struct_changed = true;
}
void Scene::objectsCountInternal(int * cnt, ObjectBase * where) {
++(*cnt);
foreach(ObjectBase * i, where->children())
objectsCountInternal(cnt, i);
}
int Scene::objectsCount(bool all) {
if (!all) return root_->childCount();
int cnt = 0;
objectsCountInternal(&cnt, root_);
return cnt;
}
void Scene::removeObjectInternal(ObjectBase * o, ObjectBase * where) {
if (destroying) return;
foreach(ObjectBase * i, where->children()) {
if (o == i) {
where->removeChild(i);
setObjectMeshChanged(i);
} else
removeObjectInternal(o, i);
}
}
void Scene::emitSelectionChanged() {
selected_top.clear();
foreach(ObjectBase * o, selected_) {
ObjectBase * po = o->selectedParent();
if (!po) po = o;
if (!selected_top.contains(po)) selected_top << po;
}
foreach(Mesh * m, geometries)
m->setAllSelectionChanged(true);
selectionChanged();
}
QString Scene::uniqueName(QString n, const QSet<QString> & names) {
if (!names.contains(n)) return n;
QString num;
while (!n.isEmpty()) {
if (n.right(1)[0].isDigit()) {
num.push_front(n.right(1));
n.chop(1);
} else
break;
}
if (!n.endsWith('_')) n += '_';
int in = num.toInt() + 1;
QString nn = n + QString::number(in).rightJustified(3, '0');
while (names.contains(nn))
nn = n + QString::number(++in).rightJustified(3, '0');
return nn;
}
void Scene::removeObject(ObjectBase * o, bool inChildren) {
if (destroying) return;
o->setScene(nullptr);
setObjectMeshChanged(o);
if (inChildren)
removeObjectInternal(o, root_);
else
root_->removeChild(o);
__objectDeleted(o);
setTreeStructChanged();
}
void Scene::removeObject(ObjectBase & o, bool inChildren) {
if (destroying) return;
removeObject(&o, inChildren);
}
void Scene::clearObjects(bool deleteAll) {
root_->clearChildren(deleteAll);
cleanUnused();
setTreeStructChanged();
emitSelectionChanged();
}
void Scene::selectObject(ObjectBase * o, bool add_to_selection) {
// qDebug() << "selectObject" << o << add_to_selection;
if (!add_to_selection || (sel_mode_ == smSingleSelection)) clearSelection();
if (o) {
if (!add_to_selection)
o->setSelected(true);
else
o->setSelected(!o->isSelected());
gatherSelection();
}
emitSelectionChanged();
}
void Scene::selectObjects(ObjectBaseList ol, bool add_to_selection) {
if (!add_to_selection || (sel_mode_ == smSingleSelection)) clearSelection();
foreach(ObjectBase * o, ol) {
if (!o) continue;
o->setSelected(true);
}
gatherSelection();
emitSelectionChanged();
}
void Scene::selectObjectsByMesh() {
ObjectBaseList csl = selected_;
QSet<Mesh *> sml;
foreach(ObjectBase * o, csl)
if (o->mesh()) sml << o->mesh();
ObjectBaseList ol = root_->children(true);
foreach(ObjectBase * o, ol) {
if (sml.contains(o->mesh())) o->setSelected(true);
}
gatherSelection();
emitSelectionChanged();
}
void Scene::selectObjectsByMaterial() {
ObjectBaseList csl = selected_;
QSet<Material *> sml;
foreach(ObjectBase * o, csl)
if (o->material()) sml << o->material();
ObjectBaseList ol = root_->children(true);
foreach(ObjectBase * o, ol) {
if (sml.contains(o->material())) o->setSelected(true);
}
gatherSelection();
emitSelectionChanged();
}
void Scene::clearSelection() {
selected_.clear();
selected_top.clear();
ObjectBaseList ol = root_->children(true);
foreach(ObjectBase * o, ol) {
o->setSelected(false);
o->setAimSelected(false);
}
emitSelectionChanged();
}
ObjectBaseList Scene::selectedObjects(bool top_only) const {
return top_only ? selected_top : selected_;
}
ObjectBase * Scene::selectedObject() const {
if (selected_.isEmpty()) return 0;
return selected_[0];
}
void gatherMeshes(ObjectBase * o, QSet<Mesh *> & ums) {
if (o->mesh()) ums << o->mesh();
for (int i = 0; i < o->childCount(); ++i)
gatherMeshes(o->child(i), ums);
}
void Scene::cleanUnused() {
QSet<Mesh *> ums;
gatherMeshes(root_, ums);
for (int i = 0; i < geometries.size(); ++i) {
if (ums.contains(geometries[i])) continue;
td_geometries << geometries[i];
geometries.removeAt(i);
--i;
}
}
const Box3D & Scene::boundingBox() const {
root_->calculateBoundingBox();
return root_->boundingBox();
}
Material * Scene::newMaterial(const QString & name) {
materials << new Material(name);
makeMaterialsUniqueNames();
mat_changed = true;
return materials.back();
}
void Scene::removeMaterial(Material * m) {
if (!m || !materials.contains(m)) return;
ObjectBaseList ol = root_->children(true);
foreach(ObjectBase * o, ol)
if (o->material_ == m) o->setMaterial(0);
materials.removeAll(m);
changed_materials.removeAll(m);
mat_changed = true;
}
void Scene::makeMaterialsUniqueNames() {
QSet<QString> names;
foreach(Material * m, materials) {
if (m->name.isEmpty()) m->name = "default_000";
m->name = uniqueName(m->name, names);
names << m->name;
}
}
ObjectBaseList Scene::objects(bool all) {
return root_->children(all);
}
void Scene::removeLight(Light * l) {
removeObject(l);
}
void Scene::dump() {
qDebug() << "Scene" << name();
qDebug() << "Meshes:" << geometries.size();
qDebug() << "Objects:" << root_->children(true).size();
}
void Scene::gatherSelection() {
selected_.clear();
ObjectBaseList ol = root_->children(true);
foreach(ObjectBase * o, ol)
if (o->isSelected()) selected_ << o;
}
void Scene::attachObject(ObjectBase * o) {
if (!o) return;
o->setScene(this);
if (o->mesh()) { // search suitable mesh in this scene
o->setMesh(attachMesh(o->mesh()));
setObjectMeshChanged(o);
}
if (o->material()) { // search suitable material in this scene
uint ohash = o->material()->hash();
bool need_new = true;
foreach(Material * m, materials) {
if (m == o->material()) { // already exists by ptr
need_new = false;
break;
}
if (m->hash() == ohash) { // already exists by hash
need_new = false;
o->setMaterial(m);
break;
}
}
if (need_new) { // need to clone material and add to scene
Material * nmat = new Material();
*nmat = *(o->material());
nmat->setMapsChanged();
o->setMaterial(nmat);
materials << nmat;
}
}
setTreeStructChanged();
}
Mesh * Scene::attachMesh(Mesh * mesh) {
if (!mesh) return 0;
uint mhash = mesh->hash();
foreach(Mesh * m, geometries) {
if (m == mesh) { // already exists by ptr
return m;
}
if (m->hash() == mhash) { // already exists by hash
return m;
}
}
// need to clone mesh and add to scene
Mesh * nmesh = mesh->clone();
geometries << nmesh;
return nmesh;
}
void Scene::setTreeChanged() {
if (destroying) return;
tree_changed = true;
foreach(Mesh * m, geometries) {
m->setAllObjectsChanged(true);
m->setAllSelectionChanged(true);
}
gatherSelection();
}
void Scene::setTreeStructChanged() {
tree_struct_changed = true;
}
void Scene::setObjectMeshChanged(ObjectBase * o) {
if (o) o->setObjectsChanged();
}
void Scene::prepareTree(ObjectBase * o) {
foreach(ObjectBase * co, o->children_) {
if (co->isHidden()) continue;
switch (co->type_) {
case ObjectBase::glLight: {
Light * l = globject_cast<Light *>(co);
lights_used[l->light_type] << l;
} break;
case ObjectBase::glMesh:
if (co->mesh()) {
geometries_used[co->pass()][co->mesh()] << co;
co->setObjectsChanged();
}
break;
case ObjectBase::glCamera: cameras_used << globject_cast<Camera *>(co); break;
default: break;
}
prepareTree(co);
}
}
bool Scene::prepare() {
changed_materials.clear();
foreach(Material * m, materials) {
if (m->_changed) {
need_reload_materials = tree_changed = true;
changed_materials << m;
}
}
ObjectBaseList aol;
if (!tree_changed && !mat_changed) return false;
aol = root_->children(true);
if (tree_changed) {
geometries_used[rpSolid].clear();
geometries_used[rpTransparent].clear();
lights_used.clear();
cameras_used.clear();
prepareTree(root_);
if (tree_struct_changed) {
tree_struct_changed = false;
cleanUnused();
QMetaObject::invokeMethod(this, "treeChanged", Qt::QueuedConnection);
}
tree_changed = false;
lights_changed = true;
}
mat_changed = false;
return true;
}
void Scene::destroy(QOpenGLExtraFunctions * f) {
foreach(Mesh * g, geometries)
g->destroy(f);
}
void Scene::destroyUnused(QOpenGLExtraFunctions * f) {
foreach(Mesh * i, td_geometries)
i->destroy(f);
qDeleteAll(td_geometries);
td_geometries.clear();
}
QDataStream & operator<<(QDataStream & s, const Scene * p) {
ChunkStream cs;
// qDebug() << "place" << p->name() << "...";
QVector<short> geom_ind, mat_ind;
ObjectBaseList cl = p->root_->children(true);
geom_ind.reserve(cl.size());
mat_ind.reserve(cl.size());
foreach(ObjectBase * c, cl) {
geom_ind << p->geometries.indexOf(c->mesh());
mat_ind << p->materials.indexOf(c->material());
}
cs.add(1, p->name_).add(10, p->geometries).add(11, p->materials).add(20, p->root_).add(21, geom_ind).add(22, mat_ind);
s << qCompress(cs.data());
return s;
}
QDataStream & operator>>(QDataStream & s, Scene *& p) {
p = new Scene();
QByteArray ba;
s >> ba;
ba = qUncompress(ba);
ChunkStream cs(ba);
QVector<short> geom_ind, mat_ind;
while (!cs.atEnd()) {
switch (cs.read()) {
case 1: cs.get(p->name_); break;
case 10: cs.get(p->geometries); break;
case 11: cs.get(p->materials); break;
case 20:
cs.get(p->root_);
p->root_->setScene(p);
break;
case 21: cs.get(geom_ind); break;
case 22: cs.get(mat_ind); break;
}
}
p->makeMaterialsUniqueNames();
ObjectBaseList cl = p->root_->children(true);
int cnt = qMin(qMin(cl.size(), geom_ind.size()), mat_ind.size());
for (int i = 0; i < cnt; ++i) {
ObjectBase * c(cl[i]);
if (geom_ind[i] >= 0) c->mesh_ = p->geometries[geom_ind[i]];
if (mat_ind[i] >= 0) c->material_ = p->materials[mat_ind[i]];
}
return s;
}

144
src/core/scene/glscene.h Normal file
View File

@@ -0,0 +1,144 @@
/*
QGL Scene
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 <http://www.gnu.org/licenses/>.
*/
#ifndef GLSCENE_H
#define GLSCENE_H
#include "gltypes.h"
class QGLENGINE_CORE_EXPORT Scene: public QObject {
Q_OBJECT
friend class RendererBase;
friend class Renderer;
friend class RendererMaterial;
friend class RendererService;
friend class RendererSelection;
friend class ObjectBase;
friend class Light;
friend QGLENGINE_CORE_EXPORT QDataStream & operator<<(QDataStream & s, const Scene * p);
friend QGLENGINE_CORE_EXPORT QDataStream & operator>>(QDataStream & s, Scene *& p);
public:
explicit Scene();
virtual ~Scene();
enum SelectionMode {
smNoSelection,
smSingleSelection,
smMultiSelection,
};
Q_ENUMS(SelectionMode)
QString name() const { return name_; }
void setName(const QString & name) { name_ = name; }
bool prepare();
Scene * clone();
/// Add object \"o\" to scene and take its ownership
/// All materials and geometries used by \"o\" tree
/// copied into this scene
void addObject(ObjectBase * o);
void addScene(const Scene * s);
void assignFrom(const Scene * s);
void clear();
void reinitAll();
int objectsCount(bool all = false);
ObjectBaseList objects(bool all = false);
ObjectBase * rootObject() { return root_; }
void removeObject(ObjectBase * o, bool inChildren = true);
void removeObject(ObjectBase & o, bool inChildren = true);
void clearObjects(bool deleteAll = false);
SelectionMode selectionMode() const { return sel_mode_; }
void setSelectionMode(SelectionMode mode) { sel_mode_ = mode; }
void selectObject(ObjectBase * o, bool add_to_selection = false);
void selectObjects(ObjectBaseList ol, bool add_to_selection = false);
void selectObjectsByMesh();
void selectObjectsByMaterial();
void clearSelection();
ObjectBaseList selectedObjects(bool top_only = false) const;
ObjectBase * selectedObject() const;
void cleanUnused();
const Box3D & boundingBox() const;
QVector<Material *> getMaterials() const { return materials; }
Material * newMaterial(const QString & name = QString());
void removeMaterial(Material * m);
void makeMaterialsUniqueNames();
void removeLight(Light * l);
void dump();
void destroy(QOpenGLExtraFunctions * f);
void destroyUnused(QOpenGLExtraFunctions * f);
protected:
void prepareTree(ObjectBase * o);
void gatherSelection();
void objectsCountInternal(int * cnt, ObjectBase * where);
void removeObjectInternal(ObjectBase * o, ObjectBase * where);
void emitSelectionChanged();
QString uniqueName(QString n, const QSet<QString> & names);
void attachObject(ObjectBase * o);
Mesh * attachMesh(Mesh * mesh);
void setTreeChanged();
void setTreeStructChanged();
void setMaterialsChanged() { mat_changed = true; }
void setLightsChanged() { lights_changed = tree_changed = true; }
void setObjectMeshChanged(ObjectBase * o);
QString name_;
ObjectBase * root_;
bool tree_changed, mat_changed, lights_changed, destroying;
bool need_reload_materials, tree_struct_changed;
QVector<bool> mat_map_changed;
QVector<Mesh *> geometries, td_geometries;
QVector<Material *> materials;
QMap<int, QMap<Mesh *, ObjectBaseList>> geometries_used;
QMap<int, QList<Light *>> lights_used;
QList<Camera *> cameras_used;
QVector<Material *> changed_materials;
SelectionMode sel_mode_;
ObjectBaseList selected_, selected_top;
protected slots:
signals:
void __objectDeleted(ObjectBase * o);
void __destroyed();
void treeChanged();
void selectionChanged();
};
QGLENGINE_CORE_EXPORT QDataStream & operator<<(QDataStream & s, const Scene * p);
QGLENGINE_CORE_EXPORT QDataStream & operator>>(QDataStream & s, Scene *& p);
#endif // GLSCENE_H