Model.hx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. package hide.view;
  2. class Model extends FileView {
  3. var tools : hide.comp.Toolbar;
  4. var obj : h3d.scene.Object;
  5. var sceneEditor : hide.comp.SceneEditor;
  6. var tree : hide.comp.SceneTree;
  7. var tabs : hide.comp.Tabs;
  8. var overlay : Element;
  9. var eventList : Element;
  10. var plight : hrt.prefab.Prefab;
  11. var light : h3d.scene.Object;
  12. var lightDirection : h3d.Vector;
  13. var aspeed : hide.comp.Range;
  14. var aloop : { function toggle( v : Bool ) : Void; var element : Element; }
  15. var apause : { function toggle( v : Bool ) : Void; var element : Element; };
  16. var aretarget : { var element : Element; };
  17. var timeline : h2d.Graphics;
  18. var timecursor : h2d.Bitmap;
  19. var frameIndex : h2d.Text;
  20. var currentAnimation : { file : String, name : String };
  21. var cameraMove : Void -> Void;
  22. var scene(get,never) : hide.comp.Scene;
  23. var rootPath : String;
  24. var root : hrt.prefab.Prefab;
  25. var selectedAxes : h3d.scene.Object;
  26. override function save() {
  27. if(!modified) return;
  28. // Save current Anim data
  29. if( currentAnimation != null ) {
  30. var hideData = loadProps();
  31. var events : Array<{ frame : Int, data : String }> = [];
  32. for(i in 0 ... obj.currentAnimation.events.length){
  33. if( obj.currentAnimation.events[i] == null) continue;
  34. for( e in obj.currentAnimation.events[i])
  35. events.push({frame:i, data:e});
  36. }
  37. hideData.animations.set(currentAnimation.file.split("/").pop(), {events : events} );
  38. var bytes = new haxe.io.BytesOutput();
  39. bytes.writeString(haxe.Json.stringify(hideData, "\t"));
  40. hxd.File.saveBytes(getPropsPath(), bytes.getBytes());
  41. }
  42. super.save();
  43. }
  44. override function onFileChanged( wasDeleted : Bool, rebuildView = true ) {
  45. if (wasDeleted ) {
  46. super.onFileChanged(wasDeleted);
  47. } else if (element.find(".heaps-scene").length == 0) {
  48. super.onFileChanged(wasDeleted);
  49. } else {
  50. super.onFileChanged(wasDeleted, false);
  51. onRefresh();
  52. }
  53. }
  54. function loadProps() {
  55. var propsPath = getPropsPath();
  56. var hideData : h3d.prim.ModelCache.HideProps;
  57. if( sys.FileSystem.exists(propsPath) )
  58. hideData = haxe.Json.parse(sys.io.File.getContent(propsPath));
  59. else
  60. hideData = { animations : {} };
  61. return hideData;
  62. }
  63. function getPropsPath() {
  64. var path = config.get("hmd.savePropsByAnimation") ? currentAnimation.file : getPath();
  65. var parts = path.split(".");
  66. parts.pop();
  67. parts.push("props");
  68. return ide.getPath(parts.join("."));
  69. }
  70. override function onDisplay() {
  71. element.html('
  72. <div class="flex vertical">
  73. <div class="toolbar"></div>
  74. <div class="flex-elt">
  75. <div class="heaps-scene">
  76. <div class="hide-scroll hide-scene-layer">
  77. <div class="tree"></div>
  78. </div>
  79. </div>
  80. <div class="tabs">
  81. <div class="tab expand" name="Model" icon="sitemap">
  82. <div class="hide-block">
  83. <table>
  84. <tr>
  85. <td><input type="button" style="width:145px" value="Export"/>
  86. <td><input type="button" style="width:145px" value="Import"/>
  87. </tr>
  88. </table>
  89. <div class="hide-scene-tree hide-list">
  90. </div>
  91. </div>
  92. <div class="props hide-scroll">
  93. </div>
  94. </div>
  95. <div class="tab expand" name="Animation" icon="cog">
  96. <div class="event-editor"> </div>
  97. </div>
  98. </div>
  99. </div>
  100. </div>
  101. ');
  102. tools = new hide.comp.Toolbar(null,element.find(".toolbar"));
  103. overlay = element.find(".hide-scene-layer .tree");
  104. tabs = new hide.comp.Tabs(null,element.find(".tabs"));
  105. eventList = element.find(".event-editor");
  106. if( rootPath == null )
  107. rootPath = config.getLocal("scene.renderProps");
  108. if( rootPath != null )
  109. root = ide.loadPrefab(rootPath, hrt.prefab.Library);
  110. if( root == null ) {
  111. var def = new hrt.prefab.Library();
  112. new hrt.prefab.RenderProps(def).name = "renderer";
  113. var l = new hrt.prefab.Light(def);
  114. l.name = "sunLight";
  115. l.kind = Directional;
  116. l.power = 1.5;
  117. var q = new h3d.Quat();
  118. q.initDirection(new h3d.Vector(-0.28,0.83,-0.47));
  119. var a = q.toEuler();
  120. l.rotationX = Math.round(a.x * 180 / Math.PI);
  121. l.rotationY = Math.round(a.y * 180 / Math.PI);
  122. l.rotationZ = Math.round(a.z * 180 / Math.PI);
  123. l.shadows.mode = Dynamic;
  124. l.shadows.size = 1024;
  125. root = def;
  126. }
  127. sceneEditor = new hide.comp.SceneEditor(this, root);
  128. sceneEditor.editorDisplay = false;
  129. sceneEditor.onRefresh = onRefresh;
  130. sceneEditor.onUpdate = update;
  131. sceneEditor.view.keys = new hide.ui.Keys(null); // Remove SceneEditor Shortcuts
  132. sceneEditor.view.keys.register("save", function() {
  133. save();
  134. skipNextChange = true;
  135. modified = false;
  136. });
  137. element.find(".hide-scene-tree").first().append(sceneEditor.tree.element);
  138. element.find(".props").first().append(sceneEditor.properties.element);
  139. element.find(".heaps-scene").first().append(sceneEditor.scene.element);
  140. sceneEditor.tree.element.addClass("small");
  141. element.find("input[value=Export]").click(function(_) {
  142. ide.chooseFileSave("renderer.prefab", function(sel) if( sel != null ) ide.savePrefab(sel, root));
  143. });
  144. element.find("input[value=Import]").click(function(_) {
  145. ide.chooseFile(["prefab"], function(f) {
  146. if( ide.loadPrefab(f, hrt.prefab.RenderProps) == null ) {
  147. ide.error("This prefab does not have renderer properties");
  148. return;
  149. }
  150. rootPath = f;
  151. rebuild();
  152. });
  153. });
  154. }
  155. inline function get_scene() return sceneEditor.scene;
  156. function selectMaterial( m : h3d.mat.Material ) {
  157. var properties = sceneEditor.properties;
  158. properties.clear();
  159. properties.add(new Element('
  160. <div class="group" name="Textures">
  161. <dl>
  162. <dt>Base</dt><dd><input type="texture" field="texture"/></dd>
  163. <dt>Spec</dt><dd><input type="texture" field="specularTexture"/></dd>
  164. <dt>Normal</dt><dd><input type="texture" field="normalMap"/></dd>
  165. </dl>
  166. </div>
  167. <br/>
  168. '),m);
  169. var e = properties.add(new Element('
  170. <div class="group" name="Material ${m.name}">
  171. </div>
  172. <dl>
  173. <dt></dt><dd><input type="button" value="Reset Defaults" class="reset"/></dd>
  174. <dt></dt><dd><input type="button" value="Save" class="save"/></dd>
  175. </dl>
  176. <br/>
  177. '));
  178. properties.addMaterial(m, e.find(".group > .content"));
  179. e.find(".reset").click(function(_) {
  180. var old = m.props;
  181. m.props = m.getDefaultModelProps();
  182. selectMaterial(m);
  183. undo.change(Field(m, "props", old), selectMaterial.bind(m));
  184. });
  185. e.find(".save").click(function(_) {
  186. h3d.mat.MaterialSetup.current.saveMaterialProps(m);
  187. });
  188. }
  189. function selectObject( obj : h3d.scene.Object ) {
  190. selectedAxes.follow = obj;
  191. var properties = sceneEditor.properties;
  192. properties.clear();
  193. var objectCount = 1 + obj.getObjectsCount();
  194. var meshes = obj.getMeshes();
  195. var vertexCount = 0, triangleCount = 0, materialDraws = 0, materialCount = 0, bonesCount = 0;
  196. var uniqueMats = new Map();
  197. for( m in obj.getMaterials() ) {
  198. if( uniqueMats.exists(m.name) ) continue;
  199. uniqueMats.set(m.name, true);
  200. materialCount++;
  201. }
  202. for( m in meshes ) {
  203. var p = m.primitive;
  204. triangleCount += p.triCount();
  205. vertexCount += p.vertexCount();
  206. var multi = Std.downcast(m, h3d.scene.MultiMaterial);
  207. var skin = Std.downcast(m, h3d.scene.Skin);
  208. if( skin != null )
  209. bonesCount += skin.getSkinData().allJoints.length;
  210. var count = if( skin != null && skin.getSkinData().splitJoints != null )
  211. skin.getSkinData().splitJoints.length;
  212. else if( multi != null )
  213. multi.materials.length
  214. else
  215. 1;
  216. materialDraws += count;
  217. }
  218. var e = properties.add(new Element('
  219. <div class="group" name="Properties">
  220. <dl>
  221. <dt>X</dt><dd><input field="x"/></dd>
  222. <dt>Y</dt><dd><input field="y"/></dd>
  223. <dt>Z</dt><dd><input field="z"/></dd>
  224. <dt>Attach</dt><dd><select class="follow"><option value="">--- None ---</option></select></dd>
  225. </dl>
  226. </div>
  227. <div class="group" name="Info">
  228. <dl>
  229. <dt>Objects</dt><dd>$objectCount</dd>
  230. <dt>Meshes</dt><dd>${meshes.length}</dd>
  231. <dt>Materials</dt><dd>$materialCount</dd>
  232. <dt>Draws</dt><dd>$materialDraws</dd>
  233. <dt>Bones</dt><dd>$bonesCount</dd>
  234. <dt>Vertexes</dt><dd>$vertexCount</dd>
  235. <dt>Triangles</dt><dd>$triangleCount</dd>
  236. </dl>
  237. </div>
  238. <br/>
  239. '),obj);
  240. var select = e.find(".follow");
  241. for( path in getNamedObjects(obj) ) {
  242. var parts = path.split(".");
  243. var opt = new Element("<option>").attr("value", path).html([for( p in 1...parts.length ) "&nbsp; "].join("") + parts.pop());
  244. select.append(opt);
  245. }
  246. select.change(function(_) {
  247. var name = select.val().split(".").pop();
  248. obj.follow = this.obj.getObjectByName(name);
  249. });
  250. }
  251. function getNamedObjects( ?exclude : h3d.scene.Object ) {
  252. var out = [];
  253. function getJoint(path:Array<String>,j:h3d.anim.Skin.Joint) {
  254. path.push(j.name);
  255. out.push(path.join("."));
  256. for( j in j.subs )
  257. getJoint(path, j);
  258. path.pop();
  259. }
  260. function getRec(path:Array<String>,o:h3d.scene.Object) {
  261. if( o == exclude || o.name == null ) return;
  262. path.push(o.name);
  263. out.push(path.join("."));
  264. for( c in o )
  265. getRec(path, c);
  266. var sk = Std.downcast(o, h3d.scene.Skin);
  267. if( sk != null ) {
  268. var j = sk.getSkinData();
  269. for( j in j.rootJoints )
  270. getJoint(path, j);
  271. }
  272. path.pop();
  273. }
  274. if( obj.name == null )
  275. for( o in obj )
  276. getRec([], o);
  277. else
  278. getRec([], obj);
  279. return out;
  280. }
  281. function makeAxes() {
  282. var g = new h3d.scene.Graphics(scene.s3d);
  283. g.lineStyle(1,0xFF0000);
  284. g.lineTo(1,0,0);
  285. g.lineStyle(1,0x00FF00);
  286. g.moveTo(0,0,0);
  287. g.lineTo(0,1,0);
  288. g.lineStyle(1,0x0000FF);
  289. g.moveTo(0,0,0);
  290. g.lineTo(0,0,1);
  291. g.lineStyle();
  292. for(m in g.getMaterials()) {
  293. m.mainPass.setPassName("overlay");
  294. m.mainPass.depth(false, Always);
  295. }
  296. return g;
  297. }
  298. function onRefresh() {
  299. var r = root.get(hrt.prefab.RenderProps);
  300. if( r != null ) r.applyProps(scene.s3d.renderer);
  301. plight = root.getAll(hrt.prefab.Light)[0];
  302. if( plight != null ) {
  303. this.light = sceneEditor.context.shared.contexts.get(plight).local3d;
  304. lightDirection = this.light.getLocalDirection();
  305. }
  306. undo.onChange = function() {};
  307. if (obj != null)
  308. obj.remove();
  309. obj = scene.loadModel(state.path, true, true);
  310. new h3d.scene.Object(scene.s3d).addChild(obj);
  311. var autoHide : Array<String> = config.get("scene.autoHide");
  312. function hidePropsRec( obj : h3d.scene.Object ) {
  313. for(n in autoHide)
  314. if(obj.name != null && obj.name.indexOf(n) == 0)
  315. obj.visible = false;
  316. for( o in obj )
  317. hidePropsRec(o);
  318. }
  319. hidePropsRec(obj);
  320. if( tree != null ) tree.remove();
  321. tree = new hide.comp.SceneTree(obj, overlay, obj.name != null);
  322. tree.onSelectMaterial = selectMaterial;
  323. tree.onSelectObject = selectObject;
  324. this.saveDisplayKey = "Model:" + state.path;
  325. tree.saveDisplayKey = this.saveDisplayKey;
  326. tools.element.empty();
  327. var anims = scene.listAnims(getPath());
  328. if( anims.length > 0 ) {
  329. var sel = tools.addSelect("play-circle");
  330. var content = [for( a in anims ) {
  331. var label = scene.animationName(a);
  332. { label : label, value : a }
  333. }];
  334. content.unshift({ label : "-- no anim --", value : null });
  335. sel.setContent(content);
  336. sel.onSelect = setAnimation;
  337. }
  338. tools.saveDisplayKey = "ModelTools";
  339. tools.addButton("video-camera", "Reset Camera", function() {
  340. sceneEditor.resetCamera();
  341. });
  342. var axes = makeAxes();
  343. axes.visible = false;
  344. selectedAxes = makeAxes();
  345. selectedAxes.visible = false;
  346. tools.addToggle("location-arrow", "Toggle Axis", function(v) {
  347. axes.visible = v;
  348. selectedAxes.visible = v;
  349. });
  350. tools.addColor("Background color", function(v) {
  351. scene.engine.backgroundColor = v;
  352. }, scene.engine.backgroundColor);
  353. aloop = tools.addToggle("refresh", "Loop animation", function(v) {
  354. if( obj.currentAnimation != null ) {
  355. obj.currentAnimation.loop = v;
  356. obj.currentAnimation.onAnimEnd = function() {
  357. if( !v ) haxe.Timer.delay(function() obj.currentAnimation.setFrame(0), 500);
  358. }
  359. }
  360. });
  361. apause = tools.addToggle("pause", "Pause animation", function(v) {
  362. if( obj.currentAnimation != null ) obj.currentAnimation.pause = v;
  363. });
  364. aretarget = tools.addToggle("share-square-o", "Retarget Animation", function(b) {
  365. setRetargetAnim(b);
  366. });
  367. aspeed = tools.addRange("Animation speed", function(v) {
  368. if( obj.currentAnimation != null ) obj.currentAnimation.speed = v;
  369. }, 1, 0, 2);
  370. initConsole();
  371. sceneEditor.onResize = buildTimeline;
  372. setAnimation(null);
  373. }
  374. function setRetargetAnim(b:Bool) {
  375. for( m in obj.getMeshes() ) {
  376. var sk = Std.downcast(m, h3d.scene.Skin);
  377. if( sk == null ) continue;
  378. for( j in sk.getSkinData().allJoints ) {
  379. if( j.parent == null ) continue; // skip root join (might contain feet translation)
  380. j.retargetAnim = b;
  381. }
  382. }
  383. }
  384. function initConsole() {
  385. var c = new h2d.Console(hxd.res.DefaultFont.get(), scene.s2d);
  386. c.addCommand("rotate",[{ name : "speed", t : AFloat }], function(r) {
  387. cameraMove = function() {
  388. var cam = scene.s3d.camera;
  389. var dir = cam.pos.sub(cam.target);
  390. dir.z = 0;
  391. var angle = Math.atan2(dir.y, dir.x);
  392. angle += r * hxd.Timer.tmod * 0.01;
  393. var ray = dir.length();
  394. cam.pos.set(
  395. Math.cos(angle) * ray + cam.target.x,
  396. Math.sin(angle) * ray + cam.target.y,
  397. cam.pos.z);
  398. sceneEditor.cameraController.loadFromCamera();
  399. };
  400. });
  401. c.addCommand("stop", [], function() {
  402. cameraMove = null;
  403. });
  404. }
  405. override function buildTabMenu() {
  406. var menu = super.buildTabMenu();
  407. var arr : Array<hide.comp.ContextMenu.ContextMenuItem> = [
  408. { label : null, isSeparator : true },
  409. { label : "Export", click : function() {
  410. ide.chooseFileSave(this.getPath().substr(0,-4)+"_dump.txt", function(file) {
  411. var lib = @:privateAccess scene.loadHMD(this.getPath(),false);
  412. var hmd = lib.header;
  413. hmd.data = lib.getData();
  414. sys.io.File.saveContent(ide.getPath(file), new hxd.fmt.hmd.Dump().dump(hmd));
  415. });
  416. } },
  417. { label : "Export Animation", enabled : currentAnimation != null, click : function() {
  418. ide.chooseFileSave(this.getPath().substr(0,-4)+"_"+currentAnimation.name+"_dump.txt", function(file) {
  419. var lib = @:privateAccess scene.loadHMD(ide.getPath(currentAnimation.file),true);
  420. var hmd = lib.header;
  421. hmd.data = lib.getData();
  422. sys.io.File.saveContent(ide.getPath(file), new hxd.fmt.hmd.Dump().dump(hmd));
  423. });
  424. } },
  425. ];
  426. return menu.concat(arr);
  427. }
  428. function setAnimation( file : String ) {
  429. scene.setCurrent();
  430. if( timeline != null ) {
  431. timeline.remove();
  432. timeline = null;
  433. }
  434. apause.toggle(false);
  435. aloop.toggle(true);
  436. aspeed.value = 1;
  437. aloop.element.toggle(file != null);
  438. aspeed.element.toggle(file != null);
  439. apause.element.toggle(file != null);
  440. aretarget.element.toggle(file != null);
  441. if( file == null ) {
  442. obj.stopAnimation();
  443. currentAnimation = null;
  444. return;
  445. }
  446. var anim = scene.loadAnimation(file);
  447. currentAnimation = { file : file, name : scene.animationName(file) };
  448. var hideData = loadProps();
  449. var animData = hideData.animations.get(currentAnimation.file.split("/").pop());
  450. if( animData != null && animData.events != null )
  451. anim.setEvents(animData.events);
  452. obj.playAnimation(anim);
  453. buildTimeline();
  454. buildEventPanel();
  455. modified = false;
  456. }
  457. function buildEventPanel(){
  458. eventList.empty();
  459. var events = @:privateAccess obj.currentAnimation.events;
  460. var fbxEventList = new Element('<div></div>');
  461. fbxEventList.append(new Element('<div class="title"><label>Events</label></div>'));
  462. function addEvent( n : String, f : Float, root : Element ){
  463. var e = new Element('<div class="event"><span class="label">"$n"</span><span class="label">$f</span></div>');
  464. root.append(e);
  465. }
  466. if(events != null) {
  467. for( i in 0...events.length ) {
  468. var el = events[i];
  469. if( el == null || el.length == 0 ) continue;
  470. for( e in el )
  471. addEvent(e, i, fbxEventList);
  472. }
  473. }
  474. eventList.append(fbxEventList);
  475. }
  476. function buildTimeline() {
  477. scene.setCurrent();
  478. if( timeline != null ) {
  479. timeline.remove();
  480. timeline = null;
  481. }
  482. if( obj.currentAnimation == null )
  483. return;
  484. var H = 15;
  485. var W = scene.s2d.width;
  486. timeline = new h2d.Graphics(scene.s2d);
  487. timeline.y = scene.s2d.height - H;
  488. timeline.beginFill(0x101010, 0.8);
  489. timeline.drawRect(0, 0, W, H);
  490. if( W / obj.currentAnimation.frameCount > 3 ) {
  491. timeline.beginFill(0x333333);
  492. for( i in 0...obj.currentAnimation.frameCount+1 ) {
  493. var p = Std.int(i * W / obj.currentAnimation.frameCount);
  494. if( p == W ) p--;
  495. timeline.drawRect(p, 0, 1, H>>1);
  496. }
  497. }
  498. var int = new h2d.Interactive(W, H, timeline);
  499. int.enableRightButton = true;
  500. timecursor = new h2d.Bitmap(h2d.Tile.fromColor(0x808080, 8, H), timeline);
  501. timecursor.x = -100;
  502. int.onPush = function(e) {
  503. if( hxd.Key.isDown( hxd.Key.MOUSE_LEFT) ){
  504. var prevPause = obj.currentAnimation.pause;
  505. obj.currentAnimation.pause = true;
  506. obj.currentAnimation.setFrame( (e.relX / W) * obj.currentAnimation.frameCount );
  507. int.startCapture(function(e) {
  508. switch(e.kind ) {
  509. case ERelease:
  510. obj.currentAnimation.pause = prevPause;
  511. int.stopCapture();
  512. case EMove:
  513. obj.currentAnimation.setFrame( (e.relX / W) * obj.currentAnimation.frameCount );
  514. default:
  515. }
  516. });
  517. }
  518. else if( hxd.Key.isDown( hxd.Key.MOUSE_RIGHT) ){
  519. var deleteEvent = function(s:String, f:Int){
  520. obj.currentAnimation.events[f].remove(s);
  521. if(obj.currentAnimation.events[f].length == 0)
  522. obj.currentAnimation.events[f] = null;
  523. buildTimeline();
  524. buildEventPanel();
  525. modified = true;
  526. }
  527. var addEvent = function(s:String, f:Int){
  528. obj.currentAnimation.addEvent(f, s);
  529. buildTimeline();
  530. buildEventPanel();
  531. modified = true;
  532. }
  533. var frame = Math.round((e.relX / W) * obj.currentAnimation.frameCount);
  534. var menuItems : Array<hide.comp.ContextMenu.ContextMenuItem> = [
  535. { label : "New", click: function(){ addEvent("NewEvent", frame); }},
  536. ];
  537. if(obj.currentAnimation.events != null && obj.currentAnimation.events[frame] != null){
  538. for(e in obj.currentAnimation.events[frame])
  539. menuItems.push({ label : "Delete " + e, click: function(){ deleteEvent(e, frame); }});
  540. }
  541. new hide.comp.ContextMenu(menuItems);
  542. }
  543. }
  544. frameIndex = new h2d.Text(hxd.res.DefaultFont.get(), timecursor);
  545. frameIndex.y = -30.0;
  546. frameIndex.textAlign = Center;
  547. frameIndex.text = "0";
  548. frameIndex.alpha = 0.5;
  549. var events = @:privateAccess obj.currentAnimation.events;
  550. if( events != null ) {
  551. for( i in 0...events.length ) {
  552. var el = events[i];
  553. if( el == null || el.length == 0 ) continue;
  554. var px = Std.int((i / obj.currentAnimation.frameCount) * W);
  555. timeline.beginFill(0xC0C0C0);
  556. timeline.drawRect(px, 0, 1, H);
  557. var py = -20;
  558. for(j in 0 ... el.length ) {
  559. var event = events[i][j];
  560. var tf = new h2d.TextInput(hxd.res.DefaultFont.get(), timeline);
  561. tf.backgroundColor = 0xFF0000;
  562. tf.onFocusLost = function(e){
  563. events[i][j] = tf.text;
  564. buildTimeline();
  565. buildEventPanel();
  566. modified = true;
  567. }
  568. tf.text = event;
  569. tf.x = px - Std.int(tf.textWidth * 0.5);
  570. tf.y = py;
  571. tf.alpha = 0.5;
  572. py -= 15;
  573. var dragIcon = new h2d.Bitmap(null, timeline);
  574. dragIcon.scaleX = 5.0;
  575. dragIcon.scaleY = 2.0;
  576. dragIcon.color.set(0.34, 0.43, 0, 1);
  577. dragIcon.x = px - (dragIcon.scaleX * 0.5 * 5);
  578. dragIcon.y = py;
  579. py -= Std.int(dragIcon.scaleY * 5 * 2);
  580. var dragInter = new h2d.Interactive(5, 5, dragIcon, null );
  581. dragInter.x = 0;
  582. dragInter.y = 0;
  583. var curFrame = i;
  584. var curPos = (curFrame / obj.currentAnimation.frameCount) * W;
  585. dragInter.onPush = function(e) {
  586. if( hxd.Key.isDown( hxd.Key.MOUSE_LEFT) ){
  587. var startFrame = curFrame;
  588. dragInter.startCapture(function(e) {
  589. switch( e.kind ) {
  590. case ERelease:
  591. dragInter.stopCapture();
  592. buildTimeline();
  593. buildEventPanel();
  594. if( curFrame != startFrame )
  595. modified = true;
  596. case EMove:
  597. var newFrame = Math.round(( (curPos + (e.relX - 2.5) * dragIcon.scaleX ) / W ) * obj.currentAnimation.frameCount);
  598. if( newFrame >= 0 && newFrame <= obj.currentAnimation.frameCount ) {
  599. events[curFrame].remove(event);
  600. if(events[newFrame] == null)
  601. events[newFrame] = [];
  602. events[newFrame].insert(0, event);
  603. curFrame = newFrame;
  604. buildTimeline();
  605. buildEventPanel();
  606. @:privateAccess dragInter.scene = scene.s2d;
  607. }
  608. default:
  609. }
  610. });
  611. }
  612. };
  613. }
  614. }
  615. }
  616. }
  617. function update(dt:Float) {
  618. var cam = scene.s3d.camera;
  619. saveDisplayState("Camera", { x : cam.pos.x, y : cam.pos.y, z : cam.pos.z, tx : cam.target.x, ty : cam.target.y, tz : cam.target.z });
  620. if( light != null ) {
  621. if( sceneEditor.isSelected(plight) )
  622. lightDirection = light.getLocalDirection();
  623. else {
  624. var angle = Math.atan2(cam.target.y - cam.pos.y, cam.target.x - cam.pos.x);
  625. light.setDirection(new h3d.Vector(
  626. Math.cos(angle) * lightDirection.x - Math.sin(angle) * lightDirection.y,
  627. Math.sin(angle) * lightDirection.x + Math.cos(angle) * lightDirection.y,
  628. lightDirection.z
  629. ));
  630. }
  631. }
  632. if( timeline != null ) {
  633. timecursor.x = Std.int((obj.currentAnimation.frame / obj.currentAnimation.frameCount) * (scene.s2d.width - timecursor.tile.width));
  634. frameIndex.text = untyped obj.currentAnimation.frame.toFixed(2);
  635. }
  636. if( cameraMove != null )
  637. cameraMove();
  638. }
  639. static var _ = FileTree.registerExtension(Model,["hmd","fbx"],{ icon : "cube" });
  640. }