앞에 올린 헤더파일에서 이어지는 내용들이다.
끝나면 전체 헤더파일을 올릴테니 가벼운 마음으로 읽어보시라.
//------------------------------+---------------------------------------------------------------
// 이것은 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;
}
}
};
//------------------------------+---------------------------------------------------------------
댓글 1