/* GLObjectBase & 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 "gltypes.h" #include "gltransform.h" class ObjectBase { friend class QGLView; friend class Scene; friend class Renderer; friend class RendererService; friend class RendererSelection; friend class MouseController; 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; 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; bool isSelectable() const {return select_;} void setSelectable(bool yes) {select_ = yes;} /* bool isWriteDepth() const {return write_depth_;} void setWriteDepth(bool yes) {write_depth_ = 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; //QVector d_vertices, d_normals, d_uvs; 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; protected: }; 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