http://www.cplusplus.com/reference/stack/stack/

이 포스팅은 위 자료를 참고로 작성되었다.


1. Stack 자료형

 - LIFO 자료형으로 나중에 들어온 자료가 가장 먼저 나온다.

 - 배열에서 한 쪽이 막힌 구조로 한 쪽으로 자료를 넣고 한 쪽으로 자료를 꺼내는 모양으로 생각하면 된다.


2. Include

 - #include <stack>


3. 선언 방법

    stack<T> a(5);

 - T에 자료형(클래스)를 넣어서 해당 자료를 저장하는 stack을 만들 수 있다.

 - 해당 선언문으로 만들어진다.(따로 new로 자료형을 만들어줄 필요는 없다.)

 - 괄호 속에 다양한 자료를 넣어 초기 값을 설정해 줄 수 있다.(숫자인 경우 stack의 크기)


4. 주요 function

 stack<int> testStack;

 1) testStack.empty();

  - 현재 Stack이 비어있는지 여부를 반환(true - 비어있음)

 2) testStack.size()

  - 현재 Stack에 Push된 Object 수를 반환

 3) testStack.top()

  - Stack에서 가장 나중에 Push된 Object를 반환한다.

  - Object의 내용만 반환하고 해당 오브젝트는 계속 Stack에 남아있다.

 4) testStack.push(1)

  - Stack에 새로운 Object를 삽입.(위 에선 1을 stack에 삽입, class Object도 가능)

 5) testStack.pop()

  - Stack에서 가장 나중에 입력된 Object를 Stack에서 버린다.(반환값은 없다)

 6) testStack.emplace(args)

  - 기본 자료형이 아닌 특정 클래스의 Stack이라면 해당 args를 그 클래스의 생성자로 넘겨 해당 클래스의 객체를 생성해서 Stack에 Push

 7) testStack.swap(anotherStack)

  - 두 Stack의 내용을 서로 바꿈.


5. 예제

#include <iostream>
#include <stack>

using namespace std;

// 명령 클래스
class Instruction
{
	//명령 번호
	int number;
	//명령 내용
	int content;

public:
	//명령 기본 생성자
	Instruction()
	{
		number = 0;
		content = 0;
	}

	//명령 생성자(각 변수에 값 삽입)
	Instruction(int num, int con)
	{
		number = num;
		content = con;
	}

	//명령 번호 반환
	int getNumber()
	{
		return number;
	}

	//명령 내용 반환
	int getContent()
	{
		return content;
	}
};

// canvas 출력
void printCanvas(int* can)
{
	for (int i = 0; i < 3; i++)
	{
		cout << can[i] << " ";
	}

	cout << endl;
}

int main()
{
	// canvas 초기화
	int canvas[3] = { 0, };

	// 되돌리기 명령 저장
	stack<instruction> undoStack;

	// 첫번쨰 지우는 명령
	Instruction eraseFirst(1, 1);
	Instruction drawFirst(0, 1);
	
	cout << "초기 상태     : ";
	printCanvas(canvas);

	// 그리기 명령
	canvas[1] = 1;
	undoStack.push(drawFirst);

	cout << "그리기 명령 1 : ";
	printCanvas(canvas);

	// 지우기 명령
	canvas[1] = 0;
	undoStack.push(eraseFirst);

	cout << "지우기 명령 1 : ";
	printCanvas(canvas);

	//그리기 명령
	canvas[2] = 1;
	undoStack.emplace(0, 2);

	cout << "그리기 명령 2 : ";
	printCanvas(canvas);

	//전부다 되돌리기
	while (!undoStack.empty())
	{
		// 명령마다 되돌리는 작업
		switch (undoStack.top().getNumber())
		{
		//그리기 되돌리기
		case 0:
			canvas[undoStack.top().getContent()] = 0;
			break;
		//지우기 되돌리기
		case 1:
			canvas[undoStack.top().getContent()] = 1;
			break;
		}

		//이미 되돌린 명령어는 삭제
		undoStack.pop();

		cout << "되돌리기      : ";
		printCanvas(canvas);
	}

	return 0;
}


6. 예제 결과

초기 상태            : 0 0 0

그리기 명령 1    : 0 1 0

지우기 명령 1    : 0 0 0

그리기 명령 2    : 0 0 1

되돌리기             : 0 0 0

되돌리기             : 0 1 0

되돌리기             : 0 0 0

과제로 했었던 OpenGL로 놀이동산 만들기!

앞에 올렸던 대부분의 OpenGL 코드를 망라한 것이라 보면 된다.


다른 놀이기구는 거의 문제 없지만

롤러코스터의 경우에는 찌그러... 졌다기 보다 움직임이 부자연스럽다.

많은 분들이 참고용으로 보셨으면 하는 마음에 올린다.



#include<stdio.h>
#include<Windows.h>
#include<GL\glut.h>
#include<GL\GLAUX.H>
#include<math.h>

#define GL_PI 3.1415f

GLfloat xRot = 0.0f;			//x방향 회전 각도
GLfloat yRot = 0.0f;			//y방향 회전 각도

GLfloat xStat = 0.0f;			//x방향 위치값
GLfloat yStat = 0.0f;			//y방향 위치값
GLfloat zStat = 0.0f;			//z방향 위치값

GLfloat vikingRot = 10.0f;		//바이킹 회전 각도
GLfloat vikingAcc = 10.0f;		//바이킹 가속도
boolean sig = false;			//바이킹 가속도 부호

GLfloat hurriRot = 0.0f;		//허리케인 링 회전 각도

int ovalA = 630;				//롤러코스터 타원 장축 a값
int ovalB = 450;				//롤러코스터 타원 단축 b값

GLfloat rolx = (GLfloat)ovalA;	//롤러코스터 x값
int rol4 = 4;					//롤러코스터 4분면 값
GLfloat bend=10.0f;				//끝의 휜 부분 속도 조절
GLfloat bendrotate = 0.0f;		//끝의 휜 부분 각도 조절

bool iCull = TRUE;
bool iOutline = FALSE;
bool iDepth = TRUE;

GLfloat amb [] = {0.3f, 0.3f, 0.3f, 1.0f};
GLfloat dif [] = {0.8f, 0.8f, 0.8f, 1.0f};
GLfloat lightpos[] = {0.0f, 500.0f, -600.0f, 1.0f};

AUX_RGBImageRec *grasstex;
GLuint texID;


void ovalFunc(GLfloat x, int split, GLfloat out[3])
{
	/* function ovalFunc()
	타원의 현재 x값과 몇사분면인지 split을 입력받아 
	좌표가 x이고 사분면 값이 split 일 때, out에 점 위치를 나타내줌.
	x : y, z 좌표를 구하고 싶은 x 값.
	split : 현재 몇 사분면인지를 나타내는 값.
	out : x좌표 입력으로 x, y, z값을 구한 값을 반환하는 변수.
	*/
	GLfloat divide = 180.0f;
	out[0] = x;
	out[1] = ovalB * sqrt((1-x*x/(ovalA*ovalA)));
	
	switch(split)										//사분면마다 부호가 달라짐
	{
	case 1:
		out[2] = 100 + 50 * cos((GL_PI/divide)*x);
		break;
	case 2 :
		out[0] = -out[0];
		out[2] = 100 + 50 * cos((GL_PI/divide)*x);
		break;
	case 3 :
		out[0] = -out[0];
		out[1] = -out[1];
		out[2] = 100 + 50 * cos((GL_PI/divide)*x);
		break;
	case 4 :
		out[1] = -out[1];
		out[2] = 100 + 50 * cos((GL_PI/divide)*x);
		break;
	default :
		out[0] = 0;
		out[1] = 0;
		out[2] = 0;
		break;
	}
}

void calcNormal(float v[3][3], float out[3])
{
	/* function calcNormal()
	점 3개를 받아 해당 삼각형의 normal vector를 구하는 함수
	v[3][3] : (x, y, z) 점 좌표 3개
	out[3] : normal 벡터를 반환받을 벡터 3개
	※ glut함수를 쓰면 느리므로 직접 제작
	*/
	float v1[3], v2[3], length;
	static const int x = 0;
	static const int y = 1;
	static const int z = 2;

	v1[x] = v[0][x]-v[1][x];	v1[y] = v[0][y]-v[1][y];	v1[z] = v[0][z]-v[1][z];
	v2[x] = v[2][x]-v[1][x];	v2[y] = v[2][y]-v[1][y];	v2[z] = v[2][z]-v[1][z];
	
	out[x] = v1[y]*v2[z] - v1[z]*v2[y];
	out[y] = v1[z]*v2[x] - v1[x]*v2[z];
	out[z] = v1[x]*v2[y] - v1[y]*v2[x];

	length = (float)sqrt(out[x]*out[x] + out[y]*out[y]+out[z]*out[z]);
	if(length == 0.0f)
		length = 1.0f;

	out[x] /= length;
	out[y] /= length;
	out[z] /= length;
}

