/* 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 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, const Scene * p); friend QGLENGINE_CORE_EXPORT QDataStream & operator>>(QDataStream & s, Scene *& p); public: enum Type { glMesh, glLight, glCamera, glParticlesSystem }; explicit ObjectBase(Mesh * geom = nullptr, Material * mat = nullptr); 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_; } 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 currentPreset().receive_shadow; } bool isCastShadows() const { return currentPreset().cast_shadow; } void setReceiveShadows(bool on); void setCastShadows(bool on); void move(const QVector3D & dv); void moveTo(const QVector3D & dv); void move(GLfloat dx, GLfloat dy, GLfloat dz = 0.); void moveTo(GLfloat dx, GLfloat dy, GLfloat dz = 0.); void moveX(GLfloat o); void moveY(GLfloat o); void moveZ(GLfloat o); void setPosX(GLfloat o); void setPosY(GLfloat o); void setPosZ(GLfloat o); void setPos(GLfloat x, GLfloat y, GLfloat z); void setPos(const QVector3D & p); void resetPos(); 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); void rotateY(GLfloat a); void rotateZ(GLfloat a); void setRotationX(GLfloat a); void setRotationY(GLfloat a); void setRotationZ(GLfloat a); void setRotation(const QVector3D & a); void resetRotation(); 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); void scale(GLfloat sx, GLfloat sy, GLfloat sz); void scale(GLfloat sx, GLfloat sy); void scale(GLfloat sx); void scaleX(GLfloat a); void scaleY(GLfloat a); void scaleZ(GLfloat a); void setScale(const QVector3D & a); void setScale(GLfloat a); void setScaleX(GLfloat a); void setScaleY(GLfloat a); void setScaleZ(GLfloat a); void resetScale(); 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(); Transform textureTransform() { return trans_texture; } void setTextureTransform(const Transform & t); void setTextureMatrix(const QMatrix4x4 & t); QMatrix4x4 textureMatrix() const; QGenericMatrix<3, 2, float> textureGLMatrix() const; bool isAcceptLight() const { return currentPreset().accept_light; } void setAcceptLight(bool yes); bool isAcceptFog() const { return currentPreset().accept_fog; } void setAcceptFog(bool 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 currentPreset().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); void setPreset(int preset); QVector3D pos_h; protected: struct Preset { bool visible = true; bool accept_light = true; bool accept_fog = true; bool cast_shadow = true; bool receive_shadow = true; Material * material = nullptr; }; friend QGLENGINE_CORE_EXPORT QDataStream & operator<<(QDataStream & s, const ObjectBase::Preset & p); friend QGLENGINE_CORE_EXPORT QDataStream & operator>>(QDataStream & s, ObjectBase::Preset & p); 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; const Preset & currentPreset() const { return presets[cur_preset]; } Preset & currentPreset() { return presets[cur_preset]; } int prev_pass = rpSolid; // Pass int cur_preset = 0; bool is_init = false, select_ = true, selected_ = false, raw_matrix = false; bool is_root = false, selected_aim = false; float line_width = -1.f; QVector presets; QColor color_ = Qt::white; uint id_ = 0; Type type_ = glMesh; Box3D bound; Transform trans, trans_texture; ObjectBaseList children_; QMatrix4x4 itransform_, mat_; QString name_; GLenum blend_src, blend_dest; ObjectBase * parent_ = nullptr; Scene * scene_ = nullptr; Mesh * mesh_ = nullptr; 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(const QVector3D & p = QVector3D(), 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; float size; Type light_type; Framebuffer shadow_map; QMatrix4x4 shadow_matrix; Map light_map; }; template inline T globject_cast(ObjectBase * object) { return reinterpret_cast(object); } template inline T globject_cast(const ObjectBase * object) { return reinterpret_cast(object); } QGLENGINE_CORE_EXPORT QDataStream & operator<<(QDataStream & s, const ObjectBase::Preset & p); QGLENGINE_CORE_EXPORT QDataStream & operator>>(QDataStream & s, ObjectBase::Preset & p); QGLENGINE_CORE_EXPORT QDataStream & operator<<(QDataStream & s, const ObjectBase * p); QGLENGINE_CORE_EXPORT 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