Branching |
Frame Based Animation |
Smoothing AnimationsIf you want animations to look good, you have to make them smooth, now in terms of real-time animations, "smooth" simply means "modified every frame". So if we go back to our first example we see this: var b = new Block(x, y); branch { var sc = new TimeScale(Black, Green, 2000); while (sc.Going) { b.Color = sc.Value; sleepframe(); } }The smooth animation is the fading of the block from black to green, this is done using a helper object called a "TimeScale" which interpolates across two values over a given time. In this case it scales from Black to Green over a span of 2 seconds. This same animation could be written as such: var b = new Block(x, y); branch { var start = global.Time; var dur = 2000; while (start+dur > global.Time) { var t = (global.Time - start)/dur; b.Color = Black*(1-t) + Green*t; sleepframe(); } b.Color = Green; }But I feel the TimeScale system makes it a lot easier to read and write. Also consider that because branching doesn�t use some silly intermediate meta-representation you can also run as much code as you want between frames, and you can create complex equations for the values, there is no need to use simple linear interpolate. Also this allows you to animate numerous things each frame without having to have numerous meta-representations. For example swapping the locations of two items, you simply make a TimeScale which goes from 0 to 1 and you use that values to move both objects, there is no need to create separate animations for each. |
The Current ImplementationThe current implementation comes with a 2D GDI+ based composition tree, and a 3D Managed DirectX based composition tree. Please note that both of these composition trees where implemented as standard .Net objects, and don�t contain any special code to make them animate. JSB naturally interacts with them creating the "illusion of animation" by modifying them over time. You can use JSB to animate any .Net based application from a WinForms app to whatever crazy interface you are creating for yourself. Please note however, that in it�s current form it is something of a throw together, so there are certain issues and it should not be consider a complete language. Hopefully someone out there with more time will find this project and clean it up, fix up a few of the performance issues, and hone it into a "real" language. However, in it�s current state you can defiantly play with it and see what you can get out of it. |
Quasi-ConclusionSo there you have it, a simplified animation model which combines the easy and simplicity of linear programming, with a frame based rendering model, the functionality of multi-threading, without the hassles of real threads, and the beauty of flowing motion without the crappy meta-representations.
|
Cool ConceptsThis is a short little list of ideas I�ve been working on which are just generally cools things that could be added to a programming language. They are mostly just programming ideas, but some also relate to animation. Some of you may say that they aren�t very "pure", which is true I some sense, but generally I find that the hacks people use to get around the "purity" of a language or API are often so hacky themselves that it�s worth it to give them a better route.
function _ageCompare(a,b) { return a.Age.CompareTo( b.Age ); } function SortByAge(list) { QuickSort(list, _ageCompare); }However this becomes complex when we have complex operations to be applied with each callback. A better solution I see is that the call back should actually execute in the function namespace. Take for instance the very popular "foreach" statement in C#, this allows you to write code right in your function which in a sense is a call back as an iterator moves across a collection. I�m recommending this mechanism be generalized by the creation of "subfunction" which creates a function which executes in it�s creators namespace whenever it is called. For instance, you want to look at every other item in a list, and if it�s age is less than a certain value, then you add it to a list: function EveryOther(list, func) { for (var i=0; i<list.Length; i++) { if (i%2 == 1) func(ob); } } function FindEveryOtherYoungerThan(list, max) { var ans = new Array(); EveryOther(list, subfunction(a) { if (a.Age < max) ans.Add( a ); } ); return ans; }In this case, EveryOther is our "complex function requiring a callback" and FindEveryOtherYoungerThan it shows how we can easily inline a subfunction so that we can keep all related logic together, and not have to worry about how we access and pass variables between the main and callback functions. Well it�s not currently added to JSB, but it could be, and I think it would make things allot easier. I�ve written too many call backs, for tree traversal or whatever and then I have to create some special data structure I can pass into. This would really have saved a lot of time, and made the code a lot easier to read. Easy Threading in JSB: The "branch" architecture used by JSB is really good for doing many things related to animation, but it still does require you to call "sleep" functions now and then to pass control back to the rest of the application. Personally I see this as giving the developer the most control and power but there are times when you don�t want to do that. For instance, in a file browser, you want to get the list of files in a directory, put up little icons, and then slowly load the thumbnails or whatever to put in them. You want however the thumbnails to load while the rest of the application is animating. Here is a simple syntax that I think would allow that, and would mean you�d get the best of both branching animation and easy control of threads: function OpenFolder() { var dir = GetCurrentDirectory(); foreach(var file in dir.Files) { var icon = new Icon(); icon.Name = file.Name; shared var done = false; thread { var det = file.LoadDetails(); //slow framesync { icon.Details = det; } var thumb = file.LoadThumb(); //slow framesync { icon.Thumb = thumb; } done = true; } branch { var rot = new Rotation(); rot.Target = icon; while (!done) { rot.Angle = (global.Time / 1000); sleepframe(); } rot.Target = null; } } }What is happening here is that for each file, a new icon is created with that files name, then a thread is created which loads the details and thumbnail of the file and updates the icon periodically. While the file data is loading, a separate branch spins the icon around to indicate that it�s loading. The "framesync" command causes the thread to pause and wait for it�s turn with the rest of the branches to execute that block, this allows you to safely interact with the other objects and not have to worry about changing them at the same time (in other words it�s a simplified way to use monitors to avoid threading errors). I feel this is a handy model for multi-threaded applications as it combines logically related blocks of code together despite whether they will be executed in parallel other threads or so forth. Oh and the "shared" command, states that a variables should be shared across the different subbranches/threads and so forth so that if it�s value is changed in one it affects the other ones (so the thread can set done to true, which branch which is spinning the icon). Dynamic Inherited Properties: JavaScript has this cool "Object" which you can create and dynamically associate properties too. So you can do stuff like "var t = new Object(); t.Age = 30;" and so forth. This is quite powerful and lets you do a lot of cool things. However, I found when I was creating more complex data structures, you land up having to create a special function to generate an Object with all your default values. So I figure why not be able to inherit them. Consider the following: var node = new Object(); node.Value = -1; node.Depth = 0; var t = inherit(node); t.Depth = 5; //at this point: t.Depth==5 and t.Value==-1 node.Value = 3; //at this point: t.Depth==5 and t.Value==3What happens here is that whenever you "set" a property on an object, it value is set on the current object. However, when you "get" a property, if the current object doesn�t have it, then it checks it�s parent to see if it has that property. And in this way, you can change the parent and it instantly propagates to it�s children. Anyway, it�s a thought, and I�m sure you can do some cool stuff to do with it. It�s in the current implementation, so feel free to play with it. Member Functions in JavaScript: one of the other problems I found when writing moderately large JavaScript applications is the lack of "member functions". This makes it awkward to write object oriented code, and you land up writing essentially C-style applications with a bunch of functions loosely connected together without the organization that OOP provides. A simple solution to this problem is a way to represent member functions, would could be done like this: var x = new Object(); x.Name = "Cat"; x.SameName = function(this, other) { return (Name == other.Name); }; var issame = x.SameName( y );Here "SameName" is a member function of x, and naming the first argument "this" means that the first argument is implicitly passed to the function when it is dereferenced and called; thus when you write "x.SameName(y)" it calls SameName and passing "x" as the value of "this" and "y" as the value of "other". Then in the function, the variable namespace is set to include the "this" object, so that any properties of "this" can be accessed like local variables. This I believe is a relatively simple and straight forward way to implement member functions, and could save a lot of time, and make the code easier to read. Nestable Comments: come on people, with all our advanced technology and we can�t nest /* */ comments! The only difficulty could be that when a /* was encountered, you would have to find it�s matching */, but you would have to make sure that you didn�t count any sub-*/�s which appeared on a line after a "//". Of course many people have taken to "//" commenting out the beginning or end "/* */" comments, so as long as you accounted for that you wouldn�t have any problems. It�s just a thought because I�ve had too many times when I�ve commented out a block including a large comment and it only worked half way. |