Hi yoahn 개발블로그

[42Seoul/Cub3d] #1 cub3d 시작하기 본문

42 SEOUL/배운 것들 정리

[42Seoul/Cub3d] #1 cub3d 시작하기

hi._.0seon 2021. 3. 12. 17:21
반응형

큡삼디는 기본적으로 컴퓨터그래픽을 이용?하는 프로젝트인데, 인트라에 있는 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(&param);
    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, &param);
    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

반응형
Comments