For an OS X desktop app, I have a canvas with an image. After a minute or two I want the canvas to appear to “flip over” to display another image, and then back to the first image after another minute or two has passed.
Basically rotating signage - flipping on an invisible horizontal line in the middle of the canvas area, if that makes sense?
Any ideas or suggestions on how to do this, preferably without using plugins?
( Yes, the goal here is gratuitous eye candy to display the logo for our conference and then an image of the conference’s twitter hash tag. )
I would just use a few timers. One to wait a minute or two and start the second. The second would set a variable to scale the image vertically then invalidate the canvas. The paint event would have code to drawpicture the logo at the width of the canvas and the height scaled by the variable. Once the scale is zero stop timer #2, swap the images and start a third timer to scale back to original size. Rinse and repeat. You could even get fancy and darken the image as it flips to create a 3d shadow effect OR you could go the opengl route for a very fancy look, but that may be overkill.
I include stock graphics from google.com so they’re not the best (can switch out with your own). But the animation demo is set to scroll randomly through all the different scene transitions. It may interest you, may not, but its available and works. I can set it to flip only if needed (and then it depends which direction flip up, down, left, right, spiral flip)
I would suggest researching Core Image (MBS will help here) as Core Image will give you the fastest possible image processing. Which is what going to need. The hardest part with animating photo transitions is rendering quick enough so that it’s smooth, and this is where I wouldn’t recommend anything except Core Image.
As for the actual animation, the best technique is to use a time frame. Basically, you’d create an object (more on this in a moment), and specify the duration. Your object would then fire an ‘animate’ function, and pass a percentage based upon timeSinceStart/Duration. This way in your animation code you simply create each frame by using a vector based upon the start frame and the end frame.
Now for the object, you have two options here. #1 Is to use a timer and fire it as quickly as possible (but no need to go faster than 60 fps as most screens cannot keep up). This way the animation can be interactive and it allows the application to do other things.
#2 The other way is to deadlock it, create a single function that calls the ‘animate’ function over and over again until the animation is complete. You’ll need to call refresh after each frame, however as you’re getting tighter loops, you can squeeze out a few more frames and also it will lock the interface at the same time. I use this method when animating interface elements.
Finally, I calculate the animate frequency based upon ( 1 second / fps ) - timeToDrawFrame.
I would start by doing some animations first (like moving an image around inside of a canvas), then research Core Image.
Best animation-to-canvas method is as I posted above…keeping animation in a thread as not to lockup your application and a thread subtimer used to update framerate as to achieve the highest framerate possible in my demo the framerate is 50 frames/sec (1000/20…human eye only sees 33fps)… if you want super high quality OpenGL
How does a thread update the UI? Doesn’t It have to use a timer to do it, so I’ve always just used a Timer at Period 16 = ~60fps. But even at this rate, because it’s not synced with screen refresh, there’s a jerkiness and I have to bump it up to 90fps for full smoothness. Does a thread somehow let you stay synced with the screen?
When you use a timer its linked to your main thread, so any intensive actions will lockup your UI or cause "flicker. " Timers, not being actual “controls,” can be created by code alone without having a member-set to dynamically create from… so you can create them in threads dynamically at will. Threads, of course run in their own memory space, and not the application’s main thread. So if you create a timer within the thread, its memory exists within the thread’s memory. Normally, threads cannot access the UI, but using a timer within the thread it is possible to access “triggers” to make UI changes directly from within Thread.Run (just as good old real studio allowed ui thread interaction :-)). Since the xojo thread class has been rewritten/updated, any possible errors are already handled by the Xojo thread class, I merely subclassed the new thread class and rewrote old features/abilities back into it
Thanks Matthew but I’m still not clear on what benefit a thread has. If a drawing is going to take a long time then I’d use a thread but if I’m drawing something that should happen 60 times a second then the drawing will need to happen in that time. A thread has to do the drawing into a picture then trigger a timer to paint the canvas with a drawpicture. A Timer just tells the canvas to paint and can draw directly to g without an extra drawpicture. Both ways need to draw the same thing in 60fps using the same execution resources (or are you getting a parallel thread somehow?).
The problem I have with a timer is that at Period 16 it’s close to triggering a new drawing for every refresh of my 60hz screen. But the timer isn’t exact and sometimes it takes too long and 2 screen refreshes pass with the same drawing, resulting in smooth 60fps motion randomly interupted with 30fps motion. Bumping it up to 90fps ensures there’s a new drawing for every screen refresh, at the downside of extra drawings.
The same thing happens for a timer with Period 33 for ~30fps. For the most part every other screen refresh is a new drawing but it’ll vary and sometimes it’s 1 or 3 refreshes between drawings causing jerkiness.
I’m wondering if your thread+timer setup is doing something to be more accurate when the timer fires so it stays in sync. I’m Looking into Core Video Display Links to get this refresh sync.
Getting back onto Justins topic, this is my attempt at the sign flippage part. All code is in MainWindow.display. No 2 timer control for sequencing (like Jim suggested and how I would do that), just click and it rotates from 0 to 180 degrees in 2 seconds then stops. opengl based. Windows needs Glut32 installed or something like that. No Linux. May not work anyways. http://home.comcast.net/~trochoid/code/signage.zip
Actually, the thread doesn’t do any of the drawing, it merely creates the timer that handles the drawing just as if using a timer only…only, the process (memory) exists in its own space outside the main app thread (as with using a thread only)… which is why there is better performance at 50 fps vs 90fps with a timer only. say for instance there was a process intensive action which occurred in the main app thread (ie propogating a listbox…using only a timer would cause the animation to “lock-up” or “skip”…where using a thread to create the timer in its own memory space, allows the canvas to update smoothly without any noticable effect. The animation process is the same as using a timer only…except the timer/canvas interaction operates seperately from the main app thread (everything exists within the main app threadfif its not seperate).
Matthew’s and Will’s projects seem to do slightly different things.
Matthew’s is an image slideshow - and Will’s is a flip sign.
Both are really good, and worthwhile additions for the community
Will, is it possible to modify your code so that once the image is flipped, clicking it again will reverse the flip?
At the moment, if the image is flipped, it jumps back to the first image and then starts again.
Thank you for the controls - I am sure you have made a lot of user’s happy
I believe you since you’d know the under-the-hood specs of the framework… but help me understand as it defies logic…
Aside from the main topic this has me curious then, as, if any class within a thread accesses the UI, it thows a ThreadAccessingUI error message correct? (True)
So creating a timer (class) in a thread (if its truly part of the main thread) should throw a “ThreadAccessingUI” error as the new thread would conflict with the main thread and UI (but it doesn’t).
In Windows using C++, the proper method to prevent lockup of the main thread, which I implemented in Xojo (and seems to work as it should with better performance than a timer alone…if the timers all exist within the same space it should render the same result if implemented in both ways??? But doesn’t…), would be to create a thread using api and within the thread create a timer using i.e. SetTimer(1000, pointer) api… which allocates the timer in the thread. I assumed Xojo did the same as it would be “best practices” and works with comparable noticable results between xojo and c++ using both methods. So you’re saying whenever a timer is created in Xojo, its actually an underlying “array of thread handles” created in the main thread with all WM_Timer messages being handled in the main app message receiver?
I’m not doubting you, merely wondering why then say Timer-A placed on the window has choppy animation with 50fps and more smooth animation at 90fps…but Timer-B created by a thread has better animating at 50fps than Timer-A at 90fps…and Timer-B at 90fps has animation quality Timer-A could never achieve.
How an object is created has no bearing at all on how its code is executed. All events are just methods. Timer actions get called as part of the main event loop, and no other way. If the timer had a Poll method, you could force the timer to run in a thread, but it doesn’t, so you can’t.
As for why you’re seeing different results, I have no idea. I can’t figure how a thread would ever help animation speed. Either your calculations take less time than it takes for a frame to expire, or it doesn’t. A thread won’t have any impact on that.