*Solved! [SDL] Blitsurface update problem *offset*

Started by
5 comments, last by TheRamon 16 years, 4 months ago
THIS PROBLEM IS SOLVED. CLICK HERE FOR THE SOLUTION Hello, I've been using SDL for a while now, but lately I stumbled upon this problem while making a program with TTF fonts. I am trying to update the surface where my mouse moves only, because I'm using rather big images, and my FPS drops to about 30 when redrawing the whole screen over and over again. Now the surface updates perfectly if I do it this way:

SDL_BlitSurface(surface1, 0, screen, &surface1rect);
SDL_BlitSurface(surface2, 0, screen, &surface2rect);


SDL_BlitSurface(TTFtext, 0, screen, &textoffset);
/*this draws the text on the screen once only,
ofcourse, and wipes it if you mouse-over it. ->Obvious */

bool done = false;
while(!done)
{
  SDL_BlitSurface(surface1, &mouserect, screen, &mouserect);
  SDL_BlitSurface(surface2, &mouserect, screen, &mouserect);
  //mouse rect's got the mouse its x and y position updated.

  SDL_Flip(screen);
}





Now , when I try to implement the mouse - rect updating, it only draws in 0,0 of my screen. (That'd be the topleft corner)

SDL_BlitSurface(surface1, 0, screen, &surface1rect);
SDL_BlitSurface(surface2, 0, screen, &surface2rect);


SDL_BlitSurface(TTFtext, 0, screen, &textoffset);
/*this draws the text on the screen once only,
ofcourse, and wipes it if you mouse-over it. ->Obvious */

bool done = false;
while(!done)
{
  SDL_BlitSurface(surface1, &mouserect, screen, &mouserect);
  SDL_BlitSurface(surface2, &mouserect, screen, &mouserect);
  /*mouse rect's got the mouse its x and y position updated.*/

  /*Now, if I try to do the same, the text only draws
  in the left corner of the screen at 0,0.
  ->  Obvious, but there isn't a way to get the offset right. Right? */
  SDL_BlitSurface(textsurface, &mouserect, screen, &mouserect);

  SDL_Flip(screen);
}





Any help would be appreciated! :) Thank you in advance! [Edited by - TheRamon on November 23, 2007 7:06:15 PM]
Advertisement
I'm not 100% sure of your problem. Are you saying that the text rectangle never has negative x and y co-ordinates?

If that is the case, then I understand the cause of your problem. SDL_BlitSurface() modifies the rectangles passed to it (as mentioned in the documentation). The solution is to track the position in a separate SDL_Rect (or better still, in a custom struct with only an X and Y co-ordinate.) and create a copy of the surface in your own blit function:

struct Position {   int x, y; // these could be floats if your game requires it};void blit( SDL_Surface *surface, const Position &pos ){   SDL_Surface *screen = SDL_GetVideoSurface();   SDL_Rect destination = {pos.x,pos.y}; // if using floats you will need to do the appropriate casting here   SDL_BlitSurface(surface,0,screen,&dest);}
Nah It's more like that my text gets drawn right here:

(my screen)
+-----------+|x          ||           ||           ||           |+-----------+

and I want it to be about here:
+-----------+|        x  ||           ||           ||           |+-----------+

but I cannot get that working, with the mouse over coordinates included.

It works fine if I have it drawn on the 0,0 position like this:
SDL_BlitSurface(textsurface, &mouserect, screen, &mouserect);
Quote:Original post by TheRamon
SDL_BlitSurface(textsurface, &mouserect, screen, &mouserect);


I doubt you should be using &mouserect as the source rectangle. Remember, the source rectangle restricts the amount of the surface drawn. For example, if you had a huge background image (say 1024x1024) you could restrict drawing to the screen dimension using a source rectangle of {x,y,800,600}

You probably want:
SDL_BlitSurface(textsurface, 0, screen, &mouserect);
Your way gives me a trail behind my mouse with the text I'm trying to draw.

:(

'cause Mouserect has the X and Y and the width and height of my mouse. *custom cursor*
Quote:Original post by TheRamon
Your way gives me a trail behind my mouse with the text I'm trying to draw.

:(

'cause Mouserect has the X and Y and the width and height of my mouse. *custom cursor*


Ok, You have two alternatives. If the background is fairly static (your text isn't moving or changing, likewise with the surfaces), you can use a double buffered surface for your mouse:
SDL_Surface *mouse = SDL_LoadBMP(...);SDL_PixelFormat *format = screen->format;// this surface saves the piece of the screen// that was there before the mouse was blittedSDL_Surface *mouseBackground = SDL_CreateRGBSurface(SDL_SWSURFACE,mouse->w,mouse->h,format->BitsPerPixel,format->Rmask,format->Gmask,format->Bmask,format->Amask);// blit surface 1, surface 2 and ttftext// set up initial mouseSDL_Rect mouseoffset = {...};SDL_BlitSurface(screen,&mouseoffset,mouseBackground,0);SDL_BlitSurface(mouse,0,screen,&mouseoffset);while(running){    if( mouse_moved )    {       // restore original backgroud       SDL_BlitSurface(mouseBackground,0,screen,&mouseoffset);       // change mouse position       mouseoffset.x = // ask SDL for mouse position       mouseoffset.y = //    ditto       // save the background of the new position       SDL_BlitSurface(screen,&mouseoffset,mouseBackground,0);       // blit the mouse in its new position       SDL_BlitSurface(mouse,0,screen,&mouseoffset);    }   }


If you do start moving the background surfaces though, you'll have to be careful. The easiest way to do that would be to restore the background, blit whatever has moved/changed, then save the new background and re-blit the mouse.

The other way is more complex IMO.

You need to calculate the position of the mouse on the surface. I am guessing that surface1 and surface2 both start at (0,0). Your text is somewhere in the middle. You would need to calculate the relative position of the mouse on these surfaces. For example, if the text is at 100,100 and is of width 100 and height 30, and the mouse is at 110,110 and has a width and height of 20, then we can use the following code to work out the relative co-ordinates of the mouse:
SDL_Rect relativeMouseCoordinates( SDL_Surface *surface, const SDL_Rect &position, const SDL_Rect &mouse ){    int xoffset = std::max(0,mouse.x - position.x);    int yoffset = std::max(0,mouse.y - position.y);    int width = std::min(surface->w, xoffset + mouse.w);    int height= std::min(surface->h, yoffset + mouse.h);    SDL_Rect rectangle = {xoffset,yoffset,width,height};    return rectangle;}


You can write another function to check if the mouse rectangle is over the other surface. Then your code becomes:

while(running){    if( mouse_moved )    {        mouseoffset = // use SDL to get mouse position                for_each( surface_on_screen )        {             if( mouseOverSurface(surface,surfacerect,mouseoffset) )             {                SDL_Rect relativeRectangle = relativeMouseCoordinates(surface,surfacerect,mouseoffset);                SDL_BlitSurface(surface,&relativeRectangle,screen,&mouseoffset);             }        }        SDL_BlitSurface(mousesurface,0,screen,&mouseoffset);    }}


As you can see, not updating the entire screen is considerably more complex. Please note that I could not test any of this code, it is all written from memory (with pseudo-code where appropriate) so you should double check all of it.

Another consideration, if you are doing an input-driven program rather than a continuous game loop consider using SDL_WaitEvent instead of PollEvent. Your program will then only do processing when the user requests it. For example, a turn based game could be implemented this way.
This helped me out great. Thank you very very much. :)

This topic is closed to new replies.

Advertisement