MiniLibX에는 AppKit과 X11이 필요하기 때문에 컴파일시 연결이 필요합니다. 기본 컴파일 프로세스는 다음과 같습니다.
개체 파일의 경우 프로젝트 루트에 mlx
이름이 지정된 디렉토리에 소스 가 있다고 가정하고 메이크파일에 다음 규칙을 추가할 수 있습니다.
%.o: %.c
$(CC) -Wall -Wextra -Werror -Imlx -c $< -o $@
필요한 내부 macOS API(애플리케이션 프로그래밍 인터페이스, 응용 프로그램에서 사용할 수 있도록, 운영 체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스)와 연결하려면 :
$(NAME): $(OBJ)
$(CC) -Lmlx -lmlx -framework OpenGL -framework AppKit -o $(NAME)
libmlx.dylib
동적 라이브러리이므로 빌드 대상과 동일한 디렉토리에 있어야 합니다 .
OpenGL : 오픈 그래픽 라이브러리은 1992년 실리콘 그래픽스사에서 만든 2차원 및 3차원 그래픽스 표준 API 규격으로, 프로그래밍 언어 간 플랫폼 간의 교차 응용 프로그래밍을 지원합니다.
AppKit : 일반적으로 AppKit이라고 하는 Application Kit는 NeXTSTEP의 그래픽 사용자 인터페이스 툴킷 입니다. Foundation 및 Display PostScript 와 함께 OpenStep API 사양의 핵심 부분 중 하나입니다. macOS와 함께 번들로 제공되는 대부분의 응용 프로그램 (예 : Finder , TextEdit , Calendar 및 Preview)은 AppKit을 사용하여 사용자 인터페이스를 제공합니다.
참고
#include <mlx.h>
void *mlx_init();
먼저 소프트웨어와 디스플레이 간의 연결을 초기화하기 위해 mlx_init()
을 사용합니다.
필요할 때 다른 함수에 전달할 수 있도록 모든 MLX 및 창 포인터를 일종의 구조체에 저장합니다.
이 연결이 설정되면 다른 MiniLibX 기능을 사용하여 "이 창에 노란색 픽셀을 그리고 싶습니다" 또는 "사용자가 키를 눌렀습니까?"와 같은 그래픽 명령을 보낼 수 있습니다.
현재 MLX 인스턴스(일반적으로 실행 중인 임의의 프로세스, 클래스의 현재 생성된 오브젝트)의 위치를 반환
→그래픽 서버와의 연결에 대한 식별자를 반환
typedef struct mlx_ptr_s
{
void *appid;
mlx_win_list_t *win_list;
mlx_img_list_t *img_list;
void (*loop_hook)(void *);
void *loop_hook_data;
void *loop_timer;
mlx_img_list_t *font;
int main_loop_active;
} mlx_ptr_t;
mlx_init으로 리턴받는 식별자입니다.
과제를 진행하며 항상 사용하게 될 식별자로 소프트웨어와 디스플레이를 연결합니다.
아래에 나올 mlx_win_list_t 구조체와 mlx_img_list_t 구조체에 대한 포인터를 멤버로 가집니다. 각각 구조체는 연결 리스트 형태를 띄고 있어 한 개의 포인터로 모든 식별자를 관리하는 것으로 보입니다.
참고
int mlx_get_screen_size(void *mlx_ptr, int *sizex, int *sizey)
void *mlx_ptr the mlx instance;
int *sizex the screen width;
int *sizey the screen height
return int has no return value (bc).
현재 스크린의 사이즈(최대 해상도)를 구하는 함수입니다.
참고
void *mlx_new_window (void *mlx_ptr, int size_x, int size_y, char *title);
새 창을 생성하는 함수입니다.
윈도우 사용 식별자인 win_ptr 포인터를 리턴한다. 실패 시 NULL을 리턴합니다.
실질적으로 리턴되는 식별자는 mlx_ptr->win_list입니다.
동적할당된 새로운 win 식별자는 mlx 식별자의 win 식별자 연결리스트의 헤드를 차지하게 됩니다.
typedef struct mlx_win_list_s
{
void *winid;
mlx_img_ctx_t *img_list;
int nb_flush;
int pixmgt;
struct mlx_win_list_s *next;
} mlx_win_list_t;
mlx_new_window로 리턴받는 식별자입니다. 말 그대로 윈도우 창과 연관된 식별자입니다.
자기 자신에 대한 포인터를 멤버로 가집니다. 연결 리스트 형태로 모든 윈도우를 관리합니다. 윈도우를 새로 생성할 때마다 새로 생성한 포인터가 next를 mlx_ptr_t의 mlx_win_list_t 포인터를 가리키며 헤드를 차지하게 됩니다.
참고
void *mlx_new_image(void *mlx_ptr, int width, int height)
메모리에 새로운 이미지를 생성합니다.
mlx_put_image_to_window ()를 사용하여 언제든지 지정된 창 내에서 이미지를 덤프하여 화면에 표시 할 수 있습니다.
나중에 이 이미지를 조작 하는 데 필요한 식별자(mlx_ing_list_t)를 반환합니다. 실패 시 NULL을 리턴합니다.
typedef struct mlx_img_list_s
{
int width;
int height;
char *buffer;
GLfloat vertexes[8];
struct mlx_img_list_s *next;
} mlx_img_list_t;
mlx_new_image로 리턴받는 식별자입니다.
mlx_win_list_t처럼 하나의 연결 리스트로 모든 이미지를 관리하게 됩니다.
참고
char *mlx_get_data_addr(void *img_ptr, int *bits_per_pixel, int *size_line, int *endian)
mlx_new_image함수를 사용하여 이미지 주소(이미지 식별자 포인터)는 가졌지만 픽셀의 주소는 가지고 있지 않습니다. 이때 픽셀의 바이트가 우리가 생각하는 이미지의 모양대로 정렬되지 않았다는 것을 이해하고 있어야 합니다.(픽셀의 주소가 char*형이므로 이차원 배열이 아님) 이때의 size_line은 실제의 창 너비와는 다릅니다. (창 너비를 더한다고 픽셀이 다음 줄으로 넘어가지 않는다) 따라서 우리는 항상 mlx_get_data_addr함수로 설정된 라인 길이를 사용하여 메모리 오프셋(픽셀의 주소)을 계산해야 합니다.
다음 공식을 사용하여 매우 쉽게 계산할 수 있습니다.
int offset = (y * size_line + x * (bits_per_pixel / 8));
생성된 이미지에 대한 정보를 리턴해서 사용자가 나중에 이미지를 수정할 수 있도록 합니다.
사용자가 나중에 수정할 수 있도록 mlx_new_image에서 생성된 이미지에 대한 메모리 주소의 시작 부분의 포인터를 반환합니다.
→반환된 주소로부터, 첫 번째 bits_per_pixel 비트가 이미지의 제일 첫 줄의 첫 번째 픽셀의 색상을 나타낸다.
→두 번째 그룹의 bits_per_pixel 비트는 첫째 줄의 두번째 픽셀을 나타내고 그런 식으로 쭉 나간다.
→주소에 size_line을 추가해서 두 번째 줄 시작점을 얻는다.
→그런 식으로 이미지의 모든 픽셀에 도달 할 수 있습니다.
char * 포인터에 연속으로 색상을 저장할 때 4칸 간격으로 저장하고 저장한 값을 뽑아올 때도 4칸 간격으로 가져오기 때문에 unsigned int형으로 형변환합니다.
int형이 아닌 unsigned int로 하는 이유는 ARGB가 가질 수 있는 값은 0x00000000 ~ 0xFFFFFFFF 로 (unsigned int) 범위와 동일하기 때문입니다.
참고
void * mlx_xpm_file_to_image(void *mlx_ptr, char *filename, int *width, int *height)
mlx_new_image와 유사하게 메모리에 새로운 이미지를 생성합니다. 이때 new_image는 빈 이미지이고, mlx_xpm_file_to_image는 xpm파일을 메모리에 생성하는 것입니다.
이미지 식별자로 null이 아닌 포인터를 반환합니다. 실패시 NULL을 반환합니다.
참고
int mlx_loop(void *mlx_ptr)
그래픽 시스템은 양방향입니다. 한쪽에서는 스크린에 디스플레이할 픽셀, 이미지 등을 명령하고, 한쪽에서는 키보드나 마우스로부터 “이벤트”를 받습니다.
이때 이벤트를 수신하는 함수입니다. 이벤트를 기다린 다음 이 이벤트와 관련된 사용자 정의 함수를 호출하는 무한 루프입니다.
다음 세 가지 이벤트에 다른 기능을 할당할 수 있습니다.
이 세가지 함수 말고도 mlx_hook이 모든 유형의 이벤트에 대한 훨씬 더 일반적인 액세스를 제공합니다. 이벤트 및 마스크 값은 X11에서 가져옵니다.
각 창은 동일한 이벤트에 대해 다른 기능을 정의할 수 있습니다.
무한루프이므로 함수 마지막에 쓰여야 합니다.
없음
참고
int mlx_hook(void *win_ptr, int x_event, int x_mask, int (*funct)(), void *param)
이벤트를 생성하는 함수입니다.
소프트웨어 구성 요소 간에 전달되는 함수 호출이나 메시지 또는 이벤트를 가로채서 운영체제, 응용 프로그램 또는 기타 소프트웨어 구성 요소의 동작을 변경하거나 증대하는데 사용되는 다양한 기술을 포함합니다. 가로채는 함수 호출, 이벤트 또는 메시지를 처리하는 코드를 후크라고 합니다.
*win_ptr : 윈도우 식별자 (mlx_new_window리턴값)
x_event : X11 라이브러리에서 정의된 event이다. 발생시키고 싶은 이벤트를 넣어주면 된다.
x_mask : MacOS에서는 사용되지 않는다. 기본적으로 0을 넣어줍니다.
int (*funct)() : 호출할 함수 포인터. 이벤트 핸들러.
이벤트를 포착했을 경우, 핸들러 함수에 키, 마우스 이벤트에 있어서 추가적인 정보가 전달됩니다. 그 정보는 아래와 같습니다 :
keycode = 어떤 키가 눌려졌는지
x, y = 창에서 눌린 마우스 클릭 좌표(X11의 경우, include 파일 “keysymdef.h”를 확인하시고, MacOS의 경우 그냥 해보세요 :) )
button = 어느 마우스 버튼이 눌렸는지
*param : 호출한 함수 내에서 필요한 파라미터 데이터의 주소값
없음
mlx_key_hook는 key를 누를때마다 이벤트가 일시적으로 발생하지만, mlx_hook는 누르고있는 상태에서 이벤트가 무한히 반복된다.
int mlx_loop_hook(void *mlx_ptr, int (*funct_ptr)(), void *param)
아무 이벤트도 일어나지 않을 경우 인자로 받았던 함수가 호출됩니다.
이벤트 발생 조건 없이 (*funct_ptr)()에 매개변수로 입력된 함수를 무한대로 실행합니다.
*mlx_ptr : 윈도우 식별자 (mlx_new_window리턴값)
(*funct_ptr)() : 호출할 함수 포인터
*param : 호출한 함수 내에서 필요한 파라미터 데이터의 주소값
없음
int mlx_destroy_image ( void *mlx_ptr, void *img_ptr )
주어진 이미지(img_ptr)을 삭제합니다.
*mlx_ptr : 연결 식별자(mlx_init 리턴값)
*img_ptr : 이미지 식별자(mlx_new_img 리턴값)
없음
int mlx_destroy_window ( void *mlx_ptr, void *win_ptr )
지정된 창을 끕니다.
*mlx_ptr : 연결 식별자(mlx_init 리턴값)
*win_ptr : 윈도우 식별자 (mlx_new_window리턴값)
없음
너무 잘 봤어요. 감사합니다. 큰 도움이 됐어요. 꾸준히 올려주세요.