[42Seoul/Cub3d] #1 cub3d 시작하기
큡삼디는 기본적으로 컴퓨터그래픽을 이용?하는 프로젝트인데, 인트라에 있는 subject 파일만 보고서는 감이 안와서 ft_server 평가받을 때 이미 하셨던 분들한테 물어봤는데 인트라에 서브젝트 파일과 같이 라이브러리 파일들이 압축파일로 있고, 그것들을 이용하는 거라고 하셔서 라이브러리 사용법부터 알아보기로 했다!
1. mlx 라이브러리
라이브러리를 사용하려고 보니 압축파일은 정말 말그대로 라이브러리 압축파일이어서 별다른 설명이 하나도 없었다. 그래서 디스코드에서 과제 해결하셨던 분들이 참고하기 좋다고 하시는 자료들을 보다가, 아래 링크에 있는 예제를 보면서 하나씩 따라해 보기로 했다!
먼저 MiniLibX 라이브러리는 Unix나 Linux의 X-Window/X11 프로그래밍 지식 없이도 쉽게 그래픽 소프트웨어를 생성할 수 있게 해준다.
간단한 윈도우를 생성하고, 그리는 도구, 이미지와 기본 이벤트 관리를 제공한다
mlx.h 파일을 인클루드하여 MiniLibX API를 사용할 수 있다.
github.com/taelee42/mlx_example
taelee42/mlx_example
Some examples for those who try to use MLX library for 42 subject CUB3D or miniRT. And some helpful links. - taelee42/mlx_example
github.com
예제 01
단순한 화면을 띄우는 예제
시작을 위해 화면을 띄우는 방법부터 보기로 했다!
#include "../mlx/mlx.h"
int main(void)
{
void *mlx;
void *win;
mlx = mlx_init();
win = mlx_new_window(mlx, 500, 500, "mlx_project");
mlx_loop(mlx);
}
- void * mlx_init();
디스플레이와 소프트웨어의 연결을 생성하기 위한 initialize - void* mlx_new_window ( void* mlx_ptr, int size_x, int size_y, char *title );
windows 관리
새로운 윈도우를 스크린 위에 생성하는 함수
mlx_init() 에서 반환된 mlx 포인터를 mlx_ptr 매개변수 자리에 넣는다. - int mlx_loop( void* mlx_ptr );
마지막에 이걸 쳐줘야 프로그램이 종료되지 않고 계속 돌아감
예제 02
#include <stdio.h>
#include <stdlib.h>
#include "../mlx/mlx.h"
#define X_EVENT_KEY_PRESS 2
#define X_EVENT_KEY_release 3
#define X_EVENT_KEY_EXIT 17 //exit key code
//Mac key code example
//All the key code example other than below is described on the site linked in READEME.md
#define KEY_ESC 53
# define KEY_Q 12
# define KEY_W 13
# define KEY_E 14
# define KEY_R 15
# define KEY_A 0
# define KEY_S 1
# define KEY_D 2
//Since key_press() can recieve only one argument, all the argument shold be gathered in one structure
//x,y and str are meaningless variables.
typedef struct s_param{
int x;
int y;
char str[3];
} t_param;
//Only param->x will be used.
void param_init(t_param *param)
{
param->x = 3;
param->y = 4;
param->str[0] = 'a';
param->str[1] = 'b';
param->str[2] = '\0';
}
int key_press(int keycode, t_param *param)
{
static int a = 0;
if (keycode == KEY_W)//Action when W key pressed
param->x++;
else if (keycode == KEY_S) //Action when S key pressed
param->x--;
else if (keycode == KEY_ESC) //Quit the program when ESC key pressed
exit(0);
printf("x: %d\n", param->x);
return (0);
}
int main(void)
{
void *mlx;
void *win;
t_param param;
param_init(¶m);
mlx = mlx_init();
win = mlx_new_window(mlx, 500, 500, "mlx_project");
printf("-------------------------------\n");
printf("'W key': Add 1 to x.\n");
printf("'S key': Subtract 1 from x\n");
printf("'ESC key': Exit this program\n");
printf("'Other keys': print current x \n");
printf("-------------------------------\n");
printf("Current x = 3\n");
mlx_hook(win, X_EVENT_KEY_PRESS, 0, &key_press, ¶m);
mlx_loop(mlx);
}
- int mlx_hook( void* win_ptr, int x_event, int x_mask, int (*funct)( ), void *param );
x_event 값에 따라 key_press, key_release, mouse 클릭, 창닫기 버튼 등 입력 받기 가능
github.com/VBrazhnik/FdF/wiki/How-to-handle-mouse-buttons-and-key-presses%3F
VBrazhnik/FdF
School 42 project // 3D Wireframe Viewer. Contribute to VBrazhnik/FdF development by creating an account on GitHub.
github.com
int x_event 파라미터 값
To handle a key press : 2
int (*funct)( ) 자리에 넣는 함수
int key_press(int keycode, void *param)
To handle a key release: 3
int key_release(int keycode, void *param)
To handle a mouse button press : 4
int mouse_press(int button, int x, int y, void *param)
To handle a mouse button release : 5
int mouse_release(int button, int x, int y, void* param)
To handle a mouse movement : 6
int mouse_move(int x, int y, void *param)
To handle a red button press ( X button ) : 17
int close(void *param)
{
(void)param;
exit(0);
}
Key codes
Mouse button codes
- Left button - 1
- Right - 2
- Middle - 3
- Scroll Up - 4
- Scroll Down - 5
- Scroll Left - 6
- Scroll Right - 7
예제 03
이미지를 스크린에 그리기
//Character '북' on the screen means 'North' in Korean.
#include <stdio.h>
#include "../mlx/mlx.h"
int main()
{
void *mlx;
void *win;
void *img;
int img_width;
int img_height;
mlx = mlx_init();
win = mlx_new_window(mlx, 500, 500, "my_mlx");
img = mlx_xpm_file_to_image(mlx, "../textures/wall_n.xpm", &img_width, &img_height);
mlx_put_image_to_window(mlx, win, img, 50, 50);
mlx_loop(mlx);
return (0);
}
- mlx_xpm_file_to_image
- mlx_png_file_to_image
파일을 이미지에 대한 포인터로 형변환
예제04
픽셀에 직접 점을 찍어서 그림을 그려 창에 띄운다.
- 이미지 저장을 위한 구조체
typedef struct s_img
{
void *img_pt;
int *data;
int size_l;
int bpp;
int endian;
} t_img;
전체 코드
# define WIN_WIDTH 800
# define WIN_HEIGHT 600
# define IMG_WIDTH 400
# define IMG_HEIGHT 300
typedef struct s_img
{
void *img_ptr;
int *data;
//You don't need to understand the 3 values below.
//After declaration, it will be automatically initialized when passed to mlx_get_data_addr function.
//아래 3개 값은 이해 안해도 사용하는데 지장이 없음.
//선언한뒤 함수의 인자로만 잘 넣어주면 알아서 정보를 받아나옴.
int size_l;
int bpp;
int endian;
} t_img;
typedef struct s_mlx
{
void *mlx_ptr;
void *win;
} t_mlx;
int main()
{
t_mlx *mlx;
int count_w;
int count_h;
t_img img;
mlx->mlx_ptr = mlx_init();
mlx->win = mlx_new_window(mlx->mlx_ptr, WIN_WIDTH, WIN_HEIGHT, "A simple example");
img.img_ptr = mlx_new_image(mlx->mlx_ptr, IMG_WIDTH, IMG_HEIGHT);
img.data = (int *)mlx_get_data_addr(img.img_ptr, &img.bpp, &img.size_l, &img.endian);
//The reason why I cast to (int *): If I let this as void * type, whenever I refer to the array values, I need to multiply them by 4.
//Check out keuhdall's github linked in my README for more information.
//여기서 (int *)를 안해주고 img.data가 void *이면 밑에 배열값들을 참조할 때 다 4를 곱해야한다.
//그렇기 때문에 int *로 캐스팅해주는편이 좋다고 한다.
//keuhdall's github가면 더 자세한 내용을 볼 수 있습니다.
count_h = -1;
while (++count_h < IMG_HEIGHT)
{
count_w = -1;
while (++count_w < IMG_WIDTH)
{
if (count_w % 2)
img.data[count_h * IMG_WIDTH + count_w] = 0xFFFFFF;
else
img.data[count_h * IMG_WIDTH + count_w] = 0xFF0000;
}
}
mlx_put_image_to_window(mlx->mlx_ptr, mlx->win, img.img_ptr, 0, 0);
mlx_loop(mlx->mlx_ptr);
return (0);
}
void *mlx_new_image(void *mlx_ptr, int width, int height)
새로운 이미지를 생성하기 위한 함수
픽셀 하나하나에 색을 찍는 방식으로 이미지를 그리는데, 화면의 픽셀 정보를 저장하는 변수는 1차원 배열로 되어있다.
1차원 배열의 크기는 (이미지 가로) * (이미지 세로) 이기 때문에
2차원 이미지의 각 열들이 한 줄로 나열되어있다고 생각하고 접근하면 된다.
image가 2차원 배열이라고 가정하면
=> img.data[count_h * IMG_WIDTH + count_w] == image[count_h][count_w]
github.com/365kim/raycasting_tutorial
365kim/raycasting_tutorial
(한글) 레이캐스팅 튜토리얼 번역. Contribute to 365kim/raycasting_tutorial development by creating an account on GitHub.
github.com
2. mlx_mms 버전 라이브러리 컴파일 방법
나는 M1 맥은 아니지만 mms가 인텔이랑 M1 아키텍처 모두에서 실행이 되어서 아키텍처 상관없이 같은 명령어를 써도 되는것 같다.
Makefile 에서 컴파일 할 때 mlx 라이브러리를 make 하면 동적 라이브러리가 생성되는데, 그 libmlx.dylib 파일을 프로젝트 루트 디렉토리에 놓고 컴파일하면 된다.
gcc -I. -Lmlx -lmlx -framework Metal -framework MetalKit -o cub3D $(SRCS)
mlx 빌드할 때 -framework OpenGL -framework Appkit 를 두고 컴파일하는게 있는데, Metal이 OpenGL의 기능을 완전히 대체하면서 성능이 더 개선된 그래픽 API로 2012 이후 출시된 모든 맥에서 지원된다고 한다.
velog.io/@seomoon/TIL-210130-M1-맥에서-minilibX-실행하기-42-cub3dminiRT
M1 맥에서 mlx(minilibX) 실행하기 (42 cub3d/miniRT)
42서울 cub3D나 miniRT 과제를 진행하려면minilibX 라이브러리를 실행해야 한다. 먼저 인트라의 cub3D/miniRT 프로젝트 페이지에서 minilibx_opengl.tgz 버전을 다운받는다.압축을 풀어서 프로젝트 루트에 위치
velog.io