最近学习SDL2中用到了垂直同步这一技术,实现动画的处理,通过百科可知,垂直同步又称场同步,场信号一般是50Hz,或者60Hz,从CRT显示器的显示原理来看,单个像素组成了水平扫描线,水平扫描线在垂直方向的堆积形成了完整的画面,电脑中图象是通过显卡来显示的,比较高端的显卡生成图像更快些,垂直同步这一技术是让显卡生成图象时收到垂直同步信号的制约,使得画面更流畅些。如果没有垂直同步,图像速度就会提升,但是也会导致画面不流畅,出现跳帧现象,画面有撕裂现象,一般都是建议开启垂直同步,使得画面看起来狠舒适,
下面代码是加上垂直同步的代码
//Using SDL and standard IO #include <SDL2/SDL.h> #include <SDL2/SDL_image.h> #include <stdio.h> #include <stdlib.h> #include <stdbool.h> //Screen dimension constants const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; #define NUMBER_CLIPS 16 bool init(); bool loadMedia(); void close(); SDL_Texture* loadTexture(char* path); SDL_Window* gWindow = NULL; SDL_Texture* gSpriteSheetTexture = NULL; SDL_Renderer* gRenderer = NULL; SDL_Rect gSpriteClips[NUMBER_CLIPS]; SDL_Rect* currRect = NULL; bool init() { bool success = true; //Initialize SDL if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() ); success = false; } else { //Create window gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN ); if( gWindow == NULL ) { printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() ); success = false; } else { int imgFlag = IMG_INIT_PNG; gRenderer = SDL_CreateRenderer(gWindow,-1, SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC); if(gRenderer == NULL) { printf("Renderer counld'nt be create SDLError:%s\n", SDL_GetError()); success = false; } if(!(IMG_Init(imgFlag) & imgFlag)) { printf("SDL_image could not initialize! SDL_image Error:%s\n",IMG_GetError()); success = false; } } } return success; } bool loadMedia() { bool success = true; char i,j; //Load splash image gSpriteSheetTexture = loadTexture("walk.png"); if(gSpriteSheetTexture == NULL) { printf("Unable to load default image %s! SDL Error:%s\n","walk.png",SDL_GetError()); success = false; } else { for(i = 0; i < 4;i++) { for(j = 0; j < 4; j++) { gSpriteClips[4*i+j].x = 32*j; gSpriteClips[4*i+j].y = 48*i; gSpriteClips[4*i+j].w = 32; gSpriteClips[4*i+j].h = 48; } } } return success; } SDL_Texture* loadTexture(char * path) { SDL_Texture* texture = NULL; SDL_Surface* loadedSurface = IMG_Load(path); if(loadedSurface == NULL) { printf("Unable to load image %s! SDL Error:%s\n",path,IMG_GetError()); } else { texture = SDL_CreateTextureFromSurface(gRenderer,loadedSurface); if(texture == NULL) { printf("Unable to optimize image %s!, SDL Error %s\n",path, SDL_GetError()); } SDL_FreeSurface(loadedSurface); } return texture; } void close() { SDL_DestroyTexture(gSpriteSheetTexture); gSpriteSheetTexture = NULL; SDL_DestroyRenderer(gRenderer); gRenderer = NULL; SDL_DestroyWindow(gWindow); gWindow = NULL; IMG_Quit(); SDL_Quit(); } int main( int argc, char* args[] ) { int frame = 0; if(!init()) { printf("Failed to Initialized!\n"); } else { if(!loadMedia()) { printf("Failed to load image!\n"); } else { bool quit = false; SDL_Event e; SDL_Rect distRect = {SCREEN_WIDTH/2 - 16, SCREEN_HEIGHT/2 - 24, 32,48}; while(!quit) { while(SDL_PollEvent(&e) != 0) { if(e.type == SDL_QUIT) { quit = true; } } SDL_SetRenderDrawColor(gRenderer,0xff,0xff,0xff,0xff); SDL_RenderClear(gRenderer); currRect = &gSpriteClips[frame/8]; SDL_RenderCopy(gRenderer, gSpriteSheetTexture,currRect,&distRect); SDL_RenderPresent(gRenderer); frame++; if(frame/8 >= NUMBER_CLIPS) { frame = 0; } } } } close(); return 0; }
画面比较流畅,当我们去掉创建渲染器的SDL_RENDERER_PRESENTVSYNC标志时,即
gRenderer = SDL_CreateRenderer(gWindow,-1, SDL_RENDERER_ACCELERATED);
明显可以看出,后者速率很快,但是运行轨迹没有前者流畅,我的监视器刷新频率是60Hz,gif动画的录制时间间隔是30ms,虽然不晓得 SDL_RenderPresent(SDL_Renderer* renderer)具体是怎么实现的,我想刷新时可能会在里面等待垂直同步信号到来吧。而且SDL_Renderer这个结构体看不到也。。。
参考链接:http://lazyfoo.net/tutorials/SDL/14_animated_sprites_and_vsync/index.php