# pouët.net

## Timing in demos.. how do I do it ?

category: general [glöplog]
Greetings !
I'm currently learning programming with C++ and DirectX9. Now I thought about how to do the timing.. and I didn't figure it out (I'm very new to DirectX or programming generally). If I would like to fade in a cube from the left, let it spin for 10 seconds and then let it then exit to the right side.. how would I do that ?

Sincerly OnTheRun
added on the 2004-01-04 13:23:08 by ontherun
the easiest to learn case (you may evolve from there on). I assume you can count milliseconds already:

Code:``` while(true) { time = timer->getMs(); cube_rotation.x = time*0.05; cube_rotation.y = time*0.04; cube_rotation.z = time*0.03; if(time<5000) { // x will be 0 in 5 seconds, starting on -100 cube_position.x = -100 + (time*100/5000) } else if(time > 15000) { // 10 seconds have passed where position hasn't changed // When time is 20000 (5 seconds after it started moving), position.x will be +100 cube_position.x = ((time-15000)*100/5000) } draw_cube(); } ```

This is BY NO MEANS the best way to do it, but it's the easiest method to start on and learn... after that, you might want to learn how to script it and fire events and stuff.
added on the 2004-01-04 13:39:17 by Jcl
A hint is the word 'interpolation', you may use different splinealgorithms to get your best results.. Some nice ones you should consider is hermite and bezier, what Jcl describes is linear interpolation.. Wich we all do somtimes when partycode, but really never should ;)

Then when you have learnt how to do this, you should sit down with paper/pencil and draw some of them, or on the screen.. Whatever :)

The point is that you want nice and smooth transitions, not linear crappy ones..
added on the 2004-01-04 13:49:04 by Hatikvah
of course, for -nice- movements, you should use splines, which will allow for greater control over everything that happens, providing you have a nice spline editor or use not-so-many control points (try to make 200 control points on paper, for a 3D movement, and you'll be fucked ;D)... this also allows for easing (like, the cube would slow down when reaching the zero point, and seem to accelerate when leaving to the right side).

-Then again-, you need linear interpolation to browse through the spline, so you better start from there, and keep investigating on your own :-D

To put it simply, linear interpolation is a 'rule of three' forumla, with one incognita... image it as:

<current_value> - <current_time>
<end_value> - <end_time>

You have only one unknown value there (that's typically the current value), so you just cross-multiply the two values you know, and divide by the third.

Imagine you want to have a variable that goes from 0 to 1000 (that's the value), in a time of 15000 milliseconds. You know the current time, the end time, and the end value, need to find the current value for this time, so you go like:

x - current_time
1000 - 15000

The result is: x = (current_time * 1000) / 15000

- current_time * 1000 <-- cross multiplying the two crossed values you already know
- / 15000 <-- divide by the third

Sorry for my shitty english... i could explain this so easily in spanish and with a paper and pen (drawing arrows ;D), hope you got the point
added on the 2004-01-04 14:02:06 by Jcl
Also, for rotations, you should be using quaternions and then convert them to matrices for multiplying the vertices of your mesh for them... this allows for spherical interpolation (slerp'ing ;D) of rotations, which works pretty nicely... just one more thing to investigate if you feel like doing so :)
added on the 2004-01-04 14:05:44 by Jcl
you can use GetTickCount() or timeGetTime() to get a millisec value... but the safest is always retrieving the value from the music player.
added on the 2004-01-04 14:08:45 by Gargaj
I wouldn´t use timeGetTime(). On my system it updates every 30 millisec, and that´s not enough if you have an unstable framerate. I use the high performance counter QueryPerformanceCounter() and QueryPerformanceFrequency(), and it worked fine so far.
added on the 2004-01-04 18:01:32 by chock
With my current standard of knowledge, I only understand the first hint from Jcl, but I'm working on it ;)
Am I right with my adoption, that the timing-code belongs in the messagehandler-loop ?
Mine looks like this at the moment:

// Struktur, in der Informationen zur Nachricht gespeichert werden
MSG msg;

// Diese Schleife läuft bis WM_QUIT gesendet wird
// Wenn eine Nachricht vorliegt, wird sie behandelt
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
lpD3DDevice = Direct3D.GetDevice();

// Beginn der Szene
Direct3D.BeginScene();

Direct3D.DrawText("yeah yeah...",100,400,D3DCOLOR_XRGB(255,255,255));

// die Quelle für das Dreieck setzen
lpD3DDevice->SetStreamSource(0,VB_Triangle,0,sizeof(CustomVertex));

// Das Dreieck ist das erste Element im Puffer
// und es wird genau ein Objekt gezeichnet
lpD3DDevice->DrawPrimitive(D3DPT_LINELIST ,0,3);

// Die Szene ist beendet
Direct3D.EndScene();
}

Sorry for asking such "simple" questions.. but i'm a real hard newbie ;)

Greetings OnTheRun
added on the 2004-01-04 19:40:05 by ontherun
obviously it has to be in your renderloop somewhere. i do (did) sg like:

----------------------------------------
while (!done) {
handle_messages();

unsigned int sync = GetTime();

clearscreen();
if (1000<sync && sync<=3000) thiseffect.render(sync-1000);
if (3000<sync && sync<=5000) thateffect.render(sync-3000);
flip();
}
----------------------------------------

(veeery pseudo :)
added on the 2004-01-04 20:08:45 by Gargaj
now thats ugly code :)
added on the 2004-01-05 03:43:25 by Hatikvah
Who hasn't coded something like this once :P (ugh, party coding sux)
added on the 2004-01-05 05:01:33 by shash
all your timing code are belong to the render loop!
added on the 2004-01-05 10:01:32 by Jcl
Quote:

// Struktur, in der Informationen zur Nachricht gespeichert werden
MSG msg;

// Diese Schleife läuft bis WM_QUIT gesendet wird
// Wenn eine Nachricht vorliegt, wird sie behandelt
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
lpD3DDevice = Direct3D.GetDevice();

// Beginn der Szene
Direct3D.BeginScene();

Direct3D.DrawText("yeah yeah...",100,400,D3DCOLOR_XRGB(255,255,255));

// die Quelle für das Dreieck setzen
lpD3DDevice->SetStreamSource(0,VB_Triangle,0,sizeof(CustomVertex));

// Das Dreieck ist das erste Element im Puffer
// und es wird genau ein Objekt gezeichnet
lpD3DDevice->DrawPrimitive(D3DPT_LINELIST ,0,3);

// Die Szene ist beendet
Direct3D.EndScene();
}

erhh.. okay, but things will (hopefully) get a tad more structured and abstract than this; the whole idea people are trying to give you is that, as far as you want it to, you need to make the appearance of your visualizers parametrizable; these parameters have to be fed by either a script or perhaps a hardcoded piece of "script" (which can be either shit ugly or quite do-able, depending on both skill and time) which consists of a solid 1-way flow including timeslice codepaths or, which is better, an event system. in the end you'll have to feed interpolation formulas with the parameters such as time or perhaps an accumulative value taken from sound analysis (think about picking a "bass band" from a spectrum, filtering it a little.. etc). there are so many ways around that it's not really easy, at least not for me since i'm utter shit at explaining anything at all, to break this down into a few lines. i think jcl did a nice job at that, and if you'll work from his simple example of 'solving' the issue, you'll hopefully encounter your own needs regarding flexibility, efficiency and results.

in the end it all falls together when your programming skills improve. besides that, it's not considered a "good" practice to place a comment above each line of code, especially not when it makes anyone who can ride a bike go 'duh' ;)

oh well. back to work.
added on the 2004-01-05 10:27:26 by superplek
Has any of you any problems with QueryPerformanceFrequency ?

I do :
_LARGE_INTEGER freq;
_LARGE_INTEGER coun;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&coun);

