miniRT 진행(2) mlx 튜토리얼 -2 미니그림판 만들기

chanykim·2020년 12월 31일
0

miniRT

목록 보기
4/10

참고
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 이 사이트에 가서 각 함수에 대한 설명을 봐야한다. 친절히 번역해주셨으니 잘 활용하는 것이 예의다!
무엇보다 우리에게 허락된 함수이기도 하고 어떤 함수인지 알아야 과제를 진행할 수 있기 때문이다.
자세한 내용은 저 곳에서 읽기로 하고 간단한 내용으로 설명한다면,

  • mlx_new_window : 윈도우 관리
  • mlx_pixel_put : 윈도우에 그리기
  • mlx_new_image : 이미지 조작
  • mlx_loop : 키보드/마우스 이벤트 처리
    으로 나누어진다. 종종 써야하는 함수들은 번역된 곳에서 가져와 설명할 예정이다.

오늘할 것은 창을 띄우고 마우스로 글씨를 써보는 것을 해볼 예정이다.
우선 이렇게 만들어보았다.

#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);
}
profile
오늘보다 더 나은 내일

0개의 댓글