How to properly use SDL_BlitSurface() with SDL_CreateRGBSurface()?
You inverted source and destination. To blit on screen, it should be
SDL_BlitSurface(layer, NULL, screen, NULL);
Vilinkameni
Updated on July 14, 2022Comments
-
Vilinkameni almost 2 years
(See "Edit 2" below for the solution.)
I need to create SDL surfaces from scratch, instead of loading them from a file. Unfortunately,
SDL_BlitSurface()
seems to render all colors as black when used with the surface generated throughSDL_CreateRGBSurface()
. This is my code:int main(int argc, char** argv) { SDL_Surface* screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE); SDL_Surface* layer = SDL_CreateRGBSurface(SDL_HWSURFACE, 100, 100, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask ); SDL_Rect rect; rect.x = 0; rect.y = 0; rect.w = 100; rect.h = 100; Uint32 blue = SDL_MapRGB(screen->format, 0, 0, 255); SDL_FillRect(layer, &rect, blue); SDL_BlitSurface(screen, NULL, layer, NULL); SDL_Flip(screen); SDL_Delay(3000); return 0; }
What I get is a black screen, instead of a 100x100 blue rectangle. What I could find by Googling doesn't seem to help me, as those questions either apply to 8bit surfaces (and setting palettes — my bpp is 32 here) or are left unanswered.
So, I would like to know how should I properly blit a generated surface onto a SDL screen.
Edit: I see it was an error in the parameter ordering. The line in question should read
SDL_BlitSurface(layer, NULL, screen, NULL);
Still, I am having trouble to achieve the same effect in my more complex C++ program. I will post the relevant parts of the code here:
main.cpp:
int main(int argc, char** argv) { SDLScreen screen(1024, 700, "Hello, SDL!"); SDL_Event event; SDLMenu menu; bool shouldQuit = false; menu.setBounds(200, 100, 200, 600); menu.setFontName("NK211.otf"); menu.setFontSize(36); menu.setEffect(sdlteShadowText); menu.addItem("New game"); menu.addItem("Load game"); menu.addItem("Save game"); menu.addItem("Exit"); menu.render(); while (!shouldQuit) { menu.draw(screen.getSurface()); SDL_Flip(screen.getSurface()); SDL_Delay(10); while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { shouldQuit = true; } else if (event.type == SDL_KEYUP) { if (event.key.keysym.sym == SDLK_q) { shouldQuit = true; } } } } }
SDLMenu.cpp:
void SDLMenu::setSelectionColorRGB(int r, int g, int b) { SDL_VideoInfo* info = (SDL_VideoInfo*)SDL_GetVideoInfo(); selectionColor = SDL_MapRGB(info->vfmt, r, g, b); } void SDLMenu::render() { SDLText* current = NULL; SDL_VideoInfo* info = (SDL_VideoInfo*)SDL_GetVideoInfo(); if (!items->empty()) { current = getItemAt(currentItem); selectionRect = getItemRect(current); setSelectionColorRGB(0,0,255); selectionCanvas = SDL_CreateRGBSurface(SDL_HWSURFACE, selectionRect->w, selectionRect->h, info->vfmt->BitsPerPixel, info->vfmt->Rmask, info->vfmt->Gmask, info->vfmt->Bmask, info->vfmt->Amask); SDL_FillRect(selectionCanvas, selectionRect, selectionColor); SDL_SaveBMP(selectionCanvas, "selection.bmp"); // debug } for (list<SDLText*>::iterator i = items->begin(); i != items->end(); i++) { (*i)->render(); } } void SDLMenu::draw(SDL_Surface* canvas) { int currentY = bounds.y; if (selectionCanvas != NULL) { SDL_BlitSurface(selectionCanvas, NULL, canvas, selectionRect); } for (list<SDLText*>::iterator i = items->begin(); i != items->end(); i++) { (*i)->draw(bounds.x, currentY, canvas); currentY += fontSize + itemGap; } }
SDLScreen.cpp:
SDLScreen::SDLScreen(int w, int h, string t, int d) : width(w), height(h), depth(d), title(t) { SDL_Init(SDL_INIT_EVERYTHING); SDL_WM_SetCaption(title.c_str(), NULL); refresh(); } void SDLScreen::refresh() { screen = SDL_SetVideoMode(width, height, 32, SDL_HWSURFACE); }
The selection rectangle for the active menu item should be blue, but it shows up in black. The file
selection.bmp
is also all black.Edit 2: I found out what created the problem. The
selectionRect
was set relative to the screen, while theselectionCanvas
had the width and height of a particular menu item. So, the filling was done out of bounds of theselectionCanvas
. Adding separateSDL_Rect
for filling solved the problem.SDL_Rect fillRect; fillRect.x = 0; fillRect.y = 0; fillRect.w = selectionRect->w; fillRect.h = selectionRect->h; SDL_FillRect(selectionCanvas, &fillRect, selectionColor); // and later... SDL_BlitSurface(selectionCanvas, NULL, canvas, selectionRect);