참고
https://github.com/psj3205/MiniLibX_man_kor/blob/main/README.md
https://refspecs.linuxfoundation.org/LSB_3.2.0/LSB-Desktop-generic/LSB-Desktop-generic/libx11-ddefs.html
우선 저번 글에서는 간단하게 화면에 색상을 띄우는 것을 했었다면 오늘은 좀 더 다양한 방식을 사용하여 mlx를 가지고 놀아보자.
https://github.com/psj3205/MiniLibX_man_kor/blob/main/README.md 이 사이트에 가서 각 함수에 대한 설명을 봐야한다. 친절히 번역해주셨으니 잘 활용하는 것이 예의다!
무엇보다 우리에게 허락된 함수이기도 하고 어떤 함수인지 알아야 과제를 진행할 수 있기 때문이다.
자세한 내용은 저 곳에서 읽기로 하고 간단한 내용으로 설명한다면,
오늘할 것은 창을 띄우고 마우스로 글씨를 써보는 것을 해볼 예정이다.
우선 이렇게 만들어보았다.
#include "includes/minirt.h"
#include <stdio.h>
#define ESC 65307
typedef struct s_data
{
void *mlx;
void *win;
int width, height;
void *img;
char *addr;
int bits_per_pixel;
int size_line;
int endian;
} t_data;
int Key_press(int key, t_data data)
{
printf("pre_key: %d\n", key);
if (key == ESC)
exit(0);
}
int Key_release(int key, t_data data)
{
printf("rel_key: %d\n", key);
if (key == ESC)
exit(0);
}
int main(void)
{
t_data data;
data.mlx = mlx_init();
data.width = 600;
data.height = 400;
data.win = mlx_new_window(data.mlx, data.width, data.height, "minirt_test");
data.img = mlx_new_image(data.mlx, 600, 400);
data.addr = mlx_get_data_addr(data.img, &data.bits_per_pixel, &data.size_line, &data.endian);
mlx_put_image_to_window(data.mlx, data.win, data.img, 0, 0);
mlx_hook(data.win, KeyPress, KeyPressMask, Key_press, 0);
mlx_hook(data.win, KeyRelease, KeyReleaseMask, Key_release, 0);
mlx_loop(data.mlx);
return (0);
}
여기서 ESC 키가 몇번인지 알아야하기 때문에 KeyPress를 사용하여 알아본 코드이다.
1. 구조체로 필요한 변수들을 묶어놓았다.
2. mlx_init();
로 시작한다.
3. 600x400 크기의 창을 설정했다.
4. mlx_new_window(....)
로 창을 만든다.
5. mlx_new_image(....)
는 메모리에 새로운 이미지를 생성합니다. 이 함수는 나중에 이미지를 조작하기 위해 필요한 void * 식별자를 반환합니다. 이미지를 생성하기 위해서는 width와 height 파라미터를 사용하는 이미지 크기가 필요합니다. mlx_ptr은 연결 식별자입니다.
6. mlx_get_data_addr(....)
은 생성된 이미지에 대한 정보를 반환하며, 나중에 사용자가 수정할 수 있습니다. img_ptr 파라미터는 사용할 이미지를 지정합니다. 다음 3개의 파리미터는 3개의 서로 다른 유효한 정수의 주소입니다. bits_per_pixel은 픽셀의 색상을 표현하는데 필요한 비트의 수로 채워집니다(색 깊이(depth of the image)라고도 불립니다). size_line은 메모리 안에서 이미지 한 줄을 저장하는데 필요한 바이트의 수입니다. 이 정보는 이미지의 한 줄에서 다른 줄로 이동하는데 사용합니다. endian은 이미지의 픽셀 색상을 little (endian == 0) 또는 big (endian == 1)에 저장해야하는지 여부를 의미합니다.
7. mlx_put_image_to_window(....)
은 (각각 mlx_ptr, win_ptr, img_ptr, x , y)이미지가 창에 배치 될 위치 좌표를 정의한다.
8. mlx_hook(data.win, KeyPress, KeyPressMask, Key_press, 0);
키보드를 눌렀을 때 이벤트.
9. mlx_hook(data.win, KeyRelease, KeyReleaseMask, Key_release, 0);
키보드를 땠을 때 이벤트.
그러면 이제 마우스를 누르고 때는 것을 만들어보자.
https://refspecs.linuxfoundation.org/LSB_3.2.0/LSB-Desktop-generic/LSB-Desktop-generic/libx11-ddefs.html 이 사이트를 참고하여 buttonpress를 찾아서 만들어보면,
mlx_hook(data.win, ButtonPress, ButtonPressMask, mouse_press, 0);
으로 만들 수 있다. 이와 같은 방법으로 마우스를 땠을 때 자리를 알아보는 것도 만든다.
이 두개를 다 했으면 이제 어떻게 움직이는지 알아야하기 때문에 마우스를 누른 시점부터 움직이는 경로를 알려줄 mlx_hook을 만든다.
mlx_hook(win, MotionNotify, PointerMotionMask, mouse_pos, 0);
지금은
이렇게 창에 마우스를 가져다대기만해도 출력이 되는데 이 함수들을 잘 엮어서 마우스를 누른 상태로 창을 돌아다녀야 print되게 만든다.
진행하는 도중에 마우스를 누른 시점에 함수를 넣었더니 seg fault가 떴다.
그래서 혹시나 버튼을 눌렀을 때 움직이면 나타내는 마스크가 있나 찾아보았고 다행히 존재하여 그것을 사용하여 마우스를 누르고 움직일 때 픽셀 위치를 나타내는 함수를 만들 수 있었다.
mlx_hook(win, MotionNotify, ButtonMotionMask, mouse_pos, 0);
여기까지 왔으니 이제 그림판을 만들어보자.
결과
결과적으로는 그릴 수 있었지만 픽셀단위로 찍어내는 것이라 마우스를 누르고 빠르게 움직이면 제대로 써지지 않는다.
그래서 mlx_pixel_put()
이 함수는 잘 안쓴다고 한다.
내일은 벡터를 이용한 그림을 그려내어 빠르게 써볼 예정이다.
최종코드
#include "includes/minirt.h"
int ft_Key_press(int key, t_data *data)
{
printf("pre_key: %d\n", key);
if (key == ESC)
exit(0);
if (key == CLEAR)
{
mlx_clear_window(data->mlx, data->win);
}
}
int ft_Key_release(int key, void *p)
{
printf("rel_key: %d\n", key);
}
int ft_mouse_press(int button, int x, int y, void *p)
{
printf("button_num: %d , press at %dx%d\n", button, x, y);
}
int ft_mouse_release(int button, int x, int y, void *p)
{
printf("button_num: %d , release at %dx%d\n", button, x, y);
}
int ft_mouse_pos(int x, int y, t_data *data)
{
printf("mouse_pos %dx%d\n", x, y);
mlx_pixel_put(data->mlx, data->win, x, y, 0xFFFFFF);
}
int main(void)
{
t_data data;
t_images imgs;
imgs.width = 600;
imgs.height = 400;
data.mlx = mlx_init();
data.win = mlx_new_window(data.mlx, imgs.width, imgs.height, "minirt_test");
data.img = mlx_new_image(data.mlx, imgs.width, imgs.height);
data.addr = mlx_get_data_addr(data.img, &data.bits_per_pixel,\
&data.size_line, &data.endian);
mlx_put_image_to_window(data.mlx, data.win, data.img, 0, 0);
mlx_hook(data.win, KeyPress, KeyPressMask, ft_Key_press, &data);
//mlx_hook(vars.win, KeyRelease, KeyReleaseMask, ft_Key_release, 0);
mlx_hook(data.win, ButtonPress, ButtonPressMask, ft_mouse_press, 0);
mlx_hook(data.win, ButtonRelease, ButtonReleaseMask, ft_mouse_release, 0);
mlx_hook(data.win, MotionNotify,ButtonMotionMask, ft_mouse_pos, &data);
mlx_loop(data.mlx);
return (0);
}