SDL Guide 中文譯版(二) (轉)

worldblog發表於2007-12-15
SDL Guide 中文譯版(二) (轉)[@more@] 

第二章 影像和影片

初始化SDL Vo顯示

影片是最常用的部分,也是SDL最完整的子。下面的初始化過程是每個SDL都要做的,即使可能有些不同。

例2-1 初始化影片

SDL_Surface *screen; /* Initialize the SDL library */ if( SDL_Init(SDL_INIT_VIDEO) < 0 ) { fprintf(stderr, "Couldn't initialize SDL: %sn", SDL_GetError()); exit(1); } /* Clean up on exit */ atexit(SDL_Quit); /* * Initialize the display in a 640x480 8-bit palettized mode, * requesting a software surface */ screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE); if ( screen == NULL ) { fprintf(stderr, "Couldn't set 640x480x8 video mode: %sn", SDL_GetError()); exit(1); }


初始化最佳影片

如果你希望某種色深(顏色數)但如果的顯示器不支援也可以接受其他色深,使用加SDL_ANYFORMAT引數的SDL_SetVideoMode。您還可以用SDL_VideoModeOK來找到與請求模式最接近的模式。

例2-2 初始化最佳影片模式

/* Have a preference for 8-bit, but accept any depth */ screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE|SDL_ANYFORMAT); if ( screen == NULL ) { fprintf(stderr, "Couldn't set 640x480x8 video mode: %sn", SDL_GetError()); exit(1); } printf("Set 640x480 at %d bits-per-pixel moden", screen->format->BitsPerPixel);


讀取並顯示BMP

當SDL已經初始化,影片模式已經選擇,下面的將讀取並顯示指定的BMP檔案。

例2-3 讀取並顯示BMP檔案

void display_bmp(char *file_name) { SDL_Surface *image; /* Load the BMP file into a surface */ image = SDL_LoaMP(file_name); if (image == NULL) { fprintf(stderr, "Couldn't load %s: %sn", file_name, SDL_GetError()); return; } /* * Palettized screen modes will have a default palette (a standard * 8*8*4 colour cube), but if the image is palettized as well we can * use that palette for a nicer colour matching */ if (image->format->palette && screen->format->palette) { SDL_SetColors(screen, image->format->palette->colors, 0, image->format->palette->ncolors); } /* Blit onto the screen surface */ if(SDL_BlitSurface(image, NULL, screen, NULL) < 0) fprintf(stderr, "BlitSurface error: %sn", SDL_GetError()); SDL_UpdateRect(screen, 0, 0, image->w, image->h); /* Free the allocated BMP surface */ SDL_FreeSurface(image); }


直接在顯示上繪圖

下面兩個函式實現在影像平面的畫素讀寫。它們被細心設計成可以用於所有色深。記住在使用前要先鎖定影像平面,之後要解鎖。

在畫素值和其紅、綠、藍值間轉換,使用SDL_GetRGB()和SDL_MapRGB()。

例2-4 getpixel()

/* * Return the pixel value at (x, y) * NOTE: The surface must be locked before calling this! */ Uint32 getpixel(SDL_Surface *surface, int x, int y) { int bpp = surface->format->BytesPerPixel; /* Here p is the address to the pixel we want to retrieve */ Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; switch(bpp) { case 1: return *p; case 2: return *(Uint16 *)p; case 3: if(SDL_BYTEORDER == SDL_BIG_ENDIAN) return p[0] << 16 | p[1] << 8 | p[2]; else return p[0] | p[1] << 8 | p[2] << 16; case 4: return *(Uint32 *)p; default: return 0; /* shouldn't happen, but avoids warnings */ } }


例2-5 putpixel()

/* * Set the pixel at (x, y) to the given value * NOTE: The surface must be locked before calling this! */ void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel) { int bpp = surface->format->BytesPerPixel; /* Here p is the address to the pixel we want to set */ Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; switch(bpp) { case 1: *p = pixel; break; case 2: *(Uint16 *)p = pixel; break; case 3: if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { p[0] = (pixel >> 16) & 0xff; p[1] = (pixel >> 8) & 0xff; p[2] = pixel & 0xff; } else { p[0] = pixel & 0xff; p[1] = (pixel >> 8) & 0xff; p[2] = (pixel >> 16) & 0xff; } break; case 4: *(Uint32 *)p = pixel; break; } }


例2-6 使用上面的putpixel()在螢幕中心畫一個黃點

