PDA

View Full Version : few questions/suggestions


Dima
02-14-2004, 01:50 PM
Hi, i have recently came upon your Wrapper, and I must say Im very satisfied with how it handles things. I like the architecture and the light weight :yes:

i have the 1.3 version, and already made a quick test app with a sphere rotating around all axis. I use the ID3DXMesh interface to create a sphere then init the sphere in CreateManaged function, I also set up the projection/view matricies, a directional light, font object and simple material in the CreateUnmanaged function. Things are working pretty nice :yes:

the Update function is very straight forward and passes 'ms' in milliseconds (frame elapsed time), this is what I did to calculate FPS:

I have 3 vars, two floats (fps and totaltime) and one int (frames) (frames = total num of updates since start), frames are set to 0 in the Init function, then in the Update function I have:

totaltime += (ms / 1000.0f); // Application running time in seconds
frames++; // Total frames elapsed
fps = frames / totaltime; // Frames per second

this is how I calculate my game FPS, I could use 1000.0f / ms; in the Update function to get FPS from current frame info only but that number jumps around all over the place, frames / totaltime is a more stable display.

Finally, this brings me to my problem: say I click on the title bar and drag the window around the screen for a while, the Update and Render functions don't get called at all in that period (pause mode?) , so when I release the window it starts running again, and the first Update call after unpausing gives me the elapsed time since last update (ms) which is very high because the timer keeps going even if the App is in pause mode. this gives me inaccurate FPS readings (using frames / totaltime) because the total time get out of sync with frames.

My question: how do I correct this without changing any code inthe wrapper?

My suggestion: Add a property to core that allows my app to either run the way it is now, or have it so it never pauses (runs all the time in the background), and also figure out how long the pause state is and subtract that from the elapsed time in the core, so the Update function's 'ms' integer returns elapsed (time - pausedtime). Say I have an object moving at 1 unit per second, and in my Update function I have object.x += 1000.0f / ms; my object moves smoothly across the screen, but if the app pauses and then gets uppaused my object will jump according to how long the app is paused.

i hope I make sence in what I say, im not a pro developer, but I want to become an Independent, and im looking forward to using your flexible wrapper in my game. I could hack up the core code and get this to work myself, but It would be nice if core supported this out of the box.

Using QueryPerformanceCounter would be a consideration but It might not be necessary.

Keep up the good work, and any responce to this long post is appreciated.

~Dima

bladder
02-14-2004, 02:39 PM
i hope I make sence in what I say, im not a pro developer, but I want to become an Independent, and im looking forward to using your flexible wrapper in my game. I could hack up the core code and get this to work myself, but It would be nice if core supported this out of the box.
Glad you're enjoying the kit. Yeah you're making perfect sence. I thought I caught that situation but apparently, I missed the size change and window move situations. The actual subtraction of the pausedTime is already in the core's game loop. Check right before the Update() function is called and you'll see a little time calculations going on.

The reason that it was causing an invalid time value is because the core actually has two booleans to determine whether to continue or not. mbPaused determines if the user has pressed the pause key or not, and while the app is paused, it will not call the update function, but it will call the render function.

The other case of mbActive makes the application do nothing at all. I set mbActive to false whenever I receive a WM_ACTIVE message with a TRUE WPARAM. Now when the window size changes or it moves, there is no WM_ACTIVE maessage, so for now, you can just add the case of WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE to the Core's message handler. I will incorporate it into the next release (1.4), should be out sometime by the end of this month or the beginning of the next.

Just stick this in somewhere in the mesasge handler


case WM_ENTERSIZEMOVE:
mbPaused = true;
startPause = timeGetTime();
break;

case WM_EXITSIZEMOVE:
mbPaused = false;
mPauseTime = timeGetTime() - startPause;
break;


And thanks, I really appreciate the feedback :)

Let me know if the above is still giving problems...

Dima
02-14-2004, 07:29 PM
Hey, thanks for such fast reply... I put in the code you provided, and it helped, but not completely.... if you click the titlebar and hold, move the window for a long time, the fps stays similar but stil loses a frame or two, this becomes apparent if I keep clicking the title bar for a while, my FPS drops by a frame or few every click.

I know very little in C++ Win32 programming, or even C++ in general, used to be a VB programmer. With the FPS calculations it's not that important to display the exact accutate FPS, but I think this would affect object movement, maybe not by much, or maybe Im being paranoid and this isn't a big deal at all.. just wondering.

