SDL_BlitSurface指定目标矩形仍全屏复制问题求助
SDL_BlitSurface 复制完整源表面问题排查
问题场景
明明给SDL_BlitSurface设置了比屏幕尺寸小的目标矩形,但它还是将整个源表面复制到了目标表面上。相关代码片段如下:
SDL_Rect rect; rect.x = 0; rect.y = 0; rect.w = SCREEN_WIDTH-200; rect.h = SCREEN_HEIGHT-200; SDL_BlitSurface(optimizedSurface, NULL, screenSurface, &rect); //Update the surface SDL_UpdateWindowSurface( window );
当前实际显示为完整图片铺满窗口,而期望效果是仅显示图片左上角一部分,尺寸为 SCREEN_WIDTH-200 × SCREEN_HEIGHT-200。
问题原因
对SDL_BlitSurface的参数逻辑理解有误:
- 当第二个参数(源矩形)为
NULL时,SDL会默认取整个源表面作为复制区域。 - 第四个参数(目标矩形)的作用是将源区域缩放后绘制到目标表面的指定位置,而非裁剪目标区域。所以即便你设置了更小的目标矩形,SDL也会把整个源表面缩放到该矩形尺寸后填满目标位置,最终看起来还是完整图片被缩放显示。
修正方案
如果要仅绘制源表面的一部分到目标表面,需要同时指定源矩形和目标矩形:
- 源矩形:定义从源表面复制的区域范围
- 目标矩形:定义该区域在目标表面的绘制位置(若不需要缩放,宽高需与源矩形一致;若要缩放则设置为目标尺寸)
修正后的代码片段
// 定义源矩形:取源表面左上角的指定区域 SDL_Rect srcRect; srcRect.x = 0; srcRect.y = 0; srcRect.w = SCREEN_WIDTH-200; srcRect.h = SCREEN_HEIGHT-200; // 定义目标矩形:绘制到目标表面的(0,0)位置,尺寸与源矩形一致(不缩放) SDL_Rect destRect; destRect.x = 0; destRect.y = 0; destRect.w = srcRect.w; destRect.h = srcRect.h; SDL_BlitSurface(optimizedSurface, &srcRect, screenSurface, &destRect); SDL_UpdateWindowSurface(window);
完整修正代码
//Using SDL and standard IO #include <SDL2/SDL.h> #include <stdio.h> #include <cstring> #include <bits/atomic_base.h> //Screen dimension constants const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; //The window we'll be rendering to SDL_Window* window = NULL; //The surface contained by the window SDL_Surface* screenSurface = NULL; //The surface of the loaded media SDL_Surface* optimizedSurface = NULL; bool loadMedia() { bool success = true; char path[] = "/home/gras/CLionProjects/SDLBonanza/resources/cock.bmp"; SDL_Surface* loadSurface = SDL_LoadBMP(path); if(loadSurface == NULL) { printf("Unable to load image: %s with error msg: %s", path, SDL_GetError()); success = false; } //optimize image on load to remove conversion when blitting optimizedSurface = SDL_ConvertSurface(loadSurface, screenSurface->format, NULL); if(optimizedSurface == NULL) { printf("The optimised image could not be computed with error: %s", SDL_GetError()); success = false; } SDL_FreeSurface(loadSurface); return success; } bool init() { bool success = true; //initialize sdl if( SDL_Init(SDL_INIT_VIDEO) < 0) { printf("SDL could not initialize with error code: %s", SDL_GetError()); success = false; } else { window = SDL_CreateWindow("Game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN); if(window == NULL) { printf("The window could not be created with error: %s", SDL_GetError()); success = false; } else { screenSurface = SDL_GetWindowSurface(window); if(screenSurface == NULL) { printf("The screen surface could not be created with error: %s", SDL_GetError()); success = false; } } } return success; } void close() { //dealocate surface SDL_FreeSurface(screenSurface); screenSurface = NULL; //dealocate window SDL_DestroyWindow(window); window = NULL; //quit sdl subsystem SDL_Quit(); } void negative() { for(int i=0; i<optimizedSurface->h; i++) { for(int j=0; j<optimizedSurface->w; j++) { Uint8* pixel = ((Uint8*)optimizedSurface->pixels + i * optimizedSurface->pitch + j * optimizedSurface->format->BytesPerPixel); for(int k=0; k< optimizedSurface->format->BytesPerPixel; k++) { *(pixel+k) = 0xFF - *(pixel+k); } } } } int main( int argc, char* args[] ) { if(!init()) { printf("The initialization failed!"); } else if(!loadMedia()) { printf("The media could not be loaded!"); } else { //Update the surface SDL_UpdateWindowSurface( window ); //Hack to get window to stay up SDL_Event e; bool quit = false; while( quit == false ) { while( SDL_PollEvent( &e ) ) { if( e.type == SDL_QUIT ) quit = true; if( e.type == SDL_KEYDOWN) { switch(e.key.keysym.sym) { case(SDLK_UP): negative(); // 定义源矩形:取源表面左上角的指定区域 SDL_Rect srcRect; srcRect.x = 0; srcRect.y = 0; srcRect.w = SCREEN_WIDTH-200; srcRect.h = SCREEN_HEIGHT-200; // 定义目标矩形:绘制到目标表面的(0,0)位置 SDL_Rect destRect; destRect.x = 0; destRect.y = 0; destRect.w = srcRect.w; destRect.h = srcRect.h; SDL_BlitSurface(optimizedSurface, &srcRect, screenSurface, &destRect); //Update the surface SDL_UpdateWindowSurface( window ); break; default: break; } } } } } //free and destroy window close(); return 0; }
内容的提问来源于stack exchange,提问作者Cristian Cutitei
相关产品推荐
相关产品推荐

