앞에 올린 헤더파일에서 이어지는 내용들이다.

끝나면 전체 헤더파일을 올릴테니 가벼운 마음으로 읽어보시라.


//------------------------------+---------------------------------------------------------------

//  이것은 PAGE 클래스다.

//  뭣에 쓰려고 만들었는고 하니,

//  화면에 보이기 전에 버퍼로 그리는 작업들을 처리하기 위해서 만들었다.

//  스프라이트를 만들수도 있고, 그냥 사각 블럭을 그려 놓을 수도 있다.

//  즉, 재사용 가능한 image resource 를 지원하기 위해 만든 자료형이다.

//  내부에 여러가지 드로잉 함수 ( 라고 쓰고 노가다 라고 읽음 ) 들을 갖고 있다.

 

#include <array>

#include <algorithm>            //  std::min, std::max


//  생성할때 템플릿 파라메터로 크기를 정할 수 있다. 동적 크기 그딴거 귀찮아 지원 안함 크게 만들어 투명 처리 하셈

//  콘솔 화면은 일반적으로 끽해야 80 컬럼 * 25 라인 이다.


template< int x_size = 80, int y_size = 25 >

class                           PAGE

{

    static  const   int         size            = x_size * y_size;

    using                       LINE            = TEX( & )[ x_size ]; // 1차원 배열로 접근하실분~

    using                       MATRIX          = TEX( & )[ y_size ][ x_size ]; // 2차원 배열로 접근하실분~


public:

    std::array< TEX, size >     buffer; // std::array 로 접근하실분~

    MATRIX&                     cells           = (MATRIX&)buffer;

    u8                          text_color      = C4::silver / C4::black; // 이거 별 쓸모 없는데 왜 만들었지

    u8                          number_color    = C4::silver / C4::black; // 그러게 말이다

    u8                          number_size     = (u8)11;                 // 끙..

    auto                        xsize() const { return  x_size; }         // 요즘 width 보다 이 네이밍이 끌린다

    auto                        ysize() const { return  y_size; }         // 요즘 height 보다 이 네이밍이 끌린다 ( width 랑 길이가 달라 짜증나거든 )


    enum    class               TEXT_ALIGN : int

    {

        left,

        right,

    };

    ///-------------------------+---------------------------------------------------------------


    CRE                         PAGE() = default;


    CRE                         PAGE( const PAGE& page )

    {

        buffer = page.buffer;

    }


    void                        fill( const TEX tex ) // 한 TeX ( 문자 + 색상 ) 으로 버퍼 채우기

    {

        buffer.fill( tex );

    }


    void                        put( const int x, const int y, const TEX tex ) // 한 Tex 찍기

    {

        cells[ y ][ x ] = tex;

    }


    void                        put( const int x, const int y, const char c ) // 한 문자 찍기

    {

        put( x, y, { text_color, c } );

    }


    auto                        center_x( const char* s ) // 가운데 정렬 지원하기 - 귀차니즘의 산물

    {

        return  x_size - strlen( s ) >> 1;

    }


    auto                        puts( const int x, const int y, const char* str ) // 문자열 찍기

    {

        int i;

        for( i = 0; str[ i ]; ++i )

            put( x + i, y, str[ i ] );

        return  x + i;

    }


    auto                        puts( const int y, const char* str ) // 중앙정렬된 문자열 찍기

    {

        return  puts( center_x( str ), y, str );

    }


    //  색상 배열을 인자로 주면 색상 배열 색을 하나씩 써서 글씨를 표현해줌. offset 을 주면 색상을 스크롤 시킴

    template< class T, uu SIZE >

    auto                        puts( const int x, const int y, const char* str,

                                      const T( &colors )[ SIZE ], const int offset = 0 )

    {

        int i;

        for( i = 0; str[ i ]; ++i )

            put( x + i, y,

                { static_cast< u8 >( colors[ ( i + offset ) % SIZE ] ), str[ i ] } );

        return  x + i;

    }


    //  당연히 위와 똑같은 함수지만 중앙정렬.

    template< class T, uu SIZE >

    auto                        puts( const int y, const char* str,

                                      const T( &colors )[ SIZE ], const int offset = 0 )

    {

        return  puts( center_x( str ), y, str, colors, offset );

    }


    //  우측정렬을 지원하는 숫자만들기 ( 앞을 공백으로 채우기 )