Again, thanks for your fast help and for the wonderful wrapper :yes:

It it even worth using PerformanceCounter? or is TimeGetTime good enough for small games?

I realy hope to see this wrapper suceed and have many new features for game making, I love the light weight :yes:

thanks again, Dima.

bladder
02-15-2004, 07:10 AM
if you click the titlebar and hold, move the window for a long time, the fps stays similar but stil loses a frame or two, this becomes apparent if I keep clicking the title bar for a while, my FPS drops by a frame or few every click.

It's not loosing a frame or two anymore, it's actually loosing a millisecond or two. So ...

I know very little in C++ Win32 programming, or even C++ in general, used to be a VB programmer. With the FPS calculations it's not that important to display the exact accutate FPS, but I think this would affect object movement, maybe not by much, or maybe Im being paranoid and this isn't a big deal at all.. just wondering.

No, you're not being paranoid, if it was loosing a frame or two then this would've been quite a big deal. But it's loosing a millisecond or two after a drag ends, so it wont effect the animations noticably at all. However it will eventually effect your fps display if you are calculating it by using the total elpased time, because everytime you drag the window or click it, the total time goes off by 2 milliseconds, and over time, that adds up a lot. So for that, you can do this:

Inside the Update() function have a static variable that adds the 'ms' variable to itself each Update call. Then once that variable reaches 1000 (as in one second), at that time calculate your fps as "1.0f / (float(ms/1000.0f))" and store that value in a float var. That way, you're fps wont jump all over the place because it will only be calculated once every second. And it would be accurate for that one frame.

Then of course if you wanted it to be as accurate as possible, you'd have to take the total elapsed frames in that 1 second and device by the total elpased time. But the above method works pretty well. And it wont be effected by the few milliseconds lost when a window is dragged around.

I think Ill probably add this directly to the Core in the next release as well. Dont worry about the animations being effected though.

bladder
02-15-2004, 07:30 AM
It it even worth using PerformanceCounter? or is TimeGetTime good enough for small games?
It is worth using QueyPerformanceCounter when you're going to be calling a time function that is more then 1 millisecond apart. The Core calls timeGetTime() once per frame, and for an end product, each frame will definetly be more then one millisecond apart.

Of course there are problems with sticking to timeGetTime(). If you run in windowed mode with VSync turned off, the time difference between frames will be less then 1 millisecond so the value passed to the Update() function will be wrong.

QPC Has quite a few syncronization issues, especially on processors that can change their speed dynamically. timeGetTime dosnt have these issues. TGT has much less overhead the QPC anyways. So QPC is infact a possiblity, but in my opinion, it's disadvantages outweigh it's advantages...

Dima
02-15-2004, 10:47 AM
I understand now, all makes sence to me. I think this is why I am getting low FPS reading when nothing is rendered, because TimeGetTime() returns at lease 1 ms? With the MS framework i get about 450 FPs in a 640x480 window with nothing rendered but the FPS text, with this wrapper I get around 300 FPS with empty screen and text, guessing it's in the timer :unsure:

I need to go to work now, but when I come back i'll look over the code of the wrapper to see ho0w things work, very interested in learning. I'll write some more useless stuff on this board when I come back,

peace, Dima

bladder
02-15-2004, 08:32 PM
With the MS framework i get about 450 FPs in a 640x480 window with nothing rendered but the FPS text, with this wrapper I get around 300 FPS with empty screen and text, guessing it's in the timer :unsure:
Also dont forget that the game loop in the game loop in the kit is doing a lot more then what the dx sdk framework does,

scene management, audio updating, input processing and quite a few different checks for different hings.

Dima
02-15-2004, 10:51 PM
apptime += (float)(ms/1000.0f);
onesecond += ms;
frames++;

if (onesecond > 1000)
{
fps = (float)(frames / (onesecond / 1000.0f));
frames = 0;
onesecond -= 1000;
}


this is my FPS code now :P , works quiet well, using 1/ms gives me 250 fps one second, next is 335, so it jumps around every second by a huge number, using frames/second gives a nice output, I get between 277 and 279 with a rotating sphere.

Dima
03-13-2004, 11:16 AM
Hey man, it's me again

Been using your dxw for a few now, and im getting things done, which is a good thing. The lightweight is very nice for performance, and everyhing is organised efficiently.

