source-tree refactoring
This commit is contained in:
91
src/core/scene/glcamera.cpp
Normal file
91
src/core/scene/glcamera.cpp
Normal 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
65
src/core/scene/glcamera.h
Normal 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
803
src/core/scene/globject.cpp
Normal 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
453
src/core/scene/globject.h
Normal 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
543
src/core/scene/glscene.cpp
Normal 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
144
src/core/scene/glscene.h
Normal 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
|
||||
Reference in New Issue
Block a user