Dad72 Posted February 8, 2016 Share Posted February 8, 2016 Hello, I am looking to create a timeline, but I do not really know the right ways to do it? Is anybody can help me or give me some line of thought. Thanks Wingnut 1 Quote Link to comment Share on other sites More sharing options...
JCPalmer Posted February 8, 2016 Share Posted February 8, 2016 The drawing part is up to you. I made my own, un-settable, always going forward TimelineControl class. It is implemented using a scene level after render. The purposes are: to pause and resume at a system wide basis. reduce error among the before renders of different meshes, if they each called BABYLON.Now themselves. switch to fixed frame rates to generate marketing animation (mp4). not working & not going to be public, so just a hook. handle tab switching / smooth resuming. I have no need to arbitrary set a time. This is a game platform / real time environment. To go backwards in a automatic, scene level way would require a system which create an audit trail of everything ever changed. My system s not yet public, so here is the source for this file: /// <reference path="./BeforeRenderer.ts"/> module QI { /** * This class is used to provide a way to render at a precise frame rate, as opposed to realtime, * as well as system level play - pause. */ export class TimelineControl{ // ======================================= Mode Control ====================================== private static _afterRenderAssigned: boolean; private static _manualFrameRate : number; private static _isRealtime = true; private static _now = 0; private static _lastRun = 0; private static _frameID = 0; // useful for new in frame detection public static CHANGED_TABS_THRESHOLD = 500; // msec private static _engine : BABYLON.Engine; // only used for MP4 recordings public static MP4Worker : Worker; /** called by POV.BeforeRenderer */ public static initialize(scene : BABYLON.Scene){ if (!TimelineControl._afterRenderAssigned){ scene.registerAfterRender(TimelineControl._manualAdvanceAfterRender); // built-in hooks for CocoonJS if (navigator.isCocoonJS){ Cocoon.App.on("activated" , TimelineControl.resumeSystem ); Cocoon.App.on("suspending", TimelineControl.pauseSystem ); } TimelineControl._engine = scene.getEngine(); TimelineControl._afterRenderAssigned = true; var logMsg = "Queued Interpolation Timeline Control system initialized, version: " + BeforeRenderer.Version; BABYLON.Tools.Log(logMsg); } } public static change(isRealTime : boolean, rateIfManual = 24) : void { TimelineControl._isRealtime = isRealTime; TimelineControl._manualFrameRate = rateIfManual; } private static _manualAdvanceAfterRender() : void { if (!TimelineControl._systemPaused){ // The system might not officially have been paused, rather browser tab switched & now switched back if (BABYLON.Tools.Now - TimelineControl._lastRun > TimelineControl.CHANGED_TABS_THRESHOLD) { TimelineControl.resumeSystem(); }else{ TimelineControl._frameID++; if (TimelineControl._isRealtime){ TimelineControl._now = BABYLON.Tools.Now; } else { TimelineControl._now += 1000 / TimelineControl._manualFrameRate; // add # of millis for exact advance if (TimelineControl.MP4Worker){ var screen = TimelineControl._engine.readPixels(0, 0, TimelineControl._engine.getRenderWidth(), TimelineControl._engine.getRenderHeight() ); // . . . } } } } TimelineControl._lastRun = BABYLON.Tools.Now; } public static sizeFor720 () : void { TimelineControl._sizeForRecording(1280, 720); } public static sizeFor1080() : void { TimelineControl._sizeForRecording(1920, 1080); } private static _sizeForRecording(width : number, height : number){ TimelineControl._engine.setSize(width, height); } // =========================================== Gets ========================================== public static get manualFrameRate() : number { return TimelineControl._manualFrameRate; } public static get isRealtime () : boolean { return TimelineControl._isRealtime; } public static get Now () : number { return TimelineControl._now; } public static get FrameID () : number { return TimelineControl._frameID; } // =================================== SYSTEM play - pause =================================== // pause & resume statics private static _systemResumeTime = 0; private static _systemPaused = false; /** system could be paused at a higher up without notification; just by stop calling beforeRender() */ public static get isSystemPaused() : boolean { return TimelineControl._systemPaused; } public static pauseSystem() : void { TimelineControl._systemPaused = true; } public static resumeSystem() : void { TimelineControl._systemPaused = false; TimelineControl._systemResumeTime = TimelineControl.Now; } public static get SystemResumeTime() : number { return TimelineControl._systemResumeTime; } } } Dad72 1 Quote Link to comment Share on other sites More sharing options...
JCPalmer Posted February 8, 2016 Share Posted February 8, 2016 I updated the source. I realized that the extra code for passive pausing do to switch browsers tabs was in the BeforeRenderer class. That class existed prior to the timeline class. I moved it here. Easier to read this way. Thanks for the thread, or probably would not have realized. Quote Link to comment Share on other sites More sharing options...
Dad72 Posted February 8, 2016 Author Share Posted February 8, 2016 JS thank you. you would not have the version Javascript. I have a bit of a hard time understanding the typescript. Thanks again Quote Link to comment Share on other sites More sharing options...
JCPalmer Posted February 8, 2016 Share Posted February 8, 2016 Not as single file. I fished it out of the file from the eclipse add-in compiler: var QI; (function (QI) { /** * This class is used to provide a way to render at a precise frame rate, as opposed to realtime, * as well as system level play - pause. */ var TimelineControl = (function () { function TimelineControl() { } /** called by POV.BeforeRenderer */ TimelineControl.initialize = function (scene) { if (!TimelineControl._afterRenderAssigned) { scene.registerAfterRender(TimelineControl._manualAdvanceAfterRender); // built-in hooks for CocoonJS if (navigator.isCocoonJS) { Cocoon.App.on("activated", TimelineControl.resumeSystem); Cocoon.App.on("suspending", TimelineControl.pauseSystem); } TimelineControl._engine = scene.getEngine(); TimelineControl._afterRenderAssigned = true; var logMsg = "Queued Interpolation Timeline Control system initialized, version: " + QI.BeforeRenderer.Version; BABYLON.Tools.Log(logMsg); } }; TimelineControl.change = function (isRealTime, rateIfManual) { if (rateIfManual === void 0) { rateIfManual = 24; } TimelineControl._isRealtime = isRealTime; TimelineControl._manualFrameRate = rateIfManual; }; TimelineControl._manualAdvanceAfterRender = function () { if (!TimelineControl._systemPaused) { // The system might not officially have been paused, rather browser tab switched & now switched back if (BABYLON.Tools.Now - TimelineControl._lastRun > TimelineControl.CHANGED_TABS_THRESHOLD) { TimelineControl.resumeSystem(); } else { TimelineControl._frameID++; if (TimelineControl._isRealtime) { TimelineControl._now = BABYLON.Tools.Now; } else { TimelineControl._now += 1000 / TimelineControl._manualFrameRate; // add # of millis for exact advance if (TimelineControl.MP4Worker) { var screen = TimelineControl._engine.readPixels(0, 0, TimelineControl._engine.getRenderWidth(), TimelineControl._engine.getRenderHeight()); } } } } TimelineControl._lastRun = BABYLON.Tools.Now; }; TimelineControl.sizeFor720 = function () { TimelineControl._sizeForRecording(1280, 720); }; TimelineControl.sizeFor1080 = function () { TimelineControl._sizeForRecording(1920, 1080); }; TimelineControl._sizeForRecording = function (width, height) { TimelineControl._engine.setSize(width, height); }; Object.defineProperty(TimelineControl, "manualFrameRate", { // =========================================== Gets ========================================== get: function () { return TimelineControl._manualFrameRate; }, enumerable: true, configurable: true }); Object.defineProperty(TimelineControl, "isRealtime", { get: function () { return TimelineControl._isRealtime; }, enumerable: true, configurable: true }); Object.defineProperty(TimelineControl, "Now", { get: function () { return TimelineControl._now; }, enumerable: true, configurable: true }); Object.defineProperty(TimelineControl, "FrameID", { get: function () { return TimelineControl._frameID; }, enumerable: true, configurable: true }); Object.defineProperty(TimelineControl, "isSystemPaused", { /** system could be paused at a higher up without notification; just by stop calling beforeRender() */ get: function () { return TimelineControl._systemPaused; }, enumerable: true, configurable: true }); TimelineControl.pauseSystem = function () { TimelineControl._systemPaused = true; }; TimelineControl.resumeSystem = function () { console.log("system resumed"); TimelineControl._systemPaused = false; TimelineControl._systemResumeTime = TimelineControl.Now; }; Object.defineProperty(TimelineControl, "SystemResumeTime", { get: function () { return TimelineControl._systemResumeTime; }, enumerable: true, configurable: true }); TimelineControl._isRealtime = true; TimelineControl._now = 0; TimelineControl._lastRun = 0; TimelineControl._frameID = 0; // useful for new in frame detection TimelineControl.CHANGED_TABS_THRESHOLD = 500; // msec // =================================== SYSTEM play - pause =================================== // pause & resume statics TimelineControl._systemResumeTime = 0; TimelineControl._systemPaused = false; return TimelineControl; })(); QI.TimelineControl = TimelineControl; })(QI || (QI = {})); Here is some of the before render which does the pause checking. Basically the rest uses TimelineControl.Now, instead. Individual mesh instances can also be paused, /** * beforeRender() registered to this._mesh. Public for sub-classing in MORPH Module. */ public _incrementallyMove() : void { // test for active instance pausing, either instance of entire system if (this._instancePaused || TimelineControl.isSystemPaused){ if (this._currentStepInSeries) this._currentStepInSeries.pause(); return; } // system active resume test if (this._lastResumeTime < TimelineControl.SystemResumeTime){ this._lastResumeTime = TimelineControl.SystemResumeTime; this.resumeInstancePlay(); // does nothing when this._currentStepInSeries === null } ... } // ================================== INSTANCE play - pause ================================== private _lastResumeTime = 0; // for passive detection of game pause private _instancePaused = false; public isInstancePaused() : boolean { return this._instancePaused; } public pauseInstance(){ this._instancePaused = true; } public resumeInstancePlay() : void { this._lastResumeTime = TimelineControl.Now; this._instancePaused = false; // cause Event in progress to calibrate for smooth resume if (this._currentStepInSeries !== null) this._currentStepInSeries.resumePlay(); } Dad72 1 Quote Link to comment Share on other sites More sharing options...
Dad72 Posted February 8, 2016 Author Share Posted February 8, 2016 Thank you JC, But how build the graphical part of the timeline (UI)? with the scale and slider, the key frame creation... Quote Link to comment Share on other sites More sharing options...
JCPalmer Posted February 8, 2016 Share Posted February 8, 2016 No clue. This is an internal control system for me. User does not have ability to change time, so I have no UI Quote Link to comment Share on other sites More sharing options...
Dad72 Posted February 8, 2016 Author Share Posted February 8, 2016 Ah, ok, this is the part that concerns me the most: the best method to do it. I'm trying to do with the classical method html / css3 and images. Quote Link to comment Share on other sites More sharing options...
dbawel Posted February 9, 2016 Share Posted February 9, 2016 Hi Dad72, If you are planning on implimenting this into the CastorGUI extension (which I really like and am using a great deal now,) I would want to use my own image files to create my own style of a graphic timeline. So if this is the case, then providing a function which I can format and insert my own style timeline would be fantastic. However, if you're not looking at implimenting this into the CastorGUI extension currently, please ignore this suggestion. However having the ability to create not only a timeline, but a control which I could use for a timeline, video control, etc. would be a great addition to CastorGUI. I'm building a video timeline control currently, and it's not fun at all. Cheers, DB Quote Link to comment Share on other sites More sharing options...
Dad72 Posted February 9, 2016 Author Share Posted February 9, 2016 hi, In fact I realized it for another project I built editor to easily create small animation 3D movie. I did not think to include it in CastorGUI. But I'm not totally against the idea of doing it, but when I have something functional, not before. Quote Link to comment Share on other sites More sharing options...
dbawel Posted February 9, 2016 Share Posted February 9, 2016 Hi, Perhaps it's not necessary to include in the CastorGUI extension, as I can use your GUIslider to create most everything I might need to build controls for video, timelines, etc. But I thought I would ask if you might be adapting something more for CastorGUI and thought to mention that in any GUI I build, I prefer not to be forced to use preset images and styles to my GUIs. Again, thanks for CastorGUI and all of the tools you have built for the BJS community. Cheers, DB Quote Link to comment Share on other sites More sharing options...
Dad72 Posted February 9, 2016 Author Share Posted February 9, 2016 Until then, I managed to do that: It's not working yet, I have only the graphics. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.