Sign in to follow this  

Creating a GUI with Direct3D

This topic is 4841 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'm trying to create some sort of GUI in 2D using Direct3D for all it's features like hardware acceleration and alpha blending. I'm having a lot of trouble. I've got quite a lot of general Direct3D information, and 2D in Direct3D information but I'm having so much trouble handling all the small images that make up GUI elements in Direct3D with all it's limitations on texure sizes and other factors. Has anyone had any experience with this? I can't find anything on the net at all and I'm pulling my hair out trying to get D3D to draw a simple window frame using PNG files that contain all the elements. I could really do with talking to someone who has experience with 2D in Direct3D. I assume most modern, professional game GUIs use Direct3D (take Square Enix's PlayOnline Viewer for example). Am I right? Any help greatly appreciated. Many thanks, Daniel

Share this post


Link to post
Share on other sites
im doing the exact same thing right now: 2d gui in direct3d. im using dx8.

i havent had any problems loading jpgs, pngs, or bmps. i use pngs for 32 bit images and they seem to work very well. everything is texquad-based. lines, circles, windows, buttons, etc. resources are preloaded at startup, too. i load my textures up into a vector and whenever i want to texture a quad, i just pass it TextureVector[5] or something and it uses that texture.

make sure you have ur texquads down, complete with showing textures properly, setting position, rotation if needed, etc. then use them to make everything else. there are lots of examples on gamedev.net, but some worked for me and some didnt

another HUGE thing is that you have to have your texture stages set right or the quad will not be visible, or a flat color.

Share this post


Link to post
Share on other sites
I use ID3DXSprite to handle GUI drawing, but the doco is not so good. It took me a while to get stuff drawing at the right place on the screen with the right scale. As far as the power-of-two texture sizes are concerned my artist ensures the gui image files are power-of-two in size so that they don't get stretched/filtered by D3DXCreateTextureFromFileEx() to a power-of-two size when loading (because that just reduces quality). Whether multiple GUIs are packed into a single texture and how they're packed is up to the artist in my case. ID3DXSprite also takes care of batching for you - you call Begin() and then a number of Draw() calls and then End() will sort by texture (if that's the sorting criteria you've chosen) and render in batches.

Also the latest release of dx9 has a GUI but I've not tried it - I found out it was coming just after I finished implementing my own GUI - doh.

Share this post


Link to post
Share on other sites
Thanks for all the tips everyone.

I get the general ideas of how to do it, it's the actual details and code implementation that I'm having trouble with.

For example, everyone says the easiest way is to make your textures square sizes with square numbers. Ok, obviously all my GUI elements aren't going to be that size so how do I implement it all using only those texture sizes.

I think the kind of problems I'm having could only be solved by reading some rendering code or something to see it exactly how the textures, images, and quads all work together and how to write them to the screen.

Has anyone got any code they could give to me that I can have a look at?

Thanks,

Daniel

Share this post


Link to post
Share on other sites
Also, you can check for a texture caps flag D3DPTEXTURECAPS_NONPOW2CONDITIONAL. This allows you to use non-power of 2 textures under certain conditions which basically 2D rendering pretty much meets. Alot more cards seem to have this flag, definitely the geforce FX series and radeons.

Share this post


Link to post
Share on other sites
Just because the textures are square doesn't mean the quad you render them to needs to be square. D3D will happily stretch, mangle, and resize the texture to fit into whatever you specify. Further D3DX's texture from file command likely will happily load non-square textures and fiddle with them so you don't need to worry about the square requirements [but don't quote me on that...]

Share this post


Link to post
Share on other sites
Thanks.

I think I'm starting to work out how to do this. I need to get my brain thinking textures and quads and not thinking about how to render pixel perfect data to the screen as in DirectDraw

Share this post


Link to post
Share on other sites
Quote:


Just because the textures are square doesn't mean the quad you render them to needs to be square. D3D will happily stretch, mangle, and resize the texture to fit into whatever you specify. Further D3DX's texture from file command likely will happily load non-square textures and fiddle with them so you don't need to worry about the square requirements [but don't quote me on that...]



Quoted :P

If I understand what you're saying, what I could do is (If indeed D3DX functions do support it) load a non square texture into a square texture object, which would automatically be stretched to fit, and then load it onto a quad which was the same size as the original image, there-by stretch it back down again to look right.

Do you think this is possible and would it mangle the image being processed like that?

