SDLで描画ライブラリの作成

今回はプレゼンハムの線分発生アルゴリズムを使って、線を描く関数を作ります。



Enterキーを押すと、ライン描画関数を使ったグラデーションの矩形を描画します。

Enterを繰り返し押下するごとに、描画する矩形の色が変わります。


main.c

#include <SDL/SDL.h>
#include "drw_line.h"

#pragma comment(lib,"SDL.lib")
#pragma comment(lib,"SDLmain.lib")

SDL_Surface *g_screen;
int rcv_event(void);

int main(int argc,char *argv[])
{
    Uint8   r,g,b;
    Uint8   flg = 1;
    Sint8   inc[3] = {1,1,-1};
    r   = 0x00;
    g   = 0x00;
    b   = 0xff;

    if( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
    {
        printf("Initialize Error : %s",SDL_GetError());
        return -1;
    }

    SDL_WM_SetCaption("SDL",NULL);

    if( (g_screen = SDL_SetVideoMode(456,456,32,SDL_SWSURFACE)) == NULL)
    {
        printf("SetVideoMode Error : %s",SDL_GetError());
        return -1;
    }

    while( flg )
    {
        SDL_FillRect(g_screen, NULL, 0x00000000);
        switch( rcv_event() )
        {
            case 1: flg = 0;    break;
            case 2:
            {
                int x1,x2,y1,y2;
                int drw_w;

                x1  = 100;
                x2  = 356;
                y1  = 100;
                y2  = 356;

                drw_w = (x2 + x1)/2;

                while(x1 <= drw_w)
                {
                    drw_line(x1,y1,x2,y1,0,(r<<16)+(g<<8)+b,g_screen);
                    drw_line(x2,y1,x2,y2,0,(r<<16)+(g<<8)+b,g_screen);
                    drw_line(x2,y2,x1,y2,0,(r<<16)+(g<<8)+b,g_screen);
                    drw_line(x1,y2,x1,y1,0,(r<<16)+(g<<8)+b,g_screen);
                    x1++;
                    x2--;
                    y1++;
                    y2--;
                    r += inc[0];
                    g += inc[1];
                    b += inc[2];
                }
                switch(flg)
                {
                case 1: inc[0] = 1,inc[1] = -1,inc[2] = -1;
                        r = 0x00,g = 0xff,b = 0xff;
                        break;
                case 2: inc[0] = -1,inc[1] = 1,inc[2] = -1;
                        r = 0xff,g = 0x00,b = 0xff;
                        break;
                case 3: inc[0] = -1,inc[1] = -1,inc[2] = 1;
                        r = 0xff,g = 0xff,b = 0x00;
                        break;
                case 4: inc[0] = -1,inc[1] = 1,inc[2] = 1;
                        r = 0xff,g = 0x00,b = 0x00;
                        break;
                }
                if( flg++ > 4){
                    flg = 1;
                    inc[0] = 1,inc[1] = 1,inc[2] = -1;
                    r = 0x00,g = 0x00,b = 0xff;
                }

            }
            SDL_Flip(g_screen);
            break;

            default:
                break;
        }
        SDL_Delay(60);
    }
    
    SDL_FreeSurface(g_screen);
    SDL_Quit();

    return 0;
}


int rcv_event( void )
{
    SDL_Event   ev;
    SDLKey      *key;

    while( SDL_PollEvent( &ev ) )
    {
        switch( ev.type )
        {
            case SDL_QUIT:
                return 1;
                break;
            case SDL_KEYDOWN:
            /************************************/
            /*      キー情報を取得する          */
            /************************************/
                key = &(ev.key.keysym.sym);
                switch( *key )
                {
                    case SDLK_ESCAPE:
                        return 1;   //終了通知
                        break;
                    case SDLK_RETURN:
                        return 2;
                    default:
                        break;
                }
            //----------------------------------//
            //      GetKeyEvent END             //
            //----------------------------------//
            default:
                break;
        }
    }
    return 0;                       //イベントなし
}

Graphics.c

#pragma     comment(lib,"SDL.lib")
#pragma     comment(lib,"SDLmain.lib")

/********************************************************************************/
/*                              関数プロトタイプ                                */
/********************************************************************************/

/********************************************************************************/
/*                                  関数の実装                                  */
/********************************************************************************/

/*----------------------------------------------------------------------*/
/*      作成日時        2009/02/10                                      */
/*      概要            プレゼンハムの線分発生アルゴリズムを使った      */
/*                      直線描画関数                                    */
/*      Descripsion                                                     */
/*      return value                                                    */
/*                                                                      */
/*----------------------------------------------------------------------*/
int     drw_line(Sint16 x0,Sint16 y0,Sint16 x1,Sint16 y1,
                            Uint8 pxl, Uint32 color, SDL_Surface *screen)
{
    if( screen->locked == 0 )
    {
        if( SDL_LockSurface( screen ) >= 0)
        {
            Uint32  *fld;
            Uint32  *adr_min;
            Uint32  *adr_max;
            Sint16  E, x, y, w;
            Sint16  cnt;
            Uint16  pitch;
            Uint8   bpp;
            Sint16  p_flg;
            const   Sint8   INC_X = (x1 - x0 >= 0)  ?   1   :   -1;
            const   Sint8   INC_Y = (y1 - y0 >= 0)  ?   1   :   -1;
            const   Uint16  REV_X = abs(2*(x1 - x0));   /*  xの補正値を設定 */
            const   Uint16  REV_Y = abs(2*(y1 - y0));   /*  yの補正値を設定 */


            adr_min = (Uint32*)screen->pixels;
            adr_max = (Uint32*)screen->pixels + screen->h * screen->w;
            x = x0;
            y = y0;
            w = screen->w;
            pitch   = screen->pitch;
            bpp     = screen->format->BytesPerPixel;
            p_flg = abs(x1-x0) - abs(y1-y0);

            if( screen->format->BitsPerPixel != 8)
            {
                color = SDL_MapRGB(screen->format,
                    (Uint8)(color>>16),(Uint8)(color>>8),(Uint8)color);
            }else{
                return -1;
            }

            if(p_flg > 0)
            {
                /*          Xの増分値が常に1以上            */

                E = -(abs(x1 - x0));
                cnt = (x < x1)  ?   x   :   x1 - (x - x1);

                do{

                    /*      描画対象のアドレスを計算        */

                    fld = adr_min + (x) + (y * w);

                    /*      描画領域から外れていなければ    */

                    if( (fld >= adr_min) && (fld < adr_max) )
                    {

                        /*  指定の色で描画する  */

                        *fld = color;
                    }
                    x += INC_X;
                    E += REV_Y;
                    if( E >= 0)
                    {
                        y += INC_Y;
                        E -= REV_X;
                    }
                }while(cnt++ < x1);
            }else
            if(p_flg < 0)
            {

                /*          Yの増分値が常に1以上            */

                E = -(abs(y1 - y0));
                cnt = (y < y1)  ?   y   :   y1 - (y - y1);

                do{

                    /*      描画対象のアドレスを計算        */

                    fld = adr_min + (x) + (y * w);

                    /*      描画領域から外れていなければ    */

                    if( (fld >= adr_min) && (fld < adr_max) )
                    {

                        /*  指定の色で描画する  */

                        *fld = color;
                    }
                    y += INC_Y;
                    E += REV_X;
                    if( E >= 0)
                    {
                        x += INC_X;
                        E -= REV_Y; 
                    }
                }while(cnt++ < y1);
            }else{

                /*          XとYの増分値が常に1             */

                cnt = (x < x1)  ?   x   :   x1 - (x - x1);

                do{

                    /*      描画対象のアドレスを計算        */

                    fld = adr_min + (x) + (y * w);

                    /*      描画領域から外れていなければ    */

                    if( (fld >= adr_min) && (fld < adr_max) )
                    {

                        /*  指定の色で描画する  */

                        *fld = color;
                    }
                    x += INC_X;
                    y += INC_Y;
                }while(cnt++ < x1);
            }

            SDL_UnlockSurface( screen );
        }else{
            //push Error Message
        }
    }
    return 0;
}