SDL: blitting a surface, clearing the blit, and blitting again?

Started by
5 comments, last by Ashitaka 16 years, 9 months ago
The title is best I could describe my question.. I have just started learning SDL (of course -_-) but I seem to understand it okay which is great! So because I am learning, I've been writing lots of code to test out how things work, like blitting things ontop of eachother and using alpha etc etc. Well I am totally stumped on something and would really appreciate your help... I've arranged it so that when i right-click on the window, it will blit a surface (its just an image but it looks like a menu). This all works fine and is nice.. but if I right click somewhere once more, it will blit it again (and so on) without removing the one made before it. So I thought to myself.. well why don't I just tell it to clear itself before blitting the new one. But I don't know how to do that! I know of SDL_FreeSurface(name); but I did some testing and I learned that even if I free the surface in the middle of the program, it wont remove what was blitted; even if I put something new into the surface and blit again. So if someone could provide me some insight into this I'd be very very happy ^^ And incase that was too long to read I'll recap with the short version: I'd like to know how to clear only all the instances of surface1 that were blitted onto surface2 without having to completely remove surface1 and re-initialize/redo IMG_Load() Also is there a way to check to see if a surface has been blitted anywhere at all?? Thank you sooo much! Your help really does have meaning.. -Ash [Edited by - Ashitaka on July 10, 2007 3:18:22 AM]
Advertisement
Using SDL_FreeSurface() is defintely not the way to do it. If you want to be able to clear a surface that you've blitted, you must save the contents of the screen in some surface and then blit your surface. Then, if you want to restore the previous contents, just blit the surface that stores them.

The above will work but I wouldn't recommended it. Usually the reason you want to restore the screen's previous contents is to blit the image somewhere else without it leaving a "trail". For example, if you draw a spaceship and then you want to move it, you can "clear" it (by restoring the previous contents of the screen), then draw it somewhere else, then "clear" it again, then draw it somewhere else.

However, if you have a lot of images on screen, this becomes inefficient and cumbersome. Instead, at the start of each frame, clear the entire screen to black or some other color (or if you have a background image that is the size of the screen, just draw that image and it will erase everything), and draw your images at their new locations. This is both simpler and more efficient.

I hope my explanation wasn't too confusing, but if you have any questions I'll be happy to answer.
Yeah when you blit a surface, you're not creating a new instance of it. You're actually copying the surface ONTO a bigger surface (the screen). Once there it stays there, part of the screen, until you write it over with something else. Like any data.

The normal way to make things look nice is to blit black over the entire screen at the start of every frame. Like this:

// main loopwhile (!done){	// blit black over everything (0xFFFFFF is the code for white)	SDL_FillRect(screen,NULL,0x000000);	// blit tanks	for (all tanks)		SDL_BlitSurface(tanksurface,screen,tank.x,tank.y);}


Oh, and by the way... SDL_FreeSurface() removes the surface from memory. So if you remove "tanksurface" you can no longer use it to blit tanks with. That's all.
----------------------~NQ - semi-pro graphical artist and hobbyist programmer
You need to refresh the background as NQ has showed to you.

If you don't do that, every new image you're going to blit on the screen
will overlap the old pixel screen data on which the image is now spreaded on.
This makes sense since you haven't requested to change anything that is out
of the new displayed image's boundaries.

All these take place inside the memory of you computer ( in a much more
complex way let's say ).
I hope this simple scheme might help you to understand the concepts we have talked
about.

http://img444.imageshack.us/my.php?image=pxldatayg6.png
Thank you everyone for your replies. Admittedly while I was at work today I was brooding on this over and over and it hit me that the blitting doesnt cause layering it just redraws the screen.. I am not stacking things ontop of eachother. Once something is drawn, whatever was underneath it before is now gone.

It hurt my head actually. I am not used to that idea, I live in a layered world. And so I thought about it.. if many things are onscreen, it is going to be really hard to keep track of what needs to be drawn in what order. Especially if I want to change the focus of surfaces, or take a surface and be able to click and drag it (will have to learn how to do this) without leaving a trail as you described but keeping everything behind it onscreen.

I pondered quite furiously and I came up with a possible solution... which is to make my own layered system. Where certain things will only be drawn to certain surfaces and not just the background surface.. so I was really excited to get home and find out how to clear the surfaces without unloading them from memory. But that doesn't seem to be a possibility so I am not sure if my layered idea will work so well.

But at least I have a better understanding now, and for that I am grateful :)
Thank you all!

-Ash

EDIT:

Wow so my layered idea is a no-go anyways because it seems that SDL_UpdateRect() is useless on surfaces that were assigned using SDL_Image(). Here's what happened.. (humour me on this)

I have 4 surfaces: screen(setvideomode), background(img_load), imeji_box(img_load), imeji_inside(img_load)

imeji_box is like a dialogue box, its the form's outline. imeji_inside is what i want to put into this box to give the illusion that they are one completed entity.

