Love Every Moment

[SOLONG] MiniLibX 라이브러리 매뉴얼 읽고 사용해보기 본문

MOMENT:: RECORD/42 SEOUL

[SOLONG] MiniLibX 라이브러리 매뉴얼 읽고 사용해보기

해 송 2022. 1. 7. 19:34
반응형

 

man minilibx_mms_20200219/man/man3/파일이름

 

 

1. MiniLibX 란?

Simple Window Interface Library for students

 

42 학생들을 위해 만들어진 작은 그래픽 라이브러리로 OpenGL 을 사용하여 화면에 무언가를 렌더링해준다.

 X-window 나 AppKit 에 대한 지식이 없어도 창을 띄우고 그림을 그릴 수 있게 해준다.

MiniLibX API 를 사용하기 위해서는 mlx.h 헤더 파일을 포함시켜야 한다.

이 헤더 파일에 들어 있는 각각의 함수가 해주는 역할은 다음과 같다.

 


 

2. 링크

 

gcc -L[miniLibX가 있는 상대 경로] -lmlx -framework OpenGL -framework Appkit -lz main.c

 

컴파일 시에 -L 플래그를 사용하여 MiniLibX 가 있는 상대 경로를 알려주어야 한다.

 

또는 Makefile 을 다음처럼 작성하면 된다.

%.o: %.c
	$(CC) -Wall -Wextra -Werror -Imlx -c $< -o $@
$(NAME): $(OBJ)
	$(CC) $(OBJ) -Lmlx -lmlx -framework OpenGL -framework AppKit -o $(NAME)

 

주의: libmlx.dylib 는 동적 라이브러리이므로 타겟을 빌드할 당시 같은 디렉토리 안에 있어야 한다.

 

 


 

3. 사용법

(1) 초기화 함수

 

mlx_init() 은 어떠한 매개변수도 필요 없으며 void * 연결 식별자를 반환한다.

사용자의 소프트웨어와 디스플레이의 연결을 초기화해준다.

만약 연결에 실패할 시에는 (void *)0, 즉 NULL 을 반환한다.

 


 

(2) 윈도우 관리 함수

 

mlx_new_window() 는 새 창을 생성하는 함수이다.

mlx_ptr 는 mlx_init이 반환한 연결 식별자, size_x 와 size_y 는 창의 크기, title 은 창의 타이틀 바에 보이는 문자열이다.

새 창 생성에 성공하면 연결을 확인하는 용도의 void * 창 식별자인 win_ptr 을 반환하고, 실패 시 NULL 을 반환한다.

참고로 MiniLibX 는 복수의 창을 처리할 수도 있다.

 

mlx_clear_window() 는 창을 검은 색으로 지우는 역할을 한다.

mlx_destroy_window() 는 창을 종료하는 역할을 한다.

두 함수 공통으로 쓰이는 매개변수 mlx_ptr 은 연결 식별자, 그리고 wini_ptr 은 창 식별자이다.

 


 

(3) 그림 함수

 

mlx_pixel_put 은 지정된 픽셀을 그리는 함수이다.

mlx_string_put 은 지정된 문자열을 그리는 함수이다.

지정된 픽셀을
color 색으로 ( 0x00RRGGBB )
win_ptr 창의
x, y 좌표(_, _) 에 그린다.

 

여기서 (0,0) 이 좌측 상단이 된다는 점을 유의해야 한다.

따라서 x는 오른쪽으로, y는 아래를 향해 포인팅하며 y 좌표가 양수면 아래로 향한다.

연결 식별자인 mlx_ptr 연결 식별자를 매개 변수로 필요로 한다.

 

 

 

Bitshifting

여기서 color 매개 변수는 int 형식으로 표현된다.

따라서 색을 TRGB 형식에 맞추어 정의하기 위해서는 비트를 전환해야 한다.

0xTTRRGGBB

 

위의 형식에서 각 문자가 의미하는 것은 T(Transparency), R(Red), G(Green), B(Blue) 이다.

각 바이트는 2^8 = 256 (1바이트=8비트) 개의 값을 가지며 범위는 0~255 가 된다.

따라서 T, R, G, B 를 합친 RGB 값은 4바이트인 int 에 완벽하게 맞는다.

각 색상의 원색을 표현하는 방법은 다음과 같다.

 

Red 0x00FF0000
Green 0x0000FF00
Blue 0x000000FF

 

