티스토리 뷰
42cursus에 있는 grahics programming과 events programming 과제들을 하기위해서는 miniLibX(이하 mlx)라는 Library의 사용이 적극 권장된다. 잘 사용해서 grahics, events programming을 하기 위해 mlx가 무엇인지 알아보도록 하자.
1. mlx는 무엇일까?
MiniLibX - Simple X-Window Interface Library for students
mlx는 X-Window에 대한 지식 없이도 쉽게 그래픽 소프트웨어을 만들 수 있도록 제작되었다. 간단한 창 생성, 그리기 도구, 이미지 및 기본적인 이벤트 관리 기능을 제공한다. X-Window란 네트워크 기반 그래픽 시스템이다. X-Window에는 X-Server와 X-Client가 있다. X-Server는 X-Client에게 명령을 받아 요청의 결과로 디스플레이 장치에 출력해준다. 또한 키보드, 마우스와 같은 사용자의 입력(events)을 X-Client에게 전달해주는 역할을 한다. mlx API를 이용하기 위해서는 mlx.h를 include해야한다. 이 헤더파일은 mlx 함수의 prototype들 만 포함되어 있고 구조체는 포함되지 않는다.
2. mlx에는 어떤 것들이 있을까?
2-1. Initialize the connection
void *mlx_init();
가장 먼저, 소프트웨어와 디스플레이 사이의 연결을 초기화 시킬 필요가 있다. 연결이 한 번 설정이 되고 나면, X-Server에 메세지를 보내기 위해 mlx에 있는 다른 함수들을 사용할 수 있다. mlx_init()은 이러한 연결을 초기화해서 만든다. 성공한다면 포인터를 반환하는데 다른 mlx의 함수들을 호출할 때 사용되는 'Connection Identifier(or Screen Connection Identifier)'이다. 실패하면 NULL 포인터를 반환한다.
2-2. Managing windows
void *mlx_new_window(void *mlx_ptr, int size_x, int size_y, char *title);
스크린에 새로운 윈도우 창을 만든다. size_x와 size_y를 이용해서 창의 크기를 결정한다. title은 창 위의 title bar에 적힐 텍스트 문자열이다. 성공한다면 포인터를 반환하는데 다른 mlx 함수들을 호출할 때 사용되는 Window Identifier다. mlx는 여러개의 윈도우 창들을 관리할 수 있다.
int mlx_clear_window(void *mlx_ptr, void *win_ptr);
주어진 윈도우 창을 검정색으로 clear하는 데 사용된다.
int mlx_destroy_window(void *mlx_ptr, void *win_ptr);
주어진 윈도우 창을 제거하는 데 사용된다.
2-3. Drawing inside windows
int mlx_pixel_put(void *mlx_ptr, void *win_ptr, int x, int y, int color);
윈도우 창 안에서 인자로 받은 (x, y)좌표에 주어진 color로 픽셀을 그린다. (0, 0)좌표는 윈도우 창의 왼쪽 상단 끝을 나타낸다.
int mlx_string_put(void *mlx_ptr, void *win_ptr, int x, int y, int color, char *string);
(x, y)좌표에 주어진 color 색상으로 주어진 string 문자열을 그린다. 위 함수들에서 color 파라미터는 int 타입을 가진다. 나타낼 수 있는 색깔은 Red, Green, Blue 3가지로 표현될 수 있다. 이 3가지 색깔은 각자 0~255사이의 값을 가지고 있다. 각 값들은 표현될 color에 대해 각 RGB가 나타내는 수치다. RGB의 값에 따라 color integer안의 byte들은 아래와 같이 채워진다.
| 0 | R | G | B | color integer
+---+---+---+---+
2-4. Manipulating images
void *mlx_new_image(void *mlx_ptr, int width, int height);
새로운 image를 메모리에 만든다. width, height 인자들로 크기를 결정한다. 성공하면 image를 조작하는데 사용될 포인터를 반환한다. 사용자는 image 안에서 그릴 수 있고 언제라도 윈도우 창 안에 그 image를 나타낼 수 있다.
int mlx_put_image_to_window(void *mlx_ptr, void *win_ptr, void *img_ptr, int x, int y);
윈도우 창 안에 그 image를 나타낼 때 사용되는 함수다. (x, y)좌표는 윈도우 창 안에서 image가 위치할 좌표이다.
char *mlx_get_data_addr(void *img_ptr, int *bits_per_pixel, int *size_line, int *endian);
만들어진 image에 대한 정보가 저장된 곳의 시작 주소를 반환한다. 사용자가 수정할 수 있도록 하기 위해서다.
bits_per_pixel은 픽셀의 색깔을 나타내는데 필요한 bit 개수를 나타낸다.(image에 대한 깊이라고도 불린다.) 예를들어, 하나의 픽셀의 색깔을 나타내는데 4bytes가 필요하다면 4bytes * (8bits / 1byte) = 32이므로 32의 값이 저장된다.
size_line은 image의 한 줄을 메모리에 저장하는데 사용되는 byte들의 개수로 채워진다. size_line을 주소에 더하면 image의 2번째 줄에 있는 첫번째 픽셀의 주소로 이동할 수 있다. 이런 방식으로 image에 있는 모든 픽셀에 접근할 수 있다.
endian은 image 안에 있는 픽셀 샐깔들이 little endian나 big endian 둘 중 어떤 방식으로 저장되는지 말해준다. (endian: 컴퓨터의 메모리와 같은 1차원의 공간에 여러 개의 연속된 대상을 배열하는 방법을 뜻한다. endian은 보통 큰 단위가 앞에 나오는 빅 엔디언(Big-endian)과 작은 단위가 앞에 나오는 리틀 엔디언(Little-endian)으로 나눌 수 있다.)
int mlx_destroy_image(void *mlx_ptr, void *img_ptr);
주어진 image를 제거한다.
unsigned int mlx_get_color_value(void *mlx_ptr, void *win_ptr, void *img_ptr, int x, int y);
디스플레이에 따라 픽셀의 샐깔을 저장하는데 사용되는 bits가 변경될 수 있다. image의 bits_per_pixel에 맞게 변환해야하고 X-Server가 이해할 수 있도록 만들어야 한다. 이러한 목적으로 만든 함수가 mlx_get_color_value()이다. RGB parameter를 unsigned int 타입으로 반환한다.
void *mlx_xpm_to_image(void *mlx_ptr, char **xpm_data, int *width, int *height);
void *mlx_xpm_file_to_image(void *mlx_ptr, char *filename, int *width, int *height);
위 함수들은 둘 다 같은 방식으로 새로운 image를 만든다. 각각 지정된 xpm_data나 filename 인자를 이용해서 image를 채운다. 성공하면 반환값으로 image를 다룰 수 있는 포인터를 반환한다.
2-5. Handle events
int mlx_loop(void *mlx_ptr);
event를 받기 위해선, 반드시 mlx_loop()를 사용해야 한다. 이 함수는 끝나지 않고 event를 기다리기 위해 무한 루프를 돈다. event를 받으면 그 event와 관련된 사용자가 정의한 함수를 호출한다. 받을 수 있는 events의 종류에는 3가지가 있다. : key, mouse, expose
1) key: 키보드의 key가 눌려졌을 때. 2) mouse: mouse의 버튼이 눌러졌을 때. 3) expose: 창(window)가 선택되어 모니터 상에서 나타났을 때
int mlx_key_hook(void *win_ptr, int (*funct_ptr)(), void *param);
int mlx_mouse_hook(void *win_ptr, int (*funct_ptr)(), void *param);
int mlx_expose_hook(void *win_ptr, int (*funct_ptr)(), void *param);
위 3개의 함수는 완전히 같은 방식으로 동작한다. funct_ptr는 event가 발생했을 때, 불러오길 원하는 함수의 포인터다. param 포인터는 함수가 호출될 때 마다 funct_ptr에 위치한 함수로 들어가는 인자다. param에는 필요한 parameters를 담은 구조체 주소를 사용하는 것이 유용하다.
int mlx_loop_hook(void *win_ptr, int (*funct_ptr)(), void *param);
위에 있는 hook 관련 함수들과 동일하게 동작하지만, mlx_loop_hook()은 아무런 event가 일어나지 않아도 호출된다. hook 관련 함수들이 호출되었을 때, fnct_ptr에 있는 함수들은 아래와 같이 인자들을 받는다.(함수들의 이름은 임의로 설정할 수 있다.)
key_hook(int keycode, void *param);
mouse_hook(int button, int x, int y, void *param);
expose_hook(void *param); loop_hook(void *param);
key_hook()에 있는 keycode는 키보드에 어떤 키가 눌려졌는지 알려주고, mouse_hook()에 있는 button과 (x, y) 좌표는 마우스의 어떤 버튼이 윈도우 창의 어느 좌표를 눌렀는지 알려준다.
int mlx_hook(void *win_ptr, int x_event, int x_mask, int (*funct)(), void *param);
일반적으로 사용이 가능하게 모든 X_Window의 events에 대해 접근가능한 mlx_hook()도 있다. 위에 있는 hook관련 함수들과 동작 방법은 같지만 x_event와 x_mask 인자를 추가로 받는다.
※
man mlx
'C' 카테고리의 다른 글
[c] strjoin 함수 구현하기 (0) | 2022.01.14 |
---|---|
[c] strdup 함수 구현하기 (0) | 2022.01.07 |
strnstr()에서 NO CRASH(no segfault) 처리 (0) | 2021.05.14 |
memcpy()와 memmove()에서 null 처리 (0) | 2021.05.13 |
void 포인터를 다른 타입으로 캐스팅하고 인덱스 이용하기 (0) | 2021.05.13 |