Object3D.hx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. package hrt.prefab;
  2. import hxd.Math;
  3. using Lambda;
  4. class Object3D extends Prefab {
  5. @:s public var x : Float = 0.;
  6. @:s public var y : Float = 0.;
  7. @:s public var z : Float = 0.;
  8. @:s public var scaleX : Float = 1.;
  9. @:s public var scaleY : Float = 1.;
  10. @:s public var scaleZ : Float = 1.;
  11. @:s public var rotationX : Float = 0.;
  12. @:s public var rotationY : Float = 0.;
  13. @:s public var rotationZ : Float = 0.;
  14. @:s public var visible : Bool = true;
  15. public function new(?parent) {
  16. super(parent);
  17. type = "object";
  18. }
  19. public function loadTransform(t) {
  20. x = t.x;
  21. y = t.y;
  22. z = t.z;
  23. scaleX = t.scaleX;
  24. scaleY = t.scaleY;
  25. scaleZ = t.scaleZ;
  26. rotationX = t.rotationX;
  27. rotationY = t.rotationY;
  28. rotationZ = t.rotationZ;
  29. }
  30. public function saveTransform() {
  31. return { x : x, y : y, z : z, scaleX : scaleX, scaleY : scaleY, scaleZ : scaleZ, rotationX : rotationX, rotationY : rotationY, rotationZ : rotationZ };
  32. }
  33. public function localRayIntersection( ctx : Context, ray : h3d.col.Ray ) : Float {
  34. return -1;
  35. }
  36. function createObject(ctx:Context) {
  37. return new h3d.scene.Object(ctx.local3d);
  38. }
  39. override function makeInstance(ctx:Context):Context {
  40. ctx = ctx.clone(this);
  41. ctx.local3d = createObject(ctx);
  42. ctx.local3d.name = name;
  43. updateInstance(ctx);
  44. return ctx;
  45. }
  46. public function setTransform(mat : h3d.Matrix) {
  47. var rot = mat.getEulerAngles();
  48. x = mat.tx;
  49. y = mat.ty;
  50. z = mat.tz;
  51. var s = mat.getScale();
  52. scaleX = s.x;
  53. scaleY = s.y;
  54. scaleZ = s.z;
  55. rotationX = Math.radToDeg(rot.x);
  56. rotationY = Math.radToDeg(rot.y);
  57. rotationZ = Math.radToDeg(rot.z);
  58. }
  59. public function getTransform( ?m: h3d.Matrix ) {
  60. if( m == null ) m = new h3d.Matrix();
  61. m.initScale(scaleX, scaleY, scaleZ);
  62. m.rotate(Math.degToRad(rotationX), Math.degToRad(rotationY), Math.degToRad(rotationZ));
  63. m.translate(x, y, z);
  64. return m;
  65. }
  66. public function getAbsPos() {
  67. var p = parent;
  68. while( p != null ) {
  69. var obj = p.to(Object3D);
  70. if( obj == null ) {
  71. p = p.parent;
  72. continue;
  73. }
  74. var m = getTransform();
  75. var abs = obj.getAbsPos();
  76. m.multiply3x4(m, abs);
  77. return m;
  78. }
  79. return getTransform();
  80. }
  81. public function applyTransform( o : h3d.scene.Object ) {
  82. o.x = x;
  83. o.y = y;
  84. o.z = z;
  85. o.scaleX = scaleX;
  86. o.scaleY = scaleY;
  87. o.scaleZ = scaleZ;
  88. o.setRotation(Math.degToRad(rotationX), Math.degToRad(rotationY), Math.degToRad(rotationZ));
  89. }
  90. override function updateInstance( ctx: Context, ?propName : String ) {
  91. var o = ctx.local3d;
  92. applyTransform(o);
  93. o.visible = visible;
  94. #if editor
  95. addEditorUI(ctx);
  96. #end
  97. }
  98. override function removeInstance(ctx: Context):Bool {
  99. if(ctx.local3d != null)
  100. ctx.local3d.remove();
  101. #if editor
  102. if( ctx.local2d != null ) {
  103. var f = Std.downcast(ctx.local2d, h2d.ObjectFollower);
  104. if( f != null && f.follow == ctx.local3d ) f.remove();
  105. }
  106. #end
  107. return true;
  108. }
  109. #if editor
  110. override function setSelected(ctx:Context, b:Bool):Bool {
  111. var materials = ctx.shared.getMaterials(this);
  112. if( !b ) {
  113. for( m in materials ) {
  114. //m.mainPass.stencil = null;
  115. m.removePass(m.getPass("highlight"));
  116. m.removePass(m.getPass("highlightBack"));
  117. }
  118. return true;
  119. }
  120. var shader = new h3d.shader.FixedColor(0xffffff);
  121. var shader2 = new h3d.shader.FixedColor(0xff8000);
  122. for( m in materials ) {
  123. if( m.name != null && StringTools.startsWith(m.name,"$UI.") )
  124. continue;
  125. var p = m.allocPass("highlight");
  126. p.culling = None;
  127. p.depthWrite = false;
  128. p.depthTest = LessEqual;
  129. p.addShader(shader);
  130. var p = m.allocPass("highlightBack");
  131. p.culling = None;
  132. p.depthWrite = false;
  133. p.depthTest = Always;
  134. p.addShader(shader2);
  135. }
  136. return true;
  137. }
  138. public function addEditorUI( ctx : Context ) {
  139. for( r in ctx.shared.getObjects(this,h3d.scene.Object) )
  140. if( r.name != null && StringTools.startsWith(r.name,"$UI.") )
  141. r.remove();
  142. // add ranges
  143. var shared = Std.downcast(ctx.shared, hide.prefab.ContextShared);
  144. if( shared != null && shared.editorDisplay ) {
  145. var sheet = getCdbType();
  146. if( sheet != null ) {
  147. var ide = hide.Ide.inst;
  148. var ranges = Reflect.field(shared.scene.config.get("sceneeditor.ranges"), sheet);
  149. if( ranges != null ) {
  150. for( key in Reflect.fields(ranges) ) {
  151. var color = Std.parseInt(Reflect.field(ranges,key));
  152. var value : Dynamic = ide.resolveCDBValue(sheet,key, props);
  153. if( value != null ) {
  154. var mesh = new h3d.scene.Mesh(h3d.prim.Cylinder.defaultUnitCylinder(128), ctx.local3d);
  155. mesh.name = "$UI.RANGE";
  156. mesh.ignoreCollide = true;
  157. mesh.ignoreBounds = true;
  158. mesh.material.mainPass.culling = None;
  159. mesh.material.name = "$UI.RANGE";
  160. mesh.setScale(value * 2);
  161. mesh.scaleZ = 0.1;
  162. mesh.material.color.setColor(color|0xFF000000);
  163. mesh.material.mainPass.enableLights = false;
  164. mesh.material.shadows = false;
  165. mesh.material.mainPass.setPassName("overlay");
  166. }
  167. }
  168. }
  169. var huds : Dynamic = shared.scene.config.get("sceneeditor.huds");
  170. var icon = Reflect.field(huds, sheet);
  171. if( icon != null ) {
  172. var t : Dynamic = ide.resolveCDBValue(sheet,icon, props);
  173. if( t != null && (t.file != null || Std.is(t,String)) ) {
  174. var obj = Std.downcast(ctx.local2d, h2d.ObjectFollower);
  175. if( obj == null || obj.follow != ctx.local3d ) {
  176. ctx.local2d = obj = new h2d.ObjectFollower(ctx.local3d, ctx.local2d);
  177. obj.horizontalAlign = Middle;
  178. obj.followVisibility = true;
  179. }
  180. if( t.file != null ) {
  181. var t : cdb.Types.TilePos = t;
  182. var bmp = Std.downcast(obj.getObjectByName("$huds"), h2d.Bitmap);
  183. if( bmp == null ) {
  184. bmp = new h2d.Bitmap(null, obj);
  185. bmp.name = "$huds";
  186. }
  187. bmp.tile = h2d.Tile.fromTexture(ctx.loadTexture(t.file)).sub(
  188. t.x * t.size,
  189. t.y * t.size,
  190. (t.width == null ? 1 : t.width) * t.size,
  191. (t.height == null ? 1 : t.height) * t.size
  192. );
  193. var maxWidth : Dynamic = huds.maxWidth;
  194. if( maxWidth != null && bmp.tile.width > maxWidth )
  195. bmp.width = maxWidth;
  196. } else {
  197. var f = Std.downcast(obj.getObjectByName("$huds_f"), h2d.Flow);
  198. if( f == null ) {
  199. f = new h2d.Flow(obj);
  200. f.name = "$huds_f";
  201. f.padding = 3;
  202. f.paddingTop = 1;
  203. f.backgroundTile = h2d.Tile.fromColor(0,1,1,0.5);
  204. }
  205. var tf = cast(f.getChildAt(1), h2d.Text);
  206. if( tf == null )
  207. tf = new h2d.Text(hxd.res.DefaultFont.get(), f);
  208. tf.text = t;
  209. }
  210. }
  211. }
  212. }
  213. }
  214. }
  215. override function makeInteractive( ctx : Context ) : hxd.SceneEvents.Interactive {
  216. var local3d = ctx.local3d;
  217. if(local3d == null)
  218. return null;
  219. var meshes = ctx.shared.getObjects(this, h3d.scene.Mesh);
  220. var invRootMat = local3d.getAbsPos().clone();
  221. invRootMat.invert();
  222. var bounds = new h3d.col.Bounds();
  223. var localBounds = [];
  224. var totalSeparateBounds = 0.;
  225. var visibleMeshes = [];
  226. var hasSkin = false;
  227. inline function getVolume(b:h3d.col.Bounds) {
  228. var c = b.getSize();
  229. return c.x * c.y * c.z;
  230. }
  231. for(mesh in meshes) {
  232. if(mesh.ignoreCollide)
  233. continue;
  234. // invisible objects are ignored collision wise
  235. var p : h3d.scene.Object = mesh;
  236. while( p != local3d ) {
  237. if( !p.visible ) break;
  238. p = p.parent;
  239. }
  240. if( p != local3d ) continue;
  241. var localMat = mesh.getAbsPos().clone();
  242. localMat.multiply(localMat, invRootMat);
  243. if( mesh.primitive == null ) continue;
  244. visibleMeshes.push(mesh);
  245. if( Std.downcast(mesh, h3d.scene.Skin) != null ) {
  246. hasSkin = true;
  247. continue;
  248. }
  249. var lb = mesh.primitive.getBounds().clone();
  250. lb.transform(localMat);
  251. bounds.add(lb);
  252. totalSeparateBounds += getVolume(lb);
  253. for( b in localBounds ) {
  254. var tmp = new h3d.col.Bounds();
  255. tmp.intersection(lb, b);
  256. totalSeparateBounds -= getVolume(tmp);
  257. }
  258. localBounds.push(lb);
  259. }
  260. if( visibleMeshes.length == 0 )
  261. return null;
  262. var colliders = [for(m in visibleMeshes) {
  263. var c : h3d.col.Collider = try m.getGlobalCollider() catch(e: Dynamic) null;
  264. if(c != null) c;
  265. }];
  266. var meshCollider = colliders.length == 1 ? colliders[0] : new h3d.col.Collider.GroupCollider(colliders);
  267. var collider : h3d.col.Collider = new h3d.col.ObjectCollider(local3d, bounds);
  268. if( hasSkin ) {
  269. collider = meshCollider; // can't trust bounds
  270. meshCollider = null;
  271. } else if( totalSeparateBounds / getVolume(bounds) < 0.5 ) {
  272. collider = new h3d.col.Collider.OptimizedCollider(collider, meshCollider);
  273. meshCollider = null;
  274. }
  275. var int = new h3d.scene.Interactive(collider, local3d);
  276. int.ignoreParentTransform = true;
  277. int.preciseShape = meshCollider;
  278. int.propagateEvents = true;
  279. int.enableRightButton = true;
  280. return int;
  281. }
  282. override function edit( ctx : EditContext ) {
  283. var props = new hide.Element('
  284. <div class="group" name="Position">
  285. <dl>
  286. <dt>X</dt><dd><input type="range" min="-10" max="10" value="0" field="x"/></dd>
  287. <dt>Y</dt><dd><input type="range" min="-10" max="10" value="0" field="y"/></dd>
  288. <dt>Z</dt><dd><input type="range" min="-10" max="10" value="0" field="z"/></dd>
  289. <dt>Scale X</dt><dd><input type="range" min="0" max="5" value="1" field="scaleX"/></dd>
  290. <dt>Scale Y</dt><dd><input type="range" min="0" max="5" value="1" field="scaleY"/></dd>
  291. <dt>Scale Z</dt><dd><input type="range" min="0" max="5" value="1" field="scaleZ"/></dd>
  292. <dt>Rotation X</dt><dd><input type="range" min="-180" max="180" value="0" field="rotationX" /></dd>
  293. <dt>Rotation Y</dt><dd><input type="range" min="-180" max="180" value="0" field="rotationY" /></dd>
  294. <dt>Rotation Z</dt><dd><input type="range" min="-180" max="180" value="0" field="rotationZ" /></dd>
  295. <dt>Visible</dt><dd><input type="checkbox" field="visible"/></dd>
  296. </dl>
  297. </div>
  298. ');
  299. ctx.properties.add(props, this, function(pname) {
  300. ctx.onChange(this, pname);
  301. });
  302. }
  303. override function getHideProps() : HideProps {
  304. // Check children
  305. var cname = Type.getClassName(Type.getClass(this)).split(".").pop();
  306. return {
  307. icon : children == null || children.length > 0 ? "folder-open" : "genderless",
  308. name : cname == "Object3D" ? "Group" : cname,
  309. };
  310. }
  311. #end
  312. override function getDefaultName() {
  313. return type == "object" ? "group" : super.getDefaultName();
  314. }
  315. static var _ = Library.register("object", Object3D);
  316. }