/*
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 .
*/
#ifndef GLOBJECT_H
#define GLOBJECT_H
#include "glframebuffer.h"
#include "glmaterial.h"
#include "gltransform.h"
#include "gltypes.h"
class ObjectBase {
friend class Scene;
friend class RendererSelection;
friend QDataStream & operator<<(QDataStream & s, const ObjectBase * p);
friend QDataStream & operator>>(QDataStream & s, ObjectBase *& p);
friend 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 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 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
inline T globject_cast(ObjectBase * object) {
return reinterpret_cast(object);
}
template
inline T globject_cast(const ObjectBase * object) {
return reinterpret_cast(object);
}
QDataStream & operator<<(QDataStream & s, const ObjectBase * p);
QDataStream & operator>>(QDataStream & s, ObjectBase *& p);
inline ObjectBaseList lights2objectList(const QList & v) {
ObjectBaseList ret;
foreach(Light * i, v)
ret << (ObjectBase *)i;
return ret;
}
inline ObjectBaseList cameras2objectList(const QList & v) {
ObjectBaseList ret;
foreach(Camera * i, v)
ret << (ObjectBase *)i;
return ret;
}
#endif // GLOBJECT_H