| 1 | /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield |
|---|
| 2 | * |
|---|
| 3 | * This library is open source and may be redistributed and/or modified under |
|---|
| 4 | * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or |
|---|
| 5 | * (at your option) any later version. The full license is in LICENSE file |
|---|
| 6 | * included with this distribution, and on the openscenegraph.org website. |
|---|
| 7 | * |
|---|
| 8 | * This library is distributed in the hope that it will be useful, |
|---|
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 11 | * OpenSceneGraph Public License for more details. |
|---|
| 12 | */ |
|---|
| 13 | // Written by Wang Rui, (C) 2010 |
|---|
| 14 | |
|---|
| 15 | #ifndef OSGPARTICLE_DOMAINOPERATOR |
|---|
| 16 | #define OSGPARTICLE_DOMAINOPERATOR |
|---|
| 17 | |
|---|
| 18 | #include <osg/Plane> |
|---|
| 19 | #include <osgParticle/Operator> |
|---|
| 20 | #include <osgParticle/Particle> |
|---|
| 21 | |
|---|
| 22 | namespace osgParticle |
|---|
| 23 | { |
|---|
| 24 | |
|---|
| 25 | |
|---|
| 26 | /** A domain operator which accepts different domain shapes as the parameter. |
|---|
| 27 | It can be derived to implement operators that require particles interacting with domains. |
|---|
| 28 | Refer to David McAllister's Particle System API (http://www.particlesystems.org) |
|---|
| 29 | */ |
|---|
| 30 | class OSGPARTICLE_EXPORT DomainOperator : public Operator |
|---|
| 31 | { |
|---|
| 32 | public: |
|---|
| 33 | struct Domain |
|---|
| 34 | { |
|---|
| 35 | enum Type |
|---|
| 36 | { |
|---|
| 37 | UNDEFINED_DOMAIN = 0, |
|---|
| 38 | POINT_DOMAIN, |
|---|
| 39 | LINE_DOMAIN, |
|---|
| 40 | TRI_DOMAIN, |
|---|
| 41 | RECT_DOMAIN, |
|---|
| 42 | PLANE_DOMAIN, |
|---|
| 43 | SPHERE_DOMAIN, |
|---|
| 44 | BOX_DOMAIN, |
|---|
| 45 | DISK_DOMAIN |
|---|
| 46 | }; |
|---|
| 47 | |
|---|
| 48 | Domain( Type t ) : r1(0.0f), r2(0.0f), type(t) {} |
|---|
| 49 | osg::Plane plane; |
|---|
| 50 | osg::Vec3 v1; |
|---|
| 51 | osg::Vec3 v2; |
|---|
| 52 | osg::Vec3 v3; |
|---|
| 53 | osg::Vec3 s1; |
|---|
| 54 | osg::Vec3 s2; |
|---|
| 55 | float r1; |
|---|
| 56 | float r2; |
|---|
| 57 | Type type; |
|---|
| 58 | }; |
|---|
| 59 | |
|---|
| 60 | DomainOperator() |
|---|
| 61 | : Operator() |
|---|
| 62 | {} |
|---|
| 63 | |
|---|
| 64 | DomainOperator( const DomainOperator& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY ) |
|---|
| 65 | : Operator(copy, copyop), _domains(copy._domains), _backupDomains(copy._backupDomains) |
|---|
| 66 | {} |
|---|
| 67 | |
|---|
| 68 | META_Object( osgParticle, DomainOperator ); |
|---|
| 69 | |
|---|
| 70 | /// Add a point domain |
|---|
| 71 | inline void addPointDomain( const osg::Vec3& p ); |
|---|
| 72 | |
|---|
| 73 | /// Add a line segment domain |
|---|
| 74 | inline void addLineSegmentDomain( const osg::Vec3& v1, const osg::Vec3& v2 ); |
|---|
| 75 | |
|---|
| 76 | /// Add a triangle domain |
|---|
| 77 | inline void addTriangleDomain( const osg::Vec3& v1, const osg::Vec3& v2, const osg::Vec3& v3 ); |
|---|
| 78 | |
|---|
| 79 | /// Add a rectangle domain |
|---|
| 80 | inline void addRectangleDomain( const osg::Vec3& corner, const osg::Vec3& w, const osg::Vec3& h ); |
|---|
| 81 | |
|---|
| 82 | /// Add a plane domain |
|---|
| 83 | inline void addPlaneDomain( const osg::Plane& plane ); |
|---|
| 84 | |
|---|
| 85 | /// Add a sphere domain |
|---|
| 86 | inline void addSphereDomain( const osg::Vec3& c, float r ); |
|---|
| 87 | |
|---|
| 88 | /// Add a box domain |
|---|
| 89 | inline void addBoxDomain( const osg::Vec3& min, const osg::Vec3& max ); |
|---|
| 90 | |
|---|
| 91 | /// Add a disk domain |
|---|
| 92 | inline void addDiskDomain( const osg::Vec3& c, const osg::Vec3& n, float r1, float r2=0.0f ); |
|---|
| 93 | |
|---|
| 94 | /// Add a domain object directly, used by the .osg wrappers and serializers. |
|---|
| 95 | void addDomain( const Domain& domain ) { _domains.push_back(domain); } |
|---|
| 96 | |
|---|
| 97 | /// Get a domain object directly, used by the .osg wrappers and serializers. |
|---|
| 98 | const Domain& getDomain( unsigned int i ) const { return _domains[i]; } |
|---|
| 99 | |
|---|
| 100 | /// Remove a domain at specific index |
|---|
| 101 | void removeDomain( unsigned int i ) |
|---|
| 102 | { if (i<_domains.size()) _domains.erase(_domains.begin() + i); } |
|---|
| 103 | |
|---|
| 104 | /// Remove all existing domains |
|---|
| 105 | void removeAllDomains() { _domains.clear(); } |
|---|
| 106 | |
|---|
| 107 | /// Get number of domains |
|---|
| 108 | unsigned int getNumDomains() const { return _domains.size(); } |
|---|
| 109 | |
|---|
| 110 | /// Apply the acceleration to a particle. Do not call this method manually. |
|---|
| 111 | void operate( Particle* P, double dt ); |
|---|
| 112 | |
|---|
| 113 | /// Perform some initializations. Do not call this method manually. |
|---|
| 114 | void beginOperate( Program* prg ); |
|---|
| 115 | |
|---|
| 116 | /// Perform some post-operations. Do not call this method manually. |
|---|
| 117 | void endOperate(); |
|---|
| 118 | |
|---|
| 119 | protected: |
|---|
| 120 | virtual ~DomainOperator() {} |
|---|
| 121 | DomainOperator& operator=( const DomainOperator& ) { return *this; } |
|---|
| 122 | |
|---|
| 123 | virtual void handlePoint( const Domain& domain, Particle* P, double dt ) { ignore("Point"); } |
|---|
| 124 | virtual void handleLineSegment( const Domain& domain, Particle* P, double dt ) { ignore("LineSegment"); } |
|---|
| 125 | virtual void handleTriangle( const Domain& domain, Particle* P, double dt ) { ignore("Triangle"); } |
|---|
| 126 | virtual void handleRectangle( const Domain& domain, Particle* P, double dt ) { ignore("Rectangle"); } |
|---|
| 127 | virtual void handlePlane( const Domain& domain, Particle* P, double dt ) { ignore("Plane"); } |
|---|
| 128 | virtual void handleSphere( const Domain& domain, Particle* P, double dt ) { ignore("Sphere"); } |
|---|
| 129 | virtual void handleBox( const Domain& domain, Particle* P, double dt ) { ignore("Box"); } |
|---|
| 130 | virtual void handleDisk( const Domain& domain, Particle* P, double dt ) { ignore("Disk"); } |
|---|
| 131 | |
|---|
| 132 | inline void computeNewBasis( const osg::Vec3&, const osg::Vec3&, osg::Vec3&, osg::Vec3& ); |
|---|
| 133 | inline void ignore( const std::string& func ); |
|---|
| 134 | |
|---|
| 135 | std::vector<Domain> _domains; |
|---|
| 136 | std::vector<Domain> _backupDomains; |
|---|
| 137 | }; |
|---|
| 138 | |
|---|
| 139 | // INLINE METHODS |
|---|
| 140 | |
|---|
| 141 | inline void DomainOperator::addPointDomain( const osg::Vec3& p ) |
|---|
| 142 | { |
|---|
| 143 | Domain domain( Domain::POINT_DOMAIN ); |
|---|
| 144 | domain.v1 = p; |
|---|
| 145 | _domains.push_back( domain ); |
|---|
| 146 | } |
|---|
| 147 | |
|---|
| 148 | inline void DomainOperator::addLineSegmentDomain( const osg::Vec3& v1, const osg::Vec3& v2 ) |
|---|
| 149 | { |
|---|
| 150 | Domain domain( Domain::LINE_DOMAIN ); |
|---|
| 151 | domain.v1 = v1; |
|---|
| 152 | domain.v2 = v2; |
|---|
| 153 | domain.r1 = (v2 - v1).length(); |
|---|
| 154 | _domains.push_back( domain ); |
|---|
| 155 | } |
|---|
| 156 | |
|---|
| 157 | inline void DomainOperator::addTriangleDomain( const osg::Vec3& v1, const osg::Vec3& v2, const osg::Vec3& v3 ) |
|---|
| 158 | { |
|---|
| 159 | Domain domain( Domain::TRI_DOMAIN ); |
|---|
| 160 | domain.v1 = v1; |
|---|
| 161 | domain.v2 = v2; |
|---|
| 162 | domain.v3 = v3; |
|---|
| 163 | domain.plane.set(v1, v2, v3); |
|---|
| 164 | computeNewBasis( v2-v1, v3-v1, domain.s1, domain.s2 ); |
|---|
| 165 | _domains.push_back( domain ); |
|---|
| 166 | } |
|---|
| 167 | |
|---|
| 168 | inline void DomainOperator::addRectangleDomain( const osg::Vec3& corner, const osg::Vec3& w, const osg::Vec3& h ) |
|---|
| 169 | { |
|---|
| 170 | Domain domain( Domain::RECT_DOMAIN ); |
|---|
| 171 | domain.v1 = corner; |
|---|
| 172 | domain.v2 = w; |
|---|
| 173 | domain.v3 = h; |
|---|
| 174 | domain.plane.set(corner, corner+w, corner+h); |
|---|
| 175 | computeNewBasis( w, h, domain.s1, domain.s2 ); |
|---|
| 176 | _domains.push_back( domain ); |
|---|
| 177 | } |
|---|
| 178 | |
|---|
| 179 | inline void DomainOperator::addPlaneDomain( const osg::Plane& plane ) |
|---|
| 180 | { |
|---|
| 181 | Domain domain( Domain::PLANE_DOMAIN ); |
|---|
| 182 | domain.plane.set(plane); |
|---|
| 183 | _domains.push_back( domain ); |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | inline void DomainOperator::addSphereDomain( const osg::Vec3& c, float r ) |
|---|
| 187 | { |
|---|
| 188 | Domain domain( Domain::SPHERE_DOMAIN ); |
|---|
| 189 | domain.v1 = c; |
|---|
| 190 | domain.r1 = r; |
|---|
| 191 | _domains.push_back( domain ); |
|---|
| 192 | } |
|---|
| 193 | |
|---|
| 194 | inline void DomainOperator::addBoxDomain( const osg::Vec3& min, const osg::Vec3& max ) |
|---|
| 195 | { |
|---|
| 196 | Domain domain( Domain::BOX_DOMAIN ); |
|---|
| 197 | domain.v1 = min; |
|---|
| 198 | domain.v2 = max; |
|---|
| 199 | _domains.push_back( domain ); |
|---|
| 200 | } |
|---|
| 201 | |
|---|
| 202 | inline void DomainOperator::addDiskDomain( const osg::Vec3& c, const osg::Vec3& n, float r1, float r2 ) |
|---|
| 203 | { |
|---|
| 204 | Domain domain( Domain::DISK_DOMAIN ); |
|---|
| 205 | domain.v1 = c; |
|---|
| 206 | domain.v2 = n; |
|---|
| 207 | domain.r1 = r1; |
|---|
| 208 | domain.r2 = r2; |
|---|
| 209 | domain.plane.set(n, c); |
|---|
| 210 | _domains.push_back( domain ); |
|---|
| 211 | } |
|---|
| 212 | |
|---|
| 213 | inline void DomainOperator::computeNewBasis( const osg::Vec3& u, const osg::Vec3& v, osg::Vec3& s1, osg::Vec3& s2 ) |
|---|
| 214 | { |
|---|
| 215 | // Copied from David McAllister's Particle System API (http://www.particlesystems.org), pDomain.h |
|---|
| 216 | osg::Vec3 w = u ^ v; |
|---|
| 217 | float det = w.z()*u.x()*v.y() - w.z()*u.y()*v.x() - u.z()*w.x()*v.y() - |
|---|
| 218 | u.x()*v.z()*w.y() + v.z()*w.x()*u.y() + u.z()*v.x()*w.y(); |
|---|
| 219 | det = 1.0f / det; |
|---|
| 220 | |
|---|
| 221 | s1.set( v.y()*w.z() - v.z()*w.y(), v.z()*w.x() - v.x()*w.z(), v.x()*w.y() - v.y()*w.x() ); |
|---|
| 222 | s1 = s1 * det; |
|---|
| 223 | s2.set( u.y()*w.z() - u.z()*w.y(), u.z()*w.x() - u.x()*w.z(), u.x()*w.y() - u.y()*w.x() ); |
|---|
| 224 | s2 = s2 * (-det); |
|---|
| 225 | } |
|---|
| 226 | |
|---|
| 227 | inline void DomainOperator::ignore( const std::string& func ) |
|---|
| 228 | { |
|---|
| 229 | OSG_NOTICE << className() << ": " << func << " domain not yet implemented. " << std::endl; |
|---|
| 230 | } |
|---|
| 231 | |
|---|
| 232 | |
|---|
| 233 | } |
|---|
| 234 | |
|---|
| 235 | #endif |
|---|