If I do it this way...

SDL_BlitSurface(background, &src, screen, &dest);
SDL_BlitSurface(imeji_box, &src, screen, &dest);
SDL_BlitSurface(imeji_inside, &src, imeji_box, &dest);
SDL_UpdateRect(imeji_box, 0, 0, 0, 0);
SDL_UpdateRect(screen, 0, 0, 0, 0);

... then screen will update to show its changes as expected/proven, but imeji_box *wont update* to have imeji_inside ontop of it until i blit imeji_inside a second time.

So if I did it this way...

SDL_BlitSurface(background, &src, screen, &dest);
SDL_BlitSurface(imeji_inside, &src, imeji_box, &dest);
SDL_BlitSurface(imeji_box, &src, screen, &dest);
//SDL_UpdateRect(imeji_box, 0, 0, 0, 0);// useless now
SDL_UpdateRect(screen, 0, 0, 0, 0);

... then now because I have blitted imeji_inside onto imeji_box *before* i blit imeji_box to screen, imeji_box will now blit with imeji_inside ontop of it.

So I am very confused as to why if I blit something to screen and then call SDL_UpdateRect(screen, 0, 0, 0, 0); it will update, but if i blit surface1 to surface2 thats been blitted, calling SDL_UpdateRect(surface2, 0, 0, 0, 0); wont do the same thing and update it. It kinda makes me sad too :(

Am I missing something or is this infact the truth? I bet its because screen has the setvideomode applied to it. So now I wonder if I can nest another surface with setvideomode inside the first one without having to create a new window/form inside or outside the main one.

I am sorry if my explanations are so long-winded.. in japanese everything is very short but its very generalized and sometimes can be hard to explain things so when i write english i tend to write a lot so english speakers can understand my explanations ^^

And of course, thank's so much for your guidance >:)

--足

[Edited by - Ashitaka on July 11, 2007 1:10:10 AM]
The surface returned by SDL_SetVideoMode() is a special type of surface. It is the only surface that is used to update your display/monitor/LCD/screen. SDL_UpdateRect(s) and SDL_Flip() can only be used on this special surface. When you modify(by blitting or filling) this surface, you have to notify the video system of the change by calling SDL_UpdateRect() or SDL_Flip() if double-buffering is used.

This surface is where your final scene will be composited. Calling SDL_UpdateRect() on any another surface will have no effect. So you were right in saying the video surface is special.

Simple layering is achieved by controlling the order of the blits(image layers) to the screen surface.
Lets assume you want to layer some images in this order. It's as easy as drawing them in the correct order.
[SKY]-[SUN]-[MOUNTAIN]-[HOUSE]
SDL_BlitSurface(sky,NULL, screen, &dest);SDL_BlitSurface(sun, NULL, screen, &dest);SDL_BlitSurface(mountain, NULL, screen, &dest);SDL_BlitSurface(house, NULL, screen, &dest);UpdateRect(screen,0,0,0,0);

You can also draw surfaces to intermediate surfaces as long as you draw the result to the screen. Here we draw the ghosts to a temp surface, then draw
the temp surface to the screen surface.
SDL_Surface* temp = SDL_CreateRGBSurface(....);//our ghost layerSDL_SetAlpha(temp,SDL_SRCALPHA,128);...SDL_FillRect(screen,NULL,0);//clear screen to blackSDL_BlitSurface(house,NULL, screen, &dest);SDL_BlitSurface(ghost1, NULL, temp, &dest);SDL_BlitSurface(ghost2, NULL, temp, &dest);SDL_BlitSurface(temp, NULL, screen, &dest);UpdateRect(screen,0,0,0,0);

So ultimately we can layer the screen in many ways. You and I may be making this more complicated than it really is.

Keep in mind that once you blit imeji_inside to imeji_box surface,the imeji_box surface is permanently changed. This means you can never use the surface again as a seperate image from imeji_inside. Lastly, the way to clear a surface is to draw over it using a color or an image.

Good Luck.
0xa0000000
Quote:Original post by Jack Sotac
Keep in mind that once you blit imeji_inside to imeji_box surface,the imeji_box surface is permanently changed. This means you can never use the surface again as a seperate image from imeji_inside. Lastly, the way to clear a surface is to draw over it using a color or an image.
Ahhh thank you for mentioning this. It probably would have come up sooner or later and I would have had some sort of hyper panic attack :P

I think I have gotten a handle on most of this so I think I am done asking questions for now. I've discovered that SDL_Image isnt even a default library.. I am using linux and when i installed SDL from the debian repositories it already stuck SDL_Image in there. I came accross a huge list of supported libraries on the SDL website and SDL_Image was there and clearly separate from the rest. Scary!

I am going to see if I can get my code to run on windoze now..

Thanks again ^^

-Ash

This topic is closed to new replies.

Advertisement