`
zpvw35zpvw
  • 浏览: 18734 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

SDL video子系统学习 (1)

 
阅读更多

SDL video子系统学习 (1)
2011年05月16日
  上次了解了SDL的框架,这次我们来看看SDL的video子系统。
  Video是SDL中使用很普遍的一类元素,有一个完整的体系结构,下面就是一些示例:
  首先是初始化视频显示,这部分是基本上所有的SDL程序都要做的。
  --------------------------------------------------------------
  #include "libnge.h"
  #include "stdio.h"
  extern"C"
  int main(int argc, char* argv[])
  {
  SDL_Surface*screen;
  /*Initialize the SDL library */
  if(SDL_Init(SDL_INIT_VIDEO) format->BitsPerPixel);
  exit(0);
  }
  ---------------------------------------------------------------
  首先,还是利用SDL_Init来初始化SDL,成功返回0否则返回-1。以初始化对象作为参数,多个参数之间用“|”隔开,SDL初始化对象有以下这些:
  SDL_INIT_TIMER              用来初始化TIMER子系统
  SDL_INIT_AUDIO               用来初始化AUDIO子系统
  SDL_INIT_VIDEO              用来初始化VIDEO子系统
  SDL_INIT_CDROM              用来初始化CDROM子系统
  SDL_INIT_JOYSTICK           用来初始化JOYSTICK子系统
  SDL_INIT_NOPARACHUATE       用来防止SDL接收错误数据
  SDL_INIT_EVENTTHREAD        用来初始化EVENT子系统
  SDL_INIT_EVERYTHING          用来初始化以上所有
  然后,利用atexit函数来设置程序正常结束前调用的函数,这里我们需要调用SDL_Quit,这样的话就我们就不需要在main函数中每个return语句前都加入SDL_Quit()了。
  下面,我们就定义了一个指向SDL_Surface结构的指针screen,在SDL中,每件物体都是一个surface,你可以拥有多个surface。可以在一个surface上进行绘图或者在其他surface上绘制另外一个surface。这里,我们需要对screen所指向的surface进行绘图,就可以使用函数SDL_SetVideoMode()来设置绘图模式。
  SDL_SetVideoMode函数原型,如果操作成功,则返回一个指向SDL_Surface的指针,否则的话返回NULL。
  SDL_Surface *SDL_SetVideoMode(int width, int height, intbpp, Uint32 flags);
  前三个参数分别为屏幕宽度,高度和屏幕上的每象素包含的位数(bits perpixel,BPP)。如果填入0则SDL会自动选择最合适的BPP。第四个参数是一些特殊标志位的集合。有以下这些:
  SDL_SWSURFACE  在系统内存中创建Surface。
  SDL_HWSURFACE  在视频内存中创建Surface。
  SDL_ASYNCBLIT  允许在显示surface上使用异步更新。在单CPU机器上会变慢,但在SMP系统上会有显著的性能提升。
  SDL_ANYFORMAT  如果指定位数的bpp不可用,那么SDL就会模拟使用阴影surface,使用SDL_ANYFORMAT则会避免,不管色深强制SDL使用视频surface。
  SDL_HWPALETTE  给予SDL特许的调色板访问权,如果设定这个标志位,就不需要总是使用SDL_SetColors或者SDL_SetPalette来获取所需的颜色。
  SDL_DOUBLEBUF  允许硬件双缓冲,但必须同时设置SDL_HWSURFACE,调用SDL_Flip将会flip整个缓冲并且更新屏幕,所有的绘制将会在当前未显示的surface上发生。如果双缓冲被允许,那么SDL_Flip将会对整个屏幕进行SDL_UpdateRect操作。
  SDL_FULLSCREEN SDL将会尝试使用全屏模式,如果硬件分辨率的调整由于某种情况无法完成,那么下一个稍高的分辨率将会被使用,并且显示窗口将会处于一个黑色背景的中央。
  SDL_OPENGL     创建一个OPENGL渲染设备上下文,但使用前必须调用函数SDL_GL_SetAttribute对OpenGL进行视频属性设置。
  SDL_OPENGLBLIT 和上一个选项一样创建一个OPENGL渲染设备上下文,但是允许使用正常的blitting操作。2D屏幕surface将会拥有一个alpha通道,而且必须调用函数SDL_UpdateRects来更新屏幕变化。
  SDL_RESIZABLE  创建一个可伸缩大小的窗口,当用户调整窗口大小时,将会触发一个SDL_VIDEORESIZE事件,SDL_SetVideoMode将会使用新大小作为参数再次被调用。
  SDL_NOFRAME    SDL_NOFRAME将会创建出一个没有标题栏和边界修饰的窗口,SDL_FULLSCREEN方式将自动设置此标志位。
  同样,我们可以调用SDL_GetError来获取发生错误的详细信息。
  下面是程序的运行截图:
  
  
  
  如果对上面的程序进行编译运行,那么只能得到一闪而过的一个黑色的窗口。若要绘制真正的图形,我们则需要对窗口进行绘制,并且对基本的键盘鼠标事件进行处理。
  下面就是一个完整的屏幕绘图的程序:
  ----------------------------------------------------------------------
  #include"libnge.h"
  #include"stdio.h"
  void Slock(SDL_Surface *screen)
  {
  if( SDL_MUSTLOCK(screen) )
  {
  if( SDL_LockSurface(screen)format, R,G, B);
  switch(screen->format->BytesPerPixel)
  {
  case 1: // Assuming 8-bpp
  {
  Uint8*bufp;
  bufp = (Uint8*)screen->pixels + y*screen->pitch + x;
  *bufp =color;
  }
  break;
  case 2: // Probably 15-bpp or16-bpp
  {
  Uint16*bufp;
  bufp =(Uint16 *)screen->pixels + y*screen->pitch/2 + x;
  *bufp =color;
  }
  break;
  case 3: // Slow 24-bpp mode,usually not used
  {
  Uint8*bufp;
  bufp = (Uint8*)screen->pixels + y*screen->pitch + x * 3;
  if(SDL_BYTEORDER== SDL_LIL_ENDIAN)
  {
  bufp[0]= color;
  bufp[1]= color >> 8;
  bufp[2]= color >> 16;
  }
  else
  {
  bufp[2]= color;
  bufp[1]= color >> 8;
  bufp[0]= color >> 16;
  }
  }
  break;
  case 4: // Probably32-bpp
  {
  Uint32*bufp;
  bufp =(Uint32 *)screen->pixels + y*screen->pitch/4 + x;
  *bufp =color;
  }
  break;
  }
  }
  voidDrawScene(SDL_Surface *screen)
  {
  Slock(screen);
  for(int x=0;xformat->BitsPerPixel);
  int done=0;
  while(done == 0)
  {
  SDL_Event event;
  while (SDL_PollEvent(&event) )
  {
  if (event.type == SDL_QUIT )
  {
  done = 1;
  }
  if (event.type == SDL_KEYDOWN )
  {
  if( event.key.keysym.sym == SDLK_ESCAPE )
  {
  done = 1;
  }
  }
  }
  DrawScene(screen);
  }
  exit(0);
  }
  ---------------------------------------------------------------
  蓝色代码是在前一份代码上添加的部分,主要是完成了绘图锁定,绘图,及消息处理。
  由于绘制的屏幕不能同时接受两个函数的同时操作,我们需要其他两个辅助函数,用于在绘制前对屏幕进行锁定,以及在绘制完成之后解除锁定。这两个工作一般由SDL_MUSTLOK(SDL_Surface*screen)和SDL_UnlockSurface(SDL_Surface*screen)完成。上面使用了两个自定义的函数,简单一些。
  然后就是绘制了,绘制的基本原理是,先在缓冲区绘制,再一次性将缓冲区绘制到屏幕上。这样比起一次一个象素点在屏幕上绘图的方式效率更高,速度更快,也不易出错。首先使用循环在screen所指向的surface(缓冲区)上绘制,然后调用SDL_Flip函数将screensurface绘制到真实电脑屏幕上。SDL_Flip函数的作用是:在支持双缓冲(double-buffering)的硬件上,建立flip并返回。硬件将等待verticalretrace,然后在下一个视频surfaceblit或者执行锁定返回前交换视频缓冲区。如果硬件不支持双缓冲,那么等同于调用SDL_UpdateRect(screen,0, 0, 0, 0),即对整个screen的绘制区域进行刷新。
  接下来是消息处理,在SDL中,采用了结构SDL_Event来描述事件,并采用循环的机制对事件进行处理,程序中使用一个SDL_Event的对象event来检查事件的发生,这里用一个while循环,不断的调用函数SDL_PollEvent来获取事件,得到的消息将会自动填充event对象,在循环内部,通过判断不同的消息类型,从而做出不同的处理。
  下面是程序运行的截图:
  
  
  
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics