1. Game Playing

 - Game Playing은 AI research의 좋은 문제이다. 

 - 결과가 간단하고, 평가하기 쉽다.

 - 특정 시간 안에 decision making을 해야 한다.


2. Game Playing as Searching

 - 두 명이서 하는 턴제보드게임일 때

 - states          : 보드의 상태

 - operators     : 규칙에 맞게 움직이는 경우들

 - initial state    : 현재의 보드 상태 

 - goal state     : 최종적으로 이기거나 지는 상태


3. Minimax Algorithm

 - 현재  상태에서 수행 가능한 operator로 진행했을 때, AI 턴일 때는 점수가 가장 높은 쪽으로, 상대방 턴일 때는 점수가 가장 낮은 쪽으로 가도록 한다.

1) 0 번위치가 현재 보드 상태라고 가정하고, depth는 4까지 탐색한다.

    (네모는 AI의 선택으로 움직일 수 있는 상태들, 동그라미는 상대의 선택으로 움직일 수 있는 상태들이다.)

    (각 네모, 동그라미 속 숫자는 클수록 AI에게 유리하다.)

 2) 왼쪽으로 계속 내려가서 4의 가장 왼쪽 노드까지 내려간다. 10과 무한대를 비교

 3) 3에서 4로 갈때는 상대의 선택이므로 AI에게 가장 불리한 선택을 한다고 가정하고 10을 선택한다.

 4) 그 뒤, 오른쪽을 탐색하고 5라는 결과를 불러온다.

 5) 2에서 3은 AI의 선택이므로 5와 10 중 더 큰 값을 가져온다.

 6) 위 과정을 계속 반복하면 -7이 가장 크므로 -7 쪽으로 움직인다.


4. Alpha-Beta Pruning

 - Minimax algorithm을 기반으로 더 빠르게 노드들을 탐색하기 위한 알고리즘

 1) Alpha Cutoff

   a) 처음 D와 E를 비교했을 때, D가 더 작으므로 B는 5가 된다. ( alpha = 5 )

   b) 그 다음 오른쪽으로 내려가서 F를 탐색한다.

   c) C는 F와 G 중에서 작은 수를 가져온다. F가 4라면 G가 어떤 수라도 C가 4보다 클 수 없다.

   d) 이미 alpha값이 5이므로 C는 4를 가져오고 G를 보지 않는다.


 2) Beta Cutoff 

   a) 처음 H와 I를 비교했을 때, I가 더 크므로 D는 5가 된다. ( beta = 5 )

   b) 그 다음 오른쪽으로 내려가서 J를 탐색한다.

   c) E는 J와 K 중에서 큰 수를 가져온다. J가 10라면 K가 어떤 수라도 E가 10보다 작을 수 없다.

   d) 이미 beta값이 5이므로 E는 10를 가져오고 K를 보지 않는다.



'AI' 카테고리의 다른 글

[AI] Knowledge Representation  (0) 2017.06.07
[AI] Constraint Satisfaction Problems  (0) 2017.06.07
[AI] Genetic Algorithm  (0) 2017.04.17
[AI]3장 Heuristic Search Tech.  (0) 2017.04.13
[AI]2장 Intelligent Software Agent, Problem, Problem spaces, Search  (2) 2017.04.13

Genetic Algorithm


1. n-Queen Problem

 1) 문제 정의 : N x N 크기의 체스판이 주어질 떄, N개의 퀸이 서로 공격이 불가능하도록 놓는 경우를 구하는 문제

 2) ex : N = 4

 

 

 

 Q

 

 

 

 

 

 

 

 Q

 

 


2. Genetic Algorithm

 1) Fitness function으로 Fitness 검사 : 어느 정도 해에 가까운지 수치값으로 나타내는 함수로 수치값을 계산

 2) 검사된 결과 중 가장 높은 값은 두 개, 다음 높은 순으로 두 개를 뽑아 서로 형질을 바꾼다.(유전)

 3) 거기에 랜덤(자리, 번호 둘다)으로 형질을 바꿔준다.(돌연변이)

   ex) ①( 3 3 4 2 )   4  4/7      ①( 3 3 | 4 2 )           ( 3 3 | 1 2 )          ( 3 ① 1 2 )

        ②( 1 2 1 2 )   1  1/7      ②( 1 2 | 1 2 )           ( 1 2 | 4 2 )          ( 1 2 4 2 )

        ③( 1 2 3 4 )   0  0/7      ①( 3 | 3 4 2 )           ( 1 | 3 4 2 )          ( 1 3 4 ④ )

        ④( 1 1 1 3 )   2  2/7      ④( 1 | 1 1 3 )           ( 3 | 1 1 3 )          ( 3 1 ③ 3 )

               ⓐ                                ⓑ                       ⓒ                      ⓓ

   ⓐ         : Fitness 검사 : 두개씩 퀸을 페어로 봤을 때 서로 공격이 불가능 한 페어의 개수를 센 값이 클수록 Fitness가 높다.

   ⓑ ~ ⓒ  : 유전 나누는 구간을 랜덤으로 정해 서로 바꾼다(위 예제에선 ①이랑 ②, ③ 이랑 ④를 바꿨다)

   ⓓ         : ⓒ가 끝난 뒤, 특정 지점의 번호를 바꿔준다.(돌연변이)


3. 장단점

 1) 장점

   ① 거의 최적에 가까운 해(near optimal)를 빠르게 찾아낼 수 있다.

   ② parallel 작업이 가능하다

 2) 단점

   ① 어떤 방식으로 최적을 구했는지 재현이 거의 불가능하다.

'AI' 카테고리의 다른 글

[AI] Knowledge Representation  (0) 2017.06.07
[AI] Constraint Satisfaction Problems  (0) 2017.06.07
[AI] Game Playing  (0) 2017.04.17
[AI]3장 Heuristic Search Tech.  (0) 2017.04.13
[AI]2장 Intelligent Software Agent, Problem, Problem spaces, Search  (2) 2017.04.13

1. Generate-and-Test

 - 단순히 풀이법을 만들어 실험해보는 방식

 1) 해결 가능한 Solution을 생성한다. 

 2) Solution이 맞는지 Test한다.

 3) 해결되면 그만두고, 실패하면 다시 1번으로 돌아간다


2. Hill Climbing

 - 현재 노드에서 가장 evaluation function 결과가 좋은 노드로 이동해 나가다가 더이상 좋은 노드가 없거나 goal state에 도착시 멈춤.

 1) 현재 노드에서 갈 수 있는 노드들을 evaluation 한다.

 2) 그 중 가장 높은 evaluation 값을 가진 노드로 이동

    만약 가장 높은 evaluation도 현재 evaluation보다 작다면 움직이지 않는다.

 3) 현재 노드가 goal state인지 확인, goal state 라면 끝, 아니면 다시 1로


3. Steepest-Ascent Hill Climbing

 - 현재 노드에서 가장 가파르게 evaluation 값이 상승하는 노드로 이동한다.

 1) 현재 노드에서 갈 수 있는 노드들을 evaluation 한다.

 2) 그 중 가장 많이 증가한 evaluation 값을 가진 노드로 이동

    만약 가장 많이 증가한 evaluation도 현재 evaluation보다 작다면 움직이지 않는다.

 3) 현재 노드가 goal state인지 확인, goal state 라면 끝, 아니면 다시 1로


4. Best-first search

 - 현재 펼쳐진 노드( evaluation을 평가했던 노드 )들 중에서 가장 큰 노드로 이동한다.

 1) 현재 노드에서 갈 수 있는 노드들을 evaluation 한다.

 2) 현재 펼쳐진 노드 중 evaluation 값이 가장 높은 노드로 이동

    evaluation 값이 가장 높은 노드가 없다면 움직이지 않음

 3) 현재 노드가 goal state인지 확인, goal state 라면 끝, 아니면 다시 1로


5. A* Search

 - 현재 펼쳐진 노드 중 evaluation 값과 start state에서 현재 노드까지 이동하는데 필요한 비용을 더한 값이 가장 작은 노드로 이동한다.
    f(n) = g(n) + h(n)   (f(n) : 총 값, g(n) : 현재 노드까지 이동하는데 소요된 비용, h(n) : goal state 까지 소모된다고 예측되는 비용)

 1) 현재 노드에서 갈 수 있는 노드들을 evaluation 하고, 현재 노드까지 소요된 비용을 더한다.

 2) 현재 펼쳐진 노드 중 계산된 값이 가장 높은 노드로 이동

    계산된 값이 가장 높은 노드가 없다면 움직이지 않음

 3) 현재 노드가 goal state인지 확인, goal state 라면 끝, 아니면 다시 1로 


6. Heuristic function estimate

 - Heuristic function을 overestimate 하지 않는 이상 admissible하다고 본다.

 - 만약 underestimate 하다면 optimal하지만 시간이 오래걸린다.

'AI' 카테고리의 다른 글

[AI] Knowledge Representation  (0) 2017.06.07
[AI] Constraint Satisfaction Problems  (0) 2017.06.07
[AI] Game Playing  (0) 2017.04.17
[AI] Genetic Algorithm  (0) 2017.04.17
[AI]2장 Intelligent Software Agent, Problem, Problem spaces, Search  (2) 2017.04.13

- AI 수업 내용 정리


1. Intelligent Software Agent

 1) 용어 정리

   - Agent : 특정 할 일을 대신 해주는 대행자

   - Intelligent Software Agent : 인공지능 소프트웨어가 할 일을 대신해 주는 것

 2) Intelligent Software Agent란?

   - Environment에서 다양한 Sensor를 통해 들어온 정보를 percept 한다.

   - percept된 정보를 토대로 정의된 State를 찾는다.

   - State에서 가능한 Action 중 Goal에 가까워 질 수 있는 Action을 Actuators로 실행.

   - Goal 도달!!

 3) 예시

   - 의료 진단 시스템( 암 진단 등... )

   - 웹 쇼핑 프로그램( 필요한 상품 추천 등... )


2. Particular Problem

 1) 문제를 정확히 정의한다

 2) 문제를 분석한다

 3) 문제를 풀기 위해 필요한 정보를 분리해낸다.

 4) 최적의 풀이기법을 정한뒤 Particular Problem에 적용시킨다


3. State space Search로 Problem을 정의하는 법

 - state를 정의

 - 가능한 모든 state set(state space)을 정의

 - 시작 state와 목표 state 정의

 - state의 전이 정의


4. water jug problem

 1) 문제 정의

   - 2개의 눈금 없는 주전자가 있고, 하나의 주전자는 4gallon, 하나의 주전자는 3gallon을 담을 수 있다.
     이 떄, 한 주전자에 4gallon 주전자에 2gallon의 물을 담을 방법은?

 2) State 정의

   - S(x, y)

   - x = 0, 1, 2, 3, 4 (4 gallon 주전자)

   - y = 0, 1, 2, 3    (3 gallon 주전자)

   - start state : S(0, 0)

   - goal state : S(2, y)

 3) production Rule

   - (x, y) if x < 4 then (4, y) : fill the 4-gallon jug

   - (x, y) if x < 3 then (x, 3) : fill the 3-gallon jug

   - .... etc 이런식으로 정의

   - 상태 전이의 룰을 정의, 순서가 없다


