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

プレゼンハムのアルゴリズムを使って、矩形を描画する関数を作ってみました。






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);

#define W   200
#define H   200

#define DRW_PARAM   RECT_WINDOW

int main(int argc,char *argv[])
{
    Uint8   flg = 1;
    Sint8   p_flg;
    Uint8   pxl = 1;
    SDL_Rect rects[9] = { 
        {   0,      0,  W,  H},
        {   200,    0,  W,  H},
        {   400,    0,  W,  H},
        {   0,      200,W,  H},
        {   200,    200,W,  H},
        {   400,    200,W,  H},
        {   0,      400,W,  H},
        {   200,    400,W,  H},
        {   400,    400,W,  H},
    };
    Uint32  color[9] = {
        0x90EE90,
        0xffff00,
        0x00ffff,
        0xff00ff,
        0x87CFFA,
        0xFFD700,
        0x008080,
        0xFFA500,
        0xD8BFD8,
    };

    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(600,600,32,SDL_SWSURFACE)) == NULL)
    {
        printf("SetVideoMode Error : %s",SDL_GetError());
        return -1;
    }

    for(p_flg = 1; flg; )
    {
        SDL_FillRect(g_screen, NULL, 0x00000000);
        switch( rcv_event() )
        {
            case 1: flg = 0;    break;
            case 2:
            break;
            default:
                {
                int idx = 0;
                int t = abs(pxl + p_flg);

                if((t >= W/2) || (t < 1)) {
                    p_flg *= -1;
                    pxl += p_flg;
                }else{
                    pxl += p_flg;
                }
                while(idx < 9)
                {
                    drw_rect(&rects[idx],pxl,color[idx],DRW_PARAM,g_screen);
                    idx++;
                }
            }
            SDL_Flip(g_screen);
                break;
        }
        SDL_Delay(60);
    }
    
    SDL_FreeSurface(g_screen);
    SDL_Quit();

    return 0;
}

Graphics.c

/*--------------------------------------*/
/*      作成日時        2009/02/15      */
/*      概要            矩形を描画する  */
/*      Descripsion                     */
/*      return value                    */
/*                                      */
/*--------------------------------------*/
int drw_rect(SDL_Rect *r, Uint8 pxl, Uint32 color, Uint8 flg, SDL_Surface *screen)
{
    Sint16  x1,y1,x2,y2;

    x1 = r->x;
    y1 = r->y;
    x2 = r->x+r->w-1;
    y2 = r->y+r->h-1;

    /********************************************/
    /*      描画する線の幅はWIDTHの半分まで     */
    /********************************************/
    if(pxl > r->w/2 || pxl < 1 )
    {
        return -1;
    }

    switch( flg )
    {
    case RECT_NORMAL:       /*      通常の矩形を描画                */
    {
        while(pxl-- > 0)
        {
            drw_line(x1, y1, x2, y1, color, screen);
            drw_line(x2, y1, x2, y2, color, screen);
            drw_line(x2, y2, x1, y2, color, screen);
            drw_line(x1, y2, x1, y1, color, screen);
            if(pxl > 0)
            {
                x1++;
                x2--;
                y1++;
                y2--;
            }
        }
        break;
    }
    case RECT_GRADATION:    /*      矩形の色をグラデーションさせる  */
    {   
        Sint16 R = color>>16&0xff;
        Sint16 G = color>>8 &0xff;
        Sint16 B = color    &0xff;

        while(pxl-- > 0)
        {
            drw_line(x1, y1, x2, y1, color, screen);
            drw_line(x2, y1, x2, y2, color, screen);
            drw_line(x2, y2, x1, y2, color, screen);
            drw_line(x1, y2, x1, y1, color, screen);
            if(pxl > 0)
            {
                x1++;
                x2--;
                y1++;
                y2--;
                R = (R - 1 < 0) ? 0 :   R - 1;
                G = (G - 1 < 0) ? 0 :   G - 1;
                B = (B - 1 < 0) ? 0 :   B - 1;
                color = (R<<16) + (G<<8) + (B);
            }
        }
        break;
    }
    case RECT_WINDOW:       /*      ウィンドウ風の図形を作成する    */
        if(r->w > DRW_MIN_W && r->h > DRW_MIN_W)
        {
            Uint8   inc_r,dec_r;
            Uint8   inc_g,dec_g;
            Uint8   inc_b,dec_b;
            Uint8   rl,rd;
            Uint8   gl,gd;
            Uint8   bl,bd;
            
            inc_r   =   (0xff - (color>>16  &0xff))/pxl;
            inc_g   =   (0xff - (color>>8   &0xff))/pxl;
            inc_b   =   (0xff - (color      &0xff))/pxl;

            dec_r   =   (color>>16  &0xff)/pxl;
            dec_g   =   (color>>8   &0xff)/pxl;
            dec_b   =   (color      &0xff)/pxl;

            rl  =   (color>>16  &0xff) + inc_r;
            gl  =   (color>>8   &0xff) + inc_g;
            bl  =   (color      &0xff) + inc_b;

            rd  =   (color>>16  &0xff) - dec_r;
            gd  =   (color>>8   &0xff) - dec_g;
            bd  =   (color      &0xff) - dec_b;

            x1 += pxl-1;
            x2 -= pxl-1;
            y1 += pxl-1;
            y2 -= pxl-1;

            /************************************/
            /*      端以外の領域を塗りつぶす    */
            /************************************/
            {
                SDL_Rect rect_t = {x1,y1,x2-x1,y2-y1};
                SDL_FillRect(screen, &rect_t, color);
            }

            while(pxl-- > 0)
            {
                color   =   (rl<<16) + (gl<<8) + (bl);
                drw_line(x1, y1, x2, y1, color, screen);
                drw_line(x1, y2, x1, y1, color, screen);
                
                color   =   (rd<<16) + (gd<<8) + (bd);
                drw_line(x2, y1, x2, y2, color, screen);
                drw_line(x2, y2, x1, y2, color, screen);
                
                if(pxl > 0)
                {
                    x1--;
                    x2++;
                    y1--;
                    y2++;
                    
                    rl += inc_r;
                    gl += inc_g;
                    bl += inc_b;

                    rd -= dec_r;
                    gd -= dec_g;
                    bd -= dec_b;
                }
            }
        }
        break;
    default:
        break;
    }
    return 0;
}