Actually I have a contribution, and a suggestion. The contribution is a 'Vertex Cache' class, basically a dynamic vertex/index buffer (modified code from dxmvp site) it works quiet well i think, but maybe you will see something I don't.

The suggestion is for the timing. There's a good article on this Here (http://www.gamasutra.com/features/20010713/dickinson_01.htm) and I also think this is more suitable for games. Basically it's separating simpipe from renpipe execution. so you execute code at sertain frequency but render every frame, sortof like this:



execution_time += ElapsedTimeInMs;
while(execution_time > 10) // 10 ms (100Hz)
{
UpdateInput();
UpdateWorld()
execution_time -= 10; // account for lost time

}
RenderFrame();



Hehe, this solution works quiet well, and the article linked explains more benefits to that system, and it's very easy to implement.

Here's the source for my VertexCache

// VertexCache.h: interface for the CVertexCache class.
//
//////////////////////////////////////////////////////////////////////
#include <d3dx9.h>

#ifndef VERTEXCACHE_H
#define VERTEXCACHE_H

class CVertexCache
{
LPDIRECT3DVERTEXBUFFER9 m_vBuf;
LPDIRECT3DINDEXBUFFER9 m_iBuf;
public:
HRESULT Flush(LPDIRECT3DDEVICE9 lpDevice);
HRESULT Start(LPDIRECT3DDEVICE9 lpDevice);
HRESULT Draw(LPDIRECT3DDEVICE9 lpDevice,UINT numVertices,UINT numIndices,const WORD *pIndexData,
const void *pVertexStreamZeroData);
CVertexCache(LPDIRECT3DDEVICE9 lpDevice,UINT maxVertices,UINT maxIndices,UINT stride,DWORD fvf,DWORD processing);
virtual ~CVertexCache();
DWORD m_fvf;
UINT m_maxVertices;
UINT m_numVertices;
UINT m_maxIndices;
UINT m_numIndices;
UINT m_stride;
BYTE *m_vertPtr;
WORD *m_indPtr;
int numflush;
};

#endif


and the cpp file

// VertexCache.cpp: implementation of the CVertexCache class.
//
//////////////////////////////////////////////////////////////////////

#include "VertexCache.h"

#define SAFE_RELEASE(x) if (x) {x->Release(); x=NULL; }

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CVertexCache::CVertexCache(LPDIRECT3DDEVICE9 lpDevice,UINT maxVertices,UINT maxIndices,UINT stride,DWORD fvf,
DWORD processing)
{

// create the vertex buffer
m_vBuf=NULL;
lpDevice->CreateVertexBuffer(maxVertices*stride,
D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY|processing,
fvf,D3DPOOL_DEFAULT,&m_vBuf, NULL);

// create the index buffer
m_iBuf=NULL;
lpDevice->CreateIndexBuffer(maxIndices*sizeof(WORD),
D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY|processing,
D3DFMT_INDEX16,D3DPOOL_DEFAULT,&m_iBuf, NULL);

// clear the vertex and index counters
m_numVertices=0;
m_numIndices=0;

// save buffer sizes, vertex format, and stride
m_maxVertices=maxVertices;
m_maxIndices=maxIndices;
m_stride=stride;
m_fvf=fvf;

// clear buffer pointers
m_indPtr=NULL;
m_vertPtr=NULL;
numflush=0;
}

CVertexCache::~CVertexCache()
{
// release vertex and index buffers
SAFE_RELEASE(m_vBuf);
SAFE_RELEASE(m_iBuf);
}

HRESULT CVertexCache::Draw(LPDIRECT3DDEVICE9 lpDevice,UINT numVertices, UINT numIndices, const WORD *pIndexData,
const void *pVertexStreamZeroData)
{
HRESULT hr;

// will this fit in the cache?
if (m_numVertices+numVertices>m_maxVertices||
m_numIndices+numIndices>m_maxIndices)

// no, flush the cache
Flush(lpDevice);

// check to see if we have pointers into buffers, lock if needed
if (!m_indPtr)
{
if (FAILED(hr=m_iBuf->Lock(0,0,(void **) &m_indPtr,D3DLOCK_DISCARD)))
return hr;
}
if (!m_vertPtr)
{
if (FAILED(hr=m_vBuf->Lock(0,0,(void **) &m_vertPtr,D3DLOCK_DISCARD)))
return hr;
}
// copy the vertices into the cache
memcpy(&m_vertPtr[m_stride*m_numVertices],pVertexStreamZeroData,m_stride*numVertices);

// save current index count
int startInd=m_numVertices;

// loop through the indices
for (int i=0;i<numIndices;i++) {

// add the index
m_indPtr[m_numIndices]=((pIndexData!=NULL)?pIndexData[i]:i)+startInd;

// increment the index counter
m_numIndices++;
}

// adjust vertex counter
m_numVertices+=numVertices;


// return success
return S_OK;
}