각 T, R, G, B 값을 원하는 방식(0xTTRRGGBB)으로 표현하기 위해서는 비트 시프팅이 필요하다.

int	create_trgb(int t, int r, int g, int b)
{
	return (t << 24 | r << 16 | g << 8 | b);
}

 

반대로, 이미 TRGB 형식으로 표현된 것에서 각각의 값을 뽑아내고 싶다면 다음의 과정을 거치면 된다.

int	get_t(int trgb)
{
	return ((trgb >> 24) & 0xFF);
}

int	get_r(int trgb)
{
	return ((trgb >> 16) & 0xFF);
}

int	get_g(int trgb)
{
	return ((trgb >> 8) & 0xFF);
}

int	get_b(int trgb)
{
	return (trgb & 0xFF);
}

 

두 함수 모두 창 밖의 모든 디스플레이를 삭제하므로 속도가 매우 느리다.

 

 


 

(4) 이미지 관리 함수

 

mlx_new_image() 는 메모리에 새로운 이미지를 생성해준다.

추후 이미지를 조작하는 데에 필요한 void * 식별자를 반환한다.

필요한 매개 변수는 생성하려는 이미지의 크기, 그리고 mlx_ptr 연결 식별자이다.

 

mlx_put_image_to_window() 는 이미지를 스크린에 출력해준다.

화면 연결, 창, 그리고 이미지를 위한 세 개의 식별자가 매개 변수로 필요하다.

x, y 는 창 내에서 이미지가 위치할 좌표를 의미한다.

 

mlx_get_data_addr() 은 생성된 이미지에 대한 정보를 반환한다.

이를 통해 사용자는 추후 이미지를 수정할 수 있다.

img_ptr 포인터는 사용하려는 이미지를 지정한다.

bits_per_pixel 은 픽셀 색상, size_line 은 메모리 상에서 이미지 한 줄을 저장하는 데에 쓰인 바이트 수, 그리고 endian 은 픽셀 색상이 리틀 엔디언과 빅 엔디언 방식 중에서 어떤 방식으로 저장되는지 구별하는데에 사용된다.

 

mlx_get_color_value() 는 이미지 내부에 색상을 저장한다.

반환값은 int 였던 color 를 unsigned color 로 변환한 값이다.

 

mlx_xpm_to_image(), mlx_xpm_file_to_image(), mlx_png_file_to_image() 는 같은 방식으로 이미지를 생성한다.

이미지 생성에 성공 시에 이미지 식별자인 img_ptr 을 반환하며, 실패 시에는 NULL 을 반환한다.

 

mlx_destroy_image() 는 주어진 이미지(img ptr)를 삭제한다.

 


 

(5) 이벤트 관리 함수

 

그래픽 시스템은 양방향이다.

한 쪽에서는 화면으로 명령을 보내 픽셀, 이미지 등을 띄운다.

다른 한 쪽에서는 키보드와 마우스로부터 이벤트를 받는다.

 

이벤트를 받기 위해 필요한 함수가 mlx_loop() 이다.

무한 루프로서 이벤트를 기다렸다가 이벤트와 연결된 사용자 정의 함수를 호출한다.

필요한 매개 변수는 mlx_ptr 뿐이며 아무 것도 반환하지 않는다.

 

키보드 키가 눌렸을 때, 마우스 버튼이 눌렸을 때, 그리고 "expose" 이벤트가 발생했을 때 각각 함수를 할당할 수 있다.

mlx_expose_hook() 은 expose 이벤트(12) 에서 mlx_hook() 함수를 부르는 것과 같다.

mlx_key_hook()은 key up 이벤트(3)에서 mlx_hook() 함수를 부르는 것과 같다.

mlx_mouse_hook()은 mouse down 이벤트(4)에서 mlx_hook() 함수를 부르는 것과 같다.

 

mlx_key_hook(), mlx_mouse_hook(), mlx_expose_hook()  은 모두 같은 방식으로 작동한다.

funct_ptr 은 이벤트가 발생하면 호출하고 싶은 함수를 가리키는 포인터이다.

이 함수 포인터는 win_ptr 에 의해 특정된 창에만 적용된다.

param 은 함수가 필요로 할 매개 변수를 저장하는 데에 사용된다.

 

mlx_loop_hook() 은 위의 세 함수와 동일하게 작동하나, 아무런 이벤트도 발생하지 않았을 경우에는 매개 변수로 받았던 함수를 호출한다.

