(SDL + C++) Can you blit from a surface to another surface then to the screen ?

Started by
6 comments, last by ASnogarD 11 years, 9 months ago
In brief , I want to build up a level using tiles then blit that level to a intermediate surface ( not the main screen surface ), then clip a portion of that intermediate surface to blit to the screen.
Is that possible ?

I cant seem to get even a basic image that was blitted to the intermediate surface to be then drawn to the screen, it displays nothing.

The rest of the code works, it displays the text and if I dont try using the experimental intermediate surface blit mode , it displays just fine but I cant seem to get whatever is blitted to the intermediate surface to be used as a source to blit to the destination.

Something like this :

Normal way : Image to surface -> surface to screen surface

What I want : Image to surface -> surface to intermediate surface -> a selected clip of the intermediate surface to screen surface.

Why ?!?

My level code builds up the levels using tiles, a collection of tiles makes a map and a set of maps makes an area. The code currently renders up to 6 maps of the 9 maps that make my test area... the 6 near the camera which is following the player.
The issue is that it draw the entire map which is 640 x 640 in size, so in effect it is drawing (640 x 3) wide x (640 x 2) high each loop, this makes it hard for me to position the 'window' the player will see, and is kind of wastefull.
I have tried to just render what the camera is over for a week or two , but that led to stuttering updating of the level as it was updating tile by tile and had to cross into several maps ( which are on different files, stored in a vector and refered to by ID ).

If this isnt possible I will probably resort to cutting out the area is built up with maps part of the code, and simply fall back to a simple single map system... but I would rather play with the more complex system as it is giving me good experience working with complex level systems.

Sumary : Is it possible to blit from a surface to another intermediate surface and then a portion of that intermediate surface to the screen ?
Advertisement

