Jump to content
  • Advertisement
Sign in to follow this  
zandman26

Headaches with anims in DX9

This topic is 4153 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have built a 3D engine in DX9 with working HLSL and camera rotations, almost everything except collision detection and animations. So instead of doing something as hard as getting a collision detection witch should work fast I thought that I would make the anims work (and also because my programing friends has bin bugging me about it). Then you go to the DX SDK and find a nice little app called SimpleAnimation_2005 and start looking at it, well so far so good you start copying code as Ive never done this before I don't want to screw things up just because I like other names on methods or just other layouts. But now after copying the code and almost understand how the code worked in SimpleAnimation_2005.cs I noticed that it had cross references everywhere and well I don't want to spend my next year just trying to clear out what all those does! So does anyone know a good tutorial on the net then send me a link and I would be most thankful. I would prefer it in C# (managed DX) but I probably could figure out how to transform C++ code in to C# too. Thanks in advance.

Share this post


Link to post
Share on other sites
Advertisement
Here you can find a very good tutorial on animating X files, and it also contains good explanations about general animation theory.

Share this post


Link to post
Share on other sites
Thanks for the link, but when I started looking on the code and other codes on the internet I found that its only one thing that I have problem with.
Its the "elapsedTime" variable in SimpleAnimation.
Sure I could have just done what Ive bin told and added the Common folder to my project but this is my game and I want full control over whats happening in it and not suddenly get strange errors because of that it conflicts with Microsofts coding.
I changed to DX9 to get full control over my project and not have some hidden code doing the work for me.
So my new question here is, the timer that gives the numbers to elapsedTime variable is that a ordinary timer or do I need to build my own timer and what should that counter count on if so?

Share this post


Link to post
Share on other sites
The elapsedTime variable stores the number of seconds elapsed between frames. It's used so that the animation speed is constant regardless of the frame rate.
You can use something like GetTickCount() or timeGetTime() to compute it, but I've heard that using the hi-res timer can give more accurate results (on some systems).

Share this post


Link to post
Share on other sites
Thanks for explaining what needed to be done, I've now started working on building this timer, next step is to figure out a way to stop them:P

Share this post


Link to post
Share on other sites
Today, I finished a timer_class in C++ that works within the main game loop. It goes like this:
#define WIN32_LEAN_AND_MEAN
#include <windows.h> // LARGE_INTEGER

class timer_class {
LARGE_INTEGER ticks_per_cycle;
LARGE_INTEGER start_tick;
LARGE_INTEGER end_tick;
public:
timer_class(unsigned desired_frequency, LARGE_INTEGER ticks_per_second){
ticks_per_cycle.QuadPart = ticks_per_second.QuadPart / desired_frequency;
};
void start(LARGE_INTEGER current_tick)
{
start_tick.QuadPart = current_tick.QuadPart;
end_tick.QuadPart = start_tick.QuadPart + ticks_per_cycle.QuadPart;
}
bool expired(LARGE_INTEGER current_tick)
{
return current_tick.QuadPart >= end_tick.QuadPart;
}
float elapsed_seconds(LARGE_INTEGER current_tick, LARGE_INTEGER ticks_per_second){
return (float)(current_tick.QuadPart-start_tick.QuadPart)/ticks_per_second.QuadPart;
}
};


I use this class in the main Message-Dispatch loop like so:
//--------------------------------------------------------------------------------------------------
// Message loop
//--------------------------------------------------------------------------------------------------
WPARAM game_engine_class::message_loop()
{
//----------------------------------------------------------------------------------------------
// Initialize timers
//----------------------------------------------------------------------------------------------
LARGE_INTEGER ticks_per_second, current_tick;
QueryPerformanceFrequency(&ticks_per_second);
timer_class render_timer(30, ticks_per_second); // Create a 30hz timer (30fps)

QueryPerformanceCounter(&current_tick);
render_timer.start(current_tick); // mark 'now' as beginning the cycle

float elapsed_seconds; // to figure actual time elapsed, and skip/catch up if necessary

//----------------------------------------------------------------------------------------------
// Message loop body
//----------------------------------------------------------------------------------------------
MSG message;
PeekMessage(&message, NULL, 0U, 0U, PM_NOREMOVE);
while(message.message != WM_QUIT)
{
//------------------------------------------------------------------------------------------
// if there's a message waiting, call message handler via Windows OS
//------------------------------------------------------------------------------------------
if( PeekMessage(&message, NULL, 0U, 0U, PM_REMOVE) ){ // do one message
TranslateMessage(&message);
DispatchMessage(&message);
}// else all caught up on messages

Sleep(1); // Make sure other apps have a turn

//------------------------------------------------------------------------------------------
// Do AI thinking, AI orders, animation stepping, rendering
//------------------------------------------------------------------------------------------

// Render timer
QueryPerformanceFrequency(&ticks_per_second);
QueryPerformanceCounter(&current_tick);
if( render_timer.expired(current_tick) ) // 'now' is >= timer's end_tick
{
elapsed_seconds = render_timer.elapsed_seconds(current_tick, ticks_per_second);
render_timer.start(current_tick); // mark beginning of next cycle

render(elapsed_seconds);
}

}// while !WM_QUIT

return message.wParam; // value from PostQuitMessage()
};