void createCylinder(GLfloat centerx, GLfloat centery, GLfloat centerz, GLfloat radius, GLfloat h)
{
	/* function createCyliner()
	원기둥의 중심 x,y,z좌표, 반지름, 높이를 받아 원기둥을 생성하는 함수(+z방향으로 원에서 늘어남)
	centerx : 원기둥 원의 중심 x좌표
	centery : 원기둥 원의 중심 y좌표
	centerz : 원기둥 원의 중심 z좌표
	radius : 원기둥의 반지름
	h : 원기둥의 높이
	*/
	GLfloat x, y, angle;

	glBegin(GL_TRIANGLE_FAN);											//원기둥의 윗면
	glNormal3f(0.0f, 0.0f, -1.0f);
	glColor3ub(139, 69, 19);
	glVertex3f(centerx, centery, centerz);
	for(angle = 0.0f; angle < (2.0f*GL_PI); angle += (GL_PI/8.0f))
	{
		x = centerx + radius*sin(angle);
		y = centery + radius*cos(angle);
		glNormal3f(0.0f, 0.0f, -1.0f);
		glVertex3f(x, y, centerz);
	}
	glEnd();

	glBegin(GL_QUAD_STRIP);												//원기둥의 옆면
	for(angle = 0.0f; angle < (2.0f*GL_PI); angle += (GL_PI/8.0f))
	{
			x = centerx + radius*sin(angle);
			y = centery + radius*cos(angle);
			glNormal3f(sin(angle), cos(angle), 0.0f);
			glVertex3f(x, y, centerz);
			glVertex3f(x, y, centerz + h);
	}
	glEnd();

	glBegin(GL_TRIANGLE_FAN);											//원기둥의 밑면
	glNormal3f(0.0f, 0.0f, 1.0f);
	glVertex3f(centerx, centery, centerz + h);
	for(angle = (2.0f*GL_PI); angle > 0.0f; angle -= (GL_PI/8.0f))
	{
		x = centerx + radius*sin(angle);
		y = centery + radius*cos(angle);
		glNormal3f(0.0f, 0.0f, 1.0f);
		glVertex3f(x, y, centerz + h);
	}
	glEnd();
}

void createShip(GLfloat x, GLfloat y, GLfloat z, GLfloat size)
{
	/* function createShip()
	중심 (x,y,z)로 부터 z축으로 길게 배 생성, 옆면 길이는 size * 2, 총 길이는 size * 4
	x : x 좌표
	y : y 좌표
	z : z 좌표
	size : 배 크기의 기본단위
	*/
	float v[3][3];
	float out[3];

	glBegin(GL_TRIANGLES);
	glColor3f(0.65f, 0.16f, 0.16f);			//바이킹 뒷 왼쪽 삼각형
	v[0][0] = x-size; v[0][1] = y; v[0][2] = z-size;
	v[1][0] = x; v[1][1] = y; v[1][2] = z-2*size;
	v[2][0] = x; v[2][1] = y-size; v[2][2] = z-size;
	calcNormal(v, out);
	glNormal3fv(out);
	glVertex3f(x-size, y, z-size);
	glVertex3f(x, y, z-2*size);
	glVertex3f(x, y-size, z-size);
	
	v[0][0] = x; v[0][1] = y-size; v[0][2] = z+size;
	v[1][0] = x; v[1][1] = y; v[1][2] = z-2*size;
	v[2][0] = x-size; v[2][1] = y; v[2][2] = z+size;
	calcNormal(v, out);
	glNormal3fv(out);
	glVertex3f(x, y-size, z+size);		//바이킹 앞 왼쪽 삼각형
	glVertex3f(x, y, z+2*size);
	glVertex3f(x-size, y, z+size);
	
	glColor3f(0.65f, 0.16f, 0.16f);			//바이킹 왼쪽 몸통
	v[0][0] = x; v[0][1] = y-size; v[0][2] = z+size;
	v[1][0] = x-size; v[1][1] = y; v[1][2] = z-size;
	v[2][0] = x; v[2][1] = y-size; v[2][2] = z-size;
	calcNormal(v, out);
	glNormal3fv(out);
	glVertex3f(x, y-size, z+size);
	glVertex3f(x-size, y, z-size);
	glVertex3f(x, y-size, z-size);
	
	v[0][0] = x-size; v[0][1] = y; v[0][2] = z-size;
	v[1][0] = x; v[1][1] = y-size; v[1][2] = z+size;
	v[2][0] = x-size; v[2][1] = y; v[2][2] = z+size;
	calcNormal(v, out);
	glNormal3fv(out);
	glVertex3f(x-size, y, z-size);
	glVertex3f(x, y-size, z+size);
	glVertex3f(x-size, y, z+size);

	glColor3f(0.65f, 0.16f, 0.16f);			//바이킹 뒷 오른쪽 삼각형
	v[0][0] = x; v[0][1] = y; v[0][2] = z-2*size;
	v[1][0] = x+size; v[1][1] = y; v[1][2] = z-size;
	v[2][0] = x; v[2][1] = y-size; v[2][2] = z-size;
	calcNormal(v, out);
	glNormal3fv(out);
	glVertex3f(x, y, z-2*size);
	glVertex3f(x+size, y, z-size);
	glVertex3f(x, y-size, z-size);
	
	v[0][0] = x; v[0][1] = y-size; v[0][2] = z+size;
	v[1][0] = x+size; v[1][1] = y; v[1][2] = z+size;
	v[2][0] = x; v[2][1] = y; v[2][2] = z+2*size;
	calcNormal(v, out);
	glNormal3fv(out);
	glVertex3f(x, y-size, z+size);		//바이킹 앞 오른쪽 삼각형
	glVertex3f(x+size, y, z+size);
	glVertex3f(x, y, z+2*size);
	
	glColor3f(0.65f, 0.16f, 0.16f);			//바이킹 오른쪽 몸통
	v[0][0] = x+size; v[0][1] = y; v[0][2] = z-size;
	v[1][0] = x; v[1][1] = y-size; v[1][2] = z+size;
	v[2][0] = x; v[2][1] = y-size; v[2][2] = z-size;
	calcNormal(v, out);
	glNormal3fv(out);
	glVertex3f(x+size, y, z-size);
	glVertex3f(x, y-size, z+size);
	glVertex3f(x, y-size, z-size);
	
	v[0][0] = x+size; v[0][1] = y; v[0][2] = z-size;
	v[1][0] = x+size; v[1][1] = y; v[1][2] = z+size;
	v[2][0] = x; v[2][1] = y-size; v[2][2] = z+size;
	calcNormal(v, out);
	glNormal3fv(out);
	glVertex3f(x+size, y, z-size);
	glVertex3f(x+size, y, z+size);
	glVertex3f(x, y-size, z+size);
	glEnd();

	glBegin(GL_POLYGON);					//바이킹 갑판
	glColor3f(0.65f, 0.16f, 0.16f);
	glNormal3f(0.0f, 1.0f, 0.0f);
	glVertex3f(x+size, y, z-size);
	glNormal3f(0.0f, 1.0f, 0.0f);
	glVertex3f(x, y, z-2*size);
	glNormal3f(0.0f, 1.0f, 0.0f);
	glVertex3f(x-size, y, z-size);
	glNormal3f(0.0f, 1.0f, 0.0f);
	glVertex3f(x-size, y, z+size);
	glNormal3f(0.0f, 1.0f, 0.0f);
	glVertex3f(x, y, z+2*size);
	glNormal3f(0.0f, 1.0f, 0.0f);
	glVertex3f(x+size, y, z+size);
	glEnd();
}