Daniel

Share this post


Link to post
Share on other sites
So, so far for my methods of how to render non square images to the screen easily but still supporting graphics cards that only support square power of two textures are:

1) Create textures the and then scale them in something like Photoshop to a supported size (e.g 32x32) and save them again. Then, when they are rendered to a quad of the correct size they'll be scaled back down to the right size.

Drawbacks: Possibly a pain for the artist and may also mangle the image during resizing up and back down.

2) Store the images normal size (e.g 20x10) and allow D3DX functions to scale them up to fit in a supported texture e.g 32x32. Then when they are rendered to a quad of the original size they will be scaled down to look right again.

Drawbacks: May also mangle the image during resizing up and back down.

3) New idea: Maybe have several different GUI components in one file that is a square power of two size. (i.e like what is often done with skin engines to store elements) and use the D3DXSprite interface which allows you to render a portion of a texture to the screen at once.

Drawbacks: relying on the D3DXSprite interface. (Does anyone know how I could do this without using the Sprite interface?) How to render a specified portion of a texture to a quad.

Share this post


Link to post
Share on other sites
#3 is the solution that I use, and I believe what the Microsoft sample SDK uses as well.

Just put all your GUI components into one 256x256 texture.

Use texture coordinates to represent each textures/sprite component you will be drawing from on the texture. For instance, your up scroll buton may be represented by the Rectangle(0.0, 0.0, 0.15, 0.15).

This has the added advantage of being extra fast as to draw all your gui components you only need one texture state change. You could also make one vertex buffer for all your relevant GUI components.

BTW, you do *not* have to use the ID3DXSprite interface to do this. In fact, you pretty much can use texture coordinates with any Direct3D implementation. You'll notice that most of the sample sprite classes in Direct3D use texture coordinates? By changing those coordinates, you change what part of the source image you are drawing from.

Share this post


Link to post
Share on other sites
With regard to irregular size GUI elements (or any other graphic), here is the strategy I use to get good results on non-power-of-two images:

1. Let's assume you're making a game element that you want to be 120x40. Your final power-of-two image is going to be 128x64, which is the next cheapest size available to you.

2. Create your actual graphics in (Photoshop/etc) using the correct aspect ratio, except make them larger to reflect the aspect ratio. In the example, your image needs to be AT LEAST 192x64 so that the final step of resizing to 128x64 does not cause upsampling in EITHER dimension. (Instead, we have 192 columns that will be compressed into 128, and 64 rows that will not be compressed at all.)

Always perform editing, adding text, working with layers, etc. on the full-size 192x64 image. Exporting into a game-usable texture is always the last step.

3. Resize (bicubic!!) the 192x64 image to 128x64, obviously you'll have to disable 'Preserve Aspect Ratio.' The image appears all squished up/distorted for now...

4. Respect the original aspect ratio when generating your vertices so the texture appears correct when rendered.

For me this process has had good results; since your textures have to be power of two, you might as well pack as much detail into them as possible. There should be minimal 'mangling' of the texture as it is resized, since there is never an upsample.

Obviously the method still isn't perfect, as your image will still be resampled twice: once in Photoshop (a high quality downsample) and once at run-time (HOPEFULLY a downsample!) Realistically, though, pixel-perfect results are basically impossible to obtain since your game could be running in any number of resolutions.

Note that this system basically assumes you have one texture per image file, as I prefer for simplicity. The drawback is that you can't render vertices in a 'batch' since every graphic requires switching to a new texture.

An alternative to this approach is the system with many GUI elements packed as efficiently as possible into a single texture (or multiple textures.) This has the obvious benefit of requiring fewer SetTexture calls, but the speed hit should be relatively minor if your GUI isn't ridiculously complicated.

Note that in a well designed D3D app the in-game units (120x40, etc) are resolution independent, but this doesn't affect the process. You should make your graphics even larger if you want additional detail when playing in high resolutions, such that the rasterization never involves upsampling your texture.

-Jay

Share this post


Link to post
Share on other sites
One more thing with regard to D3DPTEXTURECAPS_NONPOW2CONDITIONAL:

I wouldn't be surprised if some drivers that support this may just create an image that's too large and leave a lot of it blank. If that's the case, you're much better off doing things on your own! I have no evidence for that, just a thought.

-Jay

Share this post


Link to post
Share on other sites

This topic is 4841 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this