MiniLibX 는 이벤트를 포착한 경우 아래의 함수를 고정 파라미터로 호출한다.

함수 명은 임의로 정해졌으며, 우리가 스스로 만들어야 하는 함수의 원형이라고 생각하면 된다.

  • expose_hook(void *param);
  • key_hook(int keycode, void *param);
  • mouse_hook(int button, int x, int y, void *param);
  • loop_hook(void *param);

 

여기서 param 은 mlx_***_hook 의 호출에 지정된 주소로 Minilibx 에 의해 사용되거나 수정되지 않는다.

x 와 y 는 창에서 마우스를 클릭할 때의 좌표를 의미한다.

keycode 와 button 은 각각 어떤 키보드 키를 눌렀는지와 어떤 마우스 버튼을 눌렀는 지를 의미한다.

 


 

 

4. MiniLibX 를 활용해보자

(1) 초기화

#include <mlx.h>

int main(void)
{
  void *mlx;

  mlx = mlx_init();
}

 

mlx_init() 함수를 통해 MiniLibX 를 초기화하였다.

여기까지 하면 컴파일은 정상적으로 되고, 실행 파일도 열리지만 아무 창도 뜨지 않고 변화가 없다.

왜냐하면 아직 window 창을 생성하지 않았기 때문이다.

아래의 mlx_new_window() 함수를 불러 창을 생성해보자.

그리고 mlx_loop() 함수까지 불러야 창을 렌더링 할 수 있다.

 


 

(2) 창 생성

#include <mlx.h>

int     main(void)
{
    void    *mlx;
    void    *mlx_win;

    mlx = mlx_init();
    mlx_win = mlx_new_window(mlx, 1920, 1080, "Hello world!");
    mlx_loop(mlx);
}

 

mlx_new_window() 함수를 통해 너비가 1920, 높이가 1080, 제목이 "Hello World!" 인 창을 생성하였다.

이렇게 검은색으로 초기화된 창을 띄우는 것까지 성공하였다.

아직 x 버튼을 마우스로 눌러도 프로그램을 종료하도록 프로그래밍하지 않았으므로 ctrl + c 를 눌러 종료해준다.

기본적인 창 관리 능력을 갖추었으니 이제 픽셀을 윈도우에 그려보자.

 


 

(3) 이미지에 픽셀 그리기

시작하기에 앞서 mlx_pixel_put() 함수가 매우 느리다는 점을 유의해야 한다.

왜냐하면 프레임이 완전히 렌더링되기도 전에 즉시 픽셀을 그려넣으려고 하기 때문이다.

이러한 이유로 우리는 모든 픽셀을 버퍼에 담은 다음에 윈도우에 올릴 것이다.

 

우선 mlx_pixel_put() 함수가 어떤 타입의 이미지를 요구하는지 알아야 한다.

이미지 그리기를 시작하려면 우리는 중요한 변수들을 가리키는 포인터를 전달해주어야 한다.

첫 번째는 bpp(Bits per Pixel) 이다.

보통의 픽셀은 int 형식이므로 4 바이트이지만, 리틀 엔디언의 경우에는 다를 수 있다.

이 경우 원격 화면에 머무르고 있을 가능성이 높으며 8 비트 색상만 존재한다는 것을 의미한다.

이제 1920 x 1080 사이즈의 이미지를 초기화 시켜보자.

#include <mlx.h>

int	main(void)
{
	void	*img;
	void	*mlx;

	mlx = mlx_init();
	img = mlx_new_image(mlx, 1920, 1080);
}

(아직 mlx_loop() 을 코드에 넣어주지 않았으므로 잠깐 떴다가 사라지는 것은 정상이다.)

 

이제 이미지는 가지고 있지만 여기에 어떻게 픽셀을 쓸까?

이를 위해서는 바이트를 변환시킬(mutate) 메모리 주소가 필요하다.

이러한 메모리 주소는 다음을 통해 얻을 수 있다.

 

#include <mlx.h>

typedef struct	s_data {
	void	*img;
	char	*addr;
	int		bits_per_pixel;
	int		line_length;
	int		endian;
}				t_data;

int	main(void)
{
	void	*mlx;
	t_data	img;

	mlx = mlx_init();
	img.img = mlx_new_image(mlx, 1920, 1080);

	/*
	** After creating an image, we can call `mlx_get_data_addr`, we pass
	** `bits_per_pixel`, `line_length`, and `endian` by reference. These will
	** then be set accordingly for the *current* data address.
	*/
	img.addr = mlx_get_data_addr(img.img, &img.bits_per_pixel, &img.line_length,
								&img.endian);
}

 