HRESULT CVertexCache::Flush(LPDIRECT3DDEVICE9 lpDevice)
{
HRESULT hr;

numflush +=1;

// unlock the vertex and index buffers
if (m_indPtr) {
m_iBuf->Unlock();
m_indPtr=NULL;
}
if (m_vertPtr) {
m_vBuf->Unlock();
m_vertPtr=NULL;
}


// are there triangles to render?
if (m_numIndices&&m_numVertices)

// yes, render them
if (FAILED(hr=lpDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
0,0,m_numVertices,
0,m_numIndices/3)))
return hr;


// clear the vertex and index counters
m_numVertices=0;
m_numIndices=0;

// return success
return S_OK;
}

HRESULT CVertexCache::Start(LPDIRECT3DDEVICE9 lpDevice)
{
HRESULT hr;

// set the index buffer, vertex buffer, and shader for the device
lpDevice->SetIndices(m_iBuf);
lpDevice->SetStreamSource(0,m_vBuf,0,m_stride);
lpDevice->SetFVF(m_fvf);

// clear the vertex and index counters
m_numVertices=0;
m_numIndices=0;

// lock the vertex and index buffers
m_indPtr=NULL;
if (FAILED(hr=m_iBuf->Lock(0,0,(void **) &m_indPtr,D3DLOCK_DISCARD)))
return hr;
m_vertPtr=NULL;
if (FAILED(hr=m_vBuf->Lock(0,0,(void **) &m_vertPtr,D3DLOCK_DISCARD)))
return hr;

// return success
return S_OK;
}



I hope I am of any help. And once again I love the dxw.
Dima

bladder
03-14-2004, 03:38 AM
The suggestion is for the timing. There's a good article on this Here and I also think this is more suitable for games. Basically it's separating simpipe from renpipe execution. so you execute code at sertain frequency but render every frame, sortof like this:


Heh, this is straight out of Core.cpp in the 1.5 release from the Loop() function :)


mAudioPass += mFMS;

if( mAudioPass > mAudioFrequency )
{
AudioDevice::UpdateAll();
mAudioPass -= mAudioFrequency;
}

mInputPass += mFMS;

if( mInputPass > mInputFrequency )
{
InputBase::ProcessAll();
mInputPass -= mInputFrequency;
}


So that's already in there. I havent applied it to the Core::Update function though. Because applying something like that to the games "updateWorld" function is pretty much the same as limitting someones frame rate. It ruins the whole point of frame rate independant movement (FRIM). The point of FRIM is that:

1) People with higher frame rates will see smother animations and movements
2) It wont matter it the game is running at 10 fps or 1000 fps, things will always happen in uniform time.

When you apply the "Only update evety X seconds" to a game, advantage number 2 is still available so object movement timings wont be effected, BUT advantage number 1 (smoother animations) will be taken away from the people that payed more money for their systems.

The article has a good reason for doing this though, because it would be needed for the replay thing as to not produce extra (or less) frames in the replay, but I would assume that it would be most convenient for a console game, since consoles have fixed hardware and limiting frame rate there would not be a problem because a games frame rate will be the same on every single PS2 or XBOX. But with a PC you have a million and one different combinations of hardware that will produce different frame rates.

However, keeping the first advantage of FRIM is somewhat debatable, cause lets face it, who's going to really notice if a certain animation had 60 frames in the last second or 80 frames... I've already applied it to user input and audio file updation in the Core, I dont know if I'll apply it to the Update function though. I'm not too sure if Ill be applying it to the Update function though, will have to think about it some more.

Actually I have a contribution, and a suggestion. The contribution is a 'Vertex Cache' class, basically a dynamic vertex/index buffer (modified code from dxmvp site) it works quiet well i think, but maybe you will see something I don't.