5. MC problem

 1) 문제 정의

   - 3명의 식인종과 3명의 선교사가 강변에 있다. 모두 다 배를 타고 반대편 강변에 도착해야한다.
     하지만, 배의 승선 가능 인수는 2명이고, 만약 식인종이 선교사보다 수가 많다면 선교사는 죽임을 당할 수 있다. 
     이 경우, 모두 다 살아서 강을 건너는  방법은?

 2) State 정의

   - S(Can_Left, Miss_Left, BoatPos, Can_Right, Miss_Right)

   - Can_Left = 0, 1, 2, 3 ( 왼쪽 강변의 식인종 수 )

   - Miss_Left = 0, 1, 2, 3 ( 왼쪽 강변의 선교사 수)

   - Boat_Pos = Left, Right ( 현재 배 위치 )

   - Can_Right = 0, 1, 2, 3 ( 오른쪽 강변의 식인종 수)

   - Miss_Right = 0, 1, 2, 3 ( 오른쪽 강변의 선교사 수)

 3) Production Rule

   - (Can_Left, Miss_Left, Left, Can_Right, Miss_Right)
     : if Can_Left > 0 && Miss_Left > 0 then (Can_Left-1, Miss_Left-1, Right, Can_Right+1, Miss_Right+1) - Move-1m1c-lr

   - (Can_Left, Miss_Left, Right, Can_Right, Miss_Right)
     : if Can_Right > 0 && Miss_Right > 0 then (Can_Left-1, Miss_Left-1, Left, Can_Right-1, Miss_Right-1) - Move-1m1c-rl


6. Production systems

 1) 정의해야 할 것들

   - global databases 정의 = state space를 정의한다.

   - production rule을 정의

   - control strategy를 정의( 탐색 방법을 정한다 )

 2) control strategy

   - 가장 첫번쨰를 적용한다

   - 랜덤으로 룰을 적용한다

   - dfs를 이용한다

   - bfs를 이용한다

  3) heuristic search

   - 효율적으로 search를 하게 해주는 방법 ( 탐색을 줄여준다 )

   - heuristic evaluation function을 이용해 탐색의 조건을 추가해준다.

'AI' 카테고리의 다른 글

[AI] Knowledge Representation  (0) 2017.06.07
[AI] Constraint Satisfaction Problems  (0) 2017.06.07
[AI] Game Playing  (0) 2017.04.17
[AI] Genetic Algorithm  (0) 2017.04.17
[AI]3장 Heuristic Search Tech.  (0) 2017.04.13

https://github.com/open-korean-text/open-korean-text

트위터에서 개발한 한국어 분석기!

이건 또 메이븐 프로젝트이다...


1. https://maven.apache.org/download.cgi

메이븐 다운로드를 해주자.



2. 메이븐을 설치하고픈 폴더에 설치 후 환경설정 값 저장하기




3. cmd에서 확인하기

mvn --version

이라고 명령어를 넣어서 아래처럼 뜬다면 설치 성공






4. 이젠 IntelliJ 설치

https://www.jetbrains.com/idea/#chooseYourEdition

가난한 학생이므로 Community를 받자.




next의 연속.jpg




5. https://github.com/open-korean-text/open-korean-text

여기서 프로젝트를 다운받자.





6. IntelliJ에 임포트!




7. pom.xml 파일을 선택해주면 알아서 maven 프로젝트라 인식한다.


8. Next...




9. reimport!



10. mvn test

입력하기


11. 결과 출력이 됨

Test라고 된 부분에 출력이 된 것을 볼 수 있다.



소스 분석은 이후에...

'AI > Natural Language Processing' 카테고리의 다른 글

[NLP]Komoran 설치  (2) 2017.03.21

https://github.com/shin285/KOMORAN

한국에서 만든 한국어 자연어 처리 오픈소스.(위 링크는 KOMORAN 3.0 베타 - 2017.03.21 기준)

이 글은 해당 오픈소스의 설치 및 예제 소스 프로그램의 실행이 목표이다.

java언어를 썼으며, gradle project이다.


이 글에서는 eclipse - gradle - komoran - 예제 코드 실행 순으로 글을 이어나갈 것이다.



1. 우선, eclipse의 설치

http://www.eclipse.org/ide/

해당 링크로 가서 eclipse를 설치해야 한다.

저는 Java IDE를 설치했습니다.



2. Java IDE 설치 파일 다운로드

지원환경에 맞는 설치 파일을 받아야합니다.



3. 다운로드! 하지 마시고 stable 버전을 봅시다