위의 방식으로 bits_per_pixel, line_length, endian 의 주소를 전달(by reference)하게 된다.

이제 이미지 주소는 있지만 아직 픽셀이 없다.

우선 우리는 바이트가 정렬되지 않았으므로 line_length 가 실제 창의 너비와 다를 수 있다는 것을 알아야 한다.

그래서 mlx_get_data_addr() 에 의해 세팅된 line_length 를 사용하여 메모리 오프셋을 계산하여야 한다.

int offset = (y * line_length + x * (bits_per_pixel / 8));

 

이제 메모리 주소의 출발점을 알았으니 mlx_pixel_put() 함수를 따라하면서도 더 빠른 함수를 만들어보자.

 

typedef struct	s_data {
	void	*img;
	char	*addr;
	int		bits_per_pixel;
	int		line_length;
	int		endian;
}				t_data;

void	my_mlx_pixel_put(t_data *data, int x, int y, int color)
{
	char	*dst;

	dst = data->addr + (y * data->line_length + x * (data->bits_per_pixel / 8));
	*(unsigned int*)dst = color;
}

 

위의 코드는 문제가 있다.

이미지는 창에 실시간으로 보여지기 때문에, 같은 이미지를 변경하는 일은 화면이 찢어지는 듯한 현상을 일으킨다.

그래서 프레임을 일시적으로 유지시키기 위해서는 두 개 이상의 이미지를 생성해야 한다.

이렇게 되면 현재 보여지고 있는 이미지가 아닌 임시 이미지에 픽셀을 입힐 수 있게 된다.

 


 

(4) 이미지를 창에 띄우기

이제 이미지를 생성할 수 있으니 창에 띄워 실제로 우리가 볼 수 있게 할 차례이다.

예를 들어 (5,5) 자리에 빨간색 픽셀을 그려 창에 띄우는 과정을 살펴보자.

#include <mlx.h>

typedef struct	s_data {
	void	*img;
	char	*addr;
	int		bits_per_pixel;
	int		line_length;
	int		endian;
}				t_data;

void	my_mlx_pixel_put(t_data *data, int x, int y, int color)
{
	char	*dst;

	dst = data->addr + (y * data->line_length + x * (data->bits_per_pixel / 8));
	*(unsigned int*)dst = color;
}

int	main(void)
{
	void	*mlx;
	void	*mlx_win;
	t_data	img;

	mlx = mlx_init();
	mlx_win = mlx_new_window(mlx, 1920, 1080, "Hello world!");
	img.img = mlx_new_image(mlx, 1920, 1080);
	img.addr = mlx_get_data_addr(img.img, &img.bits_per_pixel, &img.line_length,
								&img.endian);
	my_mlx_pixel_put(&img, 5, 5, 0x00FF0000);
	mlx_put_image_to_window(mlx, mlx_win, img.img, 0, 0);
	mlx_loop(mlx);
}

 

참고로 0x00FF0000 은 ARGB(0, 255, 0, 0)의 16진수 표현이다.

이것을 컴파일하여 a.out 을 실행하면 아래와 같이 작은 빨간 점이 창에 보이게 된다.

 

 

 


5. Hooks

#include <mlx.h>
#include <stdio.h>

typedef struct	s_vars {
	void	*mlx;
	void	*win;
}				t_vars;

int	key_hook(int keycode, t_vars *vars)
{
	printf("Hello from key_hook!\n");
	return (0);
}

int	main(void)
{
	t_vars	vars;

	vars.mlx = mlx_init();
	vars.win = mlx_new_window(vars.mlx, 640, 480, "Hello world!");
	mlx_key_hook(vars.win, key_hook, &vars);
	mlx_loop(vars.mlx);
}

 

후킹은 이벤트를 훔쳐오는 방식이다.

즉, 컴퓨터 프로그램과 S/W 구성 요소간에 발생하는 함수 호출, 메시지 등을 중간에 바꾸거나 가로채는 기술이다.

간섭된 함수를 호출하여 이벤트를 처리하는 코드 자체를 훅(Hook)이라고 부른다.

예를 들어, 마우스 후킹은 OS 내에서 이동하는 마우스를 후킹한다.

리눅스 체제 아래에서는 리눅스 자체에서 마우스를 제어한다.

 