void createRing(GLfloat centerx, GLfloat centery, GLfloat centerz, GLfloat radius, GLfloat h, GLfloat thick)
{
	/* function createRing()
	링의 중심 x,y,z좌표, 반지름, 높이, 두께를 받아 링을 생성하는 함수
	centerx : 링의 중심 x좌표
	centery : 링의 중심 y좌표
	centerz : 링의 중심 z좌표
	radius	: 링의 반지름
	h		: 링의 높이
	thick	: 링의 두께
	*/
	GLfloat x, y, angle;

	glColor3ub(148, 0, 211);
	glBegin(GL_QUAD_STRIP);											//링의 윗면
	for(angle = (2.0f*GL_PI); angle > 0.0f; angle -= (GL_PI/8.0f))
	{
			x = centerx + radius*sin(angle);
			y = centery + radius*cos(angle);
			glNormal3f(0.0f, 0.0f, -1.0f);
			glVertex3f(x, y, centerz);
			x = centerx + (radius-thick)*sin(angle);
			y = centery + (radius-thick)*cos(angle);
			glVertex3f(x, y, centerz);
	}
	glEnd();

	int color = 0;
	glBegin(GL_QUAD_STRIP);												//링의 바깥쪽 옆면
	for(angle = 0.0f; angle < (2.0f*GL_PI); angle += (GL_PI/8.0f))
	{
			x = centerx + radius*sin(angle);
			y = centery + radius*cos(angle);
			glNormal3f(sin(angle), cos(angle), 0.0f);
			glVertex3f(x, y, centerz);
			glVertex3f(x, y, centerz + h);
			color++;
	}
	glEnd();

	glColor3ub(148, 0, 211);
	glBegin(GL_QUAD_STRIP);												//링의 안쪽 옆면
	for(angle = (2.0f*GL_PI); angle > 0.0f; angle -= (GL_PI/8.0f))
	{
			x = centerx + (radius-thick)*sin(angle);
			y = centery + (radius-thick)*cos(angle);
			glNormal3f(-sin(angle), -cos(angle), 0.0f);
			glVertex3f(x, y, centerz);
			glVertex3f(x, y, centerz + h);
	}
	glEnd();

	glBegin(GL_QUAD_STRIP);											//원기둥의 밑면
	for(angle = 0.0f; angle < (2.0f*GL_PI); angle += (GL_PI/8.0f))
	{
			x = centerx + radius*sin(angle);
			y = centery + radius*cos(angle);
			glNormal3f(0.0f, 0.0f, 1.0f);
			glVertex3f(x, y, centerz+h);
			x = centerx + (radius-thick)*sin(angle);
			y = centery + (radius-thick)*cos(angle);
			glVertex3f(x, y, centerz+h);
	}
	glEnd();
}

void createChair(GLfloat x, GLfloat y, GLfloat z, GLfloat thick, GLfloat width, GLfloat height)
{
	/* function createChair()
	의자 왼쪽 위 끝 x,y,z좌표, 등받이 높이, 앉는부분 길이를 받아 의자를 생성하는 함수
	x : 의자 왼쪽 위 끝 x좌표
	y : 의자 왼쪽 위 끝 y좌표
	z : 의자 오른쪽 위 끝 z좌표
	thick : 의자 두께
	width : 의자 가로길이
	height : 의자 세로길이
	*/
	glColor3ub(0, 0, 0);
	glBegin(GL_QUADS);
	glNormal3f(-1.0f, 0.0f, 0.0f);			//등받이 왼쪽 옆면
	glVertex3f(x, y, z);
	glVertex3f(x, y+height, z);
	glVertex3f(x+thick, y+height, z);
	glVertex3f(x+thick, y, z);
	
	glNormal3f(0.0f, 0.0f, 1.0f);			//등받이 앞면
	glVertex3f(x+thick, y, z);
	glVertex3f(x+thick, y+height, z);
	glVertex3f(x+thick, y+height, z+width);
	glVertex3f(x+thick, y, z+width);
	
	glNormal3f(1.0f, 0.0f, 0.0f);			//등받이 오른쪽 옆면
	glVertex3f(x+thick, y, z+width);
	glVertex3f(x+thick, y+height, z+width);
	glVertex3f(x, y+height, z+width);
	glVertex3f(x, y, z+width);

	glNormal3f(0.0f, 0.0f, -1.0f);			//등받이 뒷면
	glVertex3f(x, y, z+width);
	glVertex3f(x, y+height+thick, z+width);
	glVertex3f(x, y+height+thick, z);
	glVertex3f(x, y, z);
	
	glNormal3f(0.0f, 1.0f, 0.0f);			//등받이 윗면
	glVertex3f(x, y, z);
	glVertex3f(x+thick, y, z);
	glVertex3f(x+thick, y, z+width);
	glVertex3f(x, y, z+width);
	
	glNormal3f(0.0f, 1.0f, 0.0f);			//앉는 부분 윗면
	glVertex3f(x, y+height, z);
	glVertex3f(x+height, y+height, z);
	glVertex3f(x+height, y+height, z+width);
	glVertex3f(x, y+height, z+width);
	
	glNormal3f(-1.0f, 0.0f, 0.0f);			//앉는 부분 왼쪽 옆면
	glVertex3f(x, y+height, z);
	glVertex3f(x, y+height+thick, z);
	glVertex3f(x+height, y+height+thick, z);
	glVertex3f(x+height, y+height, z);

	glNormal3f(0.0f, 0.0f, -1.0f);			//앉는 부분 앞쪽
	glVertex3f(x+height, y+height, z);
	glVertex3f(x+height, y+height+thick, z);
	glVertex3f(x+height, y+height+thick, z+width);
	glVertex3f(x+height, y+height, z+width);
	
	glNormal3f(1.0f, 0.0f, 0.0f);			//앉는 부분 오른쪽 옆면
	glVertex3f(x, y+height, z+width);
	glVertex3f(x+height, y+height, z+width);
	glVertex3f(x+height, y+height+thick, z+width);
	glVertex3f(x, y+height+thick, z+width);
	
	glNormal3f(0.0f, -1.0f, 0.0f);			//앉는 부분 밑면
	glVertex3f(x, y+height+thick, z);
	glVertex3f(x, y+height+thick, z+width);
	glVertex3f(x+height, y+height+thick, z+width);
	glVertex3f(x+height, y+height+thick, z);
	glEnd();
}

void createHalfSphere(GLfloat x, GLfloat y, GLfloat z, GLfloat radius)
{
	/* function createHalfSphere()
	구의 중심 x, y, z 좌표를 받아 반구를 만드는 함수
	x : 반구의 중심 x 좌표
	y : 반구의 중심 y 좌표
	z : 반구의 중심 z 좌표
	raidus : 반구의 반지름
	*/
	GLfloat angley;		//y축 값을 구하기 위한 각도
	GLfloat nexty;		//다음 y축 값을 구하기 위한 각도
	GLfloat anglex;		//x, y축 값을 구하기 위한 각도

	glColor3ub(136, 206, 250);		//반구의 색 지정
	glBegin(GL_QUAD_STRIP);
	for(angley = 0.0f; angley <= (0.5f*GL_PI); angley += ((0.5f*GL_PI)/8.0f))		//반구만 그려야 하므로 0.5곱함
	{
		y = radius*sin(angley);					//y축 값 계산
		nexty = angley+((0.5f*GL_PI)/8.0f);		//다음 angley값 저장
		for(anglex = 0.0f; anglex < (2.0f*GL_PI); anglex += (GL_PI/8.0f))
		{
			x = radius*cos(angley)*sin(anglex);
			z = radius*cos(angley)*cos(anglex);
			glNormal3f(-cos(angley)*sin(anglex), -sin(angley), -cos(angley)*cos(anglex));	//반구의 안쪽으로 normal 벡터 생성
			glVertex3f(x, y, z);

			x = radius*cos(nexty)*sin(anglex);
			z = radius*cos(nexty)*cos(anglex);
			glNormal3f(-cos(nexty)*sin(anglex), -sin(nexty), -cos(nexty)*cos(anglex));
			glVertex3f(x, radius*sin(nexty), z);
		}
	}
	glEnd();
}

