2D myst-like engine under direct3D

Started by
7 comments, last by amarhys 18 years, 3 months ago
Hello, My name is Xavier, I am french (that's why my english is not perfect) and I just registered to Gamedev.net today. I am currently working on a 2D myst-like game. One year ago, I released a first demo which can be downloaded at http://www.amarhys.com website (both in French and English). The game engine is a 2D riven-like, I mean a slide show game with some animations on top of the main view. The first demo was developed using standard WIN32 GDI functions and to improve performances, I decided to implement a DirectX engine. I read many topics on Gamedev forums and I found a 2D tutorial too : http://www.gamedev.net/reference/articles/article1972.asp I developed a first framework based on this tutorial but the result seems bad. Indeed, performances are worst than using GDI (I tried first with the menu of the game and it is slow !). The display layout is as described below : 1) a background texture/image (fullscreen 1024x768) 2) 3x7 textures/images for menu items (about 400x80 each one, all differents) All 22 associated bitmaps are stored as "files" in system memory. Render() function blits 8 "IDirect3DTexture9" textures on 8 quads for each render pass : - 1 for background - 7 for menu items Content of "IDirect3DTexture9" textures for menu items are udpated depending on mouse position (update means released then loaded again from correct bitmap in memory). Render() function is executed in "else" condition of windows messages processing queue (i.e when no message is being processed). And the display seems very slow. I guess the way I used DirectX in my application is not optimized. Then, I have some questions (I am a "very beginner" in Direct3D and I did not find on Gamedev any topics for "Direct3D + 2D" clear enough for me :-))) : 1) Instead of blitting 8 textures on 8 quads, I guess I could blit only one texture on . I would have build this texture from n bitmaps. Is it possible ? How could I built such texture ? Is it the "batching" ? 2) Maybe I could execute Render() command in another place ? In a timer callback for example ? or a DirectX callback which is synchronised with Video Card refresh ? Does such callback exist ? I saw a onRenderFrame callback somewhere but I did not remember where :-) 3)Is blitting texture on quads is the best way to display 2D graphics ? What about sprites ? All bitmap I will manage are big size for most of them. Thank you for reading this long email. I hope someone could help me. And an HAPPY NEW YEAR 2006 to everybody. Cheers Amarhys
Advertisement
Quote:Original post by amarhys
Hello,

My name is Xavier, I am french (that's why my english is not perfect) and I just registered to Gamedev.net today.

Welcome to GameDev.net. And your English is great, by the way [smile]

Quote:The display layout is as described below :
1) a background texture/image (fullscreen 1024x768)
2) 3x7 textures/images for menu items (about 400x80 each one, all differents)

All 22 associated bitmaps are stored as "files" in system memory.

Render() function blits 8 "IDirect3DTexture9" textures on 8 quads for each render pass :
- 1 for background
- 7 for menu items

Rendering 8 textures with the sizes you mention is a trivial operation to any modern GPU, so you shouldn't get any bad performance. What I'm concerned about now is what you mean by "are stored as files in system memory". Do you create your IDirect3DTexture9 objects in the system memory pool? (D3DPOOL_SYSMEM IIRC).

Quote:Content of "IDirect3DTexture9" textures for menu items are udpated depending on mouse position (update means released then loaded again from correct bitmap in memory). Render() function is executed in "else" condition of windows messages processing queue (i.e when no message is being processed).

What do you mean by the "content is updated"? Writing to textures is a slow process. Unless you're using dynamic textures, in which case it's supposed to be faster (never used them in a practical situation).

Quote:1) Instead of blitting 8 textures on 8 quads, I guess I could blit only one texture on . I would have build this texture from n bitmaps. Is it possible ? How could I built such texture ? Is it the "batching" ?

Yes, that'd be batching the 8 calls into one. It wouldn't improve performance much for your case, though. Your problem is 99% something else.

Quote:2) Maybe I could execute Render() command in another place ? In a timer callback for example ? or a DirectX callback which is synchronised with Video Card refresh ? Does such callback exist ? I saw a onRenderFrame callback somewhere but I did not remember where :-)

No, you're doing it the right way - rendering when there are no messages.

Quote:3)Is blitting texture on quads is the best way to display 2D graphics ? What about sprites ? All bitmap I will manage are big size for most of them.

Yes, it is. Sprites (ID3DXSprite) does this under the hood for you, but it gives you the additional benefit of batching renders together if possible.

Thank you very much for your answer Muhammad.

And HAPPY NEW YEAR 2006 !!

To clarify some points from my previous post :

