[miniRT] 2. mlx를 사용하여 키보드 입력으로 도형 움직이기

Park Sejin·2020년 11월 23일
2

miniRT

목록 보기
2/5
post-thumbnail

키보드 입력으로 위에서 생성한 삼각형을 움직여보도록 하겠습니다.
miniLibX에서 키보드, 마우스 등으로부터 입력을 받기 위해서 이벤트 개념을 알아야 합니다. 이벤트는 프로그램에 의해 감지되고 처리될 수 있는 동작이나 사건을 말합니다(위키백과). miniLibX는 이벤트를 처리하기 위해서 mlx_loop() 라는 루프문이 필요합니다. 이 함수는 이벤트의 수신을 기다리고 있다가, 해당 이벤트를 생성시킵니다.

#include "mlx/mlx.h"
#include <stdio.h>
#include <stdlib.h>

#define	UP          126
#define	DOWN        125
#define	LEFT        123
#define	RIGHT       124
#define ESC         53
#define KeyPress    2
#define KeyRelease  3

typedef struct 	s_data
{
	void    *mlx;
	void    *mlx_win;
	int     width, height;
	int     x, y;
	int     up, down, left, right;
	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 ft_move(t_data *data)
{
  if (data->left == 1 && data->x > 0)
  {
    data->x -= 3;
    printf("x = %d, y= %d\n", data->x, data->y);
  }
  if (data->right == 1 && data->x + 100 < data->width)
  {
    data->x += 3;
    printf("x = %d, y= %d\n", data->x, data->y);
  }
  if (data->up == 1 && data->y > 0)
  {
    data->y -= 3;
    printf("x = %d, y= %d\n", data->x, data->y);
  }
  if (data->down == 1 && data->y + 100 < data->height)
  {
    data->y += 3;
    printf("x = %d, y= %d\n", data->x, data->y);
  }
  return (0);
}

int ft_key_press(int keycode, t_data *data)
{
  if (keycode == ESC)
  {
    mlx_destroy_window(data->mlx, data->mlx_win);
    exit(0);
  }
  if (keycode == LEFT)
    data->left = 1;
  if (keycode == RIGHT)
    data->right = 1;
  if (keycode == UP)
    data->up = 1;
  if (keycode == DOWN)
    data->down = 1;
  return (0);
}

int ft_key_release(int keycode, t_data *data)
{
  if (keycode == LEFT)
    data->left = 0;
  if (keycode == RIGHT)
    data->right = 0;
  if (keycode == UP)
    data->up = 0;
  if (keycode == DOWN)
    data->down = 0;
  return (0);
}

int ft_draw(t_data *data)
{
//	printf("ft_draw!\n");
  int i;
  int j;
  int k;
  int x = data->x;
  int y = data->y;

  for (i = 0; i < data->width; i++)
  {
    for (j = 0; j < data->height; j++)
      my_mlx_pixel_put(data, i, j, 0x00000000);
  }
  for (i = x, k = 99; i < x + 50; i++, k -= 2)
  {
    for (j = y + k; j < y + 100; j++)
      my_mlx_pixel_put(data, i, j, 0x0000FF00);
  }
  for (i = x + 50, k = 0; i < x + 100; i++, k += 2)
  {
    for (j = y + k; j < y + 100; j++)
      my_mlx_pixel_put(data, i, j, 0x0000FF00);
  }
  mlx_put_image_to_window(data->mlx, data->mlx_win, data->img, 0, 0);
  return (0);
}

int main_loop(t_data *data)
{
  ft_draw(data);
  ft_move(data);
  return (0);
}

int main(void)
{
  t_data  data;

  data.mlx = mlx_init();
  data.width = 600;
  data.height = 400;
  data.mlx_win = mlx_new_window(data.mlx, data.width, data.height, "miniRT");
  data.img = mlx_new_image(data.mlx, 600, 400);
  data.addr = mlx_get_data_addr(data.img, &data.bits_per_pixel, &data.line_length, &data.endian);

  mlx_put_image_to_window(data.mlx, data.mlx_win, data.img, 0, 0);
  data.x = 250;
  data.y = 150;
  mlx_hook(data.mlx_win, KeyPress, 1L<<0, ft_key_press, &data);
  mlx_hook(data.mlx_win, KeyRelease, 1L<<1, ft_key_release, &data);
  mlx_loop_hook(data.mlx, main_loop, &data);
  mlx_loop(data.mlx);
  return (0);
}

1. 이벤트 생성하기

mlx_hook() 함수로 이벤트를 생성할 수 있습니다. mlx_key_hook(), mlx_mouse_hook(), mlx_expose_hook() 의 각각 특정 이벤트에 대한 정의를 mlx_hook() 을 사용하여 모두 처리할 수 있습니다.

int mlx_hook(void *win_ptr, int x_event, int x_mask, int (*funct_ptr)(), void *param);

이벤트를 생성하려는 윈도우의 식별자를 win_ptr 파리미터에 지정해 줍니다. x_event, x_mask 파라미터로 이벤트 상황을 지정해줍니다(X11/X.h 문서 참고). miniLibXmlx_hook() 함수에서는 파라미터로 x_mask를 받지만 내부에서 사용을 하지 않으므로 0으로 값을 지정해도 무관합니다. funct_ptr 파라미터는 해당 이벤트가 발생할 때, 실행할 함수의 주소를 받는 함수 포인터 파라미터입니다. param 파라미터는 funct_ptr 로 호출한 함수에 필요한 파라미터 데이터를 보내주는 파라미터입니다.

2. 이벤트 수신하기

생성한 이벤트를 수신하기 위해서는 mlx_loop() 함수가 필요합니다. mlx_loop() 함수는 이벤트를 수신하고 연동된 함수를 호출하는 동작을 반복적으로 수행합니다.

3. 프레임 업데이트하기

이벤트를 수신하고 연동된 함수를 호출하여 키 입력에 대한 이미지의 x, y 좌표값 변경 작업을 성공적으로 수행했다 하더라도 화면에는 아직 반영이 되지 않았습니다. 다음 프레임에 변경된 사항을 업데이트 해주기 위해 필요한 함수가 바로 mlx_loop_hook() 함수입니다.

int mlx_loop_hook(void *mlx_ptr, int (*funct_ptr)(), void *param);

mlx_ptr 파라미터는 연결 식별자입니다. funct_ptr 파라미터, param 파라미터는 mlx_hook()funct_ptr 파라미터, param 파라미터와 동일합니다.
mlx_loop_hook() 함수는 mlx_loop() 함수가 동작하는 동안 funct_ptr 파라미터로 받은 함수를 반복적으로 호출합니다. 그렇기 때문에 이미지를 그리는 함수를 funct_ptr 파라미터에 넣어주면 새로운 좌표값에 맞는 이미지를 다시 화면에 반영할 수 있게됩니다.

참고

ft_libgfx AKA b_gfx overload
https://github.com/qst0/ft_libgfx#minilibx

42 Docs
https://harm-smits.github.io/42docs/libs/minilibx/getting_started.html

cub3d I-yohai github
https://github.com/l-yohai/cub3d/blob/master/mlx_example/05_sprite_raycast.c

0개의 댓글