Archived

This topic is now archived and is closed to further replies.

DC_Tsunami

2D GUI cursor problem

Recommended Posts

DC_Tsunami    122
I''m just starting out on my game, and I want to create a 2D GUI for it. The whole game is going to be in OpenGL, so that''s what I''m using, as I want to develop for Mac, Linux, and Windows. Anyway, I came up with two ways to render the GUI. The first way involves drawing the background from an image buffer using glDrawPixels(), drawing each button, and then drawing the mouse cursor. I found that when I did this, it absolutely killed the framerate, apparently because it takes a long time to draw an 800x600 image every frame. So I came up with a different way of doing this. I render the background once, in the first frame. I then draw all of the buttons in every frame (a different image is drawn if the mouse moves over them, or the mouse is clicked, or the appropriate hotkey is pressed, etc, so they need to be updated), and finally, I draw the mouse cursor. Since the mouse cursor moves, instead of just drawing it, I use glReadPixels() to save the place where the mouse is about to be drawn. Then I render the mouse there and the rendering for that frame is over. In the next frame, I replace the cursor with the saved image, and repeat the process. This increased framerate dramatically, to the point where the GUI was very usable. However, it did introduce one problem, which is the topic of this post (I''m getting to it! =] ). Wherever the mouse cursor goes, it leaves a trail of slightly garbled pixels. The cursor is definitely not visible after it has left, but the background looks kind of weird at that spot. Also, the longer the cursor stays in one place, the uglier it gets after it leaves (the cursor itself is unchanged, just the trail behind it). I suspect there is a problem in the way I''m using glReadPixels() and glDrawPixels(). Something is awry and it feeds back every frame. However, I''m pretty sure I''m using both functions correctly.
  
glReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels->data[0] );

glDrawPixels( handle->width, handle->height, (handle->bytes == CT_RGB) ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, handle->data[0] );
  
A couple things to note: the reason it''s data[0] and not just data is because the class I''m using supports animation. data is an array of frames; data[0] is the image buffer of the first (and only) frame. The types for data and data[0] are char** and char* respectively. CT_RGB is a constant that is used by the class. Fairly self explanatory. Oh, and handle is a pointer to the saved image (or any image that needs to be drawn for that matter). If anyone can help me, I would really, really appreciate it. I would be happy to post more code if it would help solve the problem. Again, thanks in advance!

Share this post


Link to post
Share on other sites
Shag    122
A quick question ... why are you using glReadPixels? Surely if you just draw the cursor last of all, at the current mouse position, the problem wouldn't exist.

However - are you using blending in any way? maybe that could cause visual artifacts, though from your description it seems like something else. Or maybe you're storing a 32 bit image in 24 bits? Maybe you're reading from the wrong location (xy coords). Is your data sructure appropriate for the pixel data? Are you mixing signed/unsigned data types?

Just a couple of quick ideas!

Regards

EDIT - Do you have a screen shot?

[edited by - Shag on May 6, 2002 11:33:30 PM]

Share this post


Link to post
Share on other sites
DC_Tsunami    122
I am using glReadPixels() and glDrawPixels() to save and redraw the pixels behind the mouse cursor in every frame. This is so that I don''t have to clear and redraw the entire GUI every time. glClear() is only called once at the beginning. Blending... I thought it might be that too, since it kind of looks blended. However, I did make sure to disable blending before that, and nothing changed. As for thirty-two bit vs. twenty-four bit readings, I am definitely using twenty-four bit for both. This seemed like the problem for a while because it seems almost like the pixels are out of alignment or something. Hard to say. Location I will need to double check. I''m about 99% sure it''s right though. I will make sure though. What exactly do you mean by ''is my structure appropriate for the pixel data?'' The class I''m using should be capable of holding this type of data... I don''t see any reason why it wouldn''t. Finally, signed and unsigned, everything is unsigned. Whenever I''m dealing with pixels I make sure to use unsigned char.

Thanks a lot for your suggestions. I will try reading and writing in 32-bit next and see if that makes a difference (the actual pixels are 32-bit I believe, but the glReadPixels() command is for 24-bit... that wouldn''t make a difference, would it? Hmm...). I''ll see if I can get a screenshot later tonight. Assuming your e-mail address is correct, I''ll send it to you. Thanks =]

Share this post


Link to post
Share on other sites
Bruno    155
Don''t use glReadPixels or your GUI will run at 2 fps tops..
Just bled the cursor with the background, or if you don''t want your cursor mixed witht the background, use an alpha mask.
Check out www.cfxweb.net/~projectfy , there is a GUI system there.


Bruno

Share this post


Link to post
Share on other sites
Grizwald    270
Just use textured quads. They are a WHOLE lot faster. save your perspectiv matrix, go to ortho, and BANG! Render some quads...easier too!

Share this post


Link to post
Share on other sites
ANSI2000    122
Yeah using textured quads will dramatically increase performance also you will be able to make rel nice effects...

Share this post


Link to post
Share on other sites
DC_Tsunami    122
Textured quads are nice, but they don''t allow me to use images with dimensions that are not powers of two. Is there any way around this besides just resizing the image in some graphics program?

Bruno~ the reason the GUI is not running at 2 fps is because the _only_ things I''m drawing each frame are the buttons and the cursor. I only draw the background once and I do not use glClear() in each frame.

Share this post


Link to post
Share on other sites
a person    118
just because you have to laod a texture that is a power of two dont mean that you have to use the entire texture when texturing a polygon. ie, dont use 1.0, 1.0 as your u,v coordinates. instead use realImageWidth/powerofTwoImageWidth and do the same of height.

also i highly suggest NOT reading from the backbuffer. not only is that a stupid, moronic, and ignorent thing to do, its not garunteeded to work. many drivers dont garuntee what you get in the backbuffer. they may do double buffering internal, triple buffering, or single buffereing (the one you want for it to work). they may flip the buffer (not good for you, but great for speed and evryone else), or simple blit the data (a copy which increases bandwidth usage, but is what you want to keep the back buffer consistent). opengl dont give you much control over this.

better way. DONT use glDrawPixles() to copy an image buffer, thst slow as well depending on driver implementation. either:
1. draw the entire scene each frame. no calls to glReadPixels() glWritePixels() glDrawPixels() pure polygon drawing only.
2. draw the background to a texture, then each frame draw the texture with the background as a quad filling the portion it should.

reading from vram is slow. writing directly to the backbuffer while 3d operations could be taking place is SLOW.

Share this post


Link to post
Share on other sites
DC_Tsunami    122
Thanks everyone for the replies. I knew reading/writing pixels was slow, but not THAT slow, and not that dodgy, so thanks very much for the information.

Here''s what I came up with for non-power-of-two images. I will write a few methods that will split an image into many different images that ARE powers of two, (for instance, an image width of 800, would become 512, 256, and 32), load those as GL_NEAREST filtered textures, map them onto a bunch of quads and put the textured quads in a display list. When I draw the buttons, background, cursor, etc, I''ll translate to the appropriate place in ortho, and call the list.

Does that sound workable?

Share this post


Link to post
Share on other sites