[OpenGL] 2. 마우스와 키보드로 사각형 이동

WIGWAG·2023년 3월 14일
0

OpenGL

목록 보기
3/10
  • 배경색은 짙은 회색으로 정하고, 사각형은 랜덤한 색으로 그린다.
  • 마우스를 클릭하는 곳이 중심이 되어 사각형을 그린다.
  • 키보드 입력:
    • a: 현재 그려진 사각형이 튕겨진다.
    • s: 튕기기 애니메이션이 멈춘다.

배경색은 짙은 회색으로 정하고, 사각형은 랜덤한 색으로 그린다.

glm::vec3형식으로 r,g,b 변수3개를 한꺼번에 관리한다.

const glm::vec3 background_rgb = glm::vec3(0.1, 0.1, 0.1);
glm::vec3 rect_rgb = glm::vec3((GLclampf)dist(eng), (GLclampf)dist(eng), (GLclampf)dist(eng));

glColor3f로 사각형의 색상을 바꾼다.
glRectf는 사각형을 그리는 함수로 인수는 좌하단, 우상단 좌표이다.

glClearColor(background_rgb.x, background_rgb.y, background_rgb.z, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);											
glColor3f(rect_rgb.x, rect_rgb.y, rect_rgb.z);
glRectf(GetRectCorner().x, GetRectCorner().y, GetRectCorner().z, GetRectCorner().w);

마우스를 클릭하는 곳이 중심이 되어 사각형을 그린다.

Window 좌표를 OpenGL 좌표로 변환하기
Window 좌표에서 x 범위 400 ~ 8000 ~ 1로 변환되어야 한다.
Window 좌표에서 y 범위 400 ~ 00 ~ 1로 변환되어야 한다.

GLfloat half_w = WIN_W / 2.0f;
mx = (x - half_w) / half_w;
my = (half_w - y) / half_w;

키보드 입력

타이머 함수로 사각형이 움직이고 벽에 닿으면 튕기도록 구현한다.

void Timer(int value)
{
	if (GetRectCorner().w >= 1.0f) direction = 2;
	else if (GetRectCorner().z >= 1.0f) direction = 3;
	else if (GetRectCorner().y <= -1.0f) direction = 4;
	else if (GetRectCorner().x <= -1.0f) direction = 1;

	if (direction == 1) {
		mx += 0.01f;
		my += 0.02f;
	}
	else if (direction == 2) {
		mx += 0.02f;
		my -= 0.01f;
	}
	else if (direction == 3) {
		mx -= 0.01f;
		my -= 0.02f;
	}
	else if (direction == 4) {
		mx -= 0.02f;
		my += 0.01f;
	}
	glutPostRedisplay(); // 화면 재 출력
	if (IsTimerAlive)
		glutTimerFunc(100, Timer, 1);
}
	case 'a':
		IsTimerAlive = true;
		glutTimerFunc(100, Timer, 1);
		break;
	case 's':
		IsTimerAlive = false;
		break; 

🎉완성코드

#include <GL/glew.h>
#include <GL/freeglut.h>
#include <GL/freeglut_ext.h>

#include <glm/glm.hpp>
#include <glm/ext.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include <iostream>
#include <random>

using namespace std;

random_device seeder;
const auto seed = seeder.entropy() ? seeder() : time(nullptr);
mt19937 eng(static_cast<mt19937::result_type>(seed));
uniform_real_distribution<double> dist(0.0f, 1.0f);

const int WIN_X = 10, WIN_Y = 10;
const int WIN_W = 800, WIN_H = 800;
const double RECT_WH = 0.4f;
const double HALFRECT_WH = RECT_WH / 2.0f;

const glm::vec3 background_rgb = glm::vec3(0.1, 0.1, 0.1);
glm::vec3 rect_rgb = glm::vec3((GLclampf)dist(eng), (GLclampf)dist(eng), (GLclampf)dist(eng));

bool IsTimerAlive = true;
int direction = 1;

GLfloat mx = 0.0f;
GLfloat my = 0.0f;

glm::vec4 GetRectCorner()
{
	return glm::vec4(mx - HALFRECT_WH, my - HALFRECT_WH, mx + HALFRECT_WH, my + HALFRECT_WH);
}

//--- 콜백 함수: 그리기 콜백 함수 
GLvoid drawScene()
{
	glClearColor(background_rgb.x, background_rgb.y, background_rgb.z, 1.0f);						// 바탕색을 설정
	glClear(GL_COLOR_BUFFER_BIT);											// 설정된 색으로 전체를 칠하기
	glColor3f(rect_rgb.x, rect_rgb.y, rect_rgb.z);
	glRectf(GetRectCorner().x, GetRectCorner().y, GetRectCorner().z, GetRectCorner().w);
	glutSwapBuffers();																	// 화면에 출력하기
}

//--- 콜백 함수: 다시 그리기 콜백 함수 
GLvoid Reshape(int w, int h)
{
	glViewport(0, 0, w, h);
}

void Timer(int value)
{
	if (GetRectCorner().w >= 1.0f) direction = 2;
	else if (GetRectCorner().z >= 1.0f) direction = 3;
	else if (GetRectCorner().y <= -1.0f) direction = 4;
	else if (GetRectCorner().x <= -1.0f) direction = 1;

	if (direction == 1) {
		mx += 0.01f;
		my += 0.02f;
	}
	else if (direction == 2) {
		mx += 0.02f;
		my -= 0.01f;
	}
	else if (direction == 3) {
		mx -= 0.01f;
		my -= 0.02f;
	}
	else if (direction == 4) {
		mx -= 0.02f;
		my += 0.01f;
	}
	glutPostRedisplay(); // 화면 재 출력
	if (IsTimerAlive)
		glutTimerFunc(100, Timer, 1);
}

GLvoid Keyboard(unsigned char key, int x, int y)
{
	switch (key) {
	case 'a':
		IsTimerAlive = true;
		glutTimerFunc(100, Timer, 1);
		break;
	case 's':
		IsTimerAlive = false;
		break; 
	}
	glutPostRedisplay(); //--- 배경색이 바뀔때마다 출력 콜백함수를 호출하여 화면을 refresh 한다
}

void Mouse(int button, int state, int x, int y)
{
	GLfloat half_w = WIN_W / 2.0f;
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
		mx = (x - half_w) / half_w;
		my = (half_w - y) / half_w;
	}
	glutPostRedisplay();
}

int main(int argc, char** argv)
{
	//윈도우 생성
	glutInit(&argc, argv);																// glut 초기화
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);				// 디스플레이 모드 설정
	glutInitWindowPosition(WIN_X, WIN_Y);								// 윈도우의 위치 지정
	glutInitWindowSize(WIN_W, WIN_H);									// 윈도우의 크기 지정
	glutCreateWindow("Example1");												// 윈도우 생성(윈도우 이름)

	//GLEW 초기화하기
	glewExperimental = GL_TRUE;
	if (glewInit() != GLEW_OK)
	{
		std::cerr << "Unable to initialize GLEW" << std::endl;
		exit(EXIT_FAILURE);
	}
	else
		std::cout << "GLEW Initialized\n";

	glutDisplayFunc(drawScene);													// 출력 함수의 지정
	glutReshapeFunc(Reshape);														// 다시 그리기 함수 지정
	glutKeyboardFunc(Keyboard);
	glutMouseFunc(Mouse);
	glutMainLoop();																			// 이벤트 처리 시작
}
profile
윅왁의 프로그래밍 개발노트

0개의 댓글