1) At game initialization (i.e only one time forever for one application running), bitmaps which are intented to be used often (it is the case for menu interface) are loaded into system memory (I mean a simple binary copy from the file on the disk to the system memory).
Then, when I need to display one of them, I load its copies in a IDirect3DTexture9 texture using D3D buit-in function "D3DXCreateTextureFromFileInMemoryEx" (I cannot use directly "D3DXCreateTextureFromFileEx" function as all the bitmap files are concatenated together in a global database file - to prevent the user from seeing the images before playing the game - and "D3DXCreateTextureFromFileEx" does not support an file which is already opened with a specific file pointer position.

Here is the function call :
D3DXCreateTextureFromFileInMemoryEx (d3dDevice, (LPCVOID)fm->buf, fm->fSize, 0, 0, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_DEFAULT, colorkey, &SrcInfo, NULL, &(texture.texture)


For the first display of the menu, I call 8 times the function "D3DXCreateTextureFromFileEx" for the background and the 7 initial menu items. These textures are then rendered each time Render() is executed.

Here is the code to blit the texture (taken from the tutorial from Gamedev) :
struct TLVERTEX{    float x;    float y;    float z;    float rhw;    D3DCOLOR colour;    float u;    float v;};.........void BlitD3D (IDirect3DTexture9 *texture, RECT *rDest, D3DCOLOR vertexColour){	TLVERTEX* vertices;	//Lock the vertex buffer	vertexBuffer->Lock(0, 0, (void **)&vertices, NULL);	//Setup vertices	//A -0.5f modifier is applied to vertex coordinates to match texture         //and screen coords	//Some drivers may compensate for this automatically, but on others         //texture alignment errors are introduced	//More information on this can be found in the Direct3D 9 documentation	vertices[0].colour = vertexColour;	vertices[0].x = (float) rDest->left - 0.5f;	vertices[0].y = (float) rDest->top - 0.5f;	vertices[0].z = 0.0f;	vertices[0].rhw = 1.0f;	vertices[0].u = 0.0f;	vertices[0].v = 0.0f;	vertices[1].colour = vertexColour;	vertices[1].x = (float) rDest->right - 0.5f;	vertices[1].y = (float) rDest->top - 0.5f;	vertices[1].z = 0.0f;	vertices[1].rhw = 1.0f;	vertices[1].u = 1.0f;	vertices[1].v = 0.0f;	vertices[2].colour = vertexColour;	vertices[2].x = (float) rDest->right - 0.5f;	vertices[2].y = (float) rDest->bottom - 0.5f;	vertices[2].z = 0.0f;	vertices[2].rhw = 1.0f;	vertices[2].u = 1.0f;	vertices[2].v = 1.0f;	vertices[3].colour = vertexColour;	vertices[3].x = (float) rDest->left - 0.5f;	vertices[3].y = (float) rDest->bottom - 0.5f;	vertices[3].z = 0.0f;	vertices[3].rhw = 1.0f;	vertices[3].u = 0.0f;	vertices[3].v = 1.0f;	//Unlock the vertex buffer	vertexBuffer->Unlock();	//Set texture	d3dDevice->SetTexture (0, texture);	//Draw image	d3dDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);}


I have read somewhere that lock/unlock procedure could be time/cycle consuming ? In my case, it is executed sequentially for the 8 textures to display.


2) When the mouse moves, menu items need to be updated (2 textures are updated each time: a new item is highlighted and the previous higlighted item will become normal). To update the textures, I execute IDirect3DTexture9->Release() and D3DXCreateTextureFromFileInMemoryEx again. Is there a faster way (in CPU/GPU cycles point of view I mean) to update a texture ?

Now, what I could do to optimize texture management is to create directly in memory "one time forever" all IDirect3DTexture9 textures which are often used (menu items, menu background, inventory background, inventory items ..). Then, instead of doing "release + create" to update the textures to be displayed I would just have to swap the IDirect3DTexture9 pointers.

For "almost one used" texture (game view), I can keep on using "release + create", right ? What about IDirect3DTexture9->Update ? Could I use it ? How does it work ?


3)A last point (sorry for such big messages) : I noticed "bad performances" because of the poor reactivity of the menu display with mouse moves. Maybe D3D is not the issue but rather mouse managing. I still use standard message queuing for the mouse (i.e WM_MOUSEMOVE, WM_LBUTTONDOWN, ...). Maybe I should use DirectInput for better performances ?

One time again, thanks a lot for your answers.

Amarhys
Quote:Original post by amarhys
And HAPPY NEW YEAR 2006 !!

Happy new year [smile]

Quote:
Then, when I need to display one of them, I load its copies in a IDirect3DTexture9 texture using D3D buit-in function "D3DXCreateTextureFromFileInMemoryEx" (I cannot use directly "D3DXCreateTextureFromFileEx" function as all the bitmap files are concatenated together in a global database file - to prevent the user from seeing the images before playing the game - and "D3DXCreateTextureFromFileEx" does not support an file which is already opened with a specific file pointer position.

Creating textures - and resources in general - in Direct3D is an expensive operation that should typically be done during the initialization/loading stage only. You can initially create a number of IDirect3DTexture9s and load them with the nearest 20 textures from your current location (Assuming this is an adventure game where each screen has some exit points that lead to other screens, you can tell, give a screen, what the neighboring screens are).

Quote:Here is the code to blit the texture (taken from the tutorial from Gamedev) :
*** Source Snippet Removed ***

It seems that the code doesn't use a dynamic vertex buffer, because it doesn't use the lock flag D3DLOCK_DISCARD. When you're locking and writing the contents of a vertex buffer often, make it dynamic.

Alternatively, for small numbers of vertices like what you're doing: you can use DrawPrimitiveUP, passing it a pointer to your array, and it'll do the dynamic buffer management under the hood.

Quote:2) When the mouse moves, menu items need to be updated (2 textures are updated each time: a new item is highlighted and the previous higlighted item will become normal). To update the textures, I execute IDirect3DTexture9->Release() and D3DXCreateTextureFromFileInMemoryEx again. Is there a faster way (in CPU/GPU cycles point of view I mean) to update a texture ?

This is what's killing your performance. Creating and destroying resources on the fly is a real time-consumer. Consider the following, more sensible approach:

1) Whe loading the menu, load the background texture, the normal and highlighted item textures.
2) Initially, each item's state is set to "normal".
3) When a mouse hovers over an item, switch its state to "highlighted".
4) When a mouse moves out of an item, switch its state to "normal".