/* Code to set a yellow pixel at the center of the screen */ int x, y; Uint32 yellow; /* Map the color yellow to this display (R=0xff, G=0xFF, B=0x00) Note: If the display is palettized, you must set the palette first. */ yellow = SDL_MapRGB(screen->format, 0xff, 0xff, 0x00); x = screen->w / 2; y = screen->h / 2; /* Lock the screen for direct access to the pixels */ if ( SDL_MUSTLOCK(screen) ) { if ( SDL_LockSurface(screen) < 0 ) { fprintf(stderr, "Can't lock screen: %sn", SDL_GetError()); return; } } putpixel(screen, x, y, yellow); if ( SDL_MUSTLOCK(screen) ) { SDL_UnlockSurface(screen); } /* Update just the part of the display that we've changed */ SDL_UpdateRect(screen, x, y, 1, 1); return;


並用SDL和OpenGL

SDL可以在多種平臺(/X11, , BeOS, MacClassic/Toolbox, MacOS X, Free/X11 and /X11)上建立和使用OpenGL上下文。這允許你在OpenGL程式中使用SDL的、事件、執行緒和記時器,而這些通常是GLUT的任務。

和普通的初始化類似,但有三點不同:必須傳SDL_OPENGL引數給SDL_SetVideoMode;必須使用SDL_GL_SetAttribute指定一些GL屬性(深度緩衝區位寬,幀緩衝位寬等);如果您想使用雙緩衝,必須作為GL屬性指定

例2-7 初始化SDL加OpenGL

/* Information about the current video settings. */ const SDL_VideoInfo* info = NULL; /* Dimensions of our window. */ int width = 0; int height = 0; /* Color depth in bits of our window. */ int bpp = 0; /* Flags we will pass into SDL_SetVideoMode. */ int flags = 0; /* First, initialize SDL's video subsystem. */ if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { /* Failed, exit. */ fprintf( stderr, "Video initialization failed: %sn", SDL_GetError( ) ); quit_tutorial( 1 ); } /* Let's get some video information. */ info = SDL_GetVideoInfo( ); if( !info ) { /* This should probably never happen. */ fprintf( stderr, "Video query failed: %sn", SDL_GetError( ) ); quit_tutorial( 1 ); } /* * Set our width/height to 640/480 (you would * of course let the user decide this in a normal * app). We get the bpp we will request from * the display. On X11, VidMode can't change * resolution, so this is probably being overly * safe. Under Win32, ChangeDisplaySettings * can change the bpp. */ width = 640; height = 480; bpp = info->vfmt->BitsPerPixel; /* * Now, we want to setup our requested * window attributes for our OpenGL window. * We want *at least* 5 bits of red, green * and blue. We also want at least a 16-bit * depth buffer. * * The last thing we do is request a double * buffered window. '1' turns on double * buffering, '0' turns it off. * * Note that we do not use SDL_DOUBLEBUF in * the flags to SDL_SetVideoMode. That does * not affect the GL attribute state, only * the standard 2D blitting setup. */ SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); /* * We want to request that SDL provide us * with an OpenGL window, in a fullscreen * video mode. * * EXERCISE: * Make starting windowed an option, and * handle the resize events proy with * glViewport. */ flags = SDL_OPENGL | SDL_FULLSCREEN; /* * Set the video mode */ if( SDL_SetVideoMode( width, height, bpp, flags ) == 0 ) { /* * This could happen for a variety of reasons, * including DISPLAY not being set, the specified * resolution not being available, etc. */ fprintf( stderr, "Video mode set failed: %sn", SDL_GetError( ) ); quit_tutorial( 1 ); }


OpenGL繪圖

除了初始化,在SDL程式中使用OpenGL和其他情況基本相同,是同樣函式和資料型別。但是如果您使用雙緩衝,則必須用SDL_GL_SBuffers()來前後緩衝,而不是glxSwapBuffers()(GLX)或SwapBuffers()()。

例2-8 SDL和OpenGL