우리나라 미러 사이트를 이용합시다

http://ftp.daumkakao.com/eclipse/technology/epp/downloads/release/



4. stable 버전에 맞는 폴더에 들어가 다운로드!

압축을 플고 원하는 곳으로 이동시켜 줍니다.



6. ??????

컴퓨터를 새로 사서 자바가 안깔려 있었네요 하하.....

java 없으시면 떠요...




8. Komoran 다운로드

https://github.com/shin285/KOMORAN

- KOMORAN 3.0 github 링크

readme를 읽어보면 예제에 대한 설명이 있음.

Clone or download를 누르면 zip파일로 프로젝트를 받을 수 있다.

그 후 저장하고 싶은 폴더에 저장.


9. eclipse로 프로젝트 import




10. Gradle Project 선택



11. 코모란 위치를 선택 후 프로젝트 생성



12. src/main/java - kr.co.shineware.nlp.komoran.test - KomoranTest.java

다음처럼 실행 하면 콘솔에 결과가 출력된다.



13. 결과 출력


예제 분석은 내일!

다음엔 트위터 자연어 처리 라이브러리다...

'AI > Natural Language Processing' 카테고리의 다른 글

[NLP]Twitter Korean Text  (1) 2017.03.23

1. Compiler의 탄생

 - assembly language로 프로그램 작성하였으나, Target Machine이 바뀔 때마다 다시 짜야하는 불편함이 있었음.

 - 1950년대 후반 최초의 FORTRAN Compiler 제작됨.


2. Compiler

 - 입력으로 Source Program을 받음.

 - Source Program 바탕으로 Target Machine에서 동작가능한 Target Program 생성(Source Program과 동등한 수준의 프로그램)

 - 단점 : 컴파일이 모두 끝날 때까지 오류 파악과 수정이 불리함.

 - 장점 : 실행코드 최적화에 유리


3. Interpreter and Compiler

 - 입력으로 Source Program과 Program Input Data를 받음.

 - 입력을 바탕으로 결과값을 출력.

 - 단점 : 최적화된 프로그램이 아님

 - 장점 : 소스와 데이터가 입력되어 결과가 빠르게 나오므로 코드 수정에 유리


4. Hybrid Compiler(Java)

 - 입력으로 Source Program을 받음

 - Translator를 이용 intermediate Program을 생성(Byte Code로 이루어진 프로그램)

 - Byte Code를 실행 가능한 VIrtual Machine에 Intermediate Program과 Program Input Data를 넣음

 - Virtual Machine에서 결과값 출력.


5. Cross Compiler

 - Development Environment와 Execution Environment가 다를 경우 사용

 ex) 윈도우에서 안드로이드 어플을 개발하는 경우


6. Language Processing System

 1) preprocessor : 주석, define, include 등 처리할 문장들을 처리한다.(아직 High Language)

 2) Compiler : preprocessor 결과물로 Assembly Code를 생성

 3) Assembler : Assembly Code로 Machine Code를 생성

 4) Linker/loader : Library 등 호출해 병합 후, 수행가능한 코드 생성


7. Structure of Compiler

 1) Lexical Analyzer(Scanner)

  - 컴파일러에서 다루기 쉬운 Token으로 바꿔 줌.

  - Token 바탕으로 Symbol Table 생성


 2) Syntax Analyzer(Parser)

  - 문법이 맞는지 확인.

  - Syntax Tree를 생성.


 3) Semantic Analyzer

  - Symbol Table을 참조해 각 Token의 의미를 분석.


 4) Intermediate Code Generator

  - 분석된 코드를 Intermediate Code로 바꿔줌.


 5) Machine-independent Code Optimizer

  - 중복 등 Intermediate Code가 최적화 되도록 코드 수정


 6) Code Generator

  - Target Machine에 맞도록 Machine Code 생성.


 7) Machine-Dependent Code Optimizer

  - 해당 Machine에 최적화 되도록 Machine Code 수정.


