Object.hx 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. package h3d.scene;
  2. class Object {
  3. static inline var ROT2RAD = -0.017453292519943295769236907684886;
  4. var childs : Array<Object>;
  5. public var parent(default, null) : Object;
  6. public var numChildren(get, never) : Int;
  7. public var name : Null<String>;
  8. public var x(default,set) : Float;
  9. public var y(default, set) : Float;
  10. public var z(default, set) : Float;
  11. public var scaleX(default,set) : Float;
  12. public var scaleY(default, set) : Float;
  13. public var scaleZ(default,set) : Float;
  14. public var visible : Bool = true;
  15. /**
  16. Follow a given object or joint as if it was our parent. Ignore defaultTransform when set.
  17. **/
  18. public var follow(default,set) : Object;
  19. /**
  20. This is an additional optional transformation that is performed before other local transformations.
  21. It is used by the animation system.
  22. **/
  23. public var defaultTransform(default, set) : h3d.Matrix;
  24. public var currentAnimation(default, null) : h3d.anim.Animation;
  25. var absPos : h3d.Matrix;
  26. var invPos : h3d.Matrix;
  27. var qRot : h3d.Quat;
  28. var posChanged : Bool;
  29. var lastFrame : Int;
  30. public function new( ?parent : Object ) {
  31. absPos = new h3d.Matrix();
  32. absPos.identity();
  33. x = 0; y = 0; z = 0; scaleX = 1; scaleY = 1; scaleZ = 1;
  34. qRot = new h3d.Quat();
  35. posChanged = false;
  36. childs = [];
  37. if( parent != null )
  38. parent.addChild(this);
  39. }
  40. public function playAnimation( a : h3d.anim.Animation ) {
  41. return currentAnimation = a.createInstance(this);
  42. }
  43. /**
  44. Changes the current animation. This animation should be an instance that was created by playAnimation!
  45. **/
  46. public function switchToAnimation( a : h3d.anim.Animation ) {
  47. return currentAnimation = a;
  48. }
  49. public function stopAnimation() {
  50. currentAnimation = null;
  51. }
  52. public function getObjectsCount() {
  53. var k = 0;
  54. for( c in childs )
  55. k += c.getObjectsCount() + 1;
  56. return k;
  57. }
  58. /**
  59. Transform a point from the local object coordinates to the global ones. The point is modified and returned.
  60. **/
  61. public function localToGlobal( ?pt : h3d.Vector ) {
  62. syncPos();
  63. if( pt == null ) pt = new h3d.Vector();
  64. pt.transform3x4(absPos);
  65. return pt;
  66. }
  67. /**
  68. Transform a point from the global coordinates to the object local ones. The point is modified and returned.
  69. **/
  70. public function globalToLocal( pt : h3d.Vector ) {
  71. syncPos();
  72. pt.transform3x4(getInvPos());
  73. return pt;
  74. }
  75. function getInvPos() {
  76. if( invPos == null ) {
  77. invPos = new h3d.Matrix();
  78. invPos._44 = 0;
  79. }
  80. if( invPos._44 == 0 )
  81. invPos.inverse3x4(absPos);
  82. return invPos;
  83. }
  84. /**
  85. Return the bounds of this object, in absolute position.
  86. **/
  87. public function getBounds( ?b : h3d.col.Bounds, rec = false ) {
  88. if( !rec )
  89. syncPos();
  90. if( b == null )
  91. b = new h3d.col.Bounds();
  92. if( posChanged ) {
  93. for( c in childs )
  94. c.posChanged = true;
  95. posChanged = false;
  96. calcAbsPos();
  97. }
  98. for( c in childs )
  99. c.getBounds(b, true);
  100. return b;
  101. }
  102. public function getObjectByName( name : String ) {
  103. if( this.name == name )
  104. return this;
  105. for( c in childs ) {
  106. var o = c.getObjectByName(name);
  107. if( o != null ) return o;
  108. }
  109. return null;
  110. }
  111. public function clone( ?o : Object ) : Object {
  112. if( o == null ) o = new Object();
  113. o.x = x;
  114. o.y = y;
  115. o.z = z;
  116. o.scaleX = scaleX;
  117. o.scaleY = scaleY;
  118. o.scaleZ = scaleZ;
  119. o.name = name;
  120. o.follow = follow;
  121. if( defaultTransform != null )
  122. o.defaultTransform = defaultTransform.clone();
  123. for( c in childs ) {
  124. var c = c.clone();
  125. c.parent = o;
  126. o.childs.push(c);
  127. }
  128. return o;
  129. }
  130. public function addChild( o : Object ) {
  131. addChildAt(o, childs.length);
  132. }
  133. public function addChildAt( o : Object, pos : Int ) {
  134. if( pos < 0 ) pos = 0;
  135. if( pos > childs.length ) pos = childs.length;
  136. var p = this;
  137. while( p != null ) {
  138. if( p == o ) throw "Recursive addChild";
  139. p = p.parent;
  140. }
  141. if( o.parent != null )
  142. o.parent.removeChild(o);
  143. childs.insert(pos,o);
  144. o.parent = this;
  145. o.lastFrame = -1;
  146. o.posChanged = true;
  147. }
  148. public function removeChild( o : Object ) {
  149. if( childs.remove(o) )
  150. o.parent = null;
  151. }
  152. public inline function isMesh() {
  153. return Std.is(this, Mesh);
  154. }
  155. public function toMesh() : Mesh {
  156. if( isMesh() )
  157. return cast this;
  158. throw (name == null ? "Object" : name) + " is not a Mesh";
  159. }
  160. // shortcut for parent.removeChild
  161. public inline function remove() {
  162. if( this != null && parent != null ) parent.removeChild(this);
  163. }
  164. function draw( ctx : RenderContext ) {
  165. }
  166. function set_follow(v) {
  167. posChanged = true;
  168. return follow = v;
  169. }
  170. function calcAbsPos() {
  171. qRot.saveToMatrix(absPos);
  172. // prepend scale
  173. absPos._11 *= scaleX;
  174. absPos._12 *= scaleX;
  175. absPos._13 *= scaleX;
  176. absPos._21 *= scaleY;
  177. absPos._22 *= scaleY;
  178. absPos._23 *= scaleY;
  179. absPos._31 *= scaleZ;
  180. absPos._32 *= scaleZ;
  181. absPos._33 *= scaleZ;
  182. absPos._41 = x;
  183. absPos._42 = y;
  184. absPos._43 = z;
  185. if( follow != null ) {
  186. follow.syncPos();
  187. absPos.multiply3x4(absPos, follow.absPos);
  188. posChanged = true;
  189. } else {
  190. if( parent != null )
  191. absPos.multiply3x4(absPos, parent.absPos);
  192. }
  193. // animation is applied before every other transform
  194. if( defaultTransform != null )
  195. absPos.multiply3x4(defaultTransform, absPos);
  196. if( invPos != null )
  197. invPos._44 = 0; // mark as invalid
  198. }
  199. function sync( ctx : RenderContext ) {
  200. if( currentAnimation != null ) {
  201. var old = parent;
  202. var dt = ctx.elapsedTime;
  203. while( dt > 0 && currentAnimation != null )
  204. dt = currentAnimation.update(dt);
  205. if( currentAnimation != null )
  206. currentAnimation.sync();
  207. if( parent == null && old != null ) return; // if we were removed by an animation event
  208. }
  209. var changed = posChanged;
  210. if( changed ) {
  211. posChanged = false;
  212. calcAbsPos();
  213. }
  214. lastFrame = ctx.frame;
  215. var p = 0, len = childs.length;
  216. while( p < len ) {
  217. var c = childs[p];
  218. if( c == null )
  219. break;
  220. if( c.lastFrame != ctx.frame ) {
  221. if( changed ) c.posChanged = true;
  222. c.sync(ctx);
  223. }
  224. // if the object was removed, let's restart again.
  225. // our lastFrame ensure that no object will get synched twice
  226. if( childs[p] != c ) {
  227. p = 0;
  228. len = childs.length;
  229. } else
  230. p++;
  231. }
  232. }
  233. function syncPos() {
  234. if( parent != null ) parent.syncPos();
  235. if( posChanged ) {
  236. posChanged = false;
  237. calcAbsPos();
  238. for( c in childs )
  239. c.posChanged = true;
  240. }
  241. }
  242. function emit( ctx : RenderContext ) {
  243. }
  244. function emitRec( ctx : RenderContext ) {
  245. if( !visible ) return;
  246. // fallback in case the object was added during a sync() event and we somehow didn't update it
  247. if( posChanged ) {
  248. // only sync anim, don't update() (prevent any event from occuring during draw())
  249. if( currentAnimation != null ) currentAnimation.sync();
  250. posChanged = false;
  251. calcAbsPos();
  252. for( c in childs )
  253. c.posChanged = true;
  254. }
  255. emit(ctx);
  256. for( c in childs )
  257. c.emitRec(ctx);
  258. }
  259. inline function set_x(v) {
  260. x = v;
  261. posChanged = true;
  262. return v;
  263. }
  264. inline function set_y(v) {
  265. y = v;
  266. posChanged = true;
  267. return v;
  268. }
  269. inline function set_z(v) {
  270. z = v;
  271. posChanged = true;
  272. return v;
  273. }
  274. inline function set_scaleX(v) {
  275. scaleX = v;
  276. posChanged = true;
  277. return v;
  278. }
  279. inline function set_scaleY(v) {
  280. scaleY = v;
  281. posChanged = true;
  282. return v;
  283. }
  284. inline function set_scaleZ(v) {
  285. scaleZ = v;
  286. posChanged = true;
  287. return v;
  288. }
  289. inline function set_defaultTransform(v) {
  290. defaultTransform = v;
  291. posChanged = true;
  292. return v;
  293. }
  294. /*
  295. Move along the current rotation axis
  296. */
  297. public function move( dx : Float, dy : Float, dz : Float ) {
  298. throw "TODO";
  299. posChanged = true;
  300. }
  301. public inline function setPos( x : Float, y : Float, z : Float ) {
  302. this.x = x;
  303. this.y = y;
  304. this.z = z;
  305. posChanged = true;
  306. }
  307. /*
  308. Rotate around the current rotation axis.
  309. */
  310. public function rotate( rx : Float, ry : Float, rz : Float ) {
  311. var qTmp = new h3d.Quat();
  312. qTmp.initRotate(rx, ry, rz);
  313. qRot.multiply(qTmp,qRot);
  314. posChanged = true;
  315. }
  316. public function setRotate( rx : Float, ry : Float, rz : Float ) {
  317. qRot.initRotate(rx, ry, rz);
  318. posChanged = true;
  319. }
  320. public function setRotateAxis( ax : Float, ay : Float, az : Float, angle : Float ) {
  321. qRot.initRotateAxis(ax, ay, az, angle);
  322. posChanged = true;
  323. }
  324. public function getRotation() {
  325. return qRot.toEuler();
  326. }
  327. public function getRotationQuat() {
  328. return qRot;
  329. }
  330. public function setRotationQuat(q) {
  331. qRot = q;
  332. posChanged = true;
  333. }
  334. public inline function scale( v : Float ) {
  335. scaleX *= v;
  336. scaleY *= v;
  337. scaleZ *= v;
  338. posChanged = true;
  339. }
  340. public inline function setScale( v : Float ) {
  341. scaleX = v;
  342. scaleY = v;
  343. scaleZ = v;
  344. posChanged = true;
  345. }
  346. public function toString() {
  347. return Type.getClassName(Type.getClass(this)).split(".").pop() + (name == null ? "" : "(" + name + ")");
  348. }
  349. public inline function getChildAt( n ) {
  350. return childs[n];
  351. }
  352. inline function get_numChildren() {
  353. return childs.length;
  354. }
  355. public inline function iterator() : hxd.impl.ArrayIterator<Object> {
  356. return new hxd.impl.ArrayIterator(childs);
  357. }
  358. public function dispose() {
  359. for( c in childs )
  360. c.dispose();
  361. }
  362. }