이전 gx 라이브러리 강좌를 보지 않으셨다면 꼭 보시기를 권합니다. 본 라이브러리는 강좌용으로 완벽한 라이브러리를 구현하는 것 보다 교육에 목표를 두었습니다.

또한 이러한 생각으로 강좌를 작성하고 진행하기 때문에 코드는 점차적으로 발전하는 식으로 작성됩니다. 즉, 강좌에 올려진 내용이 최종 결과물이 아니며, 계속 발전되는 코드임을 말씀드립니다.

이전 gx 0.1.0 초기화 함수에 대한 내용이 도움이 되셨나요? 결국은 시스템에 따라 달라지는 칼라 깊이에 따라 다른 함수명이나 코드를 사용하는 대신에 포인터 함수로 융통성을 준다는 얘기가 되겠습니다. 즉, 포인터 함수를 사용함으로써 칼라 깊이가 다르더라도, 프로그램을 수정하거나 재 컴파일하는 일 없이, 가급적 이미 만들어진 프로그램으로 실행할 수 있도록 한다는 것입니다.

동영상에도 말씀을 드렸습니다만, 이전 포인터 함수와의 차이점은 Device Context 정보에 자신의 그래픽 출력을 담당하는 함수를 갖도록 해서 칼라 깊이가 다른 Device Context 도 처리할 수 있도록 발전한 것입니다.

즉, 화면은 16bit 칼라인데, 출력할 bitmap 파일이 32bit라면 16bit 와 32bit 를 읽을 수 있는 함수 2개를 만들어야 합니다. 여기서 작업 내용은 같은데, 칼라 깊이만 다른 이유로 서로 다른 함수 이름을 사용하면 불편할 뿐만 아니라 디버깅도 어지럽습니다.

그런 이유로 Devie Contxet 정보에 칼라 깊이에 따라 처리 함수를 지정해 놓는다면 아래와 같이 사용하기 편리해 집니다. 아래는 화면, 즉 스크린에 대한 Device Context 정보를 구하는 루틴입니다.

dc_t *gx_screen_dc( void)
{
   dc_t  *dc;

   dc = malloc( sizeof( dc_t));
   if ( NULL != dc)
   {
      dc->width      = gx_fb.width;
      dc->height     = gx_fb.height;
      dc->dots       = gx_fb.dots;
      dc->mapped     = gx_fb.mapped;
      dc->coor_x     = 0;
      dc->coor_y     = 0;
      dc->pen_color  = clr_black;
      dc->brush_color= clr_black;

      switch( gx_fb.colors)                                             // 칼라 깊이별 처리가 다른 함수를 지정
      {
      default     :
                     dc->color = gx16_color;
                     dc->clear = gx16_clear;
                     dc->dot   = gx16_dot;
      }
   }
   return dc;
}

switch() 문을 보시면 Device Context에 포인터 함수를 두었고, 칼라 깊이에 따라서 함수를 지정하는 것을 보실 수 있습니다. 이 부분을 이제 확장해 나간다면 라이브러리 답게 다양한 칼라 깊이 문제를 해결할 수 있으리라 생각됩니다.

이렇게 dc에 처리할 함수를 지정해 놓았기 때문에 아래와 같이 같은 함수로 처리가 가능합니다.

gx_clear( dc_scr, clr_black);
gx_dot  ( dc_scr, 100, 100, clr_yellow);

gx_clear( dc_bmp, clr_black);
gx_dot  ( dc_bmp, 100, 100, clr_yellow);

이제 소스를 보겠습니다. 이런 식으로 강좌를 진행해 가면서 라이브러리를 발전시켜 나가겠습니다. 많은 기대를 부탁드립니다. ^^

gx.h

#ifndef _GX_H_
#define _GX_H_

#define  GXERR_NONE              0                          // 에러 없음
#define  GXERR_NO_DEVICE         -1                         // 장치가 없음
#define  GXERR_ACCESS_DEVICE     -2                         // 접근 권한이 없음
#define  GXERR_VSCREENINFO       -3                         // FBIOGET_VSCREENINFO를 구하지 못함
#define  GXERR_FSCREENINFO       -4                         // FBIOGET_FSCREENINFO를 구하지 못함
#define  GXERR_MEMORYMAPPING     -5                         // 프레임 버퍼 메모리 매핑에 실패

