SDL Guide 中文译版(二)

第二章 图像和视频

初始化SDL Video显示

视频是最常用的部分,也是SDL最完整的子系统。下面的初始化过程是每个SDL程序都要做的,即使可能有些不同。

例2-1 初始化视频

    SDL_Surface *screen;

    /* Initialize the SDL library */
    if( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
        fprintf(stderr,
                "Couldn't initialize SDL: %s\n", 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: %s\n",
                        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: %s\n",
                        SDL_GetError());
        exit(1);
    }
    printf("Set 640x480 at %d bits-per-pixel mode\n",
           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_LoadBMP(file_name);
    if (image == NULL) {
        fprintf(stderr, "Couldn't load %s: %s\n", 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: %s\n", 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: %s\n", 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可以在多种平台(Linux/X11, Win32, BeOS, MacOS Classic/Toolbox, MacOS X, FreeBSD/X11 and Solaris/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: %s\n",
             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: %s\n",
             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: %s\n",
             SDL_GetError( ) );
        quit_tutorial( 1 );
    }

OpenGL绘图

除了初始化,在SDL程序中使用OpenGL和其他情况基本相同,是同样函数和数据类型。但是如果您使用双缓冲,则必须用SDL_GL_SwapBuffers()来交换前后缓冲,而不是glxSwapBuffers()(GLX)或SwapBuffers()(Windows)。

例2-8 SDL和OpenGL

/*
 * SDL OpenGL Tutorial.
 * (c) Michael Vance, 2000
 * [email protected]
 *
 * Distributed under terms of the LGPL. 
 */

#include
  1<sdl sdl.h="">
  2    #include <gl gl.h="">
  3    #include <gl glu.h="">
  4    
  5    #include <stdio.h>
  6    #include <stdlib.h>
  7    
  8    static GLboolean should_rotate = GL_TRUE;
  9    
 10    static void quit_tutorial( int code )
 11    {
 12        /*
 13         * Quit SDL so we can release the fullscreen
 14         * mode and restore the previous video settings,
 15         * etc.
 16         */
 17        SDL_Quit( );
 18    
 19        /* Exit program. */
 20        exit( code );
 21    }
 22    
 23    static void handle_key_down( SDL_keysym* keysym )
 24    {
 25    
 26        /* 
 27         * We're only interested if 'Esc' has
 28         * been presssed.
 29         *
 30         * EXERCISE: 
 31         * Handle the arrow keys and have that change the
 32         * viewing position/angle.
 33         */
 34        switch( keysym-&gt;sym ) {
 35        case SDLK_ESCAPE:
 36            quit_tutorial( 0 );
 37            break;
 38        case SDLK_SPACE:
 39            should_rotate = !should_rotate;
 40            break;
 41        default:
 42            break;
 43        }
 44    
 45    }
 46    
 47    static void process_events( void )
 48    {
 49        /* Our SDL event placeholder. */
 50        SDL_Event event;
 51    
 52        /* Grab all the events off the queue. */
 53        while( SDL_PollEvent( &amp;event ) ) {
 54    
 55            switch( event.type ) {
 56            case SDL_KEYDOWN:
 57                /* Handle key presses. */
 58                handle_key_down( &amp;event.key.keysym );
 59                break;
 60            case SDL_QUIT:
 61                /* Handle quit requests (like Ctrl-c). */
 62                quit_tutorial( 0 );
 63                break;
 64            }
 65    
 66        }
 67    
 68    }
 69    
 70    static void draw_screen( void )
 71    {
 72        /* Our angle of rotation. */
 73        static float angle = 0.0f;
 74    
 75        /*
 76         * EXERCISE:
 77         * Replace this awful mess with vertex
 78         * arrays and a call to glDrawElements.
 79         *
 80         * EXERCISE:
 81         * After completing the above, change
 82         * it to use compiled vertex arrays.
 83         *
 84         * EXERCISE:
 85         * Verify my windings are correct here ;).
 86         */
 87        static GLfloat v0[] = { -1.0f, -1.0f,  1.0f };
 88        static GLfloat v1[] = {  1.0f, -1.0f,  1.0f };
 89        static GLfloat v2[] = {  1.0f,  1.0f,  1.0f };
 90        static GLfloat v3[] = { -1.0f,  1.0f,  1.0f };
 91        static GLfloat v4[] = { -1.0f, -1.0f, -1.0f };
 92        static GLfloat v5[] = {  1.0f, -1.0f, -1.0f };
 93        static GLfloat v6[] = {  1.0f,  1.0f, -1.0f };
 94        static GLfloat v7[] = { -1.0f,  1.0f, -1.0f };
 95        static GLubyte red[]    = { 255,   0,   0, 255 };
 96        static GLubyte green[]  = {   0, 255,   0, 255 };
 97        static GLubyte blue[]   = {   0,   0, 255, 255 };
 98        static GLubyte white[]  = { 255, 255, 255, 255 };
 99        static GLubyte yellow[] = {   0, 255, 255, 255 };
100        static GLubyte black[]  = {   0,   0,   0, 255 };
101        static GLubyte orange[] = { 255, 255,   0, 255 };
102        static GLubyte purple[] = { 255,   0, 255,   0 };
103    
104        /* Clear the color and depth buffers. */
105        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
106    
107        /* We don't want to modify the projection matrix. */
108        glMatrixMode( GL_MODELVIEW );
109        glLoadIdentity( );
110    
111        /* Move down the z-axis. */
112        glTranslatef( 0.0, 0.0, -5.0 );
113    
114        /* Rotate. */
115        glRotatef( angle, 0.0, 1.0, 0.0 );
116    
117        if( should_rotate ) {
118    
119            if( ++angle &gt; 360.0f ) {
120                angle = 0.0f;
121            }
122    
123        }
124    
125        /* Send our triangle data to the pipeline. */
126        glBegin( GL_TRIANGLES );
127    
128        glColor4ubv( red );
129        glVertex3fv( v0 );
130        glColor4ubv( green );
131        glVertex3fv( v1 );
132        glColor4ubv( blue );
133        glVertex3fv( v2 );
134    
135        glColor4ubv( red );
136        glVertex3fv( v0 );
137        glColor4ubv( blue );
138        glVertex3fv( v2 );
139        glColor4ubv( white );
140        glVertex3fv( v3 );
141    
142        glColor4ubv( green );
143        glVertex3fv( v1 );
144        glColor4ubv( black );
145        glVertex3fv( v5 );
146        glColor4ubv( orange );
147        glVertex3fv( v6 );
148    
149        glColor4ubv( green );
150        glVertex3fv( v1 );
151        glColor4ubv( orange );
152        glVertex3fv( v6 );
153        glColor4ubv( blue );
154        glVertex3fv( v2 );
155    
156        glColor4ubv( black );
157        glVertex3fv( v5 );
158        glColor4ubv( yellow );
159        glVertex3fv( v4 );
160        glColor4ubv( purple );
161        glVertex3fv( v7 );
162    
163        glColor4ubv( black );
164        glVertex3fv( v5 );
165        glColor4ubv( purple );
166        glVertex3fv( v7 );
167        glColor4ubv( orange );
168        glVertex3fv( v6 );
169    
170        glColor4ubv( yellow );
171        glVertex3fv( v4 );
172        glColor4ubv( red );
173        glVertex3fv( v0 );
174        glColor4ubv( white );
175        glVertex3fv( v3 );
176    
177        glColor4ubv( yellow );
178        glVertex3fv( v4 );
179        glColor4ubv( white );
180        glVertex3fv( v3 );
181        glColor4ubv( purple );
182        glVertex3fv( v7 );
183    
184        glColor4ubv( white );
185        glVertex3fv( v3 );
186        glColor4ubv( blue );
187        glVertex3fv( v2 );
188        glColor4ubv( orange );
189        glVertex3fv( v6 );
190    
191        glColor4ubv( white );
192        glVertex3fv( v3 );
193        glColor4ubv( orange );
194        glVertex3fv( v6 );
195        glColor4ubv( purple );
196        glVertex3fv( v7 );
197    
198        glColor4ubv( green );
199        glVertex3fv( v1 );
200        glColor4ubv( red );
201        glVertex3fv( v0 );
202        glColor4ubv( yellow );
203        glVertex3fv( v4 );
204    
205        glColor4ubv( green );
206        glVertex3fv( v1 );
207        glColor4ubv( yellow );
208        glVertex3fv( v4 );
209        glColor4ubv( black );
210        glVertex3fv( v5 );
211    
212        glEnd( );
213    
214        /*
215         * EXERCISE:
216         * Draw text telling the user that 'Spc'
217         * pauses the rotation and 'Esc' quits.
218         * Do it using vetors and textured quads.
219         */
220    
221        /*
222         * Swap the buffers. This this tells the driver to
223         * render the next frame from the contents of the
224         * back-buffer, and to set all rendering operations
225         * to occur on what was the front-buffer.
226         *
227         * Double buffering prevents nasty visual tearing
228         * from the application drawing on areas of the
229         * screen that are being updated at the same time.
230         */
231        SDL_GL_SwapBuffers( );
232    }
233    
234    static void setup_opengl( int width, int height )
235    {
236        float ratio = (float) width / (float) height;
237    
238        /* Our shading model--Gouraud (smooth). */
239        glShadeModel( GL_SMOOTH );
240    
241        /* Culling. */
242        glCullFace( GL_BACK );
243        glFrontFace( GL_CCW );
244        glEnable( GL_CULL_FACE );
245    
246        /* Set the clear color. */
247        glClearColor( 0, 0, 0, 0 );
248    
249        /* Setup our viewport. */
250        glViewport( 0, 0, width, height );
251    
252        /*
253         * Change to the projection matrix and set
254         * our viewing volume.
255         */
256        glMatrixMode( GL_PROJECTION );
257        glLoadIdentity( );
258        /*
259         * EXERCISE:
260         * Replace this with a call to glFrustum.
261         */
262        gluPerspective( 60.0, ratio, 1.0, 1024.0 );
263    }
264    
265    int main( int argc, char* argv[] )
266    {
267        /* Information about the current video settings. */
268        const SDL_VideoInfo* info = NULL;
269        /* Dimensions of our window. */
270        int width = 0;
271        int height = 0;
272        /* Color depth in bits of our window. */
273        int bpp = 0;
274        /* Flags we will pass into SDL_SetVideoMode. */
275        int flags = 0;
276    
277        /* First, initialize SDL's video subsystem. */
278        if( SDL_Init( SDL_INIT_VIDEO ) &lt; 0 ) {
279            /* Failed, exit. */
280            fprintf( stderr, "Video initialization failed: %s\n",
281                 SDL_GetError( ) );
282            quit_tutorial( 1 );
283        }
284    
285        /* Let's get some video information. */
286        info = SDL_GetVideoInfo( );
287    
288        if( !info ) {
289            /* This should probably never happen. */
290            fprintf( stderr, "Video query failed: %s\n",
291                 SDL_GetError( ) );
292            quit_tutorial( 1 );
293        }
294    
295        /*
296         * Set our width/height to 640/480 (you would
297         * of course let the user decide this in a normal
298         * app). We get the bpp we will request from
299         * the display. On X11, VidMode can't change
300         * resolution, so this is probably being overly
301         * safe. Under Win32, ChangeDisplaySettings
302         * can change the bpp.
303         */
304        width = 640;
305        height = 480;
306        bpp = info-&gt;vfmt-&gt;BitsPerPixel;
307    
308        /*
309         * Now, we want to setup our requested
310         * window attributes for our OpenGL window.
311         * We want *at least* 5 bits of red, green
312         * and blue. We also want at least a 16-bit
313         * depth buffer.
314         *
315         * The last thing we do is request a double
316         * buffered window. '1' turns on double
317         * buffering, '0' turns it off.
318         *
319         * Note that we do not use SDL_DOUBLEBUF in
320         * the flags to SDL_SetVideoMode. That does
321         * not affect the GL attribute state, only
322         * the standard 2D blitting setup.
323         */
324        SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
325        SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
326        SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
327        SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
328        SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
329    
330        /*
331         * We want to request that SDL provide us
332         * with an OpenGL window, in a fullscreen
333         * video mode.
334         *
335         * EXERCISE:
336         * Make starting windowed an option, and
337         * handle the resize events properly with
338         * glViewport.
339         */
340        flags = SDL_OPENGL | SDL_FULLSCREEN;
341    
342        /*
343         * Set the video mode
344         */
345        if( SDL_SetVideoMode( width, height, bpp, flags ) == 0 ) {
346            /* 
347             * This could happen for a variety of reasons,
348             * including DISPLAY not being set, the specified
349             * resolution not being available, etc.
350             */
351            fprintf( stderr, "Video mode set failed: %s\n",
352                 SDL_GetError( ) );
353            quit_tutorial( 1 );
354        }
355    
356        /*
357         * At this point, we should have a properly setup
358         * double-buffered window for use with OpenGL.
359         */
360        setup_opengl( width, height );
361    
362        /*
363         * Now we want to begin our normal app process--
364         * an event loop with a lot of redrawing.
365         */
366        while( 1 ) {
367            /* Process incoming events. */
368            process_events( );
369            /* Draw the screen. */
370            draw_screen( );
371        }
372    
373        /*
374         * EXERCISE:
375         * Record timings using SDL_GetTicks() and
376         * and print out frames per second at program
377         * end.
378         */
379    
380        /* Never reached. */
381        return 0;
382    }</stdlib.h></stdio.h></gl></gl></sdl>
Published At
Categories with Web编程
Tagged with
comments powered by Disqus