When rendering an item, set the corresponding texture to the device. If it's highlighted, set its highlighted texture. Otherwise, set the normal one.

That way, you totally remove the create/destroy calls to initialization and destruction (menu exit), which is the usage scenario Direct3D was designed to handle.

Quote:Now, what I could do to optimize texture management is to create directly in memory "one time forever" all IDirect3DTexture9 textures which are often used (menu items, menu background, inventory background, inventory items ..). Then, instead of doing "release + create" to update the textures to be displayed I would just have to swap the IDirect3DTexture9 pointers.

Exactly. Whenever you know you'll need texture X for sometime, load it beforehad and keep it.

Quote:For "almost one used" texture (game view), I can keep on using "release + create", right ? What about IDirect3DTexture9->Update ? Could I use it ? How does it work ?

Well, no. Don't keep releasing + creating unless you really have to. As for IDirect3DTexture9::Update, there's no such function [smile]. Perhaps you meant IDirect3DDevice9::UpdateTexture? This one works exactly as it says in its documentation page - I don't know anything else to add.

Quote:3)A last point (sorry for such big messages) : I noticed "bad performances" because of the poor reactivity of the menu display with mouse moves. Maybe D3D is not the issue but rather mouse managing. I still use standard message queuing for the mouse (i.e WM_MOUSEMOVE, WM_LBUTTONDOWN, ...). Maybe I should use DirectInput for better performances ?

No, nothing wrong with window messages. I've seen it recommended more than once over DirectInput, though I usually don't use DirectInput so I can't tell whether it's better or worse (performance-wise).

You have good taste in games. Myst forever! [grin]

Your game looks awesome. Great artwork. I'm currently at work so i couldn't browse your site that much, so i'm sorry if these questions are answered there:

- When are you planning to release it?
- Will it be free?

Keep up the good work!

(Sorry but i can't help with your questions.)
- blew
Hi

Thanks Muhammad [smile]

I found why D3D performances were so bad !

First, let me answer quickly to Blew :
Quote:
You have good taste in games. Myst forever!

Your game looks awesome. Great artwork. I'm currently at work so i couldn't browse your site that much, so i'm sorry if these questions are answered there:

- When are you planning to release it?
- Will it be free?

Keep up the good work!

- Yes, the game will be 100% free (but do not expect a 50 hours game, it should be a short game)
- Today, there's no real planning for the release. I would answer : when ready

Now, let us come back to D3D performances :

Looking carefully on message queue processing, I noticed that many WM_PAINT messages were sent (coming from previous GDI implementation, automatically sent by InvalidRect() functions). I removed all these messages and now the D3D performances are OK. Great !!

Just an additional question concerning IDirect3DDevice9::UpdateTexture function :
From SDK documentation, I understand that this function allows to copy a source texture to a destination texture when both texture sizes are identical. What I am looking for is a function to copy a texture as a part of another (for example, I have a 1024x1024 destination texture and I would like to copy a 256x256 source texture to destination texture at position 36,36). Does such function exist ? If not, how can I update only a portion of a texture ?

Thanks
Cheers

Amarhys
Check: Texture Sub-loading.

Quote:Original post by amarhys
- Today, there's no real planning for the release. I would answer : when ready


Please don't make this one vaporware. [grin]
- blew
Thanks for the link Muhammad, I found many others interesting Direc3D tutorials on this website.

Don't worry Blew, this game will be released ..... a day [smile]


Another simple question : how can I measure FPS for the display ?

Today, I use a simple counter. This counter is incremented by 1 each time entering the Render() loop. Every 1 second (I use a multimedia timer), I display the value of this counter and reset it. Is there a more accurate way to calculate FPS ?

Amarhys

This topic is closed to new replies.

Advertisement