키 이벤트에서의 후킹 구현해보기
#include <mlx.h>
#include <stdio.h>

typedef struct	s_vars {
	void	*mlx;
	void	*win;
}				t_vars;

int	key_hook(int keycode, t_vars *vars)
{
	printf("Hello from key_hook!\n");
	return (0);
}

int	main(void)
{
	t_vars	vars;

	vars.mlx = mlx_init();
	vars.win = mlx_new_window(vars.mlx, 640, 480, "Hello world!");
	mlx_key_hook(vars.win, key_hook, &vars);
	mlx_loop(vars.mlx);
}

 

이를 컴파일하여 실행하면 다음과 같이 아무 키보드 키를 누를 때마다 메세지가 터미널에 출력된다.

 

우리가 등록한 mlx_key_hook() 함수는 훅 함수로, 백그라운드에서 mlx_hook() 함수를 불러내는 역할을 한다.

void mlx_hook(mlx_win_list_t *win_ptr, int x_event, int x_mask, int (*f)(), void *param)

 

맥 OS 에서의 키보드 코드는 다음과 같다:

 

 

똑같은 방식으로 마우스 후킹도 구현해보자.

 

마우스 이벤트에서의 후킹 구현해보기

mouse_hook() 함수의 형식은 다음과 같다.

mouse_hook(int button, int x, int y, void *param);

 

#include <mlx.h>
#include <stdio.h>

typedef struct	s_vars {
	void	*mlx;
	void	*win;
}				t_vars;

int	mouse_hook(int button, int x, int y, t_vars *vars)
{
	printf("Hello from mouse_hook!\n");
	return (0);
}

int	main(void)
{
	t_vars	vars;

	vars.mlx = mlx_init();
	vars.win = mlx_new_window(vars.mlx, 640, 480, "Hello world!");
	mlx_mouse_hook(vars.win, mouse_hook, &vars);
	mlx_loop(vars.mlx);
}

 

우선 위에서의 키훅 함수를 따라하여 마우스훅 함수를 만들어 보았다.

아무 마우스 버튼을 누르면 터미널에 "Hello from mouse_hook!" 메시지를 띄우게 하였다. 

아직 어떤 마우스 버튼을 눌렀는지 구별한다든가 마우스의 현재 위치를 터미널에 표시하는 기능은 하지 못한다.

 

맥 OS 에서의 마우스 코드는 다음과 같다:

 

 


 

7. Events

이벤트는 MiniLibX 가 상호작용하는 애플리케이션을 작성하는 토대이다.

모든 Hook 은 이벤트가 발생할 때마다 호출되는 함수일뿐이다.

맥 OS 에서 지원하는 이벤트는 다음과 같다:

enum {
	ON_KEYDOWN = 2,
	ON_KEYUP = 3,
	ON_MOUSEDOWN = 4,
	ON_MOUSEUP = 5,
	ON_MOUSEMOVE = 6,
	ON_EXPOSE = 12,
	ON_DESTROY = 17
};

// usage:
mlx_hook(vars.win, ON_DESTROY, 0, close, &vars);

 

다음으로는 MiniLibX 와 함께 자주 쓰이는 X11 라이브러리에서 지원하는 이벤트 목록이다.

참고로 X11은 X 윈도우(X Window) 또는 X 윈도 시스템(X Window System)을 일컫는 것으로 주로 유닉스 계열 운영체제에서 사용되는 윈도 시스템 및 X 윈도우 GUI 환경이다.

X 윈도 시스템은 디스플레이 장치에 창을 표시하며 마우스와 키보드 등의 입력 장치의 상호작용 등을 관리해 GUI 환경의 구현을 위한 기본적인 프레임워크를 제공한다.

 

다음으로는 X11 마스크 목록이다.

 

이제 우리는 간단한 훅 등록 함수를 통해 앞서 배운 이벤트 중에서 어느 것이든지 등록할 수 있다.

예를 들어 mlx_key_hook()을 호출하는 대신, KeyPress 이벤트에 등록하는 것이다.

아래의 코드를 실행하면 키보드 키를 누를 때마다 창이 닫히게 된다.

#include <mlx.h>

typedef struct	s_vars {
	void	*mlx;
	void	*win;
}				t_vars;

int	close(int keycode, t_vars *vars)
{
	mlx_destroy_window(vars->mlx, vars->win);
	return (0);
}