#define  clr_clear               0x8000000                  // 출력하지 않는 색상
#define  clr_black               0x00                       // 검은 색

typedef struct framebuffer_t_ framebuffer_t;
struct framebuffer_t_
{
   int      fd;                                             // 프레임 버퍼에 대한 파일 디스크립터
   int      width;
   int      height;
   int      bytes;                                          // 메모리 전체 크기
   int      dots;
   int      colors;

   unsigned short *mapped;                                  // 메모리 매핑된 포인터
};

typedef struct dc_t_ dc_t;
struct dc_t_
{
   int      width;
   int      height;
   int      dots;
   int      coor_x;
   int      coor_y;
   int      pen_color;
   int      brush_color;
   unsigned short *mapped;                                  // 메모리 매핑된 포인터

   int  (*color)( int red, int green, int blue);
   void (*clear)( dc_t *dc, int color);
   void (*dot  )( dc_t *dc, int coor_x, int coor_y, int color);
};

extern         framebuffer_t  gx_fb;                        // 프레임 버퍼 정보

extern int     gx_init( char *dev_name);
extern void    gx_close( void);
extern dc_t   *gx_screen_dc( void);
extern void    gx_release_dc( dc_t *dc);

extern int  gx_color( dc_t *dc, int red, int green, int blue);
extern void gx_clear( dc_t *dc, int color);
extern void gx_dot  ( dc_t *dc, int coor_x, int coor_y, int color);

#endif

gx.c

#ifndef _GX_H_
#define _GX_H_

#define  GXERR_NONE              0                          // 에러 없음
#define  GXERR_NO_DEVICE         -1                         // 장치가 없음
#define  GXERR_ACCESS_DEVICE     -2                         // 접근 권한이 없음
#define  GXERR_VSCREENINFO       -3                         // FBIOGET_VSCREENINFO를 구하지 못함
#define  GXERR_FSCREENINFO       -4                         // FBIOGET_FSCREENINFO를 구하지 못함
#define  GXERR_MEMORYMAPPING     -5                         // 프레임 버퍼 메모리 매핑에 실패

#define  clr_clear               0x8000000                  // 출력하지 않는 색상
#define  clr_black               0x00                       // 검은 색

typedef struct framebuffer_t_ framebuffer_t;
struct framebuffer_t_
{
   int      fd;                                             // 프레임 버퍼에 대한 파일 디스크립터
   int      width;
   int      height;
   int      bytes;                                          // 메모리 전체 크기
   int      dots;
   int      colors;

   unsigned short *mapped;                                  // 메모리 매핑된 포인터
};

typedef struct dc_t_ dc_t;
struct dc_t_
{
   int      width;
   int      height;
   int      dots;
   int      coor_x;
   int      coor_y;
   int      pen_color;
   int      brush_color;
   unsigned short *mapped;                                  // 메모리 매핑된 포인터

   int  (*color)( int red, int green, int blue);
   void (*clear)( dc_t *dc, int color);
   void (*dot  )( dc_t *dc, int coor_x, int coor_y, int color);
};

extern         framebuffer_t  gx_fb;                        // 프레임 버퍼 정보

extern int     gx_init( char *dev_name);
extern void    gx_close( void);
extern dc_t   *gx_screen_dc( void);
extern void    gx_release_dc( dc_t *dc);

extern int  gx_color( dc_t *dc, int red, int green, int blue);
extern void gx_clear( dc_t *dc, int color);
extern void gx_dot  ( dc_t *dc, int coor_x, int coor_y, int color);

#endif

gx16.h

gx16.h 와 gx16.c 는 16bt 칼라를 처리하는 함수입니다.

#ifndef _GX_16_H_
#define _GX_16_H_

#include	<gx.h>
										// 16 bit 칼라 함수를 선언

extern int	gx16_color	( int red, int green, int blue);
extern void	gx16_clear	( dc_t *dc, int color);
extern void	gx16_dot		( dc_t *dc, int coor_x, int coor_y, int color);

#endif

gx16.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>        // abs

#include <unistd.h>        // open/close
#include <fcntl.h>         // O_RDWR
#include <sys/ioctl.h>     // ioctl
#include <sys/mman.h>      // mmap PROT_
#include <linux/fb.h>
#include <gx.h>

