Object3D.hx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. package hrt.prefab;
  2. import hxd.Math;
  3. class Object3D extends Prefab {
  4. public var local3d : h3d.scene.Object = null;
  5. @:s @:range(0,400) public var x : Float = 0.0;
  6. @:s @:range(0,400) public var y : Float = 0.0;
  7. @:s @:range(0,400) public var z : Float = 0.0;
  8. @:s public var scaleX : Float = 1.0;
  9. @:s public var scaleY : Float = 1.0;
  10. @:s public var scaleZ : Float = 1.0;
  11. var scaleArray(get, set) : Array<Float>;
  12. @:s public var rotationX : Float = 0.0;
  13. @:s public var rotationY : Float = 0.0;
  14. @:s public var rotationZ : Float = 0.0;
  15. @:s public var visible : Bool = true;
  16. #if editor
  17. public var editorIcon : h2d.ObjectFollower;
  18. #end
  19. public inline function get_scaleArray() : Array<Float> {
  20. return [scaleX, scaleY, scaleZ];
  21. }
  22. public inline function set_scaleArray(newScale: Array<Float>) : Array<Float> {
  23. scaleX = newScale[0];
  24. scaleY = newScale[1];
  25. scaleZ = newScale[2];
  26. return newScale;
  27. }
  28. public static inline function getLocal3d(prefab: Prefab) : h3d.scene.Object {
  29. var obj3d = Std.downcast(prefab, Object3D);
  30. if (obj3d != null)
  31. return obj3d.local3d;
  32. return null;
  33. }
  34. public function setTransform(mat : h3d.Matrix) {
  35. var rot = mat.getEulerAngles();
  36. x = mat.tx;
  37. y = mat.ty;
  38. z = mat.tz;
  39. var s = mat.getScale();
  40. scaleX = s.x;
  41. scaleY = s.y;
  42. scaleZ = s.z;
  43. rotationX = Math.radToDeg(rot.x);
  44. rotationY = Math.radToDeg(rot.y);
  45. rotationZ = Math.radToDeg(rot.z);
  46. }
  47. override function make( ?sh:hrt.prefab.Prefab.ContextMake) : Prefab {
  48. makeInstance();
  49. var old3d = shared.current3d;
  50. shared.current3d = local3d ?? shared.current3d;
  51. for (c in children)
  52. makeChild(c);
  53. shared.current3d = old3d;
  54. postMakeInstance();
  55. return this;
  56. }
  57. /* Override makeObject instead of this */
  58. override function makeInstance() : Void {
  59. local3d = makeObject(shared.current3d);
  60. if( local3d != null )
  61. local3d.name = name;
  62. updateInstance();
  63. }
  64. function makeObject(parent3d: h3d.scene.Object) : h3d.scene.Object {
  65. return new h3d.scene.Object(parent3d);
  66. }
  67. override function updateInstance(?propName : String ) {
  68. applyTransform();
  69. if (local3d != null) {
  70. local3d.name = name;
  71. local3d.visible = visible;
  72. }
  73. #if editor
  74. this.addEditorUI();
  75. #end
  76. }
  77. public static var _ = Prefab.register("object", Object3D);
  78. public function saveTransform() {
  79. return { x : x, y : y, z : z, scaleX : scaleX, scaleY : scaleY, scaleZ : scaleZ, rotationX : rotationX, rotationY : rotationY, rotationZ : rotationZ };
  80. }
  81. public function applyTransform() {
  82. var o = local3d;
  83. if (o == null) return;
  84. o.x = x;
  85. o.y = y;
  86. o.z = z;
  87. o.scaleX = scaleX;
  88. o.scaleY = scaleY;
  89. o.scaleZ = scaleZ;
  90. o.setRotation(Math.degToRad(rotationX), Math.degToRad(rotationY), Math.degToRad(rotationZ));
  91. }
  92. public function getTransform( ?m: h3d.Matrix ) {
  93. if( m == null ) m = new h3d.Matrix();
  94. m.initScale(scaleX, scaleY, scaleZ);
  95. m.rotate(Math.degToRad(rotationX), Math.degToRad(rotationY), Math.degToRad(rotationZ));
  96. m.translate(x, y, z);
  97. return m;
  98. }
  99. public function localRayIntersection(ray : h3d.col.Ray ) : Float {
  100. return -1;
  101. }
  102. public function loadTransform(t) {
  103. x = t.x;
  104. y = t.y;
  105. z = t.z;
  106. scaleX = t.scaleX;
  107. scaleY = t.scaleY;
  108. scaleZ = t.scaleZ;
  109. rotationX = t.rotationX;
  110. rotationY = t.rotationY;
  111. rotationZ = t.rotationZ;
  112. }
  113. public function getAbsPos( followRefs : Bool = false ) {
  114. inline function getParent( p ) {
  115. var parent = p.parent;
  116. if( parent == null && followRefs )
  117. parent = p.shared.parentPrefab;
  118. return parent;
  119. }
  120. var p = getParent(this);
  121. while( p != null ) {
  122. var obj = p.to(Object3D);
  123. if( obj == null ) {
  124. p = getParent(p);
  125. continue;
  126. }
  127. var m = getTransform();
  128. var abs = obj.getAbsPos(followRefs);
  129. m.multiply3x4(m, abs);
  130. return m;
  131. }
  132. return getTransform();
  133. }
  134. /**
  135. Returns the list of all h3d.scene.Object created by this prefab (but not
  136. the ones created by its children)
  137. **/
  138. public function getObjects<T:h3d.scene.Object>(c: Class<T> ) : Array<T> {
  139. var root = Object3D.getLocal3d(this);
  140. if(root == null) return [];
  141. var childObjs = Prefab.getChildrenRoots(root, this, []);
  142. var ret = [];
  143. function rec(o : h3d.scene.Object) {
  144. var m = Std.downcast(o, c);
  145. if(m != null) {
  146. ret.push(m);
  147. }
  148. for( child in o )
  149. if( childObjs.indexOf(child) < 0 )
  150. rec(child);
  151. }
  152. rec(root);
  153. return ret;
  154. }
  155. public function getDisplayFilters() : Array<String> {
  156. return [];
  157. }
  158. #if editor
  159. override function setSelected(b:Bool):Bool {
  160. if (local3d == null)
  161. return true;
  162. var materials = local3d.getMaterials();
  163. if( !b ) {
  164. for( m in materials ) {
  165. //m.mainPass.stencil = null;
  166. m.removePass(m.getPass("highlight"));
  167. m.removePass(m.getPass("highlightBack"));
  168. }
  169. return true;
  170. }
  171. var shader = new h3d.shader.FixedColor(0xffffff);
  172. var shader2 = new h3d.shader.FixedColor(0xff8000);
  173. for( m in materials ) {
  174. if( m.name != null && StringTools.startsWith(m.name,"$UI.") )
  175. continue;
  176. var p = m.allocPass("highlight");
  177. p.culling = None;
  178. p.depthWrite = false;
  179. p.depthTest = LessEqual;
  180. p.addShader(shader);
  181. var p = m.allocPass("highlightBack");
  182. p.culling = None;
  183. p.depthWrite = false;
  184. p.depthTest = Always;
  185. p.addShader(shader2);
  186. }
  187. return true;
  188. }
  189. public function addEditorUI() {
  190. if (local3d != null) {
  191. var objs = local3d.findAll((o) -> Std.downcast(o, h3d.scene.Object));
  192. for (obj in objs) {
  193. if (obj.name != null && StringTools.startsWith(obj.name,"$UI."))
  194. obj.remove();
  195. }
  196. }
  197. if (!hide.Ide.inst.show3DIconsCategory.get(hrt.impl.EditorTools.IconCategory.Object3D))
  198. return;
  199. // add ranges
  200. var sheet = getCdbType();
  201. if( sheet != null ) {
  202. var ide = hide.Ide.inst;
  203. var ranges = Reflect.field(ide.currentConfig.get("sceneeditor.ranges"), sheet);
  204. if( ranges != null ) {
  205. for( key in Reflect.fields(ranges) ) {
  206. var color = Std.parseInt(Reflect.field(ranges,key));
  207. var value : Dynamic = hide.comp.cdb.DataFiles.resolveCDBValue(sheet,key, props);
  208. if( value != null ) {
  209. var name = "$UI.RANGE" + key;
  210. var mesh = Std.downcast(local3d.getObjectByName(name), h3d.scene.Mesh);
  211. if (mesh == null) {
  212. mesh = new h3d.scene.Mesh(hrt.prefab.l3d.Spray.makePrimCircle(128, 0.99), local3d);
  213. }
  214. mesh.name = name;
  215. mesh.ignoreCollide = true;
  216. mesh.ignoreBounds = true;
  217. mesh.material.mainPass.culling = None;
  218. mesh.material.name = name;
  219. mesh.setScale(value);
  220. mesh.scaleZ = 0.1;
  221. mesh.material.color.setColor(color|0xFF000000);
  222. mesh.material.mainPass.enableLights = false;
  223. mesh.material.shadows = false;
  224. mesh.material.mainPass.setPassName("overlay");
  225. }
  226. }
  227. }
  228. var huds : Dynamic = ide.currentConfig.get("sceneeditor.huds");
  229. var icon = Reflect.field(huds, sheet);
  230. if( icon != null ) {
  231. var t : Dynamic = hide.comp.cdb.DataFiles.resolveCDBValue(sheet,icon, props);
  232. if( t != null && (t.file != null || Std.isOfType(t,String)) ) {
  233. var obj = editorIcon;
  234. if( obj == null || obj.follow != local3d ) {
  235. editorIcon = obj = new h2d.ObjectFollower(local3d, shared.root2d);
  236. obj.horizontalAlign = Middle;
  237. obj.followVisibility = true;
  238. obj.autoRemove = true;
  239. }
  240. if( t.file != null ) {
  241. var t : cdb.Types.TilePos = t;
  242. var bmp = Std.downcast(obj.getObjectByName("$huds"), h2d.Bitmap);
  243. var shouldAddInt = false;
  244. if( bmp == null ) {
  245. shouldAddInt = true;
  246. bmp = new h2d.Bitmap(null, obj);
  247. bmp.name = "$huds";
  248. }
  249. bmp.tile = h2d.Tile.fromTexture(shared.loadTexture(t.file)).sub(
  250. t.x * t.size,
  251. t.y * t.size,
  252. (t.width == null ? 1 : t.width) * t.size,
  253. (t.height == null ? 1 : t.height) * t.size
  254. );
  255. if (shouldAddInt) {
  256. var int = new h2d.Interactive(huds.maxWidth, huds.maxWidth, bmp);
  257. var editorContext = Std.downcast(shared, hide.prefab.ContextShared);
  258. if (editorContext != null)
  259. @:privateAccess editorContext.editor.initInteractive(this, cast int);
  260. int.propagateEvents = false;
  261. int.x = bmp.tile.dx;
  262. int.y = bmp.tile.dy;
  263. }
  264. var maxWidth : Dynamic = huds.maxWidth;
  265. if( maxWidth != null && bmp.tile.width > maxWidth )
  266. bmp.width = maxWidth;
  267. } else {
  268. var f = Std.downcast(obj.getObjectByName("$huds_f"), h2d.Flow);
  269. if( f == null ) {
  270. f = new h2d.Flow(obj);
  271. f.name = "$huds_f";
  272. f.padding = 3;
  273. f.paddingTop = 1;
  274. f.backgroundTile = h2d.Tile.fromColor(0,1,1,0.5);
  275. }
  276. var tf = cast(f.getChildAt(1), h2d.Text);
  277. if( tf == null )
  278. tf = new h2d.Text(hxd.res.DefaultFont.get(), f);
  279. tf.text = t;
  280. }
  281. }
  282. }
  283. }
  284. }
  285. public function removeEditorUI() {
  286. if (local3d != null) {
  287. var objs = local3d.findAll((o) -> Std.downcast(o, h3d.scene.Object));
  288. for (obj in objs) {
  289. if (obj.name != null && StringTools.startsWith(obj.name,"$UI."))
  290. obj.remove();
  291. }
  292. }
  293. if (editorIcon != null)
  294. editorIcon.removeChildren();
  295. }
  296. override function makeInteractive() : hxd.SceneEvents.Interactive {
  297. if(local3d == null)
  298. return null;
  299. var meshes = getObjects(h3d.scene.Mesh);
  300. var ref = Std.downcast(this, Reference);
  301. if (ref != null) {
  302. meshes = [];
  303. function rec(p : Prefab) {
  304. var o = Std.downcast(p, Object3D);
  305. if (!p.locked) {
  306. if (o != null)
  307. meshes = meshes.concat(o.getObjects(h3d.scene.Mesh));
  308. for (c in p.children)
  309. rec(c);
  310. }
  311. }
  312. if ( ref.refInstance != null )
  313. rec(ref.refInstance);
  314. }
  315. var mesh = Std.downcast(local3d, h3d.scene.Mesh);
  316. if (mesh != null ) {
  317. meshes.push(mesh);
  318. }// ctx.shared.getObjects(this, h3d.scene.Mesh);
  319. var invRootMat = local3d.getAbsPos().clone();
  320. invRootMat.invert();
  321. var bounds = new h3d.col.Bounds();
  322. var localBounds = [];
  323. var totalSeparateBounds = 0.;
  324. var visibleMeshes = [];
  325. var hasSkin = false;
  326. inline function getVolume(b:h3d.col.Bounds) {
  327. var c = b.getSize();
  328. return c.x * c.y * c.z;
  329. }
  330. for(mesh in meshes) {
  331. if(mesh.ignoreCollide)
  332. continue;
  333. // invisible objects are ignored collision wise
  334. var p : h3d.scene.Object = mesh;
  335. while( p != null && p != local3d ) {
  336. if( !p.visible ) break;
  337. p = p.parent;
  338. }
  339. if( p != local3d ) continue;
  340. var localMat = mesh.getAbsPos().clone();
  341. localMat.multiply(localMat, invRootMat);
  342. if( mesh.primitive == null ) continue;
  343. visibleMeshes.push(mesh);
  344. if( Std.downcast(mesh, h3d.scene.Skin) != null ) {
  345. hasSkin = true;
  346. continue;
  347. }
  348. var asIcon = Std.downcast(mesh, hrt.impl.EditorTools.EditorIcon);
  349. if (asIcon != null) {
  350. hasSkin = true; // hack
  351. /*var pos = asIcon.getAbsPos();
  352. bounds.addSpherePos(pos.tx, pos.ty, pos.tz, asIcon.billboardScale);*/
  353. continue;
  354. }
  355. var asIcon = Std.downcast(mesh, hrt.impl.EditorTools.EditorIcon);
  356. if (asIcon != null) {
  357. hasSkin = true; // hack
  358. /*var pos = asIcon.getAbsPos();
  359. bounds.addSpherePos(pos.tx, pos.ty, pos.tz, asIcon.billboardScale);*/
  360. continue;
  361. }
  362. var lb = mesh.primitive.getBounds().clone();
  363. lb.transform(localMat);
  364. bounds.add(lb);
  365. totalSeparateBounds += getVolume(lb);
  366. for( b in localBounds ) {
  367. var tmp = new h3d.col.Bounds();
  368. tmp.intersection(lb, b);
  369. totalSeparateBounds -= getVolume(tmp);
  370. }
  371. localBounds.push(lb);
  372. }
  373. if( visibleMeshes.length == 0 )
  374. return null;
  375. var colliders = [for(m in visibleMeshes) {
  376. var c : h3d.col.Collider = try m.getGlobalCollider() catch(e: Dynamic) null;
  377. if(c != null) c;
  378. }];
  379. var meshCollider = colliders.length == 1 ? colliders[0] : new h3d.col.Collider.GroupCollider(colliders);
  380. var collider : h3d.col.Collider = new h3d.col.ObjectCollider(local3d, bounds);
  381. if( hasSkin ) {
  382. collider = meshCollider; // can't trust bounds
  383. meshCollider = null;
  384. } else if( totalSeparateBounds / getVolume(bounds) < 0.5 ) {
  385. collider = new h3d.col.Collider.OptimizedCollider(collider, meshCollider);
  386. meshCollider = null;
  387. }
  388. var int = new h3d.scene.Interactive(collider, local3d);
  389. int.ignoreParentTransform = true;
  390. int.preciseShape = meshCollider;
  391. int.propagateEvents = true;
  392. int.enableRightButton = true;
  393. return int;
  394. }
  395. override function editorRemoveInstanceObjects() : Void {
  396. if (local3d != null)
  397. local3d.remove();
  398. if (editorIcon != null)
  399. editorIcon.remove();
  400. local3d = null;
  401. editorIcon = null;
  402. super.editorRemoveInstanceObjects();
  403. }
  404. override function edit( ctx : hide.prefab.EditContext ) {
  405. var props = new hide.Element('
  406. <div class="group" name="Position">
  407. <dl>
  408. <dt>X</dt><dd><input type="range" min="-10" max="10" value="0" field="x"/></dd>
  409. <dt>Y</dt><dd><input type="range" min="-10" max="10" value="0" field="y"/></dd>
  410. <dt>Z</dt><dd><input type="range" min="-10" max="10" value="0" field="z"/></dd>
  411. <dt>Scale</dt><dd><input type="multi-range" min="0" max="5" value="0" field="scaleArray" data-subfields="X,Y,Z"/></dd>
  412. <dt>Rotation X</dt><dd><input type="range" min="-180" max="180" value="0" field="rotationX" /></dd>
  413. <dt>Rotation Y</dt><dd><input type="range" min="-180" max="180" value="0" field="rotationY" /></dd>
  414. <dt>Rotation Z</dt><dd><input type="range" min="-180" max="180" value="0" field="rotationZ" /></dd>
  415. <dt>Visible</dt><dd><input type="checkbox" field="visible"/></dd>
  416. </dl>
  417. </div>
  418. ');
  419. ctx.properties.add(props, this, function(pname) {
  420. ctx.onChange(this, pname);
  421. });
  422. }
  423. override function getHideProps() : hide.prefab.HideProps {
  424. // Check children
  425. var cname = Type.getClassName(Type.getClass(this)).split(".").pop();
  426. return {
  427. icon : children == null || children.length > 0 ? "folder-open" : "genderless",
  428. name : cname == "Object3D" ? "Group" : cname,
  429. };
  430. }
  431. #end // if editor
  432. }