GUI, refreshing, image formats, etc...
GUI, refreshing, image formats, etc...
Hi all,
My OS's floppy and FAT drivers work( not very well :p ), so now I can load images off the floppy as a background image, my first problem is I can't find any non-compressed image formats ( or tools to convert to those formats ), second is a question: currently I refresh the background as much as I can ( so the mouse doesn't leave a trail ) is there a way i don't have to refresh the background at all ( even with the mouse moving ).
thx!
My OS's floppy and FAT drivers work( not very well :p ), so now I can load images off the floppy as a background image, my first problem is I can't find any non-compressed image formats ( or tools to convert to those formats ), second is a question: currently I refresh the background as much as I can ( so the mouse doesn't leave a trail ) is there a way i don't have to refresh the background at all ( even with the mouse moving ).
thx!
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
non-compressed image format: BMP
As for the mouse, the best solution is to use a hardware cursor. Since that's probably not available, you can try the following:
- Before you draw the mouse cursor, you make a copy of the data behind it.
- if you move the mouse, restore the copy, then make a new one. This will only makes drawing as expensive as the size of the mouse.
Should you want to draw to the screen, you can either:
- hide the mouse, draw, then restore the mouse
- make sure the mouse is nowhere near where you want to draw
- automatically update the stored image of the mouse.
If you use double buffering or page flipping, you can simply keep the backbuffer mouse-free, and only add/remove it when you copy or flip the image.
As for the mouse, the best solution is to use a hardware cursor. Since that's probably not available, you can try the following:
- Before you draw the mouse cursor, you make a copy of the data behind it.
- if you move the mouse, restore the copy, then make a new one. This will only makes drawing as expensive as the size of the mouse.
Should you want to draw to the screen, you can either:
- hide the mouse, draw, then restore the mouse
- make sure the mouse is nowhere near where you want to draw
- automatically update the stored image of the mouse.
If you use double buffering or page flipping, you can simply keep the backbuffer mouse-free, and only add/remove it when you copy or flip the image.
Since reading video-memory is typically quite slow, it might not be bad idea to indeed keep a buffer in memory, and add mouse when you move that to screen.
Ofcourse try to avoid updating more than you have to. There's no need to copy the whole screen every time something small changes. So you want to keep track of the regions that have actually changed, and only update those.
So.. if you keep a backbuffer, and the mouse moves, you copy the region where the mouse was from the backbuffer, and then copy the mouse cursor. Only complication then is that if your backbuffer is changed where the mouse is, you have to make sure you redraw the mouse as well.
There are lots of variations, but the key idea is to avoid drawing more than you actually have to, and to remember that unless you have offscreen bitmaps, it might be faster to keep a copy in memory, always edit that first, and then copy the relevant regions to screen, so you avoid having to read from the screen.
Ofcourse try to avoid updating more than you have to. There's no need to copy the whole screen every time something small changes. So you want to keep track of the regions that have actually changed, and only update those.
So.. if you keep a backbuffer, and the mouse moves, you copy the region where the mouse was from the backbuffer, and then copy the mouse cursor. Only complication then is that if your backbuffer is changed where the mouse is, you have to make sure you redraw the mouse as well.
There are lots of variations, but the key idea is to avoid drawing more than you actually have to, and to remember that unless you have offscreen bitmaps, it might be faster to keep a copy in memory, always edit that first, and then copy the relevant regions to screen, so you avoid having to read from the screen.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
Yeah, cursor is good candidate for special casing.
The idea of backing store is worth learning anyway, because it also works with stuff like menus which typically live only for a short amount of time, and which the user could browse relatively fast.
The idea of storing what is behind a window (like menu) is the "old" method in the sense that it doesn't require much memory, if you only use it for small windows which are expected to live for short amount of time. The disadvantage is the you need to invalidate the backing store if the contents behind the backed window change, which is the primary reason it only works best when you expect the window to be short-lived.
The modern variant is to go the other way, and start with the assumption that we have enough video memory (or at least RAM) to store the contents of each and every window, which are then "composed" to get the visible image you see. This naturally uses much more memory, but the advantage is that whatever you do with a certain window (redraw/move/resize/fade/hide/anything), you never have to invalidate the contents of another window, because you have the contents stored already.
If you then have hardware acceleration available to do the composition (basicly all you need is blit, with alpha if you allow alpha-channels for your windows), it becomes possible to do stuff like play a video behind a partially transparent window in a cheap way: no repaint of the top window is necessary, you just alpha-blit the transparent window on top of the video once per frame. If the windows have full alpha-channel, stuff like shadows will then be only a question of creating the shadow (which can be done either with software, with repeated alpha-blits of blackened mask of the window outline, or by letting shaders take care of the whole thing).
If you are aiming at low-end machines, without fast graphics cards, or small memory, then the traditional backing store approach is better. If you are aiming at modern desktop, plan to do accelerated drivers, and want all the modern eye-candy, you could forget about traditional backing stores, and just keep a separate buffer for each window.
YMMV.
The idea of backing store is worth learning anyway, because it also works with stuff like menus which typically live only for a short amount of time, and which the user could browse relatively fast.
The idea of storing what is behind a window (like menu) is the "old" method in the sense that it doesn't require much memory, if you only use it for small windows which are expected to live for short amount of time. The disadvantage is the you need to invalidate the backing store if the contents behind the backed window change, which is the primary reason it only works best when you expect the window to be short-lived.
The modern variant is to go the other way, and start with the assumption that we have enough video memory (or at least RAM) to store the contents of each and every window, which are then "composed" to get the visible image you see. This naturally uses much more memory, but the advantage is that whatever you do with a certain window (redraw/move/resize/fade/hide/anything), you never have to invalidate the contents of another window, because you have the contents stored already.
If you then have hardware acceleration available to do the composition (basicly all you need is blit, with alpha if you allow alpha-channels for your windows), it becomes possible to do stuff like play a video behind a partially transparent window in a cheap way: no repaint of the top window is necessary, you just alpha-blit the transparent window on top of the video once per frame. If the windows have full alpha-channel, stuff like shadows will then be only a question of creating the shadow (which can be done either with software, with repeated alpha-blits of blackened mask of the window outline, or by letting shaders take care of the whole thing).
If you are aiming at low-end machines, without fast graphics cards, or small memory, then the traditional backing store approach is better. If you are aiming at modern desktop, plan to do accelerated drivers, and want all the modern eye-candy, you could forget about traditional backing stores, and just keep a separate buffer for each window.
YMMV.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
I wanna add one more case where keeping the contents of every window separately is going to be good idea for performance: if you plan to run the GUI over network, then repainting the contents of a window will be relatively slow operation (because the window and the program it belongs to live on different sides of the network). In this case every repaint you can avoid will make the GUI feel faster.
I also want to clarify that when I say "repaint" I don't mean drawing the contents of the window to the screen, but requesting a program to come up with the contents of it's window. This can happen either because the GUI doesn't keep the contents cached and something on top of it changes, or because the program itself decides it wants to change the contents of one of it's windows. Obviously the latter cannot be avoided, but the modern "composition" method more or less eliminates the former.
I also want to clarify that when I say "repaint" I don't mean drawing the contents of the window to the screen, but requesting a program to come up with the contents of it's window. This can happen either because the GUI doesn't keep the contents cached and something on top of it changes, or because the program itself decides it wants to change the contents of one of it's windows. Obviously the latter cannot be avoided, but the modern "composition" method more or less eliminates the former.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
thanks for the replays, I am now doing this:
( at the end of mouse interrupt ) by getting rid of some global variables things will be better,
how do i read a BMP? how do I resize my BMP which could be 1024x786:32bpp to my 320x200:8bpp screen?
thx!
( at the end of mouse interrupt )
Code: Select all
put_back_Mouse(); // replace background over where mouse is
posMouse(mouse_x, mouse_y); // update global mouse position variables
get_back_Mouse(); // get the background image where mouse will be
pasteMouse(); // draw mouse
how do i read a BMP? how do I resize my BMP which could be 1024x786:32bpp to my 320x200:8bpp screen?
thx!
Remember that you want to put_back_mouse() before you draw where your mouse cursor is, and then get_back_mouse() afterwards to avoid screen-tearing if a program tries to draw on top of your mouse cursor.
BMPs are relatively nasty to read, unless you specifically make sure they are nice uncompressed or RLE compressed bitmaps. I'd suggest you use some easier-to-deal-with format. PCX used to be old-time favourite for people doing games back in DOS since the format is trivial and only does RLE compression (which is easy to deal with) but only allows 256 colors AFAIK. You can convert to truecolor as soon as you read ofcourse, but no alpha-channel that way. Ofcourse you wouldn't get alpha-channel with normal BMPs either.
If you are happy without a full alpha-channel, then the traditional approach is use one color (#FF00FF is classic) as the "transparent color". You can't have soft-edges then. Probably not a huge problem before your GUI is working.
For small things like the mouse cursor, you could use XPM format, which is basicly C-source you can #include. If you ask your image manipulation program to write an XPM for you, and open it in a text-editor, you can probably figure out how they work. At least GIMP does nice XPMs.![Smile :)](./images/smilies/icon_smile.gif)
The best option if you want full alpha is to go with PNG, and port libpng (which is very portable) since you don't want to deal with those manually. Since PNG gives you full 32-bit RGBA if you want, it's also very nice format for skinning GUI components. Then all you need is a image-scaler that allows you to leave adjustable insets unscaled, and you basicly dump it an image of a button (or full window for that matter), tell it the insets (how wide your borders are) and how big button you want to draw, and you can convert most existing desktop themes without too much work.![Wink ;)](./images/smilies/icon_wink.gif)
BMPs are relatively nasty to read, unless you specifically make sure they are nice uncompressed or RLE compressed bitmaps. I'd suggest you use some easier-to-deal-with format. PCX used to be old-time favourite for people doing games back in DOS since the format is trivial and only does RLE compression (which is easy to deal with) but only allows 256 colors AFAIK. You can convert to truecolor as soon as you read ofcourse, but no alpha-channel that way. Ofcourse you wouldn't get alpha-channel with normal BMPs either.
If you are happy without a full alpha-channel, then the traditional approach is use one color (#FF00FF is classic) as the "transparent color". You can't have soft-edges then. Probably not a huge problem before your GUI is working.
For small things like the mouse cursor, you could use XPM format, which is basicly C-source you can #include. If you ask your image manipulation program to write an XPM for you, and open it in a text-editor, you can probably figure out how they work. At least GIMP does nice XPMs.
![Smile :)](./images/smilies/icon_smile.gif)
The best option if you want full alpha is to go with PNG, and port libpng (which is very portable) since you don't want to deal with those manually. Since PNG gives you full 32-bit RGBA if you want, it's also very nice format for skinning GUI components. Then all you need is a image-scaler that allows you to leave adjustable insets unscaled, and you basicly dump it an image of a button (or full window for that matter), tell it the insets (how wide your borders are) and how big button you want to draw, and you can convert most existing desktop themes without too much work.
![Wink ;)](./images/smilies/icon_wink.gif)
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
As for resizing, you write a scaling routine, preferably with some filtering (for shrinking) and interpolation (for growing) if you want it to look good. As for reducing color-depth, that depends what kind of color management you use in your 256 color mode.
For shrinking, you can take a (properly weighted for sub-pixel accuracy) average of the area of the image that's covered by your low-resolution pixel.
For growing, you probably want to start with linear interpolation, which is simple and looks relatively ok.
The color reduction is harder, because it depends on how you allocate colors of the 256-color paletter. Probably easiest thing is to use a constant 6x6x6-color space, in which case you simply rescale the 24-bit 0-255 values to 0-5, then combine the channels by multiplying and adding (you can't use bitshifts like in 16-bit or 24-bit truecolor modes because 6 is not a power of two, but the idea is the same). That will allow treating the screen like if it was a true-color display.
For single images you get better results by finding the optimal palette instead. Finding the optimal palette then, is another good question, but I'll not go into that, because I've never tried doing it. The problem then is that if you use optimal palette separately for each image on screen, you have to switch between the palettes somehow, which will make all the other images colored wrong... so it's mostly a good approach for full-screen programs.
The 6x6x6 color cube will look much better if you DON'T use the classic "web-safe" colors, but instead take gamma into account. You can assume sRGB gamma of 2.0 so you could allocate the 6 values (of each channel separately ofcourse) such that their squares (when you consider minimum as 0, maximum as 1) lay on a straight line. This will avoid having 3/4 of the palette too dark for anything, but makes it harder to convert from 24-bit images, because you then need to gamma correct those first (take the square root of each value, where again 0 is minimum, 1 is maximum... and do a lookup table for all 256 values because it makes no sense to do it at runtime). Hopefully I got the math right. Disclaimer: I haven't actually tried this, though I plan to, so while it's theoretically sound approach, I'm not sure how much it helps.
You could also do dither for images, but I think it's good idea to do that in any application when it's drawing images, because if you do it globally for the whole GUI, you'll be dithering any colored text as well, which can make text unreadable at small sizes, and you probably don't want any bigger fonts than you absolutely need, if your resolution is 320x200.
For shrinking, you can take a (properly weighted for sub-pixel accuracy) average of the area of the image that's covered by your low-resolution pixel.
For growing, you probably want to start with linear interpolation, which is simple and looks relatively ok.
The color reduction is harder, because it depends on how you allocate colors of the 256-color paletter. Probably easiest thing is to use a constant 6x6x6-color space, in which case you simply rescale the 24-bit 0-255 values to 0-5, then combine the channels by multiplying and adding (you can't use bitshifts like in 16-bit or 24-bit truecolor modes because 6 is not a power of two, but the idea is the same). That will allow treating the screen like if it was a true-color display.
For single images you get better results by finding the optimal palette instead. Finding the optimal palette then, is another good question, but I'll not go into that, because I've never tried doing it. The problem then is that if you use optimal palette separately for each image on screen, you have to switch between the palettes somehow, which will make all the other images colored wrong... so it's mostly a good approach for full-screen programs.
The 6x6x6 color cube will look much better if you DON'T use the classic "web-safe" colors, but instead take gamma into account. You can assume sRGB gamma of 2.0 so you could allocate the 6 values (of each channel separately ofcourse) such that their squares (when you consider minimum as 0, maximum as 1) lay on a straight line. This will avoid having 3/4 of the palette too dark for anything, but makes it harder to convert from 24-bit images, because you then need to gamma correct those first (take the square root of each value, where again 0 is minimum, 1 is maximum... and do a lookup table for all 256 values because it makes no sense to do it at runtime). Hopefully I got the math right. Disclaimer: I haven't actually tried this, though I plan to, so while it's theoretically sound approach, I'm not sure how much it helps.
You could also do dither for images, but I think it's good idea to do that in any application when it's drawing images, because if you do it globally for the whole GUI, you'll be dithering any colored text as well, which can make text unreadable at small sizes, and you probably don't want any bigger fonts than you absolutely need, if your resolution is 320x200.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
No, not necessarily.GLneo wrote:thx, now i'm getting a lot of screen tearing, but i cant figure out how Linux + windows, keeps the mouse always on top with out redrawing the whole screen then the mouse on top? do i need a lot of buffers or something?
If you get screen tearing with mouse (would be easier to give precise ideas btw if you provided floppy image so we can see what happens), it's most like because you have the mouse cursor on screen, then draw on top of it, and when the mouse moves, you restore the background from it's backing store, which is no longer valid, because the contents behind the cursor changed.
The easiest approach is to simply remove the cursor (restoring from it's backing store), before anything else is drawn / updated. After the drawing finishes, you redraw the cursor (and create a new backing store). Another way to think of it, is that drawing must never be done while the cursor is visible.
A slightly more sophisticated version is to compare the area to be drawn with the area of the cursor, and only remove the cursor if those areas overlap, so you avoid doing extra work when the cursor is nowhere near the changing area.
Suppose you have for each window (x,y,w,h) with (x,y) being the top-left corner, and (w,h) being the size. For mouse cursor you need the same (mx,my,mw,mh). Now you can simply test, before drawing, that:
Code: Select all
((x > mx+mw) || (x+w < mx)) && ((y > my+mh) || (y+h < my))
Pseudocode:
Code: Select all
if overlap(area,mouse):
mouse.hide()
area.draw()
mouse.show()
else
area.draw()
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.