//--------------------------------------------------------------------
// 설명: 칼라 값을 구한다.
// 인수: red         0부터 255 사이의 red   값
//       green       0부터 255 사이의 green 값
//       blue        0부터 255 사이의 blue  값
// 참고: 16 bit 환경에 따라 shift=0:5:6:5, shift=0:11:5:0
//--------------------------------------------------------------------
int   gx16_color( int red, int green, int blue)
{
   red   >>= 3;                           // 8bit 인수 값을 칼라 bit 크기 만큼 축소
   green >>= 2;                           // 8bit 인수 값을 칼라 bit 크기 만큼 축소
   blue  >>= 3;                           // 8bit 인수 값을 칼라 bit 크기 만큼 축소
   
   return   ( red << 11) | ( green << 5) | blue;
}

//--------------------------------------------------------------------
// 설명: 스크린을 특정 칼라로 채움
// 인수: color       칼라
//--------------------------------------------------------------------
void  gx16_clear( dc_t *dc, int color)
{
   int             ndx;
   unsigned short *ptr;

   if (clr_clear > color)
   {
      ptr = dc->mapped;

      for ( ndx = 0; ndx < dc->dots; ndx++)
         *ptr++ = color;
   }     
}

//--------------------------------------------------------------------
// 설명: 점을 찍는다.
// 인수: coor_x         x 좌표
//       coor_y         y 좌표
//       color          점 색상
// 참고: 좌표 값을 확인하여 엉뚱한 좌료가 입력되도
//       실행 에러가 발생하지 않도록 한다.
//--------------------------------------------------------------------
void  gx16_dot( dc_t *dc, int coor_x, int coor_y, int color)
{
   unsigned short *ptr;

   if ( 0 > coor_x || dc->width  <= coor_x)     return;
   if ( 0 > coor_y || dc->height <= coor_y)     return;

   ptr   = dc->mapped +dc->width * coor_y + coor_x;
   *ptr  = color; 
}

sample.c

위 라이브러리를 어떻게 사용했는지에 대한 예제입니다.

#include    <stdio.h>
#include    <gx.h>         // graphic library
#include    <unistd.h>     // sleep
                      
void test( void)
{  
   dc_t    *dc;
   int      ndx;
   int      clr_yellow;

   if ( NULL != ( dc = gx_screen_dc()))
   {
      gx_clear( dc, gx_color( dc, 255,   0,   0)); sleep( 1);
      gx_clear( dc, gx_color( dc,   0, 255,   0)); sleep( 1);
      gx_clear( dc, gx_color( dc,   0,   0, 255)); sleep( 1);
      gx_clear( dc, gx_color( dc, 128, 128, 128)); sleep( 1);
      gx_clear( dc, gx_color( dc,   0, 128, 128)); sleep( 1);
      gx_clear( dc, gx_color( dc,   0,   0, 128)); sleep( 1);
      gx_clear( dc, gx_color( dc, 255, 255, 255)); sleep( 1);
      gx_clear( dc, clr_black                   ); sleep( 1);

      clr_yellow  = gx_color( dc, 255, 255, 0);
      for ( ndx = 0; ndx < 400; ndx++)
      {
         gx_dot( dc, ndx, ndx, clr_yellow);
      }              
   }
   else
   {
      printf( "스크린 dc를 얻지 못했습니다.n");
   }
}

int   main( void)
{
   switch( gx_init( "/dev/fb") )
   {
      case  GXERR_NO_DEVICE      :  printf( "프레임 버퍼 장치가 없습니다.n"              ); return -1;
      case  GXERR_ACCESS_DEVICE  :  printf( "프레임 버퍼 장치 접근 권한이 없습니다.n"    ); return -1;
      case  GXERR_VSCREENINFO    :  printf( "FBIOGET_VSCREENINFO를 실행하지 못했습니다.n"); return -1;
      case  GXERR_FSCREENINFO    :  printf( "FBIOGET_FSCREENINFO를 실행하지 못했습니다.n"); return -1;
      case  GXERR_MEMORYMAPPING  :  printf( "메모리 메핑을 못했습니다.n"                 ); return -1;
      default                    :  test();
   }

   gx_close();
   return   0;
}