There is still one question I haven't answered, that might be noticed by the observant persons: Why update the ticks_per_second every pass? The reason I've set it up (and this may be wrong) is to support AMD CPUs that do dynamic speed fallbacks. My Athlon 2.0Ghz is supposed to change speeds up to thirty times a second, according to demand. Anyone knows more details about that?

[Edited by - AngleWyrm on June 30, 2007 2:08:52 AM]

Share this post


Link to post
Share on other sites
After thinking about it some more, I realize that if the frequency changes then all bets are off. There is no way to calculate elapsed time if the frequency changed somewhere in the middle. So I have given up on monitoring frequency changes, and thus a simpler interface:

#define WIN32_LEAN_AND_MEAN
#include <windows.h> // LARGE_INTEGER, QueryPerformanceFrequency()

class timer_class {
unsigned frequency;
LARGE_INTEGER ticks_per_cycle;
LARGE_INTEGER start_tick;
LARGE_INTEGER end_tick;
static LARGE_INTEGER ticks_per_second; // global to all timers
public:
timer_class(unsigned desired_frequency);

void start(LARGE_INTEGER current_tick);
void restart(LARGE_INTEGER current_tick);
bool expired(LARGE_INTEGER current_tick);

float elapsed_seconds(LARGE_INTEGER current_tick);
};


It's also much easier to comprehend, and therefore use:

//--------------------------------------------------------------------------------------------------
// Message loop
//--------------------------------------------------------------------------------------------------
WPARAM game_engine_class::message_loop()
{
//----------------------------------------------------------------------------------------------
// Initialize timers
//----------------------------------------------------------------------------------------------
LARGE_INTEGER current_tick;
QueryPerformanceCounter(&current_tick);

timer_class render_timer(30); // create 30hz timer (30fps)
render_timer.start(current_tick);

// create other timers here (15hz animation, 10hz planning, or whathaveyou)

float elapsed_seconds;

//----------------------------------------------------------------------------------------------
// Message loop body
//----------------------------------------------------------------------------------------------
MSG message;
PeekMessage(&message, NULL, 0U, 0U, PM_NOREMOVE);
while(message.message != WM_QUIT)
{
//------------------------------------------------------------------------------------------
// if there's a message waiting, call message handler via Windows OS
//------------------------------------------------------------------------------------------
if( PeekMessage(&message, NULL, 0U, 0U, PM_REMOVE) ){ // do one message
TranslateMessage(&message);
DispatchMessage(&message);
}// else all caught up on messages

Sleep(0); // Make sure other apps have a turn, and start from here with full time slice

//------------------------------------------------------------------------------------------
// Do AI thinking, AI ordering, animation stepping, rendering
//------------------------------------------------------------------------------------------

// AI timers, animation timers, etc go here

// Render timer
QueryPerformanceCounter(&current_tick);
if( render_timer.expired(current_tick) ) // 'now' >= timer's end_tick
{
elapsed_seconds = render_timer.elapsed_seconds(current_tick);
render_timer.restart(current_tick); // begin next timing cycle

render(elapsed_seconds);
}// else not time to render yet

}// while !WM_QUIT

return message.wParam; // value from PostQuitMessage()
};


The main difference between timer.start() and timer.restart() is that the timer.start() function does a check to see if ticks_per_second has a value other than zero. If not, then it calls QueryPerformanceFrequency.

Querying the hardware and updating the current_tick could be done inside the class, with an update() function. The result is more direct, but the current implementation allows answering questions like: Will a timer expire at such-and-such time? and also allows scheduling cycle starts later/sooner than right now.

Also, it is probably possible to templatize the class with a callback function, but it would make the constructor interface less intuitive. Developer's discretion.

[Edited by - AngleWyrm on July 2, 2007 5:31:19 AM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!