8. Phases 와 Passes

 1) Phase : 컴파일러를 구성하는 논리적 component, 모든 컴파일러에 필수.

 2) Pass : 입력 데이터로 출력을 만들어 내는 것.

 3) one-pass compiler : 중간 산출물 없이 바로 Machine 코드 생성(성능이 제한적이다)

 4) multi-pass compiler : 중간에 다양한 산출물 생성 후 산출물 바탕으로 Machine 코드 생성.(분석이 많아저 성능이 뛰어남)


9. Two-pass Compiler

 - 별도의 중간 언어 코드를 생성해 중간 언어 코드로 Machine Code를 생성함.

 - 장점 : 언어마다 compiler를 만들어야 하지만, 중간 코드가 있다면 중간 코드에 대한 Machine Code 생성으로 논리적 부분만 만들면 되는 장점이 있다.

 - 이 장점도 언어의 특성이 달라지면 중간 코드도 바뀌어야 한다. 주로 비슷한 언어끼리 같은 중간 코드 사용



1. OSI 모델

 - Open Systems Interconnection의 준말

 - OSI 모델은 1970년대에 the International Standards Organization(ISO)에서 제정








L7 (Application, presentation, Session)




L4(Transport) - process-to-process message delivery


L3(Network) - source to destination


L2(Data Link) - hop-to-hop delivery


L1(Physical)



2. TCP/IP 프로토콜

 - OSI와 비슷하지만 Application 계층은 OSI에서 Application, Presentation, Session을 합친 구조

Application

(Application, Presentation, Session)

Transport 

Network 

DataLink 

Physical 



3. Physical Layer

 - bit로 통신.


4. Data Link Layer

 - Frame이 기본단위

 - Mac Address(물리적 주소)를 이용하여 hop-to-hop delivery

 - Header에 Mac Address를 붙인다.


5. Network Layer

 - Datagram이 기본 단위

 - IP Address(논리적 주소)를 이용하여 source to destination 전송

 - Header에 IP Addresss 를 붙인다.


6. Transport Layer

 - Segment(TCP) or User datagram(UDP)가 기본 단위

 - 다양한 application을 Port 번호로 구분

 - Header에 Port 번호를 붙인다.


7. 하나의 선에 여러 컴퓨터가 연결되어 있을 때

 - 1번 컴퓨터에서 데이터를 4번 컴퓨터로 보내면 이 데이터가 2, 3, 4 번 모두에게 보내진다.

 - 각 컴퓨터는 받은 데이터의 목적지 주소(Mac Address)를 보고 자신이 목적지가 아니면 데이터를 버린다.


8. IP Address를 이용한 통신 과정

 ex) 컴퓨터 src, des

      라우터, R1, R2

      src의 IP : 20, Mac : A

      des의 IP : 60, Mac : F

      R1의 IP : 25, Mac : B  (라우터는 두개의 IP와 Mac이 있다)

                 IP : 35, Mac : C

      R2의 IP : 45, Mac : D

                 IP : 55, Mac : E

      컴퓨터 src 에서 des로 데이터를 보낸다고 가정.

  1) src에서 des로 보내기 위해 R1에 데이터를 보냄 (Header : A B 60 20)

  2) R1에서 Routing Table을 뒤져서 R2로 보냄(Header : C D 60 20)

  3) R2에서 Mapping Table을 뒤져서 des로 보냄(Header : E F 60 20)

  4) des가 데이터 받음

※Routing Table은 IP 주소마다 보낼 목적지가 저장, 만약 저장된 IP가 아닐 경우 Default 값으로 전송(더 상위 라우터로 전송)

※Mapping Table은 IP 주소를 이용해 Mac 주소를 알아내기 위해 저장해둔 테이블.


9. Mac Address를 쓰는 이유

 - TCP만을 이용한다면 IP 주소만 쓰면 괜찮을 것 같지만 TCP가 아닌 다른 프로토콜도 Mac 주소를 이용해 데이터 전송 가능하므로 Mac 주소를 사용한다.

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();
}


+ Recent posts