int	main(void)
{
	t_vars	vars;

	vars.mlx = mlx_init();
	vars.win = mlx_new_window(vars.mlx, 1920, 1080, "Hello world!");
	mlx_hook(vars.win, 2, 1L<<0, close, &vars);
    // 2: X11의 이벤트 중에서 KeyPress
    // 1L<<0: X11의 마스크 중에서 KeyPressMask
	mlx_loop(vars.mlx);
}

 

 


 

8. Loops

이제 윈도우에 작은 애니메이션을 그려보자.

이를 위해서는 mlx_loop()mlx_loop_hook() 함수를 사용할 것이다.

루프는 우리가 mlx_loop_hook()에 등록해놓은 훅을 계속 호출함으로써 새로운 프레임을 렌더링하게 해준다.

루프를 시작하기 위해 mlx_loop() 함수를 호출해보자.

#include <mlx.h>

int	main(void)
{
	void	*mlx;

	mlx = mlx_init();
	mlx_loop(mlx);
}

 

아직 아무 훅도 등록하지 않았기 때문에 윈도우에 무언가를 쓸 수 없는 상태이다.

이를 위해서는 앞서 설명한 것처럼 새 윈도우를 만들고 mutation 을 사용하여야 한다. (4. MiniLibX 를 활용해보자 참고)

 

#include <mlx.h>

int	render_next_frame(void *YourStruct);

int	main(void)
{
	void	*mlx;

	mlx = mlx_init();
	mlx_loop_hook(mlx, render_next_frame, YourStruct);
	mlx_loop(mlx);
}

 

이처럼 render_next_frame() 자리에 사용자 지정 함수를, YourStruct 자리에 사용자 지정 구조체를 넣어 활용하면 된다.

 


 

9. Images

파일을 읽어서 이미지 객체에 사용하기 위해서는 XMP 또는 PNG 형식의 파일이 필요하다.

mlx_xpm_file_to_image()mlx_png_file_to_image() 함수를 호출하면 된다.

#include <mlx.h>

int	main(void)
{
	void	*mlx;
	void	*img;
	char	*relative_path = "./test.xpm";
	int		img_width;
	int		img_height;

	mlx = mlx_init();
	img = mlx_xpm_file_to_image(mlx, relative_path, &img_width, &img_height);
}

 

만약에 img 가 NULL 이라면, 이미지 읽기에 실패했다는 것을 의미한다.

이 함수는 img_width 와 img_height 변수에 이미지의 크기에 맞는 값을 설정해준다.

 


 

9. Sync

이미 우리는 mlx 를 가지고 프레임 버퍼링을 관리할 수 있지만, 매우 지루하고 시간이 오래 걸린다는 문제가 있다.

또 많은 메모리를 잡아 먹고 프레임이 지속적으로 업데이트 되어야한다는 문제도 있다.

2020 mlx 버전부터는 프레임을 동기화할 수 있게 되었으므로 스크린 버퍼링이 더 이상 필요하지 않다.

 

#define MLX_SYNC_IMAGE_WRITABLE		1
#define MLX_SYNC_WIN_FLUSH_CMD		2
#define MLX_SYNC_WIN_CMD_COMPLETED	3

int	mlx_sync(int cmd, void *ptr);

 

mlx_sync() 는 정의된 명령 코드와 함께 호출되어야 한다.

MLX_SYNC_IMAGE_WRITABLE 은 모든 후속적인 호출을 하나의 이미지에 버퍼한다.

여기서 ptr 은 mlx 이미지 객체를 가리키는 포인터이다.

스크린에 변화가 필요할 때는 기존의 이미지가 존재하는 윈도우를 치워(flush)버려야 한다.

MLX_SYNC_WIN_FLUSH_CMD 명령 코드가 여기에 쓰인다.

여기서 ptr 은 쓸어버릴 윈도우를 가리키는 포인터이다.

 

 

 

MiniLibX 파헤치기

harm-smits.github.io/42docs/ 의 번역본입니다. 리눅스 및 windows 환경이신 분들은 원문에서 세팅방법을 참고해주세요. 42 인트라넷에 이것과 관련된 영상이 있긴 합니다. 아래 링크에서 확인하세요. https

42kchoi.tistory.com

 

Getting started

Find code examples, optimization tricks, and much more.

harm-smits.github.io

 

miniRT, cub3d [시작하기 전에] MiniLibX 라이브러리 읽기 (man mlx)

🖥 42 학습 노트 by yeosong

yeosong1.github.io

 

반응형
Comments