오늘은 여러분께 작은 선물을 준비했다.


낯선 표현들이 나오지만 다음강에서 설명할테니 잠시만 어리둥절 하자.


//==============================================================================================

#pragma warning(disable: 4996)  // _CRT_SECURE_NO_WARNINGS

#include "stdafx.h"

#include <array>

#include <stdio.h>

#include <conio.h>              // _kbhit

#include <Windows.h>

//------------------------------------------------------------------------------------------------


#define CRE                     // constructor mark


using   u8                      = unsigned  char;

using   u16                     = unsigned  short;

using   u32                     = unsigned  int;

using   uu                      = std::size_t;


//------------------------------------------------------------------------------------------------


constexpr   auto                make_color16( u8  l, u8  r, u8  g, u8  b )

{

    return  u8( l << 3 | r << 2 | g << 1 | b );

}


enum    class                   C4 : u8

{

    //                      +  R  G  B

    black   = make_color16( 0, 0, 0, 0 ),

    navy    = make_color16( 0, 0, 0, 1 ),

    green   = make_color16( 0, 0, 1, 0 ),

    teal    = make_color16( 0, 0, 1, 1 ),

    maroon  = make_color16( 0, 1, 0, 0 ),

    purple  = make_color16( 0, 1, 0, 1 ),

    olive   = make_color16( 0, 1, 1, 0 ),

    silver  = make_color16( 0, 1, 1, 1 ),

    gray    = make_color16( 1, 0, 0, 0 ),

    blue    = make_color16( 1, 0, 0, 1 ),

    lime    = make_color16( 1, 0, 1, 0 ),

    aqua    = make_color16( 1, 0, 1, 1 ),

    red     = make_color16( 1, 1, 0, 0 ),

    fuchsia = make_color16( 1, 1, 0, 1 ),

    yellow  = make_color16( 1, 1, 1, 0 ),

    white   = make_color16( 1, 1, 1, 1 ),

};


constexpr   auto                operator/( const C4 fore, const C4 back )

{

    return  u8( static_cast< u8 >( back ) << 4 | static_cast< u8 >( fore ) );

};

//------------------------------------------------------------------------------------------------


class                           CONSOLE

{

    struct                      LETTER

    {

        u8                      color;

        char                    tex;

    };


    static  const   int         width   = 80;

    static  const   int         height  = 25;

    static  const   int         size    = width * height;

    using                       MATRIX  = LETTER (&)[ height ][ width ];


    char                        buffer_[ 8192 ];

    std::array< LETTER, size >  buffer;

    MATRIX&                     screen  = (MATRIX&)buffer;

    HANDLE                      handle;


    void                        go( const short x, const short y ) const

    {

        SetConsoleCursorPosition( handle, { x, y } );

    }


    void                        color( const u8 c ) const

    {

        SetConsoleTextAttribute( handle, c );

    }


    void                        resize( int w, int h ) const

    {

        COORD       coord { w, h };

        SetConsoleScreenBufferSize( handle, coord );

        SMALL_RECT  rect = { 0,0, w - 1, h - 1 };

        SetConsoleWindowInfo( handle, TRUE, &rect );

    }


public:


    CRE                         CONSOLE( bool full_screen = false )

    :   handle( GetStdHandle( STD_OUTPUT_HANDLE ) )

    {

        setvbuf( stdout, (char*)&buffer_, _IOFBF, sizeof buffer_ );

        cursor( false );

        if( full_screen )

            SetConsoleDisplayMode( handle, CONSOLE_FULLSCREEN_MODE, NULL );

        clear();

    }


    void                        cursor( const bool show ) const

    {

        CONSOLE_CURSOR_INFO info = { 1, show };

        SetConsoleCursorInfo( handle, &info );

    }


    void                        flush( const int s = size - 1 ) const

    {

        resize( width, height );

        go( 0, 0 );

        u8  old_color;

        color( old_color = buffer[ 0 ].color );

        putchar( buffer[ 0 ].tex );

        for( int i = 1; i < s; ++i )

        {

            if( old_color != buffer[ i ].color )

            {

                fflush( stdout );

                color( old_color = buffer[ i ].color );

            }

            putchar( buffer[ i ].tex );

        }

        fflush( stdout );

        go( 0, 0 );

    }


    void                        clear()

    {

        buffer.fill( { text_color, ' ' } );

        flush( size );

    }


    u8                          text_color      = 0x07;

    u8                          number_color    = 0x07;

    u8                          number_size     = 11;

    bool                        right_alignment = true;


    void                        put( const u32 x, const u32 y, const LETTER tex )

    {

        screen[ y ][ x ] = tex;

    }


    void                        put( const u32 x, const u32 y, const char c )

    {

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

    }


    auto                        puts( const u32 x, const u32 y, const char* str )

    {

        u32 i;

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

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

        return  x + i;

    }


    template< uu SIZE >

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

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

    {

        u32 i;

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

            put( x + i, y, { colors[ ( i + offset ) % SIZE ], str[ i ] } );

        return  x + i;

    }


    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( !right_alignment )

            return  p;

        return  end;

    }


    auto                        text_number( const u32 x, const u32 y,

                                             const char* s, const int n )

    {

        return  puts( puts( x, y, s ), y, to_string( n ) );

    }                                        

};

//------------------------------------------------------------------------------------------------


int main()

{

    CONSOLE stage;

    u8 color_set1[] = { 15, 7, 8 };

    stage.puts( 2, 1, "Hello teX", color_set1 );

    u8 color_set2[] = { (u8)C4::red, (u8)C4::white, (u8)C4::white, (u8)C4::white };


    stage.puts( 2, 3, "Codesafer's C++ programming guide", color_set2 );


    int i = 0;

    while( !_kbhit() )

    {

        stage.puts( 2, 5, "Codesafer's C++ programming guide", color_set2, i++ );

        stage.flush();

    }

    getchar();


    int frames = 0;

    while( !_kbhit() )

    {

        for( int i = (int)C4::blue; i < 256; i += 16 )

        {

            stage.text_color = i;

            stage.clear();

            stage.text_number( 30, 12, "Hello teX", ++frames );

            stage.flush();

        }

    }

    getchar();

    return  0;

}

//==============================================================================================


안타깝게도 Windows API 를 사용했기 때문에 VC++ 에서 밖에 컴파일되지 않는다.

내가 C++14 문법에 재미를 들인고로 Visual Studio 2015 이상을 권한다.


모든 학문이 그렇듯, 프로그래밍은 무조건 재밌게 공부해야 한다.


실행하면 다음과 같은 텍스트 애니메이션 화면이 나온다.




짧은 프레임웍이지만 이걸론 뭔가 할 수 있을 것 같은 기분이 들지 않는가?