이번 시간에는 콘솔 텍스트 화면을 제어하기 위한 공부를 하겠다.
//------------------------------+---------------------------------------------------------------
#include <cstddef> // std::size_t
#define CRE // constructor ( place holder )
using u8 = unsigned char; // 길게 치기 싫으니 난 요렇게
using u16 = unsigned short;
using u32 = unsigned int;
using uu = std::size_t;
//------------------------------+---------------------------------------------------------------
// TEX color space
// 콘솔창을 저수준 제어하기 위해서 ( 고수준은 억수로 느림 )
// 과거 호랑이 담배피던 DOS 시절, B800 : 0000 물리적인 주소에 구현되어 있던 텍스트 화면이
// 한 문자당 2바이트로 표현하던 것을 알아두면 좋다. 왜냐하면 지금도 한 문자당 2바이트를 필요로 하기 때문이다.
// 화면에 찍히는 한 문자는 아스키 코드 1 바이트, 그리고 색상 1 바이트로 이루어지는데,
// 색상은 배경색이 상위 nibble, 전경색이 ( 글씨색 ) 하위 nibble 이다.
// 각 색상은 +( 밝게 / 혹은 깜박이게 ), r, g, b 각각 1 비트씩 총 4비트로 이루어져 있다.
// lighten, red, green, blue 를 인자로 1 nibble color 를 만들어주는 코드
constexpr auto make_color16( u8 l, u8 r, u8 g, u8 b )
{
return u8( l << 3 | r << 2 | g << 1 | b );
}
// 그리하야 표준 16색의 열거형 상수를 표현했다. ( 사실 단순 증가기 땜에 rvalue 는 필요 없지만 이해를 돕고자 )
// 색상 이름 찾아보는거 귀찮았었다. ( 작년에 만든것임 )
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 ),
};
// 전경색 / 배경색 으로 코드를 작성하면 알아서 1바이트가 조합이 되게
constexpr auto operator/( C4 fore, C4 back )
{
return u8( static_cast< u8 >( back ) << 4 | static_cast< u8 >( fore ) );
};
// 전경색만 뽑아 오기
constexpr auto get_fore( u8 color )
{
return static_cast< C4 >( color & 0xF );
}
// 배경색만 뽑아오기
constexpr auto get_back( u8 color )
{
return static_cast< C4 >( color >> 4 );
}
// 뭐야? 죄다 비트연산이잖아?
// 그렇다 비트 연산 못하는 프로그래머는 솔까말 쓸모가 없다.
// 아래는 꼭 필요하진 않지만 칼라를 그레이로 바꾸기 위해 만들어봤다. ( fade in / fade out 되는것 처럼 구현 할려고 )
constexpr C4 c4_to_gray[]
{
C4::black, C4::gray, C4::gray, C4::gray, C4::gray, C4::gray, C4::gray, C4::silver,
C4::gray, C4::silver,C4::silver,C4::silver,C4::silver,C4::silver,C4::silver,C4::white,
};
constexpr u32 to_gray_level[]
{
0, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, 3,
};
// 그레이로 쓸만한게 아쉽게도 4색 뿐
constexpr C4 gray_level_to_c4[]
{
C4::black, C4::gray, C4::silver, C4::white,
};
// 증가 감소 연산만 사용해도 알아서 검은색에서 더 아래로 내려가지 않고 흰색에서 더 위로 올라가지 않게
// 32비트 리터럴 문자열을 이용한 테크닉 ( 좀전에 고안함 )
constexpr C4 level_to_c4_clamp( u32 level )
{
return gray_level_to_c4[ U"001233"[ level + 1 ] ]; // 문자열 안의 숫자 앞에 백슬래시를 붙이시라
}
// 증가 / 감소 연산만 하면 알아서 그레이 스케일 안에서 움직인다.
auto& operator++( C4& c )
{
return c = level_to_c4_clamp( to_gray_level[ static_cast< u8 >( c ) ] + 1 );
};
auto& operator--( C4& c )
{
return c = level_to_c4_clamp( to_gray_level[ static_cast< u8 >( c ) ] - 1 );
};
//------------------------------+---------------------------------------------------------------
// 위에서 말했듯, 색상을 갖고 있는 한 문자를 위한 자료형이다.
struct TEX
{
u8 color;
char letter;
CRE TEX() = default;
CRE TEX( const u8 color, const char c )
: color( color ), letter( c ) {}
CRE TEX( const int value )
: color( value & 0xFF ), letter( ( value & 0xFF00 ) >> 8 ) {}
};
//------------------------------+---------------------------------------------------------------
별거 없지? 바로 다음 레슨으로 들어가자.
ㄴ 개념글 가 있당~