return (double(coun.LowPart)/double(freq.LowPart));

for the DeltaT, and I get fine results on Athlon based machines, but on P4 with hyperthreading, the value is not 100% accurate (I would say about 99 %). Any ideas ?
added on the 2004-01-05 12:00:40 by Navis
besides that, it's not considered a "good" practice to place a comment above each line of code

especially in german... *shivers*...
added on the 2004-01-05 12:13:57 by Gargaj
rm topic.php?which=883/*.c*
added on the 2004-01-05 12:30:49 by Hatikvah
lompas: Didn't recognize that so far, but there's another problem with QueryPerformanceFrequency: On notebooks this value can skip around if the CPU switches to another clock rate.

So the safe way would be like

Code:``` double curtime; LARGE_INTEGER lastpcv; void InitTimer() { curtime=0; QueryPerformanceCounter(&lastpcv); } double GetTimer() { LARGE_INTEGER count, freq; QueryPerformanceCounter(&count); QueryPerformanceFrequency(&freq); curtime += double(count.QuadPart-lastpcv.QuadPart) / double(freq.QuadPart); lastpcv=count; return curtime; } ```

This way it's only one small stutter if the CPU changes its clock freq - instead of a timer jumping around wildly.
added on the 2004-01-05 12:47:08 by kb_
Quote:

lompas: Didn't recognize that so far, but there's another problem with QueryPerformanceFrequency: On notebooks this value can skip around if the CPU switches to another clock rate.

hm, good that you'd mention it, i did not think about it. that's *very* nasty though.. msdn ofcourse blatantly states "result never changes as long as the system runs" - which i took for granted :))
added on the 2004-01-05 12:50:37 by superplek
while( 1 )
{
printf( "LOBSTARRS DOMINATION!" );
}
added on the 2004-01-05 13:20:20 by kusma
for people having problems with multiprocessor (or hyperthreading) machines, and QueryPerformanceCount, use __int64 (if it's Visual C), instead of LARGE_INTEGER and all your problems will be gone
added on the 2004-01-05 14:55:33 by Jcl
at least, they did for me <g>
added on the 2004-01-05 14:57:59 by Jcl
kusma: that will not print anything tho until its breaked ;)
added on the 2004-01-05 15:08:37 by Hatikvah
Jcl: LARGE_INTEGER is in fact an union and the QuadPart member is __int64, so it's the same. At least it should be.
added on the 2004-01-05 15:09:09 by kb_
kb: yes, i also wondered that... but the fact is, that it worked for me :-)

lemme upload my (old, I use a much improved C# class now) C++ timer class

timer.h
timer.cpp

The only change to my old class is the int64 thing (int64 and int32 are typedefs) vs the LARGE_INTEGER (I still cast to LARGE_INTEGER when using the API). It was tested to work on a Multiprocessor machine where the other one failed miserably

I still wonder why, and didn't really got the time to get deeper into it... my motto: if it works, don't touch it :D

I'll post the same timer class, improved, bugfixed (the offset thing is bugged like shit, keep it zero and it'll do), and all in all nicer, when I get to my other machine
added on the 2004-01-05 15:15:12 by Jcl
for the last sentence... in C#, that is :)
added on the 2004-01-05 15:16:53 by Jcl