void createRail(GLfloat centerx, GLfloat centery, GLfloat centerz, GLfloat radius)
{
	/* function createRail()
	레일의 중심인 x, y, z값을 받아서 레일 반지름이 radius인 레일을 생성하는 함수.
	centerx : 레일의 중심 값 x
	centery : 레일의 중심 값 y
	centerz : 레일의 중심 값 z
	radius : 레일의 굵기(반지름
	*/
	int column=0;			//column 세주는 변수
	GLfloat angle, x, y, z;	//각도, x, y, z 좌표
	GLfloat length;			//변위 벡터 길이
	GLfloat rotate;			//변위 벡터 각도
	GLfloat currout[3];		//현재 값
	GLfloat nextout[3];		//다음 값
	GLfloat dis[3];			//변위 벡터

	for(int i = 1;i<=4;i++)		//총 4사분면
	{
		for(float j = 0;j<ovalA;j++)		//x의 최대값은 ovalA
		{
			if(j == 0)						//j==0일때는 currout도 구해줘야함
			{
				ovalFunc(j, i, currout);
			}
			else							//이 전의 nextout은 현재의 currout과 같음
			{
				currout[0] = nextout[0];
				currout[1] = nextout[1];
				currout[2] = nextout[2];
			}
			ovalFunc(j+1, i, nextout);		//nextout 값 받아옴.
			
			dis[0] = nextout[0]-currout[0];	//변위 벡터 구함
			dis[1] = nextout[1]-currout[1];
			dis[2] = nextout[2]-currout[2];

			length = (GLfloat)sqrtf(dis[0]*dis[0] + dis[1]*dis[1] + dis[2]*dis[2]);	//변위 벡터의 길이 구함
			if(length == 0) length = 1;		//벡터 길이 0이라면 1로

			dis[0] /= length;		//단위 벡터로 바꿔줌
			dis[1] /= length;
			dis[2] /= length;

			rotate = (GLfloat)asinf(dis[2])*180.0f/GL_PI;	//해당 축으로 몇도 회전시켜야 하는지 구함

			if(column % 60 == 10)		//column을 60의 간격으로 만듦
			{
				glPushMatrix();
				glTranslated(currout[0], currout[2], currout[1]);		//해당 레일로 좌표이동
				glRotated(90.0f, 1.0f, 0.0f, 0.0f);						//x축으로 90도 회전
				createCylinder(0.0f, 0.0f, 18.0f, 5.0f, currout[2]);	//cylinder 제작
				glPopMatrix();
			}

			glColor3ub(255, 0, 0);
			glPushMatrix();
			glTranslated(currout[0], currout[2], currout[1]);
			glRotatef(rotate, dis[0], dis[2], dis[1]);
			glBegin(GL_QUAD_STRIP);
			
			for(angle = 0.0f; angle <= (2.0f*GL_PI); angle += (GL_PI/8.0f))
			{
				x = radius*cos(angle)*dis[1];									//현재 x, y, z값 구함
				y = radius*sin(angle);
				z = radius*cos(angle)*dis[0];
				glNormal3f(cos(angle)*dis[1], sin(angle), cos(angle)*dis[0]);
				glVertex3f(x, y, z);
				x = dis[0]*length*2.0f + radius*cos(angle)*dis[1];				//다음 x, y, z값 구함(곡선이라 갈라지므로 길이 1.3배)
				y = dis[2]*length*2.0f + radius*sin(angle);
				z = dis[1]*length*2.0f + radius*cos(angle)*dis[0];
				glNormal3f(cos(angle)*dis[1], sin(angle), cos(angle)*dis[0]);
				glVertex3f(x, y, z);
			}
			glEnd();
			glPopMatrix();
		
			column++;
		}
	}
}

void createCar(GLfloat x, GLfloat y, GLfloat z, GLfloat bump, GLfloat width, GLfloat height, GLfloat thick)
{
	GLfloat halfw = width/2;

	glColor3ub(0, 0, 255);
	glBegin(GL_QUADS);
	glNormal3f(0.0f, -1.0f, 0.0f);				//차의 바깥쪽 밑 부분
	glVertex3f(x+halfw+bump, y, z-halfw);
	glVertex3f(x+halfw+bump, y, z+halfw);
	glVertex3f(x-halfw, y, z+halfw);
	glVertex3f(x-halfw, y, z-halfw);

	glNormal3f(0.0f, 0.0f, -1.0f);				//차의 바깥 왼쪽 옆면
	glVertex3f(x+halfw, y, z-halfw);
	glVertex3f(x-halfw, y, z-halfw);
	glVertex3f(x-halfw, y+height, z-halfw);
	glVertex3f(x+halfw, y+height, z-halfw);
	
	glNormal3f(-1.0f, 0.0f, 0.0f);				//차의 바깥쪽 뒷면
	glVertex3f(x-halfw, y, z-halfw);
	glVertex3f(x-halfw, y, z+halfw);
	glVertex3f(x-halfw, y+height, z+halfw);
	glVertex3f(x-halfw, y+height, z-halfw);

	glNormal3f(0.0f, 0.0f, 1.0f);				//차의 바깥 오른쪽 옆면
	glVertex3f(x-halfw, y, z+halfw);
	glVertex3f(x+halfw, y, z+halfw);
	glVertex3f(x+halfw, y+height, z+halfw);
	glVertex3f(x-halfw, y+height, z+halfw);

	glNormal3f(0.0f, 1.0f, 0.0f);				//차의 바깥 위 왼쪽 윗면
	glVertex3f(x-halfw, y+height, z-halfw);
	glVertex3f(x-halfw, y+height, z-halfw+thick);
	glVertex3f(x+halfw, y+height, z-halfw+thick);
	glVertex3f(x+halfw, y+height, z-halfw);

	glVertex3f(x-halfw, y+height, z+halfw);		//차의 바깥 위 오른쪽 윗면
	glVertex3f(x+halfw, y+height, z+halfw);
	glVertex3f(x+halfw, y+height, z+halfw-thick);
	glVertex3f(x-halfw, y+height, z+halfw-thick);

	glVertex3f(x-halfw, y+height, z-halfw+thick);		//차의 바깥 위 뒤쪽 윗면
	glVertex3f(x-halfw, y+height, z+halfw-thick);
	glVertex3f(x-halfw+thick, y+height, z+halfw-thick);
	glVertex3f(x-halfw+thick, y+height, z-halfw+thick);

	glNormal3f(sqrt(2.0f), sqrt(2.0f), 0.0f);		//차의 범퍼 윗부분
	glVertex3f(x+halfw, y+height, z-halfw);
	glVertex3f(x+halfw, y+height, z+halfw);
	glVertex3f(x+halfw+bump, y, z+halfw);
	glVertex3f(x+halfw+bump, y, z-halfw);

	glNormal3f(0.0f, 1.0f, 0.0f);						//차의 안쪽 밑면
	glVertex3f(x-halfw+thick, y+thick, z-halfw+thick);
	glVertex3f(x-halfw+thick, y+thick, z+halfw-thick);
	glVertex3f(x+halfw, y+thick, z+halfw-thick);
	glVertex3f(x+halfw, y+thick, z-halfw+thick);

	glNormal3f(1.0f, 0.0f, 0.0f);						//차의 안쪽 뒷면
	glVertex3f(x-halfw+thick, y+thick, z-halfw+thick);
	glVertex3f(x-halfw+thick, y+height, z-halfw+thick);
	glVertex3f(x-halfw+thick, y+height, z+halfw-thick);
	glVertex3f(x-halfw+thick, y+thick, z+halfw-thick);

	glNormal3f(-1.0f, 0.0f, 0.0f);						//차의 안쪽 앞면
	glVertex3f(x+halfw, y+thick, z-halfw+thick);
	glVertex3f(x+halfw, y+thick, z+halfw-thick);
	glVertex3f(x+halfw, y+height, z+halfw-thick);
	glVertex3f(x+halfw, y+height, z-halfw+thick);

	glNormal3f(0.0f, 0.0f, 1.0f);						//차의 안 왼쪽 옆면
	glVertex3f(x+halfw, y+thick, z-halfw+thick);
	glVertex3f(x+halfw, y+height, z-halfw+thick);
	glVertex3f(x-halfw+thick, y+height, z-halfw+thick);
	glVertex3f(x-halfw+thick, y+thick, z-halfw+thick);

	glNormal3f(0.0f, 0.0f, -1.0f);						//차의 안 오른쪽 옆면 
	glVertex3f(x+halfw, y+thick, z+halfw-thick);
	glVertex3f(x-halfw+thick, y+thick, z+halfw-thick);
	glVertex3f(x-halfw+thick, y+height, z+halfw-thick);
	glVertex3f(x+halfw, y+height, z+halfw-thick);
	glEnd();

	glBegin(GL_TRIANGLES);
	glNormal3f(0.0f, 0.0f, 1.0f);						//차의 바깥 오른쪽 삼각형
	glVertex3f(x+halfw, y, z+halfw);
	glVertex3f(x+halfw+bump, y, z+halfw);
	glVertex3f(x+halfw, y+height, z+halfw);

	glNormal3f(0.0f, 0.0f, -1.0f);						//차의 바깥 왼쪽 삼각형
	glVertex3f(x+halfw, y, z-halfw);
	glVertex3f(x+halfw, y+height, z-halfw);
	glVertex3f(x+halfw+bump, y, z-halfw);
	glEnd();

	glPushMatrix();
	glTranslatef(x, y, z);
	glRotatef(180.0f, 0.0f, 0.0f, 1.0f);
	glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
	createChair(-halfw+thick, -40.0f, -halfw+thick, 10.0f, 30.0f, 30.0f);
	glPopMatrix();

	glPushMatrix();
	glTranslatef(x, y, z);
	glRotatef(180.0f, 0.0f, 0.0f, 1.0f);
	glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
	createChair(-halfw+thick, -40.0f, 0.0f, 10.0f, 30.0f, 30.0f);
	glPopMatrix();

	glPushMatrix();
	glTranslatef(x, y, z);
	glRotatef(180.0f, 0.0f, 0.0f, 1.0f);
	glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
	createChair(thick, -40.0f, 0.0f, 10.0f, 30.0f, 30.0f);
	glPopMatrix();

	glPushMatrix();
	glTranslatef(x, y, z);
	glRotatef(180.0f, 0.0f, 0.0f, 1.0f);
	glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
	createChair(thick, -40.0f, -halfw+thick, 10.0f, 30.0f, 30.0f);
	glPopMatrix();
}