Excellent! Definetly something Ill be adapting into the dxw release after the next one :yes: Thanks.

Dima
03-14-2004, 11:00 AM
I see what you mean about limiting the Update. I seem to have this problem though, I get jerky movement from the camera, i have a scrolling camera, and I get the effect of 1 object being seen in two places at once depeending on the scrol speed. This 'Jitter' effect seems to be caused by other processes happening.

How can I get my game to run super smooth? I tried averaging last 30 or so elapsedtimes and that helped a little but still, it was jerky. Tried this on my cousins' comp, he's got a 2ghz 1gb ram sys, game stil seems to run choppy. Maybe it's the timing function? He get's like 600 fps, i get around 120. Game seems to run smoother on my computer.

I tried using the other method, updating the world with a freq, and it made no difference at 100hz, but when I set my update to 1ms, the game just started running as smooth as I could imagine. Basically code was getting executed 10 times or so, and then rendering once. This gave me unbelievable results in fullscreen at 75fps, windowed ran faster (with no VSYNC) at 120 fps, but windowed is 640x480 res. BTW, how to change fullscreen res in the DXW?

Basically im using alot of dynamic geometry, and when i update world 10 times and render once, the gameplay was incredibly smooth. I'll look into this more to find a good way to make the game run very smooth using one update and one render, and arbitary fms.

Dia Kharrat
03-14-2004, 11:59 AM
Try using the QueryPerformanceCounter function for the timer update. I believe that should give you a smoother and more accurate effect.

bladder
03-14-2004, 07:21 PM
I know exactly what you mean about this camera jitter thing, The same thing happened when I implemented the Camera class a few weeks ago. It's like the camera would switch between two angles really fast and render one the first frame and another the second frame and so on...

Mind you, I did fix it however. I dont really remember what the problem was though :D. The next release is actually ready and it has all these improvements and everything. Its just that Im having some website related problems which will hopefully be solved some time soon so that I can upload the new release...

The switching between fullscreen can also be achieved by using the console in the next release, and by pressing ALT+ENTER. For a temporary fix (just until the next version is released) you can check out the thread just below the "mysql warning" thread. I think that has a temporary fix that you can add somewhere.

Dima
03-15-2004, 09:29 AM
Wow, I cant believe the new release will have all these new refinements. Great work.

Still wondering how you fixd the camera jitter, hehe. I compute vector in XY plane from camera xy position to the player xy, then mutliply that vector by the timeelapsed. vec*(ms/1000), this makes the camera 'follow' something, so the further player gets away from the camera, faster the camera travels to catch up. Same thing for the lookat point for the camera. This helps with the jitters somewhat, but at low fps even 37, i see two of things, so I dunno...

Again though, I am impressed with how much you'r putting into the DXW, good work my man, i could really use a console and a few UI parts about now ;7

Dima

bladder
03-16-2004, 05:34 AM
I've just implimented an FPS style camera so far. strafe left, right, mouse look, and forward back/up down. If I remember correctly, I got rid of the jitter by playing with how the view matrix was created (I remember playing around with order of operations a lot). I know its not the answer you're looking for but I really cant remember what the problem was.

Find a few camera tutorials on the net, and see how they do things, maybe you'll find something that you're forgetting to do, or something you are doing that you shouldnt be doing.

UI parts is on the todo list. I actually have such a huge todo list its scary, sometimes I dont know what to do next even though the list is huge.

Dima
03-16-2004, 09:32 AM
Sounds good,

My camera is pretty smooth at 75 fps now, I did this weid thing by checking for irregular returns from the timeGetTime() function. Sometimes the function will return consecutive numbers, and that'll jerk gameplay by rendering the same frame again.

at around 37 FPS camera seems jittery, the gameplay is smooth but everything kinda blurs out and I see two of objects, gives me a headache after a while looking at that. at high fps everything is smooth though. Maybe 37 fps is supposed to be like that, but i get a 2 millimeter offset, and see two images at that distance. I'm Rendering and Updating once per frame, not by a frequency. If camera moves slow the effect is less notisible.

When is the next release coming out? :D

bladder
03-17-2004, 04:08 AM
When is the next release coming out?

Any day now. (most probably) Within the next week (s) for sure maybe (It seems too dangerous to give an exact date :P).

In all seriousness though, before the end of this week.