드디어 마지막 헤더파일이다.

이번엔 콘솔 화면을 제어하기 위한 Windows API 함수들과 함께한다.

저수준의 제어를 하지 않고 화면에 출력할 경우,

80컬럼 25라인째 되는 우측 하단에 한 문자를 찍는 순간 한 줄 자동 스크롤되어버리는걸 경험하게 될 것이다.

이 코드들을 통해서 화면전체를 마음껏 쓸 수 있게 되며,

고수준 함수에 비해 엄청난 출력속도를 보여줄 것이다.


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


#include <conio.h>              //  _kbhit

#include <Windows.h>


//  기본 콘솔 크기는 80 컬럼, 25 라인

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

class                           SCREEN

{

    char                        buffer[ 8192 ];

    HANDLE                      handle;


    //  화면의 특정 좌표로 커서를 옮기기 ( gotoxy )

    //  그전까지 버퍼링 된 출력을 내보내야 ( fflush ) 의도대로 동작될 것이다.

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

    {

        fflush( stdout );

        SetConsoleCursorPosition( handle, { x, y } );

    }


    //  출력할 색상 정하기

    auto                        color( const u8 c ) const

    {

        fflush( stdout );

        SetConsoleTextAttribute( handle, c );

        return  c;

    }


    //  창 크기 조절하기

    void                        resize( short w, short h ) const

    {

        COORD       coord { w, h };

        SetConsoleScreenBufferSize( handle, coord );

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

        SetConsoleWindowInfo( handle, TRUE, &rect );

    }


public:

    //  화면에 그릴 페이지를 하나 만들어 두자. 일종의 off_screen buffer 구실을 한다.

    PAGE< x_size, y_size >      top_page;


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


    //  전체화면 모드를 지원할 수 있지만, 뭐 별로 쓸모 없을것 같다. 커서는 안보이게 해두자. 게임만들꺼니까.

    CRE                         SCREEN( bool full_screen = false )

    :   handle( GetStdHandle( STD_OUTPUT_HANDLE ) )

    {

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

        if( full_screen )

            SetConsoleDisplayMode( handle, CONSOLE_FULLSCREEN_MODE, NULL );

        SetConsoleMode( handle, 0x0008 ); // DISABLE_NEWLINE_AUTO_RETURN

        cursor( false );

    }


    auto                        xsize() const { return  x_size; }


    auto                        ysize() const { return  y_size; }


    void                        cursor( const bool show ) const

    {

        CONSOLE_CURSOR_INFO info = { 1, show };

        SetConsoleCursorInfo( handle, &info );

    }


    //  임시버퍼를 통해 실제 출력하는 함수. 모아서 버리기~

    void                        flush()

    {

        resize( x_size, y_size );

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

        for( int y = 0; y < y_size; ++y )

        {

            go( 0, y );

            TEX* scanline = top_page.cells[ y ];

            for( int x = 0; x < x_size; ++x )

            {

                if( old_color != scanline[ x ].color )

                    old_color = color( scanline[ x ].color );

                putchar( scanline[ x ].letter );

            }

        }

        fflush( stdout );

    }


    //  fade in / out 을 지원하기 위한 함수. 뭐 별거 없다.

    template< class F >

    void                        fade( const int delay, F operation )

    {

        top_page.gray();

        flush();

        for( int i = 0; i < 4; ++i )

        {

            ::Sleep( delay );

            operation();

            flush();

        }

    }


    void                        fadeout( const int delay = 1000 )

    {

        fade( delay, [ this ]{ top_page.lighten(); } );

    }


    void                        fadein( const int delay = 1000 )

    {

        fade( delay, [ this ]{ top_page.darken(); } );

    }


    //  키입력을 대기하면서 뭔가 주어진 일을 하다가 입력받은 키를 리턴한다.

    template< class F = void(*)() >

    auto                        waitfor_press( F f = []{} )

    {

        while( !_kbhit() ) f();

        return  getchar();

    }

};

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


쉽죠~ 헤더파일은 끝났으니 바로 예제로 넘어가자.