void renderViking()
{
	glPushMatrix();									//바이킹 왼쪽 앞 기둥
	glRotatef(90.0f, 0.7f, 0.3f, 0.0f);				
	createCylinder(5.0f, 0.0f, 0.0f, 15.0f, 200.0f);

	glPopMatrix();									//바이킹 왼쪽 앞 기둥
	glPushMatrix();
	glRotatef(90.0f, 0.7f, -0.3f, 0.0f);
	createCylinder(-5.0f, 0.0f, 0.0f, 15.0f, 200.0f);

	glPopMatrix();									//뒤쪽으로 이동
	glTranslatef(0.0f, 0.0f, -120.f);
	glPushMatrix();

	glPopMatrix();									//바이킹 오른쪽 뒷 기둥
	glPushMatrix();
	glRotatef(90.0f, 0.7f, 0.3f, 0.0f);
	createCylinder(5.0f, 0.0f, 0.0f, 15.0f, 200.0f);

	glPopMatrix();									//바이킹 왼쪽 뒷 기둥
	glPushMatrix();
	glRotatef(90.0f, 0.7f, -0.3f, 0.0f);
	createCylinder(-5.0f, 0.0f, 0.0f, 15.0f, 200.0f);
	
	glPopMatrix();									//바이킹 윗 기둥
	createCylinder(0.0f, 0.0f, 0.0f, 15.0f, 120.0f);

	glTranslated(0.0f, 0.0f, 60.0f);				//바이킹 지탱 기둥
	glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
	glRotatef(vikingRot, 0.0f, 1.0f, 0.0f);
	createCylinder(0.0f, 0.0f, 0.0f, 15.0f, 130.0f);

	glPopMatrix();									//배 생성
	glPushMatrix();
	glTranslatef(0.0f, 180.0f, 440.0f);
	glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
	glRotatef(vikingRot, -1.0f, 0.0f, 0.0f);
	createShip(0.0f, -130.0f, 0.0f, 50.0f);
}

void renderHurricane()
{
	glPopMatrix();									//허리케인 오른쪽 앞 기둥
	glPushMatrix();
	glRotatef(90.0f, 0.7f, 0.3f, 0.0f);
	createCylinder(5.0f, 0.0f, 0.0f, 15.0f, 200.0f);

	glPopMatrix();									//허리케인 왼쪽 앞 기둥
	glPushMatrix();
	glRotatef(90.0f, 0.7f, -0.3f, 0.0f);
	createCylinder(-5.0f, 0.0f, 0.0f, 15.0f, 200.0f);

	glPopMatrix();									//뒤쪽으로 이동
	glTranslatef(0.0f, 0.0f, -200.f);
	glPushMatrix();

	glPopMatrix();									//허리케인 오른쪽 뒷 기둥
	glPushMatrix();
	glRotatef(90.0f, 0.7f, 0.3f, 0.0f);
	createCylinder(5.0f, 0.0f, 0.0f, 15.0f, 200.0f);

	glPopMatrix();									//허리케인 왼쪽 뒷 기둥
	glPushMatrix();
	glRotatef(90.0f, 0.7f, -0.3f, 0.0f);
	createCylinder(-5.0f, 0.0f, 0.0f, 15.0f, 200.0f);
	
	glPopMatrix();									//허리케인 윗 기둥
	createCylinder(0.0f, 0.0f, -15.0f, 15.0f, 230.0f);

	glTranslated(0.0f, 0.0f, 95.0f);				//허리케인 지탱 기둥
	glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
	glRotatef(vikingRot, 0.0f, 1.0f, 0.0f);
	createCylinder(0.0f, 0.0f, 0.0f, 15.0f, 130.0f);
	glPushMatrix();

	glTranslated(0.0f, 0.0f, 130.0f);				//지탱기둥과 링사이 연결기둥
	glRotated(90.0f, 1.0f, 0.0f, 0.0f);
	glRotated(hurriRot, 0.0f, 1.0f, 0.0f);
	createCylinder(0.0f, 0.0f, 0.0f, 10.0f, 30.0f);

	glRotated(90.0f, 0.0f, 1.0f, 0.0f);
	createCylinder(0.0f, 0.0f, 0.0f, 10.0f, 30.0f);

	glRotated(90.0f, 0.0f, 1.0f, 0.0f);
	createCylinder(0.0f, 0.0f, 0.0f, 10.0f, 30.0f);

	glRotated(90.0f, 0.0f, 1.0f, 0.0f);
	createCylinder(0.0f, 0.0f, 0.0f, 10.0f, 30.0f);

	glPopMatrix();									//링 생성
	glTranslated(0.0f, 0.0f, 110.0f);
	glRotated(hurriRot, 0.0f, 0.0f, 1.0f);
	createRing(0.0f, 0.0f, 0.0f, 50, 30, 20);

	glRotated(90.0f, 1.0f, 0.0f, 0.0f);				//8개의 의자 생성
	createChair(50.0f, 0.0f, -15.0f, 10, 30, 30);
	glRotated(45.0f, 0.0f, 1.0f, 0.0f);
	createChair(50.0f, 0.0f, -15.0f, 10, 30, 30);
	glRotated(45.0f, 0.0f, 1.0f, 0.0f);
	createChair(50.0f, 0.0f, -15.0f, 10, 30, 30);
	glRotated(45.0f, 0.0f, 1.0f, 0.0f);
	createChair(50.0f, 0.0f, -15.0f, 10, 30, 30);
	glRotated(45.0f, 0.0f, 1.0f, 0.0f);
	createChair(50.0f, 0.0f, -15.0f, 10, 30, 30);
	glRotated(45.0f, 0.0f, 1.0f, 0.0f);
	createChair(50.0f, 0.0f, -15.0f, 10, 30, 30);
	glRotated(45.0f, 0.0f, 1.0f, 0.0f);
	createChair(50.0f, 0.0f, -15.0f, 10, 30, 30);
	glRotated(45.0f, 0.0f, 1.0f, 0.0f);
	createChair(50.0f, 0.0f, -15.0f, 10, 30, 30);
}