    template< TEXT_ALIGN align >

    auto                        to_string( const int n ) const

    {

        static  char    numstr[ 14 ];

        int* c = (int*)numstr;

        c[ 2 ] = c[ 1 ] = c[ 0 ] = 0x20202020;


        bool    neg = false;

        u32     u   = n;

        if( n < 0 ) neg = true, u = -n;


        char*   p   = numstr + ( sizeof numstr - 1 );

        char*   end = p - number_size;

        do *--p = u % 10 + '0', u /= 10; while( u );

        if( neg ) *--p = '-';


        if( align == TEXT_ALIGN::left )

            return  p;

        return  end;

    }


    //  위의 함수를 이용해서 숫자를 찍는다.

    template< TEXT_ALIGN align = TEXT_ALIGN::right >

    auto                        text_number( const int x, const int y,

                                             const char* s, const int n )

    {

        return  puts( puts( x, y, s ), y, to_string< align >( n ) );

    }


    //  가로줄 긋기. 뭐 별거 없지?

    void                        horz_line( const int left, const int right,

                                           const int y, const TEX tex )

    {

        for( int x = left; x < right; ++x )

            put( x, y, tex );

    }


    //  세로줄 긋기.

    void                        vert_line( const int x, const int top,

                                           const int bottom, const TEX tex )

    {

        for( int y = top; y < bottom; ++y )

            put( x, y, tex );

    }


    //  사각형 채우기.

    void                        rectangle( const int left, const int top,

                                           const int right, const int bottom, TEX tex )

    {

        const   int y2  = bottom - 1;

        horz_line( left, right, top, tex );

        horz_line( left, right, y2, tex );

        for( int y = top + 1; y < y2; ++y )

            horz_line( left, right, y, tex );

    }


    //  사각 테두리 그리기

    void                        frame( const int left, const int top,

                                       const int right, const int bottom, TEX tex )

    {

        const   int y2  = bottom - 1;

        horz_line( left, right, top, tex );

        horz_line( left, right, y2, tex );

        vert_line( left, top + 1, y2, tex );

        vert_line( right - 1, top + 1, y2, tex );

    }


    //  진한 사각 테두리 그리기 ( 텍스트 한 문자는 세로로 길기 땜에 가로로 두칸 찍어줘야 이쁨 )

    void                        frame_bold( const int left, const int top,

                                            const int right, const int bottom, TEX tex )

    {

        const   int y2  = bottom - 1;

        frame( left, top, right, bottom, tex );

        vert_line( left + 1, top + 1, y2, tex );

        vert_line( right - 2, top + 1, y2, tex );

    }


    //  다른 PAGE 를 이 페이지 위에 그릴 수 있음. ( 비로소 재귀적인 쓰임이 가능 )

    template< int w, int h >

    void                        draw( const int left, const int top, const PAGE< w, h >& page )

    {

        const   int l   = std::max( 0, -left );

        const   int t   = std::max( 0, -top  );

        const   int r   = std::min( w, x_size - left );

        const   int b   = std::min( h, y_size - top  );

        for( int y = t; y < b; ++y )

        {

            const   int yt = y + top;

            for( int x = l; x < r; ++x )

                if( page.cells[ y ][ x ].letter ) //  null 문자면 투명처리됨

                    put( x + left, yt, page.cells[ y ][ x ] );

        }

    }


    //  이 PAGE 를 그레이스케일로 변환

    void                        gray()

    {

        for( auto& tex : buffer )

            tex.color       = c4_to_gray[ static_cast< u8 >( get_fore( tex.color ) ) ] /

                              c4_to_gray[ static_cast< u8 >( get_back( tex.color ) ) ];

    }


    //  한칸 밝은 그레이톤으로

    void                        lighten()

    {

        for( auto& tex : buffer )

        {

            auto    fore    = get_fore( tex.color );

            auto    back    = get_back( tex.color );

            tex.color       = ++fore / ++back;

        }

    }


    //  한칸 어두운 그레이톤으로

    void                        darken()

    {

        for( auto& tex : buffer )

        {

            auto    fore    = get_fore( tex.color );

            auto    back    = get_back( tex.color );

            tex.color       = --fore / --back;

        }

    }

};

//------------------------------+---------------------------------------------------------------


바로 다음으로 넘어가자.