1110 lines
23 KiB
C++
1110 lines
23 KiB
C++
/*
|
|
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) {
|
|
blend_src = GL_SRC_ALPHA;
|
|
blend_dest = GL_ONE_MINUS_SRC_ALPHA;
|
|
mat_.setToIdentity();
|
|
mesh_ = geom;
|
|
setPreset(0);
|
|
currentPreset().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->presets = presets;
|
|
o->cur_preset = cur_preset;
|
|
o->color_ = color_;
|
|
o->type_ = type_;
|
|
o->raw_matrix = raw_matrix;
|
|
o->mat_ = mat_;
|
|
o->trans = trans;
|
|
o->trans_texture = trans_texture;
|
|
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->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 (currentPreset().material)
|
|
if (currentPreset().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 currentPreset().visible;
|
|
if (!currentPreset().visible) return false;
|
|
ObjectBase * p = parent_;
|
|
while (p) {
|
|
if (!p->currentPreset().visible) return false;
|
|
p = p->parent_;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void ObjectBase::setVisible(bool v) {
|
|
currentPreset().visible = v;
|
|
setSceneTreeChanged();
|
|
}
|
|
|
|
|
|
void ObjectBase::setVisibleForAllPresets(bool v) {
|
|
for (auto & p: presets)
|
|
p.visible = v;
|
|
}
|
|
|
|
|
|
void ObjectBase::setReceiveShadows(bool on) {
|
|
currentPreset().receive_shadow = on;
|
|
setObjectsChanged();
|
|
}
|
|
|
|
|
|
void ObjectBase::setCastShadows(bool on) {
|
|
currentPreset().cast_shadow = on;
|
|
if (type_ == glLight)
|
|
((Light *)this)->apply();
|
|
else
|
|
setObjectsChanged();
|
|
}
|
|
|
|
void ObjectBase::move(const QVector3D & dv) {
|
|
trans.setTranslation(pos() + dv);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::moveTo(const QVector3D & dv) {
|
|
trans.setTranslation(dv);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::move(GLfloat dx, GLfloat dy, GLfloat dz) {
|
|
move(QVector3D(dx, dy, dz));
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::moveTo(GLfloat dx, GLfloat dy, GLfloat dz) {
|
|
moveTo(QVector3D(dx, dy, dz));
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::moveX(GLfloat o) {
|
|
trans.setTranslationX(posX() + o);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::moveY(GLfloat o) {
|
|
trans.setTranslationY(posY() + o);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::moveZ(GLfloat o) {
|
|
trans.setTranslationZ(posZ() + o);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::setPosX(GLfloat o) {
|
|
trans.setTranslationX(o);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::setPosY(GLfloat o) {
|
|
trans.setTranslationY(o);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::setPosZ(GLfloat o) {
|
|
trans.setTranslationZ(o);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::setPos(GLfloat x, GLfloat y, GLfloat z) {
|
|
trans.setTranslation(QVector3D(x, y, z));
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::setPos(const QVector3D & p) {
|
|
trans.setTranslation(p);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::resetPos() {
|
|
trans.setTranslation(QVector3D());
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::rotateX(GLfloat a) {
|
|
raw_matrix = false;
|
|
trans.setRotationX(trans.rotationX() + a);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::rotateY(GLfloat a) {
|
|
raw_matrix = false;
|
|
trans.setRotationY(trans.rotationY() + a);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
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::setRotationX(GLfloat a) {
|
|
raw_matrix = false;
|
|
trans.setRotationX(a);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::setRotationY(GLfloat a) {
|
|
raw_matrix = false;
|
|
trans.setRotationY(a);
|
|
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::setRotation(const QVector3D & a) {
|
|
raw_matrix = false;
|
|
trans.setRotation(a);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::resetRotation() {
|
|
raw_matrix = false;
|
|
trans.setRotation(QVector3D());
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::scale(const QVector3D & sv) {
|
|
raw_matrix = false;
|
|
trans.setScale(trans.scale3D() * sv);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::scale(GLfloat sx, GLfloat sy, GLfloat sz) {
|
|
raw_matrix = false;
|
|
scale(QVector3D(sx, sy, sz));
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::scale(GLfloat sx, GLfloat sy) {
|
|
raw_matrix = false;
|
|
scale(QVector3D(sx, sy, sy));
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::scale(GLfloat sx) {
|
|
raw_matrix = false;
|
|
scale(QVector3D(sx, sx, sx));
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::scaleX(GLfloat a) {
|
|
raw_matrix = false;
|
|
trans.setScaleX(trans.scale3D().x() + a);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::scaleY(GLfloat a) {
|
|
raw_matrix = false;
|
|
trans.setScaleY(trans.scale3D().y() + a);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::scaleZ(GLfloat a) {
|
|
raw_matrix = false;
|
|
trans.setScaleZ(trans.scale3D().z() + a);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::setScale(const QVector3D & a) {
|
|
raw_matrix = false;
|
|
trans.setScale(a);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::setScale(GLfloat a) {
|
|
raw_matrix = false;
|
|
trans.setScale(a);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::setScaleX(GLfloat a) {
|
|
raw_matrix = false;
|
|
trans.setScaleX(a);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::setScaleY(GLfloat a) {
|
|
raw_matrix = false;
|
|
trans.setScaleY(a);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::setScaleZ(GLfloat a) {
|
|
raw_matrix = false;
|
|
trans.setScaleZ(a);
|
|
buildTransform();
|
|
}
|
|
|
|
|
|
void ObjectBase::resetScale() {
|
|
raw_matrix = false;
|
|
trans.setScale(1.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::setPreset(int preset) {
|
|
if (preset < 0) preset = 0;
|
|
if (presets.size() <= preset) presets.resize(preset + 1);
|
|
cur_preset = preset;
|
|
for (auto * c: children_)
|
|
c->setPreset(preset);
|
|
}
|
|
|
|
|
|
QVector<int> ObjectBase::availablePresets() const {
|
|
QVector<int> ret;
|
|
for (int i = 0; i < presets.size(); ++i)
|
|
ret << i;
|
|
return ret;
|
|
}
|
|
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
|
|
void ObjectBase::setTextureTransform(const Transform & t) {
|
|
trans_texture = t;
|
|
setObjectsChanged();
|
|
}
|
|
|
|
|
|
void ObjectBase::setTextureMatrix(const QMatrix4x4 & t) {
|
|
trans_texture.setMatrix(t);
|
|
setObjectsChanged();
|
|
}
|
|
|
|
|
|
QMatrix4x4 ObjectBase::textureMatrix() const {
|
|
return trans_texture.matrix();
|
|
}
|
|
|
|
|
|
QGenericMatrix<3, 2, float> ObjectBase::textureGLMatrix() const {
|
|
QGenericMatrix<3, 2, float> ret = textureMatrix().toGenericMatrix<3, 2>();
|
|
ret(0, 2) = -trans_texture.translation().x();
|
|
ret(1, 2) = -trans_texture.translation().y();
|
|
return ret;
|
|
}
|
|
|
|
|
|
void ObjectBase::setAcceptLight(bool yes) {
|
|
currentPreset().accept_light = yes;
|
|
setObjectsChanged();
|
|
}
|
|
|
|
|
|
void ObjectBase::setAcceptFog(bool yes) {
|
|
currentPreset().accept_fog = yes;
|
|
setObjectsChanged();
|
|
}
|
|
|
|
|
|
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) {
|
|
currentPreset().material = m;
|
|
if (with_children)
|
|
for (auto * i: children_)
|
|
i->setMaterial(m, true);
|
|
setObjectsChanged();
|
|
if (scene_) scene_->mat_changed = scene_->tree_changed = true;
|
|
}
|
|
|
|
|
|
void ObjectBase::setMaterialForPreset(Material * m, int p, bool with_children) {
|
|
if (p < 0 || p >= presets.size()) return;
|
|
presets[p].material = m;
|
|
if (with_children)
|
|
for (auto * i: children_)
|
|
i->setMaterialForPreset(m, p, true);
|
|
setObjectsChanged();
|
|
if (scene_) scene_->mat_changed = scene_->tree_changed = true;
|
|
}
|
|
|
|
|
|
Material * ObjectBase::materialForPreset(int p) {
|
|
if (p < 0 || p >= presets.size()) return nullptr;
|
|
return presets[p].material;
|
|
}
|
|
|
|
|
|
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(const QVector3D & p, const QColor & c, float i): AimedObject(), shadow_map(nullptr, 0, false) {
|
|
type_ = glLight;
|
|
light_type = Omni;
|
|
intensity = i;
|
|
color_ = c;
|
|
angle_start = angle_end = 90.;
|
|
decay_linear = decay_quadratic = decay_start = 0.;
|
|
decay_const = decay_end = 1.;
|
|
size = 0.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->trans_texture = trans_texture;
|
|
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;
|
|
o->shadow_map.reinit();
|
|
return o;
|
|
}
|
|
|
|
|
|
void Light::apply() {
|
|
if (scene_) scene_->setLightsChanged();
|
|
}
|
|
|
|
|
|
QDataStream & operator<<(QDataStream & s, const ObjectBase::Preset & p) {
|
|
ChunkStream cs;
|
|
cs.add(1, p.visible).add(2, p.accept_light).add(3, p.accept_fog).add(4, p.cast_shadow).add(5, p.receive_shadow);
|
|
s << cs.data();
|
|
return s;
|
|
}
|
|
QDataStream & operator>>(QDataStream & s, ObjectBase::Preset & p) {
|
|
ChunkStream cs(s);
|
|
cs.readAll();
|
|
cs.get(1, p.visible).get(2, p.accept_light).get(3, p.accept_fog).get(4, p.cast_shadow).get(5, p.receive_shadow);
|
|
return s;
|
|
}
|
|
|
|
|
|
QDataStream & operator<<(QDataStream & s, const ObjectBase * p) {
|
|
ChunkStream cs;
|
|
// qDebug() << "place" << p->name() << "...";
|
|
cs.add(1, int(p->type_))
|
|
.add(7, p->raw_matrix)
|
|
.add(8, p->line_width)
|
|
.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)
|
|
.add(21, p->trans_texture)
|
|
.add(22, p->presets);
|
|
// 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())
|
|
.add(112, l->size)
|
|
.add(113, l->light_map);
|
|
}
|
|
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->currentPreset().accept_light = cs.getData<bool>();
|
|
break;
|
|
case 3:
|
|
if (p) p->currentPreset().accept_fog = cs.getData<bool>();
|
|
break;
|
|
case 4:
|
|
if (p) p->currentPreset().visible = cs.getData<bool>();
|
|
break;
|
|
case 5:
|
|
if (p) p->currentPreset().cast_shadow = cs.getData<bool>();
|
|
break;
|
|
case 6:
|
|
if (p) p->currentPreset().receive_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 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 21:
|
|
if (p) p->trans_texture = cs.getData<Transform>();
|
|
break;
|
|
case 22:
|
|
if (p) {
|
|
p->presets = cs.getData<QVector<ObjectBase::Preset>>();
|
|
if (p->presets.isEmpty()) p->presets.resize(1);
|
|
}
|
|
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 112:
|
|
if (l) l->size = cs.getData<double>();
|
|
break;
|
|
case 113:
|
|
if (l) l->light_map = cs.getData<Map>();
|
|
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;
|
|
}
|