void renderLetsTwist()
{
	glRotated(60.0f, 1.0f, 0.0f, 0.0f);
	createCylinder(0.0f, 0.0f, 0.0f, 25.0f, 300.0f);		//바닥 지탱 기둥

	glRotated(90.0f, 0.0f, 1.0f, 0.0f);
	glRotated(hurriRot, 1.0f, 0.0f, 0.0f);
	createCylinder(0.0f, 0.0f, -50.0f, 25.0f, 200.0f);		//바닥 지탱 기둥과 회전원기둥을 연결하는 기둥
	glRotated(hurriRot, 0.0f, 0.0f, 1.0f);
	createCylinder(0.0f, 0.0f, 150.0f, 40.0f, 50.0f);		//회전 원기둥
	
	glTranslatef(0.0f, 0.0f, 175.0f);
	glRotated(90.0f, 0.0f, 1.0f, 0.0f);
	createCylinder(0.0f, 0.0f, 0.0f, 15.0f, 150.0f);		//6개 기둥 중 1번째 기둥
	glPushMatrix();
	
	glRotatef(hurriRot, 0.0f, 0.0f, 1.0f);
	createRing(0.0f, 0.0f, 50.0f, 25.0f, 100.0f, 10.0f);		//1번째 기둥의 돌아가는 링과 의자 2개
	createChair(25.0f, -15.0f, 85.0f, 10.0f, 30.0f, 30.0f);
	createChair(25.0f, -15.0f, 120.0f, 10.0f, 30.0f, 30.0f);

	glPopMatrix();
	glRotated(60.0f, 1.0f, 0.0f, 0.0f);
	createCylinder(0.0f, 0.0f, 0.0f, 15.0f, 150.0f);		//6개 기둥 중 2번째 기둥
	glPushMatrix();
	
	glRotatef(hurriRot, 0.0f, 0.0f, 1.0f);
	createRing(0.0f, 0.0f, 50.0f, 25.0f, 100.0f, 10.0f);		//2번째 기둥의 돌아가는 링과 의자 2개
	createChair(25.0f, -15.0f, 85.0f, 10.0f, 30.0f, 30.0f);
	createChair(25.0f, -15.0f, 120.0f, 10.0f, 30.0f, 30.0f);

	glPopMatrix();
	glRotated(60.0f, 1.0f, 0.0f, 0.0f);
	createCylinder(0.0f, 0.0f, 0.0f, 15.0f, 150.0f);
	glPushMatrix();
	
	glRotatef(hurriRot, 0.0f, 0.0f, 1.0f);
	createRing(0.0f, 0.0f, 50.0f, 25.0f, 100.0f, 10.0f);		//3번째 기둥의 돌아가는 링과 의자 2개
	createChair(25.0f, -15.0f, 85.0f, 10.0f, 30.0f, 30.0f);
	createChair(25.0f, -15.0f, 120.0f, 10.0f, 30.0f, 30.0f);

	glPopMatrix();
	glRotated(60.0f, 1.0f, 0.0f, 0.0f);
	createCylinder(0.0f, 0.0f, 0.0f, 15.0f, 150.0f);
	glPushMatrix();
	
	glRotatef(hurriRot, 0.0f, 0.0f, 1.0f);
	createRing(0.0f, 0.0f, 50.0f, 25.0f, 100.0f, 10.0f);		//4번째 기둥의 돌아가는 링과 의자 2개
	createChair(25.0f, -15.0f, 85.0f, 10.0f, 30.0f, 30.0f);
	createChair(25.0f, -15.0f, 120.0f, 10.0f, 30.0f, 30.0f);

	glPopMatrix();
	glRotated(60.0f, 1.0f, 0.0f, 0.0f);
	createCylinder(0.0f, 0.0f, 0.0f, 15.0f, 150.0f);
	glPushMatrix();
	
	glRotatef(hurriRot, 0.0f, 0.0f, 1.0f);
	createRing(0.0f, 0.0f, 50.0f, 25.0f, 100.0f, 10.0f);		//5번째 기둥의 돌아가는 링과 의자 2개
	createChair(25.0f, -15.0f, 85.0f, 10.0f, 30.0f, 30.0f);
	createChair(25.0f, -15.0f, 120.0f, 10.0f, 30.0f, 30.0f);

	glPopMatrix();
	glRotated(60.0f, 1.0f, 0.0f, 0.0f);
	createCylinder(0.0f, 0.0f, 0.0f, 15.0f, 150.0f);
	
	glRotatef(hurriRot, 0.0f, 0.0f, 1.0f);
	createRing(0.0f, 0.0f, 50.0f, 25.0f, 100.0f, 10.0f);		//6번째 기둥의 돌아가는 링과 의자 2개
	createChair(25.0f, -15.0f, 85.0f, 10.0f, 30.0f, 30.0f);
	createChair(25.0f, -15.0f, 120.0f, 10.0f, 30.0f, 30.0f);
}

void renderRollerCoaster()
{
	GLfloat currout[3];

	createRail(0.0f, 0.0f, 0.0f, 20.0f);							//레일 생성
	ovalFunc(rolx, rol4, currout);									//움직일 경로 좌표 값 받아옴

	glPushMatrix();
	glTranslated(currout[0], currout[2]+15.0f, currout[1]);			//차체 구현할 좌표로 translate
	if(rol4 == 4 || rol4 == 3)
	{
		glRotatef(180.0f, 0.0f, 1.0f, 0.0f);						//3, 4분면 곡선 차체 반대로
		if(rol4 == 4)	glRotatef(-bendrotate, 0.0f, 1.0f, 0.0f);	//차체 회전 구현
		else			glRotatef(bendrotate, 0.0f, 1.0f, 0.0f);
	}
	else
	{
		if(rol4 == 2)	glRotatef(-bendrotate, 0.0f, 1.0f, 0.0f);	//차체 회전 구현
		else			glRotatef(bendrotate, 0.0f, 1.0f, 0.0f);
	}
	createCar(0.0f, 0.0f, 0.0f, 20.0f, 70.0f, 30.0f, 5.0f);			//차체 생성
	glPopMatrix();
}

void RenderScene(void)
{
	glShadeModel(GL_SMOOTH);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	if(iCull)
		glEnable(GL_CULL_FACE);
	else
		glDisable(GL_CULL_FACE);
	if(iDepth)
		glEnable(GL_DEPTH_TEST);
	else
		glDisable(GL_DEPTH_TEST);
	if(iOutline)
		glPolygonMode(GL_BACK,GL_LINE);
	else
		glPolygonMode(GL_BACK,GL_FILL);

	glFrontFace(GL_CCW);

	glEnable(GL_TEXTURE_2D);

	grasstex = auxDIBImageLoad("brick.bmp");
	glGenTextures(1, &texID);
	glBindTexture(GL_TEXTURE_2D, texID);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, 3, grasstex->sizeX, grasstex->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, grasstex->data);
	glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_REPLACE);

	glEnable(GL_LIGHTING);
	glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
	glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
	glEnable(GL_LIGHT0);

	glEnable(GL_COLOR_MATERIAL);
	glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
	glPushMatrix();

	glPopMatrix();
	glPushMatrix();
	glTranslatef(xStat, yStat-10.0f, zStat-1000.f);
	glRotatef(xRot, 1.0f, 0.0f, 0.0f);
	glRotatef(yRot, 0.0f, 1.0f, 0.0f);
	glPushMatrix();

	glPopMatrix();								//하늘 생성
	glPushMatrix();
	createHalfSphere(0.0f, 0.0f, 0.0f, 2000.0f);

	glPopMatrix();								//지면 생성
	glPushMatrix();
	glBindTexture(GL_TEXTURE_2D, texID);
	glColor3ub(255, 255, 255);
	glBegin(GL_QUADS);
	glNormal3f(0.0f, 1.0f, 0.0f);
	glTexCoord2f(10.0f, 10.0f);
	glVertex3d(2000.0f, 0.0f, 2000.0f);
	glTexCoord2f(0.0f, 10.0f);
	glVertex3d(2000.0f, 0.0f, -2000.0f);
	glTexCoord2f(0.0f, 0.0f);
	glVertex3d(-2000.0f, 0.0f, -2000.0f);
	glTexCoord2f(10.0f, 0.0f);
	glVertex3d(-2000.0f, 0.0f, 2000.0f);
	glEnd();
	glDisable(GL_TEXTURE_2D);

	glPopMatrix();
	glPushMatrix();
	glTranslatef(0.0f, 0.0f, -500.0f);
	renderRollerCoaster();							//롤러코스터 생성

	glPopMatrix();
	glPushMatrix();
	glTranslatef(600.0f, 180.0f, 500.0f);
	glPushMatrix();
	renderHurricane();								//허리케인 생성

	glPopMatrix();
	glPushMatrix();
	glTranslatef(0.0f, 180.0f, 500.0f);				
	renderViking();									//바이킹 생성

	glPopMatrix();
	glTranslatef(-600.0f, 250.0f, 500.0f);
	renderLetsTwist();								//렛츠 트위스트 생성

	glPopMatrix();
	glutSwapBuffers();
}