/* * SDL OpenGL Tutorial. * (c) Michael Vance, 2000 * briareos@lokigames.com * * Distributed under terms of the LGPL. */ #include #include #include #include #include static GLboolean should_rotate = GL_TRUE; static void quit_tutorial( int code ) { /* * Quit SDL so we can release the fullscreen * mode and restore the previous video settings, * etc. */ SDL_Quit( ); /* Exit program. */ exit( code ); } static void handle_key_down( SDL_keysym* keysym ) { /* * We're only interested if 'Esc' has * been presssed. * * EXERCISE: * Handle the arrow keys and have that change the * viewing position/angle. */ switch( keysym->sym ) { case SDLK_ESCAPE: quit_tutorial( 0 ); break; case SDLK_SPACE: should_rotate = !should_rotate; break; default: break; } } static void process_events( void ) { /* Our SDL event placeholder. */ SDL_Event event; /* Grab all the events off the queue. */ while( SDL_PollEvent( &event ) ) { switch( event.type ) { case SDL_KEYDOWN: /* Handle key presses. */ handle_key_down( &event.key.keysym ); break; case SDL_QUIT: /* Handle quit requests (like Ctrl-c). */ quit_tutorial( 0 ); break; } } } static void draw_screen( void ) { /* Our angle of rotation. */ static float angle = 0.0f; /* * EXERCISE: * Replace this awful mess with vertex * arrays and a call to glDrawElements. * * EXERCISE: * After completing the above, change * it to use compiled vertex arrays. * * EXERCISE: * Verify my windings are correct here ;). */ static GLfloat v0[] = { -1.0f, -1.0f, 1.0f }; static GLfloat v1[] = { 1.0f, -1.0f, 1.0f }; static GLfloat v2[] = { 1.0f, 1.0f, 1.0f }; static GLfloat v3[] = { -1.0f, 1.0f, 1.0f }; static GLfloat v4[] = { -1.0f, -1.0f, -1.0f }; static GLfloat v5[] = { 1.0f, -1.0f, -1.0f }; static GLfloat v6[] = { 1.0f, 1.0f, -1.0f }; static GLfloat v7[] = { -1.0f, 1.0f, -1.0f }; static GLubyte red[] = { 255, 0, 0, 255 }; static GLubyte green[] = { 0, 255, 0, 255 }; static GLubyte blue[] = { 0, 0, 255, 255 }; static GLubyte white[] = { 255, 255, 255, 255 }; static GLubyte yellow[] = { 0, 255, 255, 255 }; static GLubyte black[] = { 0, 0, 0, 255 }; static GLubyte orange[] = { 255, 255, 0, 255 }; static GLubyte purple[] = { 255, 0, 255, 0 }; /* Clear the color and depth buffers. */ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); /* We don't want to modify the projection matrix. */ glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); /* Move down the z-axis. */ glTranslatef( 0.0, 0.0, -5.0 ); /* Rotate. */ glRotatef( angle, 0.0, 1.0, 0.0 ); if( should_rotate ) { if( ++angle > 360.0f ) { angle = 0.0f; } } /* Send our triangle data to the pipeline. */ glBegin( GL_TRIANGLES ); glColor4ubv( red ); glVertex3fv( v0 ); glColor4ubv( green ); glVertex3fv( v1 ); glColor4ubv( blue ); glVertex3fv( v2 ); glColor4ubv( red ); glVertex3fv( v0 ); glColor4ubv( blue ); glVertex3fv( v2 ); glColor4ubv( white ); glVertex3fv( v3 ); glColor4ubv( green ); glVertex3fv( v1 ); glColor4ubv( black ); glVertex3fv( v5 ); glColor4ubv( orange ); glVertex3fv( v6 ); glColor4ubv( green ); glVertex3fv( v1 ); glColor4ubv( orange ); glVertex3fv( v6 ); glColor4ubv( blue ); glVertex3fv( v2 ); glColor4ubv( black ); glVertex3fv( v5 ); glColor4ubv( yellow ); glVertex3fv( v4 ); glColor4ubv( purple ); glVertex3fv( v7 ); glColor4ubv( black ); glVertex3fv( v5 ); glColor4ubv( purple ); glVertex3fv( v7 ); glColor4ubv( orange ); glVertex3fv( v6 ); glColor4ubv( yellow ); glVertex3fv( v4 ); glColor4ubv( red ); glVertex3fv( v0 ); glColor4ubv( white ); glVertex3fv( v3 ); glColor4ubv( yellow ); glVertex3fv( v4 ); glColor4ubv( white ); glVertex3fv( v3 ); glColor4ubv( purple ); glVertex3fv( v7 ); glColor4ubv( white ); glVertex3fv( v3 ); glColor4ubv( blue ); glVertex3fv( v2 ); glColor4ubv( orange ); glVertex3fv( v6 ); glColor4ubv( white ); glVertex3fv( v3 ); glColor4ubv( orange ); glVertex3fv( v6 ); glColor4ubv( purple ); glVertex3fv( v7 ); glColor4ubv( green ); glVertex3fv( v1 ); glColor4ubv( red ); glVertex3fv( v0 ); glColor4ubv( yellow ); glVertex3fv( v4 ); glColor4ubv( green ); glVertex3fv( v1 ); glColor4ubv( yellow ); glVertex3fv( v4 ); glColor4ubv( black ); glVertex3fv( v5 ); glEnd( ); /* * EXERCISE: * Draw text telling the user that 'Spc' * pauses the rotation and 'Esc' quits. * Do it using vetors and textured quads. */ /* * Swap the buffers. This this tells the to * render the next frame from the contents of the * back-buffer, and to set all rendering operations * to occur on what was the front-buffer. * * Double buffering prevents nasty visual tearing * from the application drawing on areas of the * screen that are being updated at the same time. */ SDL_GL_SwapBuffers( ); } static void setup_opengl( int width, int height ) { float ratio = (float) width / (float) height; /* Our shading model--Gouraud (smooth). */ glShadeModel( GL_SMOOTH ); /* Culling. */ glCullFace( GL_BACK ); glFrontFace( GL_CCW ); glEnable( GL_CULL_FACE ); /* Set the clear color. */ glClearColor( 0, 0, 0, 0 ); /* Setup our viewport. */ glViewport( 0, 0, width, height ); /* * Change to the projection matrix and set * our viewing volume. */ glMatrixMode( GL_PROJECTION ); glLoadIdentity( ); /* * EXERCISE: * Replace this with a call to glFrustum. */ gluPerspective( 60.0, ratio, 1.0, 1024.0 ); } int main( int argc, char* argv[] ) { /* Information about the current video settings. */ const SDL_VideoInfo* info = NULL; /* Dimensions of our window. */ int width = 0; int height = 0; /* Color depth in bits of our window. */ int bpp = 0; /* Flags we will pass into SDL_SetVideoMode. */ int flags = 0; /* First, initialize SDL's video subsystem. */ if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { /* Failed, exit. */ fprintf( stderr, "Video initialization failed: %sn", SDL_GetError( ) ); quit_tutorial( 1 ); } /* Let's get some video information. */ info = SDL_GetVideoInfo( ); if( !info ) { /* This should probably never happen. */ fprintf( stderr, "Video query failed: %sn", SDL_GetError( ) ); quit_tutorial( 1 ); } /* * Set our width/height to 640/480 (you would * of course let the user decide this in a normal * app). We get the bpp we will request from * the display. On X11, VidMode can't change * resolution, so this is probably being overly * safe. Under Win32, ChangeDisplaySettings * can change the bpp. */ width = 640; height = 480; bpp = info->vfmt->BitsPerPixel; /* * Now, we want to setup our requested * window attributes for our OpenGL window. * We want *at least* 5 bits of red, green * and blue. We also want at least a 16-bit * depth buffer. * * The last thing we do is request a double * buffered window. '1' turns on double * buffering, '0' turns it off. * * Note that we do not use SDL_DOUBLEBUF in * the flags to SDL_SetVideoMode. That does * not affect the GL attribute state, only * the standard 2D blitting setup. */ SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); /* * We want to request that SDL provide us * with an OpenGL window, in a fullscreen * video mode. * * EXERCISE: * Make starting windowed an option, and * handle the resize events properly with * glViewport. */ flags = SDL_OPENGL | SDL_FULLSCREEN; /* * Set the video mode */ if( SDL_SetVideoMode( width, height, bpp, flags ) == 0 ) { /* * This could happen for a variety of reasons, * including DISPLAY not being set, the specified * resolution not being available, etc. */ fprintf( stderr, "Video mode set failed: %sn", SDL_GetError( ) ); quit_tutorial( 1 ); } /* * At this point, we should have a properly setup * double-buffered window for use with OpenGL. */ setup_opengl( width, height ); /* * Now we want to begin our normal app process-- * an event l with a lot of redrawing. */ while( 1 ) { /* Process incoming events. */ process_events( ); /* Draw the screen. */ draw_screen( ); } /* * EXERCISE: * Record timings using SDL_GetTicks() and * and print out frames per second at program * end. */ /* Never reached. */ return 0; }


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-993816/,如需轉載,請註明出處,否則將追究法律責任。

相關文章