[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

[background=rgb(250, 251, 252)]Is it possible to blit from a surface to another intermediate surface and then a portion of that intermediate surface to the screen ?[/background]

[/font]
[/quote]
Yes.


[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

[background=rgb(250, 251, 252)]I cant seem to get even a basic image that was blitted to the intermediate surface to be then drawn to the screen, it displays nothing.[/background]

[/font]
...
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

[background=rgb(250, 251, 252)]Why ?!?[/background]

[/font]
[/quote]
Without seeing the code we can but guess. My instinct would be to double check how you are creating the intermediate surface.

This is a modified OnDraw function where I was trying to get a normal picture to blit to the surf_Trial surface, then call the proper OnDraw function to blit to the surface.


bool R_Surface::OnDraw_exp(SDL_Surface* surf_Source, int X, int Y) {
// Check if either Dest or Source surfaces are NULL
if(surf_Source == NULL) {
// If NULL return false
return false;
}
// A rectangle to hold X and Y co-ords
SDL_Rect DestR;
DestR.x = X;
DestR.y = Y;
// Put the contents of the source surface onto the destination surface
// at the X and Y given by the DestR object
SDL_BlitSurface(surf_Source, NULL, surf_Trial, &DestR);
OnDraw(surf_Trial,10,10);
// Surface was blitted successfully
return true;
}


surf_Trial pointer is declared in the header : extern SDL_Surface* surf_Trial; and set to NULL in the cpp file : extern SDL_Surface* surf_Trial = NULL;

The image I am trying to blit is declared in a different class, so is its surface but its pretty basic ... a surface is declared in the header file (none extern) , initiated in the contructor to NULL, the loader is also the typical load image and convert to screen format to opimise it.

... is that enough code to go with ? The whole lot is too much to post as it a framework for me to use to program other 2D games so it handles a lot of stuff.

EDIT: I forgot to mention the part that calls the experimental function : R_Surface::OnDraw_exp(surf_Splash, 650, 5);
surf_Splash is the image, and all I was trying to do was blit the image onto the intermediate surface (surf_Trial) and then blit the contents of the surf_Trial onto the main display surface (surf_Display).
A NULL surface won't work. You need to pass a valid surface as the third parameter to SDL_BlitSurface(). Are you called SDL_CreateRGB[A]() anywhere?
I wasnt but I done some more researching and googling and tried this to make a blank surface...


bool R_Surface::SetSurfaceFormat(SDL_Surface* surf_Trial) {
SDL_Surface* surf_Temp = NULL;

int width = 900;
int height = 900;
if((surf_Temp = SDL_CreateRGBSurface(SDL_SWSURFACE,width,height,32,0,0,0,0)) == NULL) {

R_Font::AddConsole("& Failed to create Surface");
return false;
}
if((surf_Trial = SDL_DisplayFormat(surf_Temp)) == NULL ) {
R_Font::AddConsole("& Failed to convert surface");
return false;
}
// Free the temp surface as we dont need it
SDL_FreeSurface(surf_Temp);
return true;
}


But while it compiles fine, it still doesnt display the image at all. I also seem to be going over my head with this little experiment... I thought it would be pretty easy, blit to one surface all the maps that may be visible to the camera, then clip a part of that surface to the screen. tongue.png

The code seems to work...it isnt returning NULL ( otherwise the code would of shown me an error in my programs little 'console' ).

I am pretty sure I am not covering up the image with another.
Ahh this is frustrating...

EDIT: I did a check on the blitting operation and it is failing to blit the surface, so its not the image isnt showing...the blit has failed somewhere.

EDIT 2 : I'll try experimenting with this in a smaller code block, a simple setup to play with the feature and see what I get without the over all framework adding extra elements to the mix. Thanks for the help.... least I know it can be done...somehow.
One option is to simplify. Right now you have(at least) 3 objects, the image, the off-screen buffer and the screen. An error or bug in any of these could cause the program to not display the image. Not to mention the rest of your framework.

We can provide that it works by building a simple test environment. I recommend having a separate project geared up and ready to go for this - a SDL test enviornment would consist of minimal setup and a simple render/event loop.


  • The first step might be to check that the screen is working - simply filling it with some arbitrary colour like red. Don't blit anything else, just SDL_FillRect.

  • Next create the in memory buffer and blit that to the screen. The screen should now be black again - hopefully the red has been overwritten but we may have introduced a bug in the screen code.

  • Then fill the off screen buffer with a different colour, like green. This will prove that both the screen and the buffer are most likely working. If we are paranoid, we can use SDL_SaveBMP on the off screen buffer to double check.

  • Try loading the image and blitting it directly to the screen. It should write over the green colour.

  • Finally, we blit it to the off screen buffer. If everything has gone right, it should still stay on the screen. If not, we might use SDL_SaveBMP() and the other debugging techniques to investigate the newest problem.

  • You might also want to add any optimisation steps such as display format calls now, given that you are happy with the functional part of the code.

This is a bottom-up approach to debugging, we start with something simple and keep adding to it - proving to ourselves at each step that it is working. Because each step is so simple, when we reach the step that introduces the problem this should be obvious.

For example, we might find a problem when we have just added the memory buffer. So now we can investigate - are zeros valid values for the last four parameters to SDL_CreateRGBSurface()?

On the other hand, you might get all of this working in your simple test environment but still not have it work in your actual code. The other approach is to start with your current project (possibly copied into a backup location if you do not use version control (hint: always use version control!)). Start commenting out parts of the code that could be negatively interacting with the "happy path". This takes more experience and intuition than the bottom up approach.


[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

[background=rgb(250, 251, 252)]I did a check on the blitting operation and it is failing to blit the surface, so its not the image isnt showing...the blit has failed somewhere.[/background]

[/font]
[/quote]
Can you explain what you mean by this? Is the return value of SDL_BlitSurface() indicating an error? If so, what does SDL_GetError() tell you?

Add GetError to my console report and it reports : SDL_UpperBlit: passed a NULL surface

I got the values for the CreateRGBSurface from the example at :
http://sdl.beuc.net/...reateRGBSurface

using the default values, as I havent messed about with the RGB masks nor set the Alpha (except for colour key transparency , in the actual image I am trying to blit not the intermediate surface ).

It has gone over my head at this stage, a bit more in depth than I expected so I am kind of winging it so to speak.

Its not hyper crtical I get this to work, I can merely convert the level and map parts to a single map, which makes rendering just what the camera see relatively simple, its because the level is spit into small maps that I need to try fancy tricks to control the camera... the tutorial I was following left it with just a half done level rendering in the bottom corner of a 640x480 window ( and yes that is how it comes out if you take the tutorials own compiled example...same thing ).

EDIT: I have no idea why it considers either surfaces to be NULL, the source is a working image that displays on the screen ... I am using it as a test , so I know that image is fine ... the only NULL surface left must be the surf_Trial, the one being created with CreateRGBSurface.
Reporting some success, got the image to show.

Wierd though, I cant understand the reason it worked. See I tested for NULL when using CreateRGBsurface and when it converted, even tested it just before it left the function and surf_Trial wasnt NULL, however if I tested for NULL before I call the OnDraw_exp function...it is NULL despite the surface not being NULL before the call.
I went with the theory that converting the surface in the function would not alter the actual surface, thus when it left the function it was NULL... so I made the function return the result of a SDL_DisplayFormat , and made surf_Trial = the retrun value... and it worked.

So it seemed for that issue , the problem was a scope mistake on my part.... phew, so I finally have a blank surface I can use to pass images to, now I got to pass 6 maps worth of tiles to the surface and cut out the part I want to keep...

... tommorrow :P

Once again thanks for the help Rip-Off, appreciate it.

This topic is closed to new replies.

Advertisement