void ProcessMenu(int value)
{
	switch(value)
	{
	case 1:
		iDepth = !iDepth;
		break;
	case 2:
		iCull = !iCull;
		break;
	case 3:
		iOutline = !iOutline;
		break;
	}

	glutPostRedisplay();
}

void KeyControl(int key, int x, int y)
{
	if(key == GLUT_KEY_DOWN)
		xRot -= 5.0f;
	if(key == GLUT_KEY_UP)
		xRot += 5.0f;
	if(key == GLUT_KEY_RIGHT)
		yRot -= 5.0f;
	if(key == GLUT_KEY_LEFT)
		yRot += 5.0f;

	glutPostRedisplay();
}

void myKeyboard(unsigned char key, int x, int y)
{
	switch(key)
	{
	case 'W' :
	case 'w' :
		zStat += 10.0f;
		break;
	case 'S' :
	case 's' :
		zStat -= 10.0f;
		break;
	case 'Q' :
	case 'q' :
		xStat += 10.0f;
		break;
	case 'A' :
	case 'a' :
		xStat -= 10.0f;
		break;
	case 'E' :
	case 'e' :
		yStat += 10.0f;
		break;
	case 'D' :
	case 'd' :
		yStat -= 10.0f;
		break;
	case 'Z' :
	case 'z' :
		exit(0);
		break;
	}
}

void SetupRC(void)
{
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}

void ChangeSize(GLsizei w, GLsizei h)
{
	GLfloat fAspect = (GLfloat)w/(GLfloat)h;

	glViewport(0,0,w,h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gluPerspective(60.0f, fAspect, 1.0f, 3000.0f);
	
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void TimerFunc(int value)
{
	glutPostRedisplay();

	if(vikingAcc <= -10.0f)			//바이킹 가속도의 부호가 바뀌는 지점
		sig = true;
	if(vikingAcc >= 10.0f)
		sig = false;

	if(vikingRot != 0.0f)			//0도일때는 가속도가 붙지 않는다.
	{
		if(sig)						//부호에 따라 가속도 증가 및 감소
			vikingAcc++;
		else
			vikingAcc--;
	}
	
	vikingRot += vikingAcc;			//바이킹의 위치 계산

	hurriRot += 5.0f;				//5도 씩 회전
	if(hurriRot >= 360.0f)			//360도 이상이 될 때 0으로 초기화
		hurriRot = 0;
	
	if(rol4 % 2 == 0)				//2, 4사분면
	{
		if(rolx >= (ovalA-100.0f))		//끝의 휜 부분에서 x 증가값 감소
		{
			rolx-=bend;
			if(bend != 10.0f) bend+=0.5;
		}
		else
			rolx -= 10.0f;
	}
	else							//1, 3사분면
	{
		if(rolx >= (ovalA-100.0f))		//끝의 휜 부분에서 x 증가값 감소
		{
			rolx+=bend;
			if(bend != 1.0f) bend-=0.5;
		}
		else
			rolx += 10.0f;
	}

	if(rolx >= (ovalA-260.0f))			//끝의 휜 부분에서 차체를 회전시킴
	{
		if(rol4 % 2 == 0)
		{
			if(bendrotate != 0.0f) 
				bendrotate -= 3.0;
		}
		else
		{
			if(bendrotate != 90.0f) 
				bendrotate += 3.0;
		}
	}

	if(rolx > ovalA || rolx < 0.0f)
	{
		switch(rol4)
		{
		case 1:						//1사분면 끝
			rol4 = 4;
			rolx = (GLfloat)ovalA;
			bend = 5.0f;
			break;
		case 2:						//2사분면 끝
			rol4 = 1;
			rolx = 0.0f;
			bend = 10.0f;
			bendrotate = 0.0f;
			break;
		case 3:						//3사분면 끝
			rol4 = 2;
			rolx = (GLfloat)ovalA;
			bend = 5.0f;
			break;
		case 4:						//4사분면 끝
			rol4 = 3;
			rolx = 0.0f;
			bend = 10.0f;
			bendrotate = 0.0f;
			break;
		}
	}
	
	glutTimerFunc(100, TimerFunc, 1);
}

void main(void)
{
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(400, 400);
	glutCreateWindow("BounceRectangle");
	glutReshapeFunc(ChangeSize);
	glutTimerFunc(33,TimerFunc,1);
	glutSpecialFunc(KeyControl);
	glutKeyboardFunc(myKeyboard);
	glutDisplayFunc(RenderScene);
	glutCreateMenu(ProcessMenu);
	glutAddMenuEntry("깊이 테스트", 1);
	glutAddMenuEntry("은면 제거", 2);
	glutAddMenuEntry("뒷면 라인 그리기", 3);
	glutAttachMenu(GLUT_RIGHT_BUTTON);
	SetupRC();
	glutMainLoop();
}


Command Pattern


1. 정의

- 요청을 캡슐화 해서 사용자가 보낸 요청에 대한 정보를 저장, 취소 등 할 수 있도록 하는 패턴


2. 설명

- 다양한 요청을 똑같은 함수의 호출로 처리 가능토록 인터페이스로 구현.

- 커맨드를 만들 때 해당 인터페이스를 상속받아 구현

- 커맨드를 저장하여 해당 커맨드의 로그를 남기거나 할 수 있다


3. 장/단점

1) 장점

- 작업 요청 로그를 남기거나 할 때 쓰면 쉽게 구현이 가능

2) 단점

- 객체의 캡슐화 하기 어려운 요청의 경우 구현이 힘들 수 있다.


4. 예제 코드

using System;
using System.Collections.Generic;

namespace CommandPattern
{
    // Command 인터페이스
    interface ICommand
    {
        // 실행
        int[,] Execute();
        // 되돌리기
        int[,] Undo();
    }

    class DrawSquareCommand : ICommand
    {
        // 왼쪽 위 좌표
        private int x1, y1;

        // 오른쪽 아래 좌표
        private int x2, y2;

        // 사각형 색깔
        private int color;

        // 이전의 캔버스를 저장
        private int[,] canvas;

        // 현재 캔버스와 사각형 좌표들을 받음
        public DrawSquareCommand(int[,] old, int x1, int y1, int x2, int y2, int color)
        {
            canvas = new int[ old.GetLength( 0 ), old.GetLength( 1 ) ];

            for(int i=0 ;i= x1 && i <= x2 && j >= y1 && j <= y2 )
                    {
                        resultCanvas[ i, j ] = color;
                    }
                    else
                        resultCanvas[ i, j ] = canvas[ i, j ];
                }
            }

            return resultCanvas;
        }

        // 사각형 그리기 되돌리기
        public int[,] Undo()
        {
            return canvas;
        }
    }

    class DrawCircleCommand : ICommand
    {
        // 중심 좌표
        private int x1, y1;

        // 원 반지름
        private int squareRadius;

        // 원 색깔
        private int color;

        // 이전의 캔버스를 저장
        private int[,] canvas;

        // 현재 캔버스와 사각형 좌표들을 받음
        public DrawCircleCommand(int[,] old, int x1, int y1, int radius, int color)
        {
            canvas = new int[ old.GetLength( 0 ), old.GetLength( 1 ) ];

            for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
            {
                for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
                {
                    canvas[ i, j ] = old[ i, j ];
                }

            }

            this.x1 = x1;
            this.y1 = y1;

            squareRadius = radius * radius;

            this.color = color;
        }

        // 사각형 그리기 실행
        public int[,] Execute()
        {
            // 결과 값 저장할 변수
            int[,] resultCanvas = new int[ canvas.GetLength( 0 ), canvas.GetLength( 1 ) ];

            // 원 그림
            for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
            {
                for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
                {
                    if ( ( i - x1 ) * ( i - x1 ) + ( j - y1 ) * ( j - y1 ) <= squareRadius ) 
                    {
                        resultCanvas[ i, j ] = color;
                    }
                    else
                        resultCanvas[ i, j ] = canvas[ i, j ];
                }
            }

            return resultCanvas;
        }

        // 원 그리기 되돌리기
        public int[,] Undo()
        {
            return canvas;
        }
    }

    class DrawLineCommand : ICommand
    {
        // 왼쪽 위 좌표
        private int x1, y1;

        // 오른쪽 아래 좌표
        private int x2, y2;

        // 사각형 색깔
        private int color;

        // 이전의 캔버스를 저장
        private int[,] canvas;

        // 현재 캔버스와 사각형 좌표들을 받음
        public DrawLineCommand(int[,] old, int x1, int y1, int x2, int y2, int color)
        {
            canvas = new int[ old.GetLength( 0 ), old.GetLength( 1 ) ];

            for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
            {
                for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
                {
                    canvas[ i, j ] = old[ i, j ];
                }
            }

            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;

            this.color = color;
        }

        // 사각형 그리기 실행
        public int[,] Execute()
        {
            // 결과 값 저장할 변수
            int[,] resultCanvas = new int[ canvas.GetLength( 0 ), canvas.GetLength( 1 ) ];

            // 기울기를 구할 수 없을 때
            if (x2 == x1)
            {
                // 선 그림
                for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
                {
                    for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
                    {
                        if ( i == x1 && j >= y1 && j <= y2 )
                        {
                            resultCanvas[ i, j ] = color;
                        }
                        else
                            resultCanvas[ i, j ] = canvas[ i, j ];
                    }
                }
            }
            else
            {
                // 기울기
                float slope = ( float ) ( y2 - y1 ) / ( x2 - x1 );

                // y 절편
                float yIntercept = y1 - ( x1 * slope );
                
                // 선 그림
                for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
                {
                    for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
                    {
                        if ( i >= x1 && i <= x2 && j >= y1 && j <= y2 )
                        {
                            if ( j == ( int ) ( slope * i + yIntercept ) )
                            {
                                resultCanvas[ i, j ] = color;
                            }
                            else
                                resultCanvas[ i, j ] = canvas[ i, j ];
                        }
                        else
                            resultCanvas[ i, j ] = canvas[ i, j ];
                    }
                }
            }

            return resultCanvas;
        }

        // 선 그리기 되돌리기
        public int[,] Undo()
        {
            return canvas;
        }
    }

    class CommandManager
    {
        // 실행취소 기록
        private Stack undoHistory;
        // 다시실행 기록
        private Stack redoHistory;

        public CommandManager()
        {
            undoHistory = new Stack();
            redoHistory = new Stack();
        }

        // 명령 실행
        public int[,] ExecuteCommand(ICommand com)
        {
            // 일반 명령 실행 시 다시 실행 기록은 삭제.
            redoHistory.Clear();

            // 실행할 명령을 실행취소 기록에 넣어줌.
            undoHistory.Push( com );
            
            return com.Execute();
        }

        // 실행 취소
        public int[,] UndoCommand()
        {
            ICommand undoCom = undoHistory.Pop();
            redoHistory.Push( undoCom );

            return undoCom.Undo();
        }

        // 다시 실행
        public int[,] RedoCommand()
        {
            ICommand redoCom = redoHistory.Pop();
            undoHistory.Push( redoCom );

            return redoCom.Execute();
        }
    }

    class Program
    {
        public static void PrintCanvas(int[,] canvas)
        {
            for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
            {
                for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
                {
                    Console.Write( canvas[ i, j ] );
                    Console.Write( " " );
                }
                Console.Write( "\n" );
            }
            Console.Write( "\n" );
        }

        public static void UpdateCanvas(int[,] canvas, int[,] newCanvas)
        {
            for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
            {
                for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
                {
                    canvas[ i, j ] = newCanvas[ i, j ];
                }
            }
        }

        static void Main(string[] args)
        {
            // canvas 생성
            int[,] canvas = new int[ 10, 10 ];

            // canvas 초기화
            for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
            {
                for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
                {
                    canvas[ i, j ] = 0;
                }
            }

            Console.WriteLine( "==================== 초기 캔버스 ====================" );
            PrintCanvas( canvas );

            // 명령 매니저 생성
            CommandManager cManager = new CommandManager();

            // 원 그리기 명령 생성 후 실행
            DrawCircleCommand dCircle = new DrawCircleCommand( canvas, 5, 5, 3, 5 );
            UpdateCanvas(canvas, cManager.ExecuteCommand( dCircle ));
            Console.WriteLine( "==================== 1.원 그리기 ====================" );
            PrintCanvas( canvas );

            // 사각형 그리기 명령 생성 후 실행
            DrawSquareCommand dSquare = new DrawSquareCommand( canvas, 4, 4, 6, 6, 3 );
            UpdateCanvas( canvas, cManager.ExecuteCommand( dSquare ) );
            Console.WriteLine( "================== 2.사각형 그리기 ==================" );
            PrintCanvas( canvas );

            // 선 그리기 명령 생성 후 실행
            DrawLineCommand dLine = new DrawLineCommand( canvas, 4, 4, 6, 6, 1 );
            UpdateCanvas( canvas, cManager.ExecuteCommand( dLine ) );
            Console.WriteLine( "==================== 3.선 그리기 ====================" );
            PrintCanvas( canvas );

            // 되돌리기 명령 실행
            UpdateCanvas( canvas, cManager.UndoCommand() );
            Console.WriteLine( "================== 2번으로 되돌리기 =================" );
            PrintCanvas( canvas );

            // 되돌리기 명령 실행
            UpdateCanvas( canvas, cManager.UndoCommand() );
            Console.WriteLine( "================== 1번으로 되돌리기 =================" );
            PrintCanvas( canvas );

            // 다시 실행 명령 실행
            UpdateCanvas( canvas, cManager.RedoCommand() );
            Console.WriteLine( "================== 2번으로 다시실행 =================" );
            PrintCanvas( canvas );
        }
    }
}


5. 출력 결과물


==================== 초기 캔버스 ====================
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

==================== 1.원 그리기 ====================
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 5 0 0 0 0
0 0 0 5 5 5 5 5 0 0
0 0 0 5 5 5 5 5 0 0
0 0 5 5 5 5 5 5 5 0
0 0 0 5 5 5 5 5 0 0
0 0 0 5 5 5 5 5 0 0
0 0 0 0 0 5 0 0 0 0
0 0 0 0 0 0 0 0 0 0

================== 2.사각형 그리기 ==================
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 5 0 0 0 0
0 0 0 5 5 5 5 5 0 0
0 0 0 5 3 3 3 5 0 0
0 0 5 5 3 3 3 5 5 0
0 0 0 5 3 3 3 5 0 0
0 0 0 5 5 5 5 5 0 0
0 0 0 0 0 5 0 0 0 0
0 0 0 0 0 0 0 0 0 0

==================== 3.선 그리기 ====================
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 5 0 0 0 0
0 0 0 5 5 5 5 5 0 0
0 0 0 5 1 3 3 5 0 0
0 0 5 5 3 1 3 5 5 0
0 0 0 5 3 3 1 5 0 0
0 0 0 5 5 5 5 5 0 0
0 0 0 0 0 5 0 0 0 0
0 0 0 0 0 0 0 0 0 0

================== 2번으로 되돌리기 =================
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 5 0 0 0 0
0 0 0 5 5 5 5 5 0 0
0 0 0 5 3 3 3 5 0 0
0 0 5 5 3 3 3 5 5 0
0 0 0 5 3 3 3 5 0 0
0 0 0 5 5 5 5 5 0 0
0 0 0 0 0 5 0 0 0 0
0 0 0 0 0 0 0 0 0 0

================== 1번으로 되돌리기 =================
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 5 0 0 0 0
0 0 0 5 5 5 5 5 0 0
0 0 0 5 5 5 5 5 0 0
0 0 5 5 5 5 5 5 5 0
0 0 0 5 5 5 5 5 0 0
0 0 0 5 5 5 5 5 0 0
0 0 0 0 0 5 0 0 0 0
0 0 0 0 0 0 0 0 0 0

================== 2번으로 다시실행 =================
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 5 0 0 0 0
0 0 0 5 5 5 5 5 0 0
0 0 0 5 3 3 3 5 0 0
0 0 5 5 3 3 3 5 5 0
0 0 0 5 3 3 3 5 0 0
0 0 0 5 5 5 5 5 0 0
0 0 0 0 0 5 0 0 0 0
0 0 0 0 0 0 0 0 0 0


'C# > Design Pattern' 카테고리의 다른 글

[Design Pattern C#]Singleton Pattern  (0) 2016.11.26

+ Recent posts