교재 제목 : OpenGL 을이용한항공기계기판설계 2014-01-20 한국폴리텍대학항공캠퍼스 윤근수 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 0
목차 1. OpenGL 개요및구성... 9 1.1. 개요... 9 1.2. 설치... 11 1.3. 개발환경... 12 1.4. 구성... 13 2. 프로젝트개요... 17 2.1. 콘솔프로젝트... 17 2.2. 윈도우프로젝트... 22 2.3. 목표프로젝트... 25 2.3.1. 전방향시현기 (Head-up Display)... 27 2.3.2. 전자식비행계기 (EFI)... 28 3. OpenGL 의기초... 29 3.1. 기본타입... 29 3.2. OpenGL 의함수형식... 30 3.3. 색상변경... 32 3.4. 상태머신... 38 4. GLUT 개요... 44 4.1. GLUT... 44 4.2. 입력처리... 49 4.3. 팝업메뉴... 54 4.4. 애니메이션... 59 4.5. Win32 OpenGL 예제... 63 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 1
5. 항공기계기판이해... 69 5.1. Pitch,Roll,Yaw... 69 5.1.1. Pitch... 69 5.1.2. Roll... 69 5.1.3. Yaw... 70 5.2. Compass(Heading Indicator)... 71 5.3. Artificial Horizon(Attitude Indicator)... 71 5.4. 고도계 (Altimeter)... 73 5.5. Airspeed Indicator (ASI)... 74 5.6. 전방향시현기 (HUD)... 75 6. 항공기계기판설계 1 ( 콘솔프로젝트 )... 79 6.1. 점... 79 6.2. 선... 84 6.3. 삼각형... 92 6.4. 사각형... 97 6.5. 다각형... 100 6.6. 방위지시계 (Bearing Pointer)... 106 6.7. 러버라인 (Lubber Line)... 108 6.8. 코스방향제어 (Course Arrow Control Box)... 110 6.9. 고정표지 (Fixed Marker)... 112 6.10. 각도 (Degree)... 114 6.11. 기타정보... 116 6.12. 전자식수평자세지시계 (EHSI)... 118 6.13. 블랜딩... 121 6.14. 안티알리아싱... 128 6.15. 전방향시현기 (HUD)... 134 한국폴리텍대학항공캠퍼스항공제어시스템과 페이지 2
6.16. 전자식수평위치방향계 (EHSD)... 140 6.17. 전자식자세방향지시계 (EADI)... 144 7. 항공기계기판설계 2 ( 윈도우프로젝트 )... 148 7.1. 프로젝트생성... 150 7.2. OpenGL 설정... 152 7.3. 메시지핸들러추가... 158 7.4. 점... 166 7.5. 선... 169 7.6. 삼각형... 172 7.7. 사각형... 175 7.8. 다각형... 178 7.9. 방위지시계 (Bearing Pointer)... 182 7.10. 러버라인 (Lubber Line)... 185 7.11. 코스방향제어 (Course Arrow Control Box)... 188 7.12. 고정표지 (Fixed Marker)... 191 7.13. 각도 (Degree)... 195 7.14. 기타정보... 198 7.15. 타이머를이용한이벤트처리... 201 7.16. Menu 를이용한 Color 속성변경... 205 7.17. 전자식수평자세지시계 (EHSI)... 212 7.18. 전방향시현기 (HUD)... 216 7.19. 전자식수평위치방향계 (EHSD)... 222 7.20. 전자식자세방향지시계 (EADI)... 226 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 3
그림목차 그림 1-1 opengl.zip 압축파일리스트... 11 그림 1-2 OpenGL 홈페이지화면... 15 그림 1-3 OpenGL 다운로드링크... 15 그림 1-4 OpenGL 라이브러리압축파일... 16 그림 2-1 Visual C++ 새프로젝트설정... 16 그림 2-2 Visual C++ 응용프로그램설정... 18 그림 2-3 Visual C++ 새항목추가화면... 19 그림 2-4 ConsoleOpenGL 실행... 19 그림 2-5 Visual C++ Win32 프로젝트항목설정... 19 그림 2-6 Visual C++ Win32 응용프로그램옵션설정... 23 그림 2-7 WinOpenGL 실행... 25 그림 2-8 OpenGL으로설계된항공기계기판실행... 25 그림 3-1 OpenGL 함수명명법... 30 그림 3-2 ChangeState 실행... 34 그림 3-3 ChangeState 실행... 38 그림 3-4 상태머신개념... 39 그림 3-5 상태머신실행... 41 그림 4-1 glutinput 실행... 54 그림 4-2 glutmenu 실행... 59 그림 4-3 glutani 실행... 63 그림 4-4 Win32OpenGL 속성페이지... 66 그림 4-5 Win32 GDI 실행... 67 그림 5-1 Pitch... 678 그림 5-2 Roll... 70 그림 5-3 Yaw... 70 그림 5-4 방위표시기... 191 그림 5-5 수평표시기... 72 그림 5-6 고도표시기... 73 그림 5-7 속도표시기... 74 그림 5-8 전방향시현기 (HUD)... 76 그림 5-9 전방향시현기심볼 (HUD)... 766 그림 6-1 점... 81 그림 6-2 점... 83 그림 6-3 선... 195 그림 6-4 삼각형... 86 그림 6-5 정점의순서... 87 그림 6-6 삼각형... 87 그림 6-7 선굵기... 89 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 4
그림 6-8 점선... 90 그림 6-9 점선의패턴... 919 그림 6-10 삼각형... 93 그림 6-11 연속삼각형... 94 그림 6-12 연속삼각형의정점순서... 94 그림 6-13 부채... 96 그림 6-14 사각형... 98 그림 6-15 마름모... 99 그림 6-16 다각형의조건... 19 그림 6-17 항공기... 19 그림 6-18 정점순서... 19 그림 6-19 다각형... 103 그림 6-20 평면위의정점... 1044 그림 6-21 정점과선분... 104 그림 6-22 방위지시계... 19 그림 6-23 러버라인 (Lubber Line)... 19 그림 6-24 코스방향제어... 19 그림 6-25 고정표지 (Fixed Marker)... 19 그림 6-26 각도 (Degree)... 19 그림 6-27 기타정보... 19 그림 6-28 전자식수평자세지시계 (EHSI)... 19 그림 6-29 블랜딩적용전... 19 그림 6-30 블랜딩적용전... 196 그림 6-31 안티알리아싱적용전... 132 그림 6-32 안티알리아싱적용후... 133 그림 6-33 전방향시현기 (HUD)... 19 그림 6-34 전방향시현기 (HUD) 추가코드... 19 그림 6-35 전자식수평위치방향계 (EHSD)... 1940 그림 6-36 전자식수평위치방향계추가코드... 143 그림 6-37 전자식자세방향지시계 (EADI)... 19 그림 6-38 전자식자세방향지시계추가코드... 147 그림 7-1 MFC 프로젝트생성... 150 그림 7-2 MFC 응용프로그램마법사... 151 그림 7-3 MFC 응용프로그램종류... 151 그림 7-4 stdafx.h 파일설정... 153 그림 7-5 멤버변수멤버함수추가... 154 그림 7-6 MFC OpenGL... 157 그림 7-7 메시지핸들러추가 - 1... 19 그림 7-8 메시지핸들러추가 - 2... 159 그림 7-9 메시지핸들러추가 - 3... 160 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 5
그림 7-10 메시지핸들러추가 - 4... 161 그림 7-11 메시지핸들러추가 - 5... 162 그림 7-12 메시지핸들러추가 - 6... 163 그림 7-13 메시지핸들러추가 - 7... 164 그림 7-14 메시지핸들러적용된 EHSI... 165 그림 7-15 점... 19 그림 7-16 선... 19 그림 7-17 삼각형... 1973 그림 7-18 사각형... 19 그림 7-19 다각형... 19 그림 7-20 방위지시계... 193 그림 7-21 러버라인 (Lubber Line)... 197 그림 7-22 코스방향제어... 19 그림 7-23 고정표지... 19 그림 7-24 각도 (Degree)... 19 그림 7-25 기타정보... 200 그림 7-26 타이머 - 1... 203 그림 7-27 타이머 - 2... 202 그림 7-28 타이머 - 3... 205 그림 7-29 타이머 - 4... 206 그림 7-30 Color 속성변경 - 1... 207 그림 7-31 Color 속성변경 - 2... 206 그림 7-32 Color 속성변경 - 3... 207 그림 7-33 Color 속성변경 - 4... 208 그림 7-34 Color 속성변경 - 5... 209 그림 7-35 Color 속성변경 - 6... 211 그림 7-36 전자식수평자세지시계 (EHSI)... 214 그림 7-37 전방향시현기 (HUD)... 219 그림 7-38 HUD 추가파일... 217 그림 7-39 전자식수평위치방향계 (EHSD)... 214 그림 7-40 전자식수평위치방향계 (EHSD) 추가파일... 223 그림 7-41 전자식자세방향지시계 (EADI)... 19 그림 7-42 전자식자세방향지시계 (EADI) 추가파일... 19 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 6
표목차 표 1-1 운영체제별라이브러리... 오류! 책갈피가정의되어있지않습니다. 표 3-1 타입정의... 20 표 3-2 BUFFER 삭제인수... 오류! 책갈피가정의되어있지않습니다. 표 3-3 마스크인자... 오류! 책갈피가정의되어있지않습니다. 표 4-1 디스플레이모드... 오류! 책갈피가정의되어있지않습니다. 표 6-1 정점 (Vertex) 모드... 오류! 책갈피가정의되어있지않습니다. 표 6-2 블랜딩모드... 오류! 책갈피가정의되어있지않습니다. 표 6-3 블랜딩모드연산식... 오류! 책갈피가정의되어있지않습니다. 표 7-1 컴파일러버전에따른 MFC 버전... 오류! 책갈피가정의되어있지않습니다. 코드목차 코드 2-1 ConsoleOpenGL... 20 코드 2-2 WinOpenGL... 24 코드 2-3 항공기계기판코드... 27 코드 3-1 ChangeState... 34 코드 3-2 ChangeState... 36 코드 3-3 ChangeState... 37 코드 3-4 상태머신예제... 40 코드 4-1 main문예제... 48 코드 4-2 DoKeyboard문예제... 49 코드 4-3 glutinput문예제... 53 코드 4-4 glutmenu문예제... 58 코드 4-5 glutani 문예제... 62 코드 4-6 Win32OpenGL 예제... 66 코드 6-1 점 (Dot)... 80 코드 6-2 점 (Dot) Dispay 함수... 81 코드 6-4 선... 86 코드 6-5 점선... 90 코드 6-9 다각형을이용한항공기... 102 코드 6-10 방위지시계... 107 코드 6-11 러버라인... 109 코드 6-12 코스방향제어... 111 코드 6-13 고정표지... 113 코드 6-14 각도... 115 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 7
코드 6-15 기타정보... 117 코드 6-16 전자식수평자세지시계 (EHSI)... 120 코드 6-17 블랜딩... 125 코드 6-18 안티알리아싱... 131 코드 6-19 전방향시현기... 139 코드 6-20 전자식수평위치방향계... 142 코드 6-21 전자식자세방향지시계... 146 코드 7-3 MFC OpenGL... 156 코드 7-8 점... 168 코드 7-9 선... 171 코드 7-10 삼각형... 174 코드 7-11 사각형... 177 코드 7-12 다각형... 181 코드 7-13 방위지시계... 184 코드 7-14 러버라인... 187 코드 7-15 코스방향제어... 190 코드 7-16 고정표지... 194 코드 7-17 각도... 197 코드 7-18 기타정보... 200 코드 7-19 타이머 - 1... 203 코드 7-20 타이머 - 2... 204 코드 7-22 Color 속성변경 - 2... 210 코드 7-23 전자식수평지시계 (EHSI)... 215 코드 7-24 전방향시현기 (HUD)... 221 코드 7-25 EHSD... 225 코드 7-26 전자식자세방향지시계 (EADI)... 229 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 8
1. OpenGL 개요및구성 1.1. 개요 OpenGL(Open Graphics Library) 은 1992년실리콘그래픽스사에서만든 2차원및 3차원그래픽스표준 API(Application Programming Interface) 규격으로, 프로그래밍언어간플랫폼간의교차응용프로그래밍을지원한다. 이 API는약 250여개가량의함수호출을이용하여단순한기하도형에서부터복잡한삼차원장면을생성할수있다. OpenGL은현재 CAD, 가상현실, 정보시각화, 비행시뮬레이션등의분야에서활용되고있다. 또한컴퓨터게임분야에서도널리활용되고있으며, 마이크로소프트사의 Direct3D와함께컴퓨터그래픽세계를양분하고있다. Direct3D와는달리, 표준안이여러관련업체의토론과제안으로이루어지기에버전업데이트는느린편이다. OpenGL을사용하여개발된대표적인게임은이드소프트웨어의퀘이크, 둠3 시리즈이다. 현재비영리기술컨소시엄인크로노스그룹에의하여관리되고있다. GLUT(OpenGL Utility Toolkit) 은호스트운영체제와시스템수준의입출력을가능하게만드는 OpenGL 프로그램용유틸리티라이브러리이다. 주요한기능으로창의크기와형태를정의하고제어하며, 키보드와마우스입력을감지하는기능이있다. 뿐만아니라정육각형, 구, 유타찻잔과같은컴퓨터그래픽스에서요긴한몇가지기하학적인기본객체 (geometric primitives) 를그려주는루틴도가지고있으며, 팝업메뉴를생성하는기능도제공한다. GLUT의두가지중요한목적은운영체제사이의이식성이좋은코드를구현하자는것과 OpenGL을쉽게익히도록하는것이다. 실제로 OpenGL 프로그래밍을 GLUT을사용하게되면매우적은라인과운영체제에대한깊이있는지식이없더라도쉽게프로그램을작성할수있다. 모든 GLUT는 glutpostredisplay, glutcreatewindow와같이 glut라는접두사로시작한다. OpenGL ES ( 임베디드단말을위한 OpenGL) 는크로노스그룹이정의한 3 차원컴퓨터그래픽스 API 인 OpenGL 의서브셋으로, 휴대전화, PDA 등과같은임베디드단말을위한 API 이다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 9
OpenGL ES는 Khronos 그룹 (http://www.khronos.org) 이관리하는데이미 PDA, 휴대폰을포함한모바일기기에포팅이되어있는실제적인표준이라고할수있다. 현재모바일자바 3D(M3G) 와는어느정도경쟁관계에있지만시장에빨리진출했고 Symbian, Brew와같은네이티브플랫폼에서는속도가 M3G보다빠르다. OpenGL ES는기본적으로 OpenGL에기반을두고있으므로기존의 OpenGL 응용프로그램들을포팅하기는쉽다. OpenGL ES(Embedded Systems) 주요특징 1) 로열티없는실제적인업계표준 OpenGL ES 는공개표준으로누구든지스펙은다운로드받을수있으며 OpenGL ES 에기반한제품을출하할 수있다. 2) 작은코드크기와낮은전력소모임베디드시스템은 400M Hz+64M 램이장착된 PDA에서부터 50MHz+1M 램이장착된휴대폰까지다양하다. OpenGL ES는이러한다양한환경에사용될수있도록코드크기가작으며동작에필요한메모리나명령 / 데이터트래픽도최소화되어있다. 또부동소수점이외에도고정소수점 (Fixd point) 연산을사용할수있다 ( 부동소수점연산을사용할수없거나매우느린임베디드시스템에도움이된다 ). 사용자입장에서다운로드받아야할프로그램의크기가보다작아지며적은메모리만을차지한다. 3) 매끄러운하드웨어가속 OpenGL ES는비록고정된그래픽프로세싱파이프라인을사용하지만각각의과정은어플리케이션수정없이하드웨어가속, 소프트웨어, 또는하드웨어가속과소프트웨어의조합으로실행될수있다. 따라서개발자들은고속의하드웨어가속이되는장비와그렇지않은장비모두를매끄럽게지원할수있다. 4) 확장성 & 진보 OpenGL ES는 OpenGL 확장매커니즘 (OpenGL Extension Mechanism) 을통해서진보된하드웨어기능을사용하거나업데이트할수있게지원한다. 만약확장기능이널리사용되면그기능은 OpenGL ES의표준으로포함될수있다. 이러한방식은 OpenGL ES이잘관리되면서도빠르게진보할수있도록한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 10
5) 손쉬운사용 OpenGL ES 는 OpenGL 에기반하며직관적인디자인과명령으로구성되어있다. 기존의 OpenGL 어플리케이션 을 OpenGL ES 로포팅하거나반대의작업을하는데수월하다. 1.2. 설치 1) OpenGL 다운로드첨부된 opengl.zip을다운받고압축을풀어준다. 2) OpenGL 설치 A) 압축을풀면다음과같은파일들이나타난다. 그림 1-1 opengl.zip 압축파일리스트 B) *.dll 파일모두 c:\windows\system32 폴더에넣어준다. (64 비트의경우 c:\windows\syswow64 폴더에도넣어준다.) C) *.lib 파일모두 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 11
비주얼스튜디오 2008의경우 C:\Program Files\Microsoft Visual Studio 9.0\VC\lib 폴더에넣어준다. 비주얼스튜디오 2010의경우 C:\Program Files\Microsoft Visual Studio 10.0\VC\lib 폴더에넣어준다. (64비트운영체제의경우폴더가 C:\Program Files (x86) 에있다.) D) *.h파일모두비주얼스튜디오 2008의경우 C:\Program Files\Microsoft Visual Studio 9.0\VC\include 에 gl이라는폴더를만들어넣어준다. 비주얼스튜디오 2010의경우 C:\Program Files\Microsoft Visual Studio 10.0\VC\include 에 gl이라는폴더를만들어넣어준다. (64비트운영체제의경우폴더가 C:\Program Files (x86) 에있다.) 1.3. 개발환경 OpenGL은플랫폼과언어에독립적이므로학습및개발환경이광범위하다. 어떤운영체제에서나사용할수있으며아이폰이나안드로이드같은모바일환경에서도활용할수있다. 그러나학습을위한환경은 PC가가장편리하다. 설사최종타겟이모바일이더라도일단 PC 환경에서기본개념을실습한후모바일환경에서달라지는부분만따로학습하는것이현명하다. 모바일환경은에뮬레이터상에서결과를확인하므로절차가번거롭고느리다. OpenGL 학습에가장권장되는환경은윈도우즈플랫폼에서 C 컴파일러를사용하는것이다. 무엇보다대중적이고개발환경을구축하기도쉽기때문이다. 이강좌에서는비주얼스튜디오 2010으로프로젝트를제공한다. 전통적으로많이사용되는비주얼 C++ 6.0도실습컴파일러로충분하지만실습을위해일부러따로설치하는것도무척귀찮은일이다. 실무프로젝트를위해어차피 2010이설치되어있는경우가많으므로이컴파일러를기준으로한다. 리눅스이거나다른컴파일러를사용하더라도개발과정에는큰차이점이없다. 이강좌는 C/C++ 문법과컴파일 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 12
러사용법은안다고가정한다. 3차원그래픽은본질적으로수학을많이사용하므로기본적인수학적개념이필요하다. 그런데, 복잡한수학적계산이엄청나게많이사용되지만그걸대신해주는것이바로 OpenGL이다. 개념만이해하고 OpenGL을잘이용하면된다. 마치컴퓨터를잘몰라도웹서핑이나게임을잘할수있는것과비슷하다. 상세하게는몰라도내부동작을대충이나마유추할수있는정도면충분하다. OpenGL의연산과정을잘알고있으면함수들의인터페이스를더잘이해할수있고에러발생시대처능력이향상된다. C 언어외에 3DS MAX 같은 3차원그래픽소프트웨어를사용해본경험이있다면많은도움이된다. 1.4. 구성 OpenGL 은다음두가지라이브러리로구성되어있다. GL : 가장기본적인그리기기능을제공하는핵심라이브러리이며 OpenGL 의본체에해당한다. 기초도형 을랜더링하는함수들이포함되어있다. 시스템디렉토리에 opengl32.dll(773k) 파일로제공되며미리설치되 어있다. GLU : GL 의도우미역할을하는유틸리티라이브러리이다. 분할, 투영등의고급기능을제공하며원구나 원뿔, 원기둥등의테스트입체도형을생성하는편의기능도제공한다. glu32.dll(127k) 파일로제공된다. 내 부적으로 GL 함수를호출하므로 GL 의일부로취급하기도한다. OpenGL은순수한그래픽라이브러리이며그래픽관련기능만제공한다. 그래픽을출력하려면윈도우가있어야하고사용자로부터입력도받아야하는데 OpenGL은이런기능을전혀제공하지않는다. 본연의임무가아닌기능은과감하게제외함음으로써전문성을높이고그럼으로써플랫폼독립성이확보되는것이다. 반면 DirectX는입출력기능까지제공하므로윈도우즈에서만사용가능하다. 플랫폼마다윈도우를생성및관리하는방법이다르고입출력방법도상이하다. 그래서윈도우나입출력관련기능은플랫폼마다제공되는고유의명령어를직접사용해야한다. 이들을통칭하여 OpenGL 보조라이브러리 (AUX) 라고부르며운영체제별로다음과같은라이브러리가제공된다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 13
표 1-1 운영체제별라이브러리 운영체제유닉스 X 윈도우윈도우즈애플매킨토시 IBM OS/2 라이브러리 GLX WGL AGL PGL 플랫폼마다특성이다르므로 AUX도완전히다를수밖에없다. 그래픽프로그래머가개별운영체제의 GUI를직접다루어야하며플랫폼별로프로그램을따로만들어야하는불편함이있다. 예를들어윈도우즈환경에서 OpenGL을사용한다면 WGL 라이브러리도구사할수있어야하며 Win32의구조도대충이나마알아야한다. 껍데기없이그래픽코드만으로프로그램을만들수는없으므로실무에서는어쩔수없는일이다. 그러나학습을하는입장에서는그래픽외의코드까지공부하는것이너무귀찮고시간도많이걸린다. 하지만최소한출력해볼창은만들어야뭔가를그려볼수있으므로그래픽이론보다는창을만드는것을먼저배워야한다. 다행히이런불편함을해소해주는통합보조라이브러리가있다. SGI의직원인마크킬가드 (Mark Kilgard) 아저씨가이런목적으로 GLUT 라이브러리를제작하여배포한다. GLUT은운영체제를추상화함으로써동일한예제를다양한운영체제에서실행할수있도록한다. 운영체제의내부를잘몰라도몇줄의코드만으로그래픽입출력환경을쉽게구현할수있으며하나의소스로여러운영체제에서실행해볼수있다. 그래서학습용으로는 GLUT이최적의해결책이다. 환경설정에대한부분은 GLUT에게맡기고그래픽관련코드만작성하면된다. 그러나 GLUT은개별운영체제의고유한기능을활용하지못하고공통적인부분만추상화하므로섬세함은떨어질수밖에없다. 극히기본적인기능만제공할뿐이므로실제프로젝트를할때는운영체제에맞는 AUX를사용해야한다. GLUT는 OpenGL의일부가아니므로운영체제에포함되어있지않다. 그래서다운로드받아설치해야한다. GLUT는 OpenGL의홈페이지에서쉽게구할수있다. 다음사이트를방문해보자. http://www.opengl.org 이사이트에서 OpenGL 의각종스펙문서와예제, 레퍼런스등이제공되며관련툴들도배포한다. 메뉴바의 오른쪽에는크로노스그룹의링크도마련되어있다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 14
그림 1-2 OpenGL 홈페이지화면 상단메뉴의 Coding Resources/GLUT & Utility Libraries 로들어간다. 첫번째항목인 About GLUT 을선택하면아 래쪽에다운로드링크가있다. 자신의환경에맞는링크를선택하되 Win32 for Intel 이대부분일것이다. 그림 1-3 OpenGL 다운로드링크 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 15
그림 1.3 OpenGL 다운링크 소스도공개되어있으므로관심있는사람은분석해보도록하자. 다운로드받은압축파일에는다음 5 개의파 일이포함되어있다. 그림 1-4 OpenGL 라이브러리압축파일 각파일들을해당폴더로복사하면 GLUT 설치가완료된다. DLL 파일은운영체제의 System32 폴더로복사하고 헤더파일과임포트라이브러리 (*.lib) 는컴파일러의해당폴더로복사한다. 복사위치는컴파일러버전에따라다 른데 VS 2010 버전의경우다음경로에복사한다. C:\Program Files\Microsoft SDKs\Windows\v7.0A glut 관련자료는 opengl.org 의 Documentation/Specification/GLUT 에있다. 웹에서 HTML 로바로볼수도있고 pdf 로다운로드하여인쇄해볼수도있는데필요한함수만그때그때찾아보는것이좋다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 16
2. 프로젝트개요 2.1. 콘솔프로젝트 첫번째 OpenGL 예제를만들어보자. 첫예제이므로 EHSI 프로젝트중하나인비행기하나만그려보기로한 다. 개발절차를실습해보는것이주된목적이므로소스내용은아직몰라도상관없다. 비주얼스튜디오 2010 을 실행하고다음실습을진행한다. 메뉴에서파일 / 새로만들기 / 프로젝트항목을선택한다. 그림 2-1 Visual C++ 새프로젝트설정 Win32 콘솔응용프로그램을선택하고프로젝트이름은 ConsoleOpenGL 로입력한다. 적당한실습폴더를선 택하되이강좌는 C:\OpenGLExam 폴더에저장했다. 확인버튼을누르면마법사가나타나며응용프로그램종 류가콘솔로이미선택되어있다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 17
그림 2-2 Visual C++ 응용프로그램설정 다른옵션은건드릴필요없고추가옵션에서빈프로젝트체크박스를선택한다. 미리제공되는템플릿을사용하는것도가능은하다. 그러나크로스플랫폼을고려해야하므로미리컴파일된헤더니리소스니하는것들은배제하는것이좋다. 마법사가만들어주는프레임워크는실무프로젝트시에상당히편리하지만이렇게만들면비주얼스튜디오전용의예제가되어버린다. 소스차원의이식성확보를위해가급적이면순수한 C 코드로작성하는것이유리하다. 프로젝트껍데기만만든후프로젝트 / 새항목추가를선택하여소스파일을만든다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 18
그림 2-3 Visual C++ 새항목추가화면 아무내용도없는빈소스파일이프로젝트에추가된다. 이파일에다음과같이입력한다. OpenGL 의 Hello World 버전이라고할수있는데계기판의항공기를 Display 하도록작성했다. ConsoleOpenGL #include <gl/glut.h> void EHSI() glclear(gl_color_buffer_bit); glenable(gl_line_smooth); glcolor3f(1.0f, 1.0f, 0.0f); glbegin(gl_line_strip); glvertex2f(0,30); glvertex2f(6,12); glvertex2f(15,7); glvertex2f(15,4); glvertex2f(9,2); glvertex2f(8,-1); glvertex2f(25,-12); glvertex2f(25,-18); glvertex2f(12,-22); glvertex2f(12,-25); glvertex2f(8,-27); glvertex2f(6,-30); glvertex2f(2,-30); glvertex2f(1,-27); glvertex2f(-1,-27); glvertex2f(-2,-30); glvertex2f(-6,-30); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 19
glvertex2f(-8,-27); glvertex2f(-12,-25); glvertex2f(-12,-22); glvertex2f(-25,-18); glvertex2f(-25,-12); glvertex2f(-8,-1); glvertex2f(-9,2); glvertex2f(-15,4); glvertex2f(-15,7); glvertex2f(-6,12); glvertex2f(0,30); glend(); glflush(); void DoDisplay() glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glenable(gl_map1_vertex_3); glenable(gl_blend); glpushmatrix(); glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); EHSI(); glpopmatrix(); void main() glutinitwindowposition (100, 200); glutinitwindowsize(576, 576); glutcreatewindow("mfd_hsi"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 2-1 ConsoleOpenGL OpenGL 을사용하려면주요헤더파일인 gl.h 와 glu.h 도포함시키는것이원칙적이나이예제는 glut.h 하나만 포함시켰다. glut 헤더파일을열어보면다음과같은구문이있기때문이다. 알아서필요한파일을포함시켜주 므로이헤더파일하나만포함하면된다. #include <GL/gl.h> #include <GL/glu.h> 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 20
외부라이브러리를사용하려면임포트라이브러리도연결해야한다. 프로젝트옵션의설정페이지에서 opengl32.lib, glu32.lib, glut32.lib 를링크해야하는데 glut.h 에다음구문이작성되어있으므로그러지않아도상 관없다. #pragma comment (lib, "opengl32.lib") /* link with Microsoft OpenGL lib */ #pragma comment (lib, "glu32.lib") /* link with OpenGL Utility lib */ #pragma comment (lib, "glut32.lib") /* link with Win32 GLUT lib */ 이구문은비주얼 C++ 의확장문법이며헤더파일에서필요한설정을직접변경하므로아주편리하다. 결국 OpenGL 을사용하기위한준비는 glut.h 헤더파일하나만포함하면되는셈이다. 컴파일하여실행해보자. 콘솔 프로젝트이므로콘솔창이먼저뜨고별도의그래픽창이실행되어비행기를그릴것이다. 그림 2-4 ConsoleOpenGL 실행 뒤쪽의콘솔창은별하는일없이그냥실행된것이고삼각형이그려진윈도우가 OpenGL창이다. 삼각형을출력하기만할뿐아직별다른코드가없으므로입력에는전혀반응하지않는다. 창의크기를조정하면삼각형크기도비례적으로바뀐다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 21
2.2. 윈도우프로젝트 콘솔프로젝트도 Win32 응용프로그램이고 glut가그래픽창을생성해주므로실습에별문제는없다. 형태가단순해서소스양이적고 C 표준을준수하므로다른운영체제나컴파일러에서도수정없이컴파일된다. 한마디로이식성이뛰어나다. 그러나콘솔창이뜬후실행윈도우가뜬다는면에서보기좋지않고테스트후콘솔창도직접닫아야한다는면에서불편하다. 다음은윈도우버전의예제를작성해보자. 새프로젝트를만들되 Win32 프로젝트항목을선택하고프로젝트이름은 WinOpenGL로입력한다. 그림 2-5 Visual C++ Win32 프로젝트항목설정 마법사는응용프로그램종류옵션을 Windows 응용프로그램으로선택해준다. 콘솔프로젝트와마찬가지로아 래쪽의빈프로젝트옵션을선택한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 22
그림 2-6 Visual C++ Win32 응용프로그램옵션설정 WinOpenGL.cpp 파일을프로젝트에추가하고다음소스를작성한다. WinOpenGL #include <windows.h> #include <gl/glut.h> void EHSI() glclear(gl_color_buffer_bit); glenable(gl_line_smooth); glcolor3f(1.0f, 1.0f, 0.0f); glbegin(gl_line_strip); glvertex2f(0,30); glvertex2f(6,12); glvertex2f(15,7); glvertex2f(15,4); glvertex2f(9,2); glvertex2f(8,-1); glvertex2f(25,-12); glvertex2f(25,-18); glvertex2f(12,-22); glvertex2f(12,-25); glvertex2f(8,-27); glvertex2f(6,-30); glvertex2f(2,-30); glvertex2f(1,-27); glvertex2f(-1,-27); glvertex2f(-2,-30); glvertex2f(-6,-30); glvertex2f(-8,-27); glvertex2f(-12,-25); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 23
glvertex2f(-12,-22); glvertex2f(-25,-18); glvertex2f(-25,-12); glvertex2f(-8,-1); glvertex2f(-9,2); glvertex2f(-15,4); glvertex2f(-15,7); glvertex2f(-6,12); glvertex2f(0,30); glend(); glflush(); void DoDisplay() glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glenable(gl_map1_vertex_3); glenable(gl_blend); glpushmatrix(); glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); EHSI(); glpopmatrix(); int APIENTRY WinMain(HINSTANCE hinstance,hinstance hprevinstance,lpstr lpszcmdparam,int ncmdshow) glutinitwindowposition (100, 200); glutinitwindowsize(576, 576); glutcreatewindow("mfd_hsi"); glutdisplayfunc(dodisplay); glutmainloop(); return 0; 코드 2-2 WinOpenGL 콘솔프로젝트와소스내용은거의동일하다. 진입점이 main 에서 WinMain 으로바뀌었고 WinMain 의인수에사 용된타입들을위해 windows.h 를포함한정도만다르다. 실행해보자. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 24
그림 2-7 WinOpenGL 실행 실행결과는동일하되콘솔창이열리지않고바로 OpenGL 윈도우가열리므로훨씬더깔끔하고편리하다. 그러나 WinMain은윈도우즈운영체제에서만존재하는진입점이므로리눅스나매킨토시에서는이예제를실행해볼수없다는맹점이있다. 타환경에서는 WinMain을 main으로바꿔줘야만컴파일된다. 콘솔프로젝트가좀구닥다리이고창이두개나열려불편하지만이식성은훨씬더좋다. 사실두프로젝트형식은거의차이가없다. 이책에서는윈도우버전으로예제를만들기로한다. 왜냐하면대부분의사람들이윈도우즈환경에서실습을할것이고매실습마다창을두개씩이나열었다닫았다하는것이너무불편하기때문이다. 2~3개의예제를같이실행해놓고비교할때는창이 4개, 6개씩이나열리므로정신이엄청사납다. 실무프로젝트가아니라학습용이므로학습에효율적인쪽으로선택했다. 2.3. 목표프로젝트 뭔가를처음배울때는모든예제를직접만들어보는것이좋다. 눈으로훑어보는것과손가락으로직접입력해가면코드한줄한줄을읽는것은실습의깊이가확연하게다르다. 문제는시간이다. 그래서이강좌는모든예제를컴파일가능한프로젝트로제공한다. 컴파일러설치하고프로젝트열어서직접컴파일해볼수도있고의심가는부분은마음내키는데로뜯어볼수도있다. 그러나이또한시간이많이걸리는일이다. 그래서재컴파일하지않고도모든예제를가급적이면신속하게살펴볼수있도록예제를작성했다. OpenGL의예제들은대부분그리기코드가주이므로달라지는부분은 Display 출력함수의코드뿐이다. 프로젝트의골격은거의비슷하며무엇을어떻게그리는가만달라질뿐이다. 그래서예제를너무많이만들지않고한한국폴리텍대학항공캠퍼스항공제어시스템과페이지 25
예제에비슷비슷한코드를통합적으로작성해두었다. 각각의코드를주석으로묶어두는방법도흔히사용되지만그러자면주석편집후재컴파일이라는번거로운과정을거쳐야한다. 다음절에서만들어볼 MFD_EHSI 예제의전체소스는다음과같이작성되어배포된다. 세개의코드가한예제에작성되어있는셈이다. #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" #include "NaviSymbol.h" void CrossLine(); void CrossLineE(); void PitchLadder(int xpitch, int xroll); void neddlebar(int xpitch, int xroll); void SkyLand(int xpitch, int xroll); void Rollscale(); void aircraft(); void modechange(); void HNum(int num); void FPM(float x, float y); void Air(float Airy); void Alt(float Alty); void EnBox(); void HNumDraw(float Alty,float Airy, int Hsrx); void HSR(int Hsrx); void MyTimer(int Value); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////... //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void main() point[hud].startxp=0; point[hud].startyp=0; point[hud].endxp=576; point[hud].endyp=576; point[hud].type=hud; point[hud].size=large; point[hud].position=left; point[adi].startxp=576; point[adi].startyp=0; point[adi].endxp=288; point[adi].endyp=288; point[adi].type=adi; point[adi].size=small; point[adi].position=down; point[hsi].startxp=576; point[hsi].startyp=288; point[hsi].endxp=288; point[hsi].endyp=288; point[hsi].type=hsi; point[hsi].size=small; point[hsi].position=up; point[hsd].startxp=864; point[hsd].startyp=0; point[hsd].endxp=576; point[hsd].endyp=576; point[hsd].type=hsd; point[hsd].size=large; point[hsd].position=right; set=0; 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 26
glutinitdisplaymode(glut_double GLUT_RGBA); glutinitwindowposition (100, 200); glutinitwindowsize(1440, 576); glutcreatewindow("mfd"); glutdisplayfunc(display); glutmousefunc(mymouseclick); glutmotionfunc(mymouseover); gluttimerfunc(1, Timer, 1); glutmainloop(); 코드 2-3 항공기계기판코드 MFD 프로젝트는아래와같이 Display 된다. 아래의 Display 는항공기의전자식계기판이다. 항공기전자식계기 판은주로 HUD, ADI, HIS, HSD 등으로구성이되고, 아래에주요기능에대해설명을하였다. 그림 2-8 OpenGL 으로설계된항공기계기판실행 2.3.1. 전방향시현기 (Head-up Display) 영국의 BAE 가개발한사방 25 시야각을지닌 HUD 는조종사로하여금전방캐노피바깥의실제상황을보면서 동시에각종정보를한눈에식별할수있도록한다. HUD 에는항공기조종에필수적인고도, 속도, 자세등항법 정보와무장모드에따른표적조준을위한심볼및정보를표시한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 27
2.3.2. 전자식비행계기 (EFI) 전자식비행계기 (EFI : Electronic Flight Instrument) 는전자시현방식의계기로써 EADI(Electronic Attitude Director Indicator : 전자식자세방향지시계 ), EHSI(Electronic Horizontal Situation Indicator : 전자식수평자세지시계 ), EAI(Electronic Altitude Indicator : 전자식고도계 ), EMASI(Electronic Mach Airspeed Indicator : 전자식속도계 ) 로구성되어있다. EADI, EHSI, EAI, EMASI 는각각독립적으로시현된다. 각계기들의전자시현정보및모드는아래와같다. 1) EADI (Electronic Attitude Director Indicator) 전자식자세방향지시계항공기의상승각 후퇴각 회전각등전후좌우의수평상태를알려주는계기로, 항공기의핵심계기이다. 서브모드 (Sub-Mode) 로는 NAV(Navigation), ILS(Instrument Landing System) 모드등이있다. 2) EHSI (Electronic Horizontal Situation Indicator) 전자식수평자세지시계조종사가방향을찾는비행에서수행해야할적절한변화를보여주는전기적비행과항법계기이다. 서브모드로 (Sub-Mode) 는 NAV(Navigation), TCN(Tacan), VOR(VHF omnidirectional radio range) 모드등이있다. 3) EAI (Electronic Altitude Indicator) 전자식고도계항공기고도정보를보여주는계기이다. 서브모드 (Sub-Mode) 로는 ALT 모드등이있다. main() 문에는 HUD, ADI, HSI, HSD 가포함되어있다. 이 HUD, ADI, HIS, HSD 를구현하기위한주요세부함수들 은 main() 문윗부분에정의되어있다. 그외함수들은 *.h 파일과 *.c 파일에정의되어있다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 28
3. OpenGL 의기초 3.1. 기본타입 OpenGL 자체는 C 언어로제작되었지만함수수준의라이브러리이므로특정언어에종속되지는않는다. 그래 서타입도독립적으로정의하여사용한다. 비록 C 언어의타입과거의유사하지만차후 C 언어의타입이달라질 수도있고플랫폼에따라약간씩차이도있으므로영향을최소화하기위해고유의타입을정의해두었다. 표 3-1 타입정의 OpenGL 타입 C 타입 접두어 GLbyte signed char b GLshort short s GLint, GLsizei int, long i GLfloat, GLclampf float f GLdouble, GLclampd double d GLubyte, GLboolean unsigned char ub GLushort unsigned short us GLuint, GLenum, GLbitfield unsigned long ui 대부분은 C타입에대한별명으로정의되어있어 C 언어에익숙한사람은이타입들에대해서도쉽게익숙해질것이다. C 타입명앞에 GL 접두어를붙인정도에불과하다. 그러나상식과다른부분이있으므로몇가지주의사항을잘알아두어야한다. 정수형인 GLint는 32비트의정수로정의되어있으며길이가고정적이다. C 언어에서 int는운영체제에따라달라지는가변타입이지만 OpenGL의 GLint는항상 32비트이다. GLsizei는 GLint와같은타입이지만크기값을나타내는값에주로사용된다. 이런식으로같은타입에대해서도용도에따라별칭이정의되어있다. 진위형을나타내는 GLboolean은부호없는 1바이트정수로정의되어있다. C 언어는 4바이트의 BOOLEAN 열거형을정의하고진위형상수로 TRUE, FALSE를사용하는데크기가다르지만같은정수형이므로이타입과호환된다. TRUE, FALSE를사용할수도있고 GL_TRUE, GL_FALSE를사용할수도있되둘다정의는동일하다. 그러나 C++ 의 bool 타입과는호환성이좋지않으므로섞어서사용하지않는것이좋다. 에러는나지않지만경고가발생하며 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 29
잠재적인문제가될수도있다. 실수타입인 GLclampf, GLclampd의 clamp라는단어의의미는값의범위가 0.0 ~ 1.0 사이로제한된다는뜻이다. 색상의강도나텍스처의좌표처럼범위가명확한값을지정할때이타입을흔히사용한다. 타입명에 clamp가들어있으면유효한값은 0 ~ 1 사이임을바로알수있다. 3.2. OpenGL 의함수형식 OpenGL 함수들은일반함수와구분하기위해예외없이접두어가붙는다. gl 라이브러리의함수는 gl 접두어로시작하고 glu의라이브러리는 glu로시작한다. 마찬가지로 glut 소속의함수는 glut 접두가붙는다. 접두만으로도 OpenGL 함수임을쉽게알수있다. OpenGL은 C 수준의함수들로구성되어있으므로객체지향과는거리가멀다. 그래서함수오버로딩 (Overloading) 을지원하지않으며인수의개수와타입이다른동명함수를작성할수없다. 동일한동작을하되인수목록이다르면함수의이름도매번달라져야한다. 대표적인예로정점의좌표를정의하는 glvertex 함수를보자. 그림 3-1 OpenGL 함수명명법 이함수는 GL 라이브러리소속이므로접두로 gl이붙으며정점을정의하므로함수의이름은 Vertex이다. 함수명뒤에는인수의개수와타입을명시하는접미어가각각 3종류, 4종류가붙는다. 3차원상의좌표는 x, y, z 세가지값으로표현하는것이원칙적이되분수표현을위해 w로분모를지정할수있다. 또평면상의정점인경우는 z 좌표를생략하고 x, y만밝힐수도있다. w가생략되면 1로간주되며 z를생략하면 0으로간주한다. 인수의개수는 2개, 3개, 4개세가지종류가있다. 각인수의타입은 GLshort, GLint, GLfloat, GLdouble 4가지타입으로전달가능하다. 보통은실수값인 GLfloat를많이사용하지만소수부가필요없다면 GLint 타입을사용할수도있고더높은정밀도가요구되면 GLdouble 타한국폴리텍대학항공캠퍼스항공제어시스템과페이지 30
입을쓸수도있다. 평면상에삼각형을그리는첫예제에서는 2개의실수로좌표를지정했으므로 glvertex2f 함수를호출했다. 이함수명은 GL 라이브러리에속한 Vertex 함수이며인수는 2개이고인수타입은 GLfloat를취한다는뜻이다. 또좌표를구성하는값들을개별인수로전달하는대신배열로전달할수도있다. 이때는함수명제일뒤에배열 (Vector) 을의미하는 v 접두어가추가로붙는다. 다음두호출문은동일하다. 세개의정수를 glvertex3i 함수의인수목록에나열할수도있고세정수를가지는배열을정의한후 glvertex3iv 함수로배열을전달할수도있다. 전달방식만다를뿐결국지정하는좌표는동일하다. glvertex3i(1,2,3); int arv[]=1,2,3]; glvertex3iv(arv); 개수, 타입, 배열여부의모든조합을취하면 glvertex 함수만해도 3 * 4 * 2 = 24 개의함수그룹이정의된다. 24 개나되는함수의원형을일일이밝힐수는없으며또한그럴필요도없다. 그래서다음과같이간략하게표기한 다. glvertex[2,3,4][s,i,f,d][v](x,y,z,w) [ ] 괄호안의문자들은선택적이라는뜻이다. 인수의타입도함수명에따라가변적으로달라지므로인수목록에는이름만밝히고타입은적지않는다. 또인수의개수도함수에따라달라지므로최대개수의인수목록을적어놓았다. 함수를칭할때는접미를제외하고통칭하여함수의이름만밝히는것이보통이다. glvertex 뿐만아니라다른함수들도마찬가지이다. 특정함수명을인터넷으로검색할때도접미는빼고검색하는것이바람직하다. OpenGL이오버로딩을지원하지않는이유는객체지향기법이일반화되기전에작성했기때문이다. 그러나속도최적화를위해객체지향을선택하지않은면도있다. 원론적으로객체지향의 C++ 은절차적인 C언어보다작고빠를수없기때문이다. 최적의속도를요하는그래픽라이브러리로서합당한선택이기는하지만함수명에대한오버로딩미지원은살짝쿵아쉬운부분이다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 31
3.3. 색상변경 이제예제를조금씩변경해보면서 OpenGL 함수를하나둘씩익혀보자. 윈도우의배경색상이칙칙한검정색으 로되어있는데디폴트가검정색이기때문이다. 다음함수로배경색을바꿔보자. void glclearcolor(glclampf red, GLclampf green, GLclampf blue, GLclampf alpha); 4개의인수는 RGBA 각색상요소의강도를지정한다. 각요소의강도는 0 ~ 1 사이의실수값이며 0이면해당요소가하나도없는것이고 1이면최대밝기이다. 타입명에 clamp가들어간인수는모두 0 ~ 1 사이의범위를가진다. (1,1,1,1) 은모든요소가최대밝기이므로흰색이고 (0,0,0,0) 은검정색이다. 투명도를지정하는알파값은블랜딩등에활용되는데당장은사용되지않는다. 이함수는이후부터배경으로사용할색상을지정하기만할뿐실제배경을지우지는않는다. 배경을실제로지울때는다음함수를호출한다. void glclear(glbitfield mask); 인수로어떤버퍼를지울것인가를지정한다. OR 연산자로연결하여두개이상의버퍼를한꺼번에지울수도 있다. 버퍼를지우는것은대단히대용량의쓰기동작이라시간이오래걸린다. 두개이상의버퍼를지울때는 가급적이면 OR 연산자로한꺼번에지우는것이속도상유리하다. 표 3-2 BUFFER 삭제인수 버퍼 설명 GL_COLOR_BUFFER_BIT 색상버퍼를지운다. GL_DEPTH_BUFFER_BIT 깊이버퍼를지운다. GL_STENCIL_BUFFER_BIT 스텐실버퍼를비운다. GL_ACCUM_BUFFER_BIT 누적버퍼를비운다. 그래픽정보들은여러버퍼에나누어저장된다. 색상버퍼는이미지의색상값이저장되는버퍼이며여기에있는정보들이모니터에출력된다. 우리가흔히비디오램이라고부르는영역이며픽셀버퍼, 래스터버퍼라고도부른다. 픽셀버퍼라는말은화소의정보가저장되었다는뜻인데각화소는색상의조합으로구성되므로색상버퍼라한국폴리텍대학항공캠퍼스항공제어시스템과페이지 32
고도부르는것이다. glclearcolor로지정해놓은색으로색상버퍼를가득채우면이것이곧화면을지우는것이된다. 나머지버퍼들은좀더복잡한정보를저장하는데현재단계에서는설명하기어려우므로차후따로연구해보기로하자. DoDisplay에서뭔가를출력할때는이전영상을제거하기위해 glclear로화면을먼저지워야하며그래서항상 glclear문이선두에온다. 다음예제는배경색을빨간색으로변경한다. ChangeState void DoDisplay() glclearcolor(1.0, 0.0, 0.0, 1.0); glclear(gl_color_buffer_bit); glbegin(gl_triangle_strip); glvertex2f(0,30); glvertex2f(6,12); glvertex2f(0,0); glvertex2f(15,7); glvertex2f(15,4); glvertex2f(0,0); glvertex2f(9,2); glvertex2f(8,-1); glvertex2f(0,0); glvertex2f(25,-12); glvertex2f(25,-18); glvertex2f(0,0); glvertex2f(12,-22); glvertex2f(12,-25); glvertex2f(0,0); glvertex2f(8,-27); glvertex2f(6,-30); glvertex2f(0,0); glvertex2f(2,-30); glvertex2f(1,-27); glvertex2f(0,0); glvertex2f(-1,-27); glvertex2f(-2,-30); glvertex2f(0,0); glvertex2f(-6,-30); glvertex2f(-8,-27); glvertex2f(0,0); glvertex2f(-12,-25); glvertex2f(-12,-22); glvertex2f(0,0); glvertex2f(-25,-18); glvertex2f(-25,-12); glvertex2f(0,0); glvertex2f(-8,-1); glvertex2f(-9,2); glvertex2f(0,0); glvertex2f(-15,4); glvertex2f(-15,7); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 33
glvertex2f(0,0); glvertex2f(-6,12); glvertex2f(0,30); glvertex2f(0,0); glend(); glflush(); 코드 3-1 ChangeState glclear 를호출하기전에 glclearcolor 를호출하여배경색상을빨간색으로바꾸어두었다. R 요소만최대치이고 나머지는 0 이므로빨간색이며삼각형뒤쪽의배경이빨간색으로바뀔것이다. 그림 3-2 ChangeState 실행 배경색상은한번지정해놓으면다른값으로바꾸지않는한은계속유지된다. 그래서매번그리기를할때마다 지정할필요없이프로그램초기화시에별도의함수에서따로설정하는것이원칙적이다. 구조상으로는다음코드 가더바람직하다. ChangeState int APIENTRY WinMain(HINSTANCE hinstance,hinstance hprevinstance,lpstr lpszcmdparam,int ncmdshow) glutcreatewindow("opengl"); glutdisplayfunc(dodisplay); DoInit(); glutmainloop(); return 0; 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 34
void DoInit() glclearcolor(1.0, 0.0, 0.0, 1.0); void DoDisplay() glclear(gl_color_buffer_bit); glbegin(gl_triangle_strip); glvertex2f(0,30); glvertex2f(6,12); glvertex2f(0,0); glvertex2f(15,7); glvertex2f(15,4); glvertex2f(0,0); glvertex2f(9,2); glvertex2f(8,-1); glvertex2f(0,0); glvertex2f(25,-12); glvertex2f(25,-18); glvertex2f(0,0); glvertex2f(12,-22); glvertex2f(12,-25); glvertex2f(0,0); glvertex2f(8,-27); glvertex2f(6,-30); glvertex2f(0,0); glvertex2f(2,-30); glvertex2f(1,-27); glvertex2f(0,0); glvertex2f(-1,-27); glvertex2f(-2,-30); glvertex2f(0,0); glvertex2f(-6,-30); glvertex2f(-8,-27); glvertex2f(0,0); glvertex2f(-12,-25); glvertex2f(-12,-22); glvertex2f(0,0); glvertex2f(-25,-18); glvertex2f(-25,-12); glvertex2f(0,0); glvertex2f(-8,-1); glvertex2f(-9,2); glvertex2f(0,0); glvertex2f(-15,4); glvertex2f(-15,7); glvertex2f(0,0); glvertex2f(-6,12); glvertex2f(0,30); glvertex2f(0,0); glend(); glflush(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 35
코드 3-2 ChangeState 초기화만하는 DoInit 함수를따로만들고메인에서메시지루프에들어가기전에한번만초기화한다. 결과는같지만 DoDisplay는윈도우크기가바뀌거나출력내용이바뀔때마다자주호출되므로초기화시점으로는적당하지않다. 불필요하게같은배경색을매번지정할필요는없는것이다. 이예제처럼하는것이원칙이다. 그러나함수를따로만들어야된다는면에서너무번거롭고코드를볼때도두함수를같이봐야하므로정신사납다. 그래서그냥 DoDisplay 선두에서초기화하는형식으로예제를작성했으며앞으로도그럴것이다. 가급적한함수내에코드를집중시켜위에서아래로코드를읽음으로써효과를살펴볼수있도록했다. 이번에는배경색이아닌삼각형의색상을바꾸어보자. 도형의색상은다음함수로지정한다. 정확하게는도형의색상이아닌정점의색상을변경하는데정점의색상이결과적으로도형의색상이된다. glcolor[3,4][b,s,i,f,d,ub,us,ui][v](red, green, blue, alpha) 세가지색상요소의강도를실수로지정하는 glcolor3f 가가장일반적이다. 0 ~ 255 까지의정수로강도를지정할 때는 glcolor3ub 함수도종종사용되는데윈도우즈나웹환경의색상포맷과동일해서친숙하다. 다음은빨간색 비행기를그린다. void DoDisplay() glclear(gl_color_buffer_bit); glcolor3f(1.0, 0.0, 0.0); glbegin(gl_triangle_strip); glvertex2f(0,30); glvertex2f(6,12); glvertex2f(0,0); glvertex2f(15,7); glvertex2f(15,4); glvertex2f(0,0); glvertex2f(9,2); glvertex2f(8,-1); glvertex2f(0,0); glvertex2f(25,-12); glvertex2f(25,-18); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 36
glvertex2f(0,0); glvertex2f(12,-22); glvertex2f(12,-25); glvertex2f(0,0); glvertex2f(8,-27); glvertex2f(6,-30); glvertex2f(0,0); glvertex2f(2,-30); glvertex2f(1,-27); glvertex2f(0,0); glvertex2f(-1,-27); glvertex2f(-2,-30); glvertex2f(0,0); glvertex2f(-6,-30); glvertex2f(-8,-27); glvertex2f(0,0); glvertex2f(-12,-25); glvertex2f(-12,-22); glvertex2f(0,0); glvertex2f(-25,-18); glvertex2f(-25,-12); glvertex2f(0,0); glvertex2f(-8,-1); glvertex2f(-9,2); glvertex2f(0,0); glvertex2f(-15,4); glvertex2f(-15,7); glvertex2f(0,0); glvertex2f(-6,12); glvertex2f(0,30); glvertex2f(0,0); glend(); glflush(); 코드 3-3 ChangeState 비행기를그리기전에정점의색을빨간색으로지정했으므로모든정점은빨간색으로찍히며이정점들로구성 된비행기내부도빨간색으로채색된다. glcolor3ub(255, 0, 0); 로지정해도결과는동일하다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 37
그림 3-3 ChangeState 실행 3.4. 상태머신 그래픽출력에는좌표뿐만아니라아주많은요소들이개입된다. 색상, 굵기, 모양, 조명, 각종모드등등여러가지정보들이필요하다. 그리기함수들은도형출력을위해이모든정보들을참조하지만그렇다고해서이정보들을모두함수의인수로전달할수는없다. 그렇게하다가는인수목록이한없이길어질것이며잘바뀌지도않는값을매번전달하는것도낭비이다. 그래서 OpenGL은그리기에필요한여러가지정보들을상태머신 (State Machine) 에저장한다. 상태머신이란상태를저장하는장소이며그리기에영향을미치는여러변수값들이집합이다. 앞항에서실습해본배경색상은 GL_COLOR_CLEAR_VALUE 상태변수에저장되며현재정점의색상은 GL_CURRENT_COLOR 상태변수에저장된다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 38
그림 3-4 상태머신개념 모든그리기함수들은인수로전달받은것외의정보들에대해서는상태변수값을읽어사용한다. 상태변수들은적당한디폴트로초기화되어있는데예를들어배경색은검정색이고정점의색은흰색이다. 디폴트를바꾸고싶으면변경함수로언제든지다른값으로바꿀수있다. 배경색을바꾸고싶으면 glclearcolor 함수를호출하고정점의색상은 glcolor 함수로바꾼다. 상태머신은전역적이며영속적인저장소이므로한번지정해놓은상태변수는다른값으로바꾸기전에는계속유효하다. 그래서같은값이라면이전값을계속사용할수있으며매번새로지정할필요가없다. 다음예제로테스트해보자. void DoDisplay() glclear(gl_color_buffer_bit); glbegin(gl_triangle_strip); glvertex2f(0,30); glcolor3f(0.0, 1.0, 0.0); glvertex2f(6,12); glvertex2f(0,0); glvertex2f(15,7); glvertex2f(15,4); glcolor3f(1.0, 0.0, 0.0); glvertex2f(0,0); glvertex2f(9,2); glvertex2f(8,-1); glvertex2f(0,0); glcolor3f(0.0, 1.0, 0.0); glvertex2f(25,-12); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 39
glvertex2f(25,-18); glvertex2f(0,0); glvertex2f(12,-22); glcolor3f(0.0, 0.0, 1.0); glvertex2f(12,-25); glvertex2f(0,0); glvertex2f(8,-27); glvertex2f(6,-30); glcolor3f(0.0, 1.0, 0.0); glvertex2f(0,0); glvertex2f(2,-30); glvertex2f(1,-27); glvertex2f(0,0); glcolor3f(1.0, 0.0, 0.0); glvertex2f(-1,-27); glvertex2f(-2,-30); glvertex2f(0,0); glvertex2f(-6,-30); glcolor3f(0.0, 1.0, 0.0); glvertex2f(-8,-27); glvertex2f(0,0); glvertex2f(-12,-25); glvertex2f(-12,-22); glcolor3f(0.0, 0.0, 1.0); glvertex2f(0,0); glvertex2f(-25,-18); glvertex2f(-25,-12); glvertex2f(0,0); glvertex2f(-8,-1); glcolor3f(0.0, 1.0, 0.0); glvertex2f(-9,2); glvertex2f(0,0); glvertex2f(-15,4); glvertex2f(-15,7); glcolor3f(1.0, 0.0, 0.0); glvertex2f(0,0); glvertex2f(-6,12); glvertex2f(0,30); glvertex2f(0,0); glend(); glflush(); 코드 3-4 상태머신예제 윗쪽꼭지점부터반시계방향으로돌며다섯개의정점을지정하여오각형을그렸다. 각정점마다다양한색을지 정했는데정점의색상이제각각이면다각형내부는각정점의거리에따라색상을부드럽게섞어서그린다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 40
그림 3-5 상태머신실행 첫번째정점은흰색인데디폴트가흰색이므로굳이흰색으로지정할필요가없다. 코드에서주석처리한 glcolor 호출문은있으나마나한호출문이다. 두번째정점은빨간색으로바꾼후그렸으므로빨간색이다. 이후부터정점의색은계속빨간색이유지되며별지정없이출력한세번째정점은역시빨간색이다. 이경우도정점을그리기전에빨간색으로바꿀필요가없다. 마지막두정점은각각초록색, 파란색으로출력했으며이전색상과다르므로이때는 glcolor 호출문이필요하다. 색상뿐만아니라상태머신에저장되어있는모든값이이런식으로관리된다. 상태값은전역적이므로함수내부에서뿐만아니라외부에서바꾼값에도영향을받으며어디서바꾸었건한번설정한값은다른값으로덮어쓰기전에는계속유효하다. 상태머신에는색상처럼복잡한정보도있지만특정기능을사용할것인가아닌가를지정하는단순한진위형옵션들도많이있다. on/off 두가지값을가지는상태는다음함수로설정, 해제, 조사한다. void glenable(glenum cap); void gldisable(glenum cap); GLboolean glisenabled(glenum cap); 설정값은열거형으로지정하는데수십가지의값이있다. 예를들어 GL_FOG 는안개효과이며 GL_LIGHTING 은 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 41
조명효과이다. 해당기능을쓰고싶으면 glenable 로활성화하고그만쓰고싶으면 gldisable 로취소하면된다. 각기능에대해서는해당주제를다룰때다시소개할것이다. 진위형이아닌상태값은다음함수들로조사한다. void glgetintegerv(glenum pname, GLint * params); void glgetfloatv(glenum pname, GLfloat * params); void glgetdoublev(glenum pname, GLdouble * params); void glgetbooleanv(glenum pname, GLboolean * params); 첫번째인수는알고싶은상태변수값이며두번째인수는상태값을리턴받을배열이다. 상태변수에따라필요 한배열의크기는달라진다. 예를들어현재설정된색상값을알고싶다면다음과같이호출한다. 색상은 4 개의 실수로구성되므로배열크기도 4 로준비해야한다. GLfloat arcolor[4]; glgetfloatv(gl_current_color, arcolor); 원하는상태대로출력하려면상태변수부터먼저설정해야한다. 이것저것많은상태를바꾸다보면이전상태 로돌아가기어려워지는데이때는현재상태의일부를스택에저장해놓았다가복구한다. 다음함수는상태값중 원하는부분을스택에넣고뺀다. void glpushattrib(glbitfield mask); void glpopattrib(void); 저장대상이되는상태값은그룹별로비트마스크로정의되어있다. 그룹별로다음과같은정보들이저장되는데 일부만보이므로정확한목록은레퍼런스를참조하기바란다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 42
표 3-3 마스크인자 마스크 설명 GL_COLOR_BUFFER_BIT GL_CURRENT_BIT GL_DEPTH_BUFFER_BIT GL_ENABLE_BIT GL_FOG_BIT GL_HINT_BIT GL_LIGHTING_BIT GL_BLEND, GL_DITHER 현재색상, 현재법선, GL_EDGE_FLAG GL_DEPTH_TEST GL_COLOR_MATERIAL, GL_DEPTH_TEST, GL_CULL_FACE GL_FOG, 안개색상, 밀도, 시작점, 끝점 GL_POINT_SMOOTH_HINT, GL_LINE_SMOOTH_HINT GL_LIGHTING 복잡한출력을하려면상태를자주바꿔야하는데이전상태값으로그대로돌아오려면스택에저장해놓는것 이편리하다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 43
4. GLUT 개요 4.1. GLUT 문자기반의콘솔창에화려한그래픽을그릴수는없으므로 3차원이든 2차원이든그래픽을출력하려면윈도우가필요하다. 그러나 OpenGL은윈도우시스템과의독립성확보를위해윈도우관리에대해서는어떠한기능도제공하지않는다. 그래픽코드를윈도우시스템과완전히분리해야플랫폼독립성을확보할수있기때문이다. OpenGL의의도된빈틈을메워주는것이각운영체제별로제공되는 AUX 라이브러리이다. 그러나 AUX는거의운영체제전반의지식을요구하므로처음학습용으로는부적합하다. OpenGL 예제를만들기위해 X 윈도우시스템의 Xlib이나 Motif, 매킨토시의 GUI를먼저배워야한다면정말맥빠질것이다. AUX는기능은섬세하지만운영체제마다판이하게틀려호환성에도불리하다. Win32 API로멋진프로그램을만들어봤자그프로그램은윈도우즈에서만실행될뿐이다. 이런단점을일거에해소해주는것이바로 GLUT이다. GLUT의고수준인터페이스는기반운영체제들을완벽하게추상화하여플랫폼독립성을제공한다. GLUT이제공하는기능은그래픽과는거의상관없는기능들이며쉽게말해서그래픽을그리기위한껍데기를만들어주는것이다. 그러나이걸대충이라도알아야창을만들어간단한삼각형쪼가리라도뿌려보고입력을받아출력에변화를줄수있다. 그래서 OpenGL 학습을위해 GLUT을우선적으로연구해봐야하는것이다. 어디까지나학습을위한도구일뿐이므로너무상세하게연구할필요는없다. 어차피상용프로그램을만들어야한다면 GLUT으로는한계가있어타겟플랫폼의 AUX를사용해야한다. 여기서는이후의강좌실습을위해필요한부분까지만학습해볼것이다. 주요함수들에대해간략하게소개만하고간단한예제로동작만확인해본다. void glutinit(int *argcp, char **argv); 이함수는 GLUT 라이브러리를초기화하고기반플랫폼의윈도우시스템과연결한다. 인수는 main 으로부터전달 받은 argc 의주소와 argv 의배열을전달하는데 argc 가내부에서변경될수도있으므로반드시참조로전달해야 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 44
한다. 명령행인수는윈도우시스템초기화방법에대한정보를제공하는데주로 X 윈도우를위한것들이며다른시스템에는해당되지않는다. glutinit 함수가하는가장중요한일은에러처리이다. 윈도우시스템과연결할수없다거나해당운영체제가그래픽인터페이스를제공하지않는다면에러메시지를출력하고프로그램을강제종료하는극단적인방어가주된임무이다. 우리가실습하고있는윈도우즈환경은확실한그래픽운영체제이고명령행인수를받지도않으므로 glutinit을굳이호출하지않아도상관없다. GLUT의가장중요한기능은그래픽을출력할수있는윈도우를생성하는것이다. 윈도우를생성하기전에윈도우의여러가지옵션들을먼저설정해야한다. 다음두함수는윈도우의위치나크기를지정한다. 윈도우를생성하기전에미리원하는크기와위치를전달해야한다. void glutinitwindowsize(int width, int height); void glutinitwindowposition(int x, int y); 인수로폭과높이그리고 (x, y) 좌표를전달한다. 윈도우의좌표는당연히화면좌상단을원점으로한다. 윈도우의크기는의미가약간다른데창의크기를지정하는것이아니라작업영역의크기를지정함을주의하자. 창의크기는작업영역크기에타이틀바와경계선이더해지므로지정한크기보다조금더크게생성된다. 예를들어크기를 100*100으로지정했다면윈도우의크기가 100*100인것이아니라윈도우안쪽의그래픽출력영역이 100*100이라는뜻이다. 당연히윈도우크기는이보다조금더크다. 왜이렇게되어있을까는조금만생각해보면짐작할수있는데윈도우시스템마다타이틀바두께가제각각이기때문이다. 중요한것은그래픽이출력될작업영역의크기이지윈도우자체의크기가아니다. 플랫폼에따른이런차이점들을잘추상화해주는것이 GLUT의주임무이다. 크기와위치를지정한다고해서운영체제가반드시이대로윈도우를생성한다고보장할수는없다. GLUT은단순히의도를밝힐뿐이며이부탁을들어줄것인가는순전히운영체제마음이다. 위치와크기를생략하면화면좌상단에 300*300 정도의적당한크기로윈도우를생성한다. 이디폴트크기는예제작성에아주적합하므로이강좌에서는이두함수를굳이호출하지않는다. 다음함수는디스플레이모드를설정한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 45
void glutinitdisplaymode(unsigned int mode); 디스플레이모드는그리기표면의주요특징들을결정한다. 윈도우를생성한후에는변경할수없으므로처음에잘결정해야한다. 여러개의모드를 OR 연산자로묶어서지정하되상호배타적인속성의플래그들은하나만지정해야한다. 예를들어싱글버퍼와더블버퍼는둘중하나를선택하는것이므로두플래그를같이쓸수는없다. 표 4-1 디스플레이모드 모드 설명 GLUT_RGBA, GLUT_RGB 트루컬러모드이다. 이값이디폴트이다. GLUT_INDEX 팔레트를사용하는인덱스모드이다. 몇가지기능에한계 가있어거의사용되지않는다. GLUT_SINGLE 싱글버퍼를사용한다. 이값이디폴트이다. GLUT_DOUBLE 더블버퍼를사용한다. GLUT_DEPTH 깊이버퍼를사용한다. GLUT_ACCUM 누적버퍼를사용한다. GLUT_ALPHA 색상에알파요소를사용한다. GLUT_STENCIL 스텐실버퍼를사용한다. GLUT_MULTISAMPLE 멀티샘플링을지원한다. 이기능을사용하려면클라이언트 와서버가모두지원해야한다. GLUT_STEREO 스테레오윈도우를생성한다. GLUT_LUMINANCE 루미넌스 (luminance) 색상모델을사용한다. 디스플레이모드의디폴트는트루컬러모드에싱글버퍼를사용하는것이다. 그리고깊어버퍼는디폴트로사용 하는것으로되어있다. 즉, 별다른지정이없으면다음과같이초기화하는것과동일하다. 디폴트대로사용하려 면이함수를굳이호출하지않아도상관없다. glutinitdisplaymode(glut_single GLUT_RGB GLUT_DEPTH); 물론더블버퍼링이필요하면원하는모드로변경해야한다. 윈도우의위치와크기, 디스플레이모드까지결정했 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 46
으면다음함수를호출하여윈도우를생성한다. 그래픽을출력하려면필수적으로호출해야하는함수이다. int glutcreatewindow(char *name); 윈도우는상단에제목을가지는데제목문자열을인수로지정한다. 단순한문자열이므로원하는대로지정하면된다. 윈도우를지칭하는유일한 ID가리턴되는데이 ID는차후윈도우를관리할때사용된다. 윈도우는탑레벨로생성되며곧바로보이고활성상태가된다. 그러나화면에실제로보이려면그리기메시지를최소한한번은처리해야한다. 다음함수는메시지루프를실행한다. void glutmainloop(void); 모든윈도우시스템은이벤트드리븐방식으로동작한다. 이함수는계속실행되면서사용자나시스템에의해발 생한메시지를받아메시지처리함수를호출하는중요한역할을한다. 메시지를처리하는콜백함수는메시지 루프로들어가기전에다음함수들로미리등록해두어야한다. void glutdisplayfunc(void (*func)(void)); void glutkeyboardfunc(void (*func)(unsigned char key, int x, int y)); void glutmousefunc(void (*func)(int button, int state, int x, int y)); void glutreshapefunc(void (*func)(int width, int height)); 화면을그릴때, 키보드입력을받았을때, 마우스입력을받았을때, 윈도우크기가변경되었을때호출할함수를등록하는것이다. 각콜백의원형은등록함수의인수목록에나타나있으므로이원형대로함수를생성하고함수명을등록함수의인수로전달하면된다. glutmainloop는끊임없이메시지큐를감시하며메시지가들어올때마다대응되는콜백함수를계속호출한다. 이미등록한콜백을해제할때는인수로 NULL을전달한다. 이외에도특수키, 마우스이동, 팝업메뉴선택등의이벤트를처리하는여러가지콜백들이있다. 관심있는이벤트에대해콜백을등록하되 OpenGL의주목적은그래픽을그리는것이므로그리기콜백은선택의여지없이반드시등록해야한다. 다음함수는윈도우의캡션문자열을변경한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 47
void glutsetwindowtitle(char *name); 캡션은윈도우의제목을보여주는역할을하지만실행중에변수값을찍어보고싶을때도아주유용하다. OpenGL은폰트출력이번거로와캡션외에는정보를실시간으로출력해볼만한장치가없다. 앞으로예제에서변수값확인을위해이함수를종종사용할것이다. 지금까지의예제에서는 WinMain에서다음세줄의코드만호출한다. glutcreatewindow("opengl"); glutdisplayfunc(dodisplay); glutmainloop(); 윈도우만들고출력콜백을등록한후메시지루프를돌리기만한다. 명령행인수를해석할필요도없고모드를바꿀필요도없고키보드입력도받지않으므로아주간단하다. 앞으로의예제는조금더복잡해질것이다. 위치나크기에대한지정이없으므로화면좌상단에 300 * 300 크기로작게열린다. 다음과같이수정하면윈도우가좀더커진다. main void main() glutinitwindowsize(800, 600); glutinitwindowposition(100,100); glutcreatewindow("opengl"); glutdisplayfunc(dodisplay); glutmainloop(); return 0; 코드 4-1 main 문예제 사용자가실행중에창의크기를조정할수있고위치도마음대로옮길수있으므로초기크기나위치는사실큰 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 48
의미가없다. 4.2. 입력처리 그래픽프로그램의주기능은출력이므로입력기능은사실크게필요치않으며그래서 OpenGL 자체는입력기능이아예없다. 하지만사용자의지시를받아그래픽상태를변경한다거나변수값을실행중에바꿔변화를관찰해보려면입력기능이필수적이다. 매번변수값을바꿔재컴파일해보기는너무번거롭다. 다행히 GLUT은기본적인입력기능을제공한다. 다음함수들로콜백을지정하면입력시해당함수가호출된다. void glutkeyboardfunc(void (*func)(unsigned char key, int x, int y)); void glutspecialfunc(void (*func)(int key, int x, int y)); void glutmousefunc(void (*func)(int button, int state, int x, int y)); 각콜백이등록하는입력함수의원형은인수목록의함수포인터타입에명시되어있다. 예를들어키보드입 력을받는함수는다음원형대로작성해야한다. 물론함수의이름은명칭일뿐이므로사용자가마음대로정할 수있다. 이강좌에서는 Do + 이벤트명형식을일관되게사용하고있다. main void DoKeyboard(unsigned char key, int x, int y) 코드 4-2 DoKeyboard 문예제 key 인수는입력된문자의아스키코드값이며조합키까지적용된것이다. A 키를 Shift와함께눌렀으면 A가전달되며그냥눌렀으면 a가전달된다. Ctrl, Alt, Shift 조합키의상태를따로조사하려면 glutgetmodifiers 함수를호출한다. x, y 인수는키입력시의마우스커서위치이되큰실용성은없다. Keyboard 함수는문자키만입력받을뿐커서이동키나펑션키같은특수키는입력받을수없다. 특수키는 Special 함수로입력받는다. 이함수는특수키만입력받을뿐일반문자키는입력받지못한다. 키의종류에따라입력받한국폴리텍대학항공캠퍼스항공제어시스템과페이지 49
는콜백이완전히분리되어있는셈이다. key 인수로눌러진키의코드가전달되는데각키에대해다음과같은 상수들이정의되어있다. GLUT_KEY_F1~ GLUT_KEY_LEFT GLUT_KEY_RIGHT GLUT_KEY_UP GLUT_KEY_DOWN GLUT_KEY_PAGE_UP GLUT_KEY_PAGE_DOWN GLUT_KEY_HOME GLUT_KEY_END GLUT_KEY_INSERT Mouse 함수는마우스버튼입력을받는다. button은눌러진마우스버튼의이름이며 GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON 셋중하나이다. 마우스버튼이하나밖에없는시스템에서는왼쪽버튼만눌러진다. state는버튼의상태이며 GLUT_DOWN, GLUT_UP 둘중하나이다. x, y 인수는마우스버튼이눌러진윈도우상의좌표이다. 이함수는마우스버튼의누름과놓음만인식할뿐이며이동시에는호출되지않는다. 마우스이동시의이벤트콜백은다음두함수로지정한다. void glutmotionfunc(void (*func)(int x, int y)); void glutpassivemotionfunc(void (*func)(int x, int y)); glutmotionfunc 의콜백함수는마우스버튼을누른채로윈도우내부에서움직일때에호출되며 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 50
glutpassivemotionfunc은버튼을누르지않고움직일때호출되는콜백함수를지정한다. 드래그처리를하려면이두이벤트를처리해야한다. 어느윈도우시스템에나키보드와마우스입력을처리하는방식은사실비슷하므로조금이라도경험이있다면이함수들은쉽게사용할수있을것이다. 다음예제는키보드와마우스입력을받아도형의색상이나위치를변경한다. 입력에대해그래픽출력을약간씩바꿔보는전형적인예제이다. glutinput #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" #include <stdio.h> void DoDisplay(); void DoKeyboard(unsigned char key, int x, int y); void DoSpecial(int key, int x, int y); void DoMouse(int button, int state, int x, int y); const GLfloat size = 0.2; const GLfloat step = 0.01; GLfloat nx, ny; GLboolean bgray = GL_FALSE; void main() glutcreatewindow("opengl"); glutdisplayfunc(dodisplay); glutkeyboardfunc(dokeyboard); glutspecialfunc(dospecial); glutmousefunc(domouse); glutmainloop(); void DoKeyboard(unsigned char key, int x, int y) switch(key) case 'r': case 'R': glclearcolor(1.0, 0.0, 0.0, 1.0); break; case 'g': case 'G': glclearcolor(0.0, 1.0, 0.0, 1.0); break; case 'b': 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 51
case 'B': glclearcolor(0.0, 0.0, 1.0, 1.0); break; glutpostredisplay(); void DoSpecial(int key, int x, int y) switch(key) case GLUT_KEY_LEFT: nx -= step; break; case GLUT_KEY_RIGHT: nx += step; break; case GLUT_KEY_UP: ny += step; break; case GLUT_KEY_DOWN: ny -= step; break; char info[128]; sprintf(info, "x=%.2f, y=%.2f", nx, ny); glutsetwindowtitle(info); glutpostredisplay(); void DoMouse(int button, int state, int x, int y) if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) bgray =!bgray; glutpostredisplay(); void DoDisplay() glclear(gl_color_buffer_bit); if (bgray) glcolor3f(0.5, 0.5, 0.5); else glcolor3f(1.0, 1.0, 1.0); glbegin(gl_triangle_strip); glvertex2f((nx + 0)/100, (ny + 30)/100); glvertex2f((nx + 6)/100, (ny + 12)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 15)/100, (ny + 7)/100); glvertex2f((nx + 15)/100, (ny + 4)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 9)/100, (ny + 2)/100); glvertex2f((nx + 8)/100, (ny + -1)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 25)/100, (ny + -12)/100); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 52
glvertex2f((nx + 25)/100, (ny + -18)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 12)/100, (ny + -22)/100); glvertex2f((nx + 12)/100, (ny + -25)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 8)/100, (ny + -27)/100); glvertex2f((nx + 6)/100, (ny + -30)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 2)/100, (ny + -30)/100); glvertex2f((nx + 1)/100, (ny + -27)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -1)/100, (ny + -27)/100); glvertex2f((nx + -2)/100, (ny + -30)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -6)/100, (ny + -30)/100); glvertex2f((nx + -8)/100, (ny + -27)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -12)/100, (ny + -25)/100); glvertex2f((nx + -12)/100, (ny + -22)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -25)/100, (ny + -18)/100); glvertex2f((nx + -25)/100, (ny + -12)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -8)/100, (ny + -1)/100); glvertex2f((nx + -9)/100, (ny + 2)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -15)/100, (ny + 4)/100); glvertex2f((nx + -15)/100, (ny + 7)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -6)/100, (ny + 12)/100); glvertex2f((nx + 0)/100, (ny + 30)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glend(); glflush(); 코드 4-3 glutinput 문예제 검정바탕에흰색삼각형을화면중앙에그려놓았다. 위치는 nx, ny 두변수로지정하고삼각형의색상은 bgray 변수로통제한다. 키보드이벤트에서이변수들의값을조작함으로써그래픽을바꿔본다. 커서이동키를누르면 nx, ny 값을증감시키고마우스왼쪽버튼을누르면 bgray 변수를토글한다. 또 r, g, b 문자를입력하면배경색상도바꾸어본다. 그리기에관련된값을변경한후다음함수로다시그린다. void glutpostredisplay(void); 이함수는윈도우가다시그려져야함을표시하기만할뿐즉시그리기를하지는않는다. 다시그릴필요가있음 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 53
( 전문용어로무효하다고표현한다 ) 을표시만해놓으면메시지루프가적당한때에 Display 콜백을호출하도록 되어있다. 실행한후키보드나마우스등으로조작해보자. 그림 4-1 glutinput 실행 특별히어려운코드는없고지극히평이하다. 콜백함수를원형에맞게작성해놓고 WinMain에서콜백함수를등록해놓았다. 키보드입력함수는대문자와소문자를 case 문에나란히적음으로써둘다인정한다. 커서이동키로도형의위치를이동시킬때마다현재좌표를문자열로조립하여타이틀바에보여준다. 앞으로의예제들도이와비슷한방식으로키보드나마우스입력을받아그리기에사용되는값들을실행중에바꿔볼것이다. 3D 그래픽은각도를움직여봐야모양을제대로확인할수있으며재컴파일하지않고도실행중에함수의인수들을요모조모바꿔봄으로써이해력을높일수있기때문이다. 4.3. 팝업메뉴 키보드나마우스는손가락으로콕콕눌러입력할수있으므로조작이쉽다는장점이있는반면어떤키에어떤기능이할당되어있는지알수없어직관적이지못하다. 반면팝업메뉴는기능의목록을문자열형태로나열할수있으므로사용법을외우지않아도쉽게이해할수있다는이점이있다. 그래서이강좌는팝업메뉴를적극적으로활용한다. 앞서작성했던 Primitive 등의예제에서이미팝업메뉴를사용한적이있다. GLUT은이런테스트목적으로팝업메뉴기능을제공한다. 어느윈도우시스템이나팝업메뉴는제공하므로명령이나옵션을나열하기에는최적이다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 54
팝업메뉴는다음함수로생성한다. int glutcreatemenu(void (*func)(int value)); 인수로메뉴항목을선택했을때호출될콜백함수를지정한다. 콜백함수는선택된메뉴항목의 ID 를인수로전 달받는다. 콜백은메뉴항목의 ID 에따라대응되는처리를할것이다. 이함수는메뉴생성후메뉴의 ID 를리턴 하는데이 ID 를다음함수로전달함으로써현재메뉴로지정한다. void glutsetmenu(int menu); int glutgetmenu(void); 새로생성된메뉴는자동으로현재메뉴가되므로굳이 glutsetmenu 를호출하지않아도상관없다. 둘이상의메 뉴를생성해놓고번갈아사용하고싶을때 glutsetmenu 가필요하다. 다음함수는메뉴를파괴한다. void glutdestroymenu(int menu); 메뉴는껍데기일뿐이므로이안에실제명령에해당하는내용물을채워야한다. 메뉴내에메뉴항목이나서브 메뉴는다음함수로추가한다. 캡션문자열과항목의 ID 를지정한다. void glutaddmenuentry(char *name, int value); void glutaddsubmenu(char *name, int menu); 다음함수들은메뉴를마우스버튼에부착하거나뗀다. 어떤동작에대해메뉴를호출할것인지를지정하는데 GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON 중하나의값을지정하되메뉴는통상마우 스오른쪽버튼에부착한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 55
void glutattachmenu(int button); void glutdetachmenu(int button); 다음함수는메뉴항목을실행중에변경한다. 순서값으로변경대상항목을지정하고새로운캡션, 새로운 ID 를 지정한다. 순서값은위쪽부터순서대로 1 이다. 사실상 ID 를바꿀일은거의없고캡션정도를바꾸는경우가종 종있다. void glutchangetomenuentry(int entry, char *name, int value); 다음예제는팝업메뉴로도형의색상과배경색상을변경한다. 그리기에사용할변수들을메뉴로바꿔보는예 이다. glutmenu #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" #include <stdio.h> void DoDisplay(); void DoMenu(int value); GLfloat nx, ny; void main() glutcreatewindow("opengl"); // 서브메뉴미리준비 GLint SubMenu = glutcreatemenu(domenu); glutaddmenuentry("red",4); glutaddmenuentry("green",5); glutaddmenuentry("blue",6); // 메인메뉴생성 glutcreatemenu(domenu); glutaddmenuentry("white",1); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 56
glutaddmenuentry("black",2); glutaddmenuentry("gray",3); // 서브메뉴를메인메뉴에붙인다. glutaddsubmenu("triangle Color",SubMenu); glutattachmenu(glut_right_button); glutdisplayfunc(dodisplay); glcolor3f(1.0, 0.0, 0.0); glutmainloop(); void DoMenu(int value) switch(value) case 1: glclearcolor(1.0, 1.0, 1.0, 1.0); break; case 2: glclearcolor(0.0, 0.0, 0.0, 1.0); break; case 3: glclearcolor(0.5, 0.5, 0.5, 1.0); break; case 4: glcolor3f(1.0, 0.0, 0.0); break; case 5: glcolor3f(0.0, 1.0, 0.0); break; case 6: glcolor3f(0.0, 0.0, 1.0); break; glutpostredisplay(); void DoDisplay() glclear(gl_color_buffer_bit); nx = 0; ny = 0; glbegin(gl_triangle_strip); glvertex2f((nx + 0)/100, (ny + 30)/100); glvertex2f((nx + 6)/100, (ny + 12)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 15)/100, (ny + 7)/100); glvertex2f((nx + 15)/100, (ny + 4)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 9)/100, (ny + 2)/100); glvertex2f((nx + 8)/100, (ny + -1)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 25)/100, (ny + -12)/100); glvertex2f((nx + 25)/100, (ny + -18)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 57
glvertex2f((nx + 12)/100, (ny + -22)/100); glvertex2f((nx + 12)/100, (ny + -25)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 8)/100, (ny + -27)/100); glvertex2f((nx + 6)/100, (ny + -30)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 2)/100, (ny + -30)/100); glvertex2f((nx + 1)/100, (ny + -27)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -1)/100, (ny + -27)/100); glvertex2f((nx + -2)/100, (ny + -30)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -6)/100, (ny + -30)/100); glvertex2f((nx + -8)/100, (ny + -27)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -12)/100, (ny + -25)/100); glvertex2f((nx + -12)/100, (ny + -22)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -25)/100, (ny + -18)/100); glvertex2f((nx + -25)/100, (ny + -12)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -8)/100, (ny + -1)/100); glvertex2f((nx + -9)/100, (ny + 2)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -15)/100, (ny + 4)/100); glvertex2f((nx + -15)/100, (ny + 7)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -6)/100, (ny + 12)/100); glvertex2f((nx + 0)/100, (ny + 30)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glend(); glflush(); 코드 4-4 glutmenu 문예제 이예제는서브메뉴를포함하고있다. 서브메뉴를미리준비해두고메인메뉴생성후서브메뉴를메인메뉴 의항목으로붙여야한다. 서브메뉴는필요한만큼더붙일수있다. 메뉴를마우스오른쪽버튼에부착했으므로 오른쪽버튼을누르면팝업메뉴가나타난다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 58
그림 4-2 glutmenu 실행 메뉴를선택했을때의동작은 DoMenu 함수에서처리한다. 메인메뉴항목과서브메뉴항목의콜백함수를굳이따로만들필요는없다. ID만확실하게구분된다면같은콜백함수를공유할수있다. DoMenu는 glclearcolor 나 glcolor 함수를호출하여선택된메뉴항목에대응되는색상을변경한다. 메뉴항목을선택하면배경색이바뀌며서브메뉴안의메뉴를선택하면도형이색상이바뀔것이다. GLUT이제공하는메뉴는별도의리소스를필요로하지도않고코드로간단하게생성및처리할수있어아주편리하다. 그러나메뉴항목사이에구분선을넣거나체크표시를토글하는고급기능은제공하지않으므로단순한테스트용으로만쓸수있는정도이다. 메뉴항목의사용여부를지정하거나실행중에메뉴항목을첨삭하는등의고급기능이필요하다면각플랫폼별로제공되는메뉴 API를직접사용해야한다. 이강좌의예제들은팝업메뉴를아주즐겨사용한다. Action 변수로 DoDisplay 함수의동작을선택함으로써한예제에여러가지그리기코드를통합적으로작성할수있어서좋고재컴파일없이실행중에값을바꿔볼수있다는면에서아주편리하다. 대부분의예제에팝업메뉴를채용하고있으므로예제를실행할때마다마우스오른쪽버튼을한번씩눌러보기바란다. 4.4. 애니메이션 GLUT 은반복적인처리가필요할때주로사용되는타이머이벤트도제공한다. 타이머구현은운영체제마다다르 지만 GLUT 의다음함수를호출하면운영체제에상관없이타이머를만들수있다. 다음함수로타이머콜백함수 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 59
를등록한다. void gluttimerfunc(unsigned int millis, void (*func)(int value), int value); millis 후에 func 함수를호출하며인수로 value를전달한다. value는타이머콜백으로전달되어작업거리를지시하는데타이머의용도가하나뿐이라면아무값이나주어도상관없다. 콜백을등록해놓으면 millis 후에콜백함수가호출된다. 주의할것은일반적인타이머와는달리주기적으로호출되는것이아니라딱한번만호출된다는것이다. 주기적으로계속호출하려면콜백함수에서자신을다시호출해야한다. 지속적으로호출되는방식에비해약간불편하지만매호출시마다다음주기를가변적으로결정할수있다는면에서활용성은오히려더높다. 더이상타이머호출이필요없으면콜백을재등록하지않으면된다. WinMain에서는다만시동만걸어줄뿐이고다음타이머호출시점은콜백함수가자체적으로결정할수있다. 타이머의용도는여러가지가있지만대표적인예가애니메이션이다. 일정한간격으로출력을계속바꾸면그림이움직이는것처럼보인다. 애니메이션을할때는더블버퍼링을사용하는것이좋다. 한버퍼에서지웠다그리기를계속반복하면깜박거림이발생하여눈에거슬리므로두개의버퍼를교대로사용한다. 초기화시에 GLUT_DOUBLE 플래그를전달하면 OpenGL은두개의버퍼를준비한다. glutinitdisplaymode(glut_double GLUT_RGB); 두버퍼는각각전면 (Front buffer 또는 On Screen Buffer), 후면 (Back Buffer 또는 Off Screen Buffer) 라고부른다. 전면버퍼는현재화면에출력된버퍼이며백버퍼는안쪽에숨겨진버퍼이다. 더블버퍼링옵션이켜지면그래픽카드는항상전면버퍼를모니터에뿌리지만모든그리기동작은백버퍼에서수행된다. 그래서그리는중간과정이사용자눈에보이지않으며깜박거림도없다. 백버퍼에그림을다그렸으면다음함수로버퍼를통째로교체한다. glutswapbuffers(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 60
전면버퍼와후면버퍼가일시에교체됨으로써백버퍼에미리준비해놓은그림이뿅하고나타난다. 순간적으로교체되므로깜박거림은전혀느낄수없다. 이과정을계속반복하면애니메이션이되는것이다. 버퍼를교체하는것자체가출력이므로 glflush는호출하지않아도상관없다. 다음예제는삼각형도형을좌우로이동시키는간단한애니메이션을보여준다. glutani #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" #include <stdio.h> void DoDisplay(); void DoTimer(int value); const GLfloat size = 0.2 * 100; GLfloat dx = 0.02 * 10; GLfloat nx, ny; void main() glutinitdisplaymode(glut_double GLUT_RGB); glutcreatewindow("opengl"); glutdisplayfunc(dodisplay); gluttimerfunc(30, DoTimer, 1); glutmainloop(); void DoTimer(int value) nx += dx; ny = 0; if (nx + size > 1*100 nx - size < -1*100) dx *= -1; glutpostredisplay(); gluttimerfunc(30, DoTimer, 1); void DoDisplay() glclear(gl_color_buffer_bit); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 61
glbegin(gl_triangle_strip); glvertex2f((nx + 0)/100, (ny + 30)/100); glvertex2f((nx + 6)/100, (ny + 12)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 15)/100, (ny + 7)/100); glvertex2f((nx + 15)/100, (ny + 4)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 9)/100, (ny + 2)/100); glvertex2f((nx + 8)/100, (ny + -1)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 25)/100, (ny + -12)/100); glvertex2f((nx + 25)/100, (ny + -18)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 12)/100, (ny + -22)/100); glvertex2f((nx + 12)/100, (ny + -25)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 8)/100, (ny + -27)/100); glvertex2f((nx + 6)/100, (ny + -30)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + 2)/100, (ny + -30)/100); glvertex2f((nx + 1)/100, (ny + -27)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -1)/100, (ny + -27)/100); glvertex2f((nx + -2)/100, (ny + -30)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -6)/100, (ny + -30)/100); glvertex2f((nx + -8)/100, (ny + -27)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -12)/100, (ny + -25)/100); glvertex2f((nx + -12)/100, (ny + -22)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -25)/100, (ny + -18)/100); glvertex2f((nx + -25)/100, (ny + -12)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -8)/100, (ny + -1)/100); glvertex2f((nx + -9)/100, (ny + 2)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -15)/100, (ny + 4)/100); glvertex2f((nx + -15)/100, (ny + 7)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glvertex2f((nx + -6)/100, (ny + 12)/100); glvertex2f((nx + 0)/100, (ny + 30)/100); glvertex2f((nx + 0)/100, (ny + 0)/100); glend(); glutswapbuffers(); 코드 4-5 glutani 문예제 코드의구조는아주간단하다. WinMain에서 DoTimer 함수를 0.03초후에호출하도록등록했다. 0.03초후에 DoTimer가호출되면 x값을 dx만큼증감시키되화면가장자리에닿으면 dx의부호를바꾸어반대방향으로움직이도록한다. dx가 0.02로정의되어있으므로타이머이벤트가한번발생할때마다삼각형이 0.02만큼이동한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 62
DoTimer 의마지막줄에서자기자신을 0.03 초후에다시호출함으로써이동이계속반복된다. 이처리가생략되 면타이머는딱한번만호출되므로애니메이션이실행되지않을것이다. 실행해보면삼각형이좌우로왔다리갔 다리하면서방황할것이다. 그림 4-3 glutani 실행 이예제는더블버퍼링과타이머콜백을설명하기위한예제이며도형의 x 좌표를직접조작하는단순한방법을 사용했다. OpenGL 에는애니메이션을위한더좋은방법들이많이준비되어있다. 변환을사용하면이동뿐만아 니라회전, 확대등의다양한애니메이션을훨씬더빠른속도로구현할수있다. 4.5. Win32 OpenGL 예제 지금우리는윈도우즈환경에서 GLUT으로 OpenGL 예제를만들고있다. GLUT은어디까지나플랫폼추상층을제공하는도우미일뿐 OpenGL의필수도구는아니다. 이말은즉 GLUT을사용하지않고도 AUX 라이브러리를제공하는임의의플랫폼에서동작하는완벽한 OpenGL 프로그램을만들수있다는얘기이다. 윈도우즈는 OpenGL 지원을위해운영체제차원에서관련 wgl 함수들을제공한다. 이함수들을사용하면 OpenGL을위한출력표면을만들수있고이표면에대해모든 OpenGL 함수가출력을내보낼수있다. 그외에모든윈도우즈기능을 100% 활용할수있으므로그래픽이나입출력모두원하는형태로만들수있다. 과연그것이가능한지 GLUT을사용하지않고순수한 Win32 API만으로 OpenGL 예제를만들어보자. 다음예제는일반적인윈도우즈응용프로그램이다. 앞서작성했던예제에비해거대한구조체가등장하고뭔가복잡해보이는메시지처리함수도사용되어어지러워보인다. 소스가길어보이지만사실 Win32를잘하는사람에게는 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 63
아주쉬운소스이다. Win32OpenGL #include <windows.h> #include <gl/gl.h> #include <gl/glu.h> LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); void DoDisplay(); HINSTANCE g_hinst; HWND hwndmain; LPCTSTR lpszclass=text("opengl"); HDC hdc; HGLRC hrc; int APIENTRY WinMain(HINSTANCE hinstance,hinstance hprevinstance,lpstr lpszcmdparam,int ncmdshow) HWND hwnd; MSG Message; WNDCLASS WndClass; g_hinst=hinstance; WndClass.cbClsExtra=0; WndClass.cbWndExtra=0; WndClass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); WndClass.hCursor=LoadCursor(NULL,IDC_ARROW); WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION); WndClass.hInstance=hInstance; WndClass.lpfnWndProc=WndProc; WndClass.lpszClassName=lpszClass; WndClass.lpszMenuName=NULL; WndClass.style=CS_HREDRAW CS_VREDRAW CS_OWNDC; RegisterClass(&WndClass); hwnd=createwindow(lpszclass,lpszclass, WS_OVERLAPPEDWINDOW WS_CLIPCHILDREN WS_CLIPSIBLINGS, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,(HMENU)NULL,hInstance,NULL); ShowWindow(hWnd,nCmdShow); while (GetMessage(&Message,NULL,0,0)) TranslateMessage(&Message); DispatchMessage(&Message); return (int)message.wparam; void DoDisplay() glclear(gl_color_buffer_bit); glbegin(gl_triangles); glvertex2f(0.0, 0.5); glvertex2f(-0.5, -0.5); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 64
glvertex2f(0.5, -0.5); glend(); glfinish(); LRESULT CALLBACK WndProc(HWND hwnd,uint imessage,wparam wparam,lparam lparam) switch (imessage) case WM_CREATE: hwndmain=hwnd; PIXELFORMATDESCRIPTOR pfd; int npixelformat; hdc=getdc(hwnd); memset(&pfd, 0, sizeof(pfd)); pfd.nsize = sizeof(pfd); pfd.nversion = 1; pfd.dwflags = PFD_DRAW_TO_WINDOW PFD_SUPPORT_OPENGL; pfd.ipixeltype = PFD_TYPE_RGBA; pfd.ccolorbits = 32; npixelformat = ChoosePixelFormat(hdc, &pfd); SetPixelFormat(hdc, npixelformat, &pfd); hrc=wglcreatecontext(hdc); wglmakecurrent(hdc, hrc); return 0; case WM_PAINT: DoDisplay(); SetTextColor(hdc, RGB(255,255,0)); SetBkMode(hdc,TRANSPARENT); TextOutA(hdc,10,10,"Win32 OpenGL",12); ValidateRect(hWnd, NULL); return 0; case WM_SIZE: glviewport( 0, 0, LOWORD(lParam), HIWORD(lParam)); glmatrixmode(gl_projection); glloadidentity(); glortho(-1, 1, -1, 1, 1, -1); glmatrixmode(gl_modelview ); glloadidentity(); return 0; case WM_DESTROY: wglmakecurrent(hdc, NULL); wgldeletecontext(hrc); ReleaseDC(hWnd,hdc); PostQuitMessage(0); return 0; return(defwindowproc(hwnd,imessage,wparam,lparam)); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 65
코드 4-6 Win32OpenGL 예제 프로젝트를만드는방법은기존의예제와동일하다. 그러나 glut.h가빠짐으로인해몇가지추가처리가필요하다. 먼저 gl.h와 glu.h 헤더파일을직접인클루드해야한다. 뿐만아니라라이브러리링크란에 opengl32.lib와 glu32.lib도연결해주어야한다. glut.h에작성되어있는 #pragma comment 문이없어졌으므로임포트라이브러리지정은수동으로바뀌었다. 그림 4-4 Win32OpenGL 속성페이지 윈도우를생성하는것은 Win32의고유코드로쉽게처리할수있다. 하지만일반적인윈도우에비해몇가지차이점이있다. OpenGL은자주화면을바꾸므로반드시 CS_OWNDC 스타일을지정하여전용 DC를할당해주어야빠른그리기를할수있다. 또자식윈도우와형제윈도우에대한클리핑을지정하여 OpenGL이다른창위에그리지않도록해야한다. 이렇게만들어진윈도우는일반적인윈도우일뿐 OpenGL이그리기에사용할수있는윈도우는아니다. OpenGL 이창에그리기를하려면랜더링컨텍스트를생성하여윈도우의 DC와연결해야한다. 이처리를 WM_CREATE에서하고있다. 랜더링컨텍스트를생성하기위해그리기표면의특성을픽셀포맷으로작성하고그래픽카드가지원하는모드중의하나를선택해야한다. 이작업은 PIXELFORMATDESCRIPTOR 구조체와 ChoosePixelFormat 함수로수행하며선택한픽셀포맷을 SetPixelFormat 함수로결정한다. wglcreatecontext 함수로 OpenGL 그리기 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 66
를위한랜더링컨텍스트를생성하고 wglmakecurrent 함수로현재컨텍스트를활성화하면이후부터윈도우에그리기를수행할수있다. 윈도우의크기가결정되는 WM_SIZE 메시지에서뷰포트를윈도우크기에맞게설정하고직교투영함수로클리핑영역을설정한다. 이예제의 WM_SIZE 처리는지금까지의예제에서는없었던것인데그이유는 GLUT이무난하게디폴트처리를해주었기때문이다. 지금은그런서비스가없으므로모든것을직접해야한다. 뷰포트는윈도우크기에맞추었고클리핑영역은 GLUT의디폴트와맞추었다. 물론원하는대로변경가능하다. 실제그리기를수행하는 WM_PAINT에서는도형을그린다. 기존예제와비슷함을강조하기위해 DoDisplay 함수로그리기코드를분리해두었다. 랜더링컨텍스트만제대로생성되어있다면 OpenGL의그리기코드를그대로활용할수있다. 뿐만아니라덤으로 Win32의 GDI 출력도같이내보낼수있다. 실행해보면삼각형과함께왼쪽위에문자열이하나출력될것이다. 그림 4-5 Win32 GDI 실행 이문자열은 Win32의 TextOut 함수로수행하되프로젝트설정이유니코드로되어있으므로 TextOutA 함수를호출했다. 문자열은 OpenGL이출력한그림위에배치되므로 OpenGL이완전히그린후에별도로그려야한다. 그러기위해 DoDisplay 함수의끝에서 glflush 대신 glfinish 함수를호출했다. glfinish는완전히그릴때까지대기하는특성이있어 OpenGL 출력과 Win32 출력을분리하는역할을한다. glflush를쓰면다시그리기를즉시하지않으므로 GDI 출력이 OpenGL 출력에덮여버린다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 67
그까짓문자열하나출력하는게뭐대단하냐고하겠지만결코그렇지않다. OpenGL은입체도형은그럴싸하게잘그려내지만문자열출력기능은따로제공하지않는다. 본연의임무가아니기하고그래픽화면에서는문자조차도그림으로그려야하기때문이다. 정문자열을출력하려면일일이비트맵폰트를만들어그려야한다. Win32 는간단한함수호출하나만으로문자열을출력할수있고색상, 모드등을자유로이선택할수있으며트루타입의모든이점을활용할수있다. 이예제의모든코드를다이해할필요는없다. 다만이실습을통해 GLUT이어떤역할을하는지, 장단점이무엇인지만파악하면된다. 보다시피동일한예제를만드는데도 Win32로는굉장히많은코드가필요하다. 모든것을일일이직접처리해야한다. 더구나이렇게만든프로그램은윈도우즈전용이므로호환성에지극히불리하다. Win32 뿐만아니라매킨토시나리눅스용 AUX도동일한문제점이있다. 그러나 GLUT을사용하지않을때의이점또한만만치않다. 위예에서보다시피트루타입글꼴을편리하게출력할수있으며팝업메뉴에구분선이나체크표시도달수있다. 키보드키의동시입력도처리할수있으며멀티스레드와동기화, 파일입출력, 네트워크, 데이터베이스지원등해당플랫폼이제공하는모든이점을완벽하게누릴수있다. 그래서상용프로그램을만들때는타겟플랫폼의 AUX를사용하지않을수없다. GLUT은어디까지나실습용, 테스트용의라이브러리임을잊지말자. 물론 GLUT도계속업그레이드되고있으므로이것만으로도상당한수준의프로그램을만들수있지만최종제품을위한해결책이라보기는어렵다. 학습에필요한만큼만연구해두고더필요하면그때연구해도늦지않다. 그래서여기서도예제제작에딱필요한만큼만소개했다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 68
5. 항공기계기판이해 5.1. Pitch,Roll,Yaw 비행기는 3 차원운동을한다. 그 3 차원운동에대한축에대한구성이 Pitch, Roll, Yaw 이다. 비행기의조종은 바로이 3 가지성분의조합으로이루어진다. 5.1.1. Pitch Pitch 는비행기의기수가상하운동을하는것을말한다. 그림 5-1 Pitch 5.1.2. Roll Roll 은비행기를동체를축으로할때동체를중심으로날개를좌, 우로기울이는것을말한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 69
그림 5-2 Roll 5.1.3. Yaw Yaw 는비행기의날개를수평으로유지한채로비행기기수를좌, 우로움직이는것을말한다. 그림 5-3 Yaw 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 70
5.2. Compass(Heading Indicator) Compass 는현재비행기가진행하고있는방향을가르킨다. 각도의출발점은북 (000) 이며, 시계방향으로각도가 증가하여북 (360) 에서끝난다. 그러나계기판에는끝에숫자가빠져있으므로읽거나말할때는끝에 '0' 을붙여준 다. 아래의계기는서쪽 (275 도 ) 를지시하고있다. 그림 5-4 방위표시기 방위표시는다음과같습니다. 표 5-1 방위표시 방위를읽는방법은북 (zero-zero-zero), 동 (zero-nine-zero), 남 (one-eight-zero), 서 (two-seven-zero) 로읽는다. 5.3. Artificial Horizon(Attitude Indicator) Artificial Horizon은가장중요한계기중에하나이다. 이계기는 Pitch,Bank(Roll) 두가지정보를동시에보여준다. 또한비행중시계가불량할때, 이계기를참조하며비행할수있다. 계기의움직임은모형비행기는고정되어있으며가운데원과작은흰색삼각형이움직여비행기의 bank각과 pich를나타낸다. 아래의계기에있는중앙의모형비행기는현재비행기의자세를나타낸다. 윘쪽에있는파란색은하늘을나타한국폴리텍대학항공캠퍼스항공제어시스템과페이지 71
낸다. 밑부분고등색은땅을나타낸다. 그리고중앙의흰선은지평선을다타낸다. 그림 5-5 수평표시기 따라서, pilot 은현재고도에서모형비행기의위치에따라비행기기수가아래로향하고있는지위로향하고있는 지를알수있다. 상단에있는흰색삼각형 : 현재비행기의 bank(roll) 각도를나타낸다원주위에있는눈금 : bank 각도를나타내며작은눈금은10도, 큰눈금 30도를나타낸다. 조종간을좌측으로밀면흰색삼각형은좌측으로움직이며, 조종간을우측으로밀면흰색삼각형은우측으로움직인다. 원안에있는눈금 : pitch 각도를나타낸다. [pitch up] 조종간을몸쪽으로당기면가운데있는원이내려오며상대적으로모형비행기의위치가올라가보인다. ( pitch 각 : 이때비행기의중심이가운데있는원안의눈금과만날때읽혀지는숫자가 pitch 각이다.) [pitch down] 조종간을몸바깥쪽으로밀면가운데있는원이올라오며상대적으로모형비행기의위치가내려가보인다. 예 ) 30 도 bank 로좌측으로선회 : 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 72
조종간을좌측으로서서히밀면흰색삼각형이좌측으로움직이며, 이후흰색삼각형이좌측의 첫번째큰눈금에위치하고있도록하면여러분은 30 도 (bank) 각으로좌측으로선회하고있는것 이다. 예 ) pitch 15 도로비행 : 조종간을몸쪽으로서서히당겨모형비형기의중앙이파란색부분에있는 10 과 20 의사이의정 중앙에위치하도록한다. 예 ) pitch 15 도, bank 각 30 도로좌측으로선회 : 조종간을서서히당겨모형비행기가 15 도에위치하도록유지하면서다시조종간을좌측으로서 서히밀어작은삼각형이좌측의첫번째큰눈금에위치하도록한다. 5.4. 고도계 (Altimeter) 고도계 (Altimeter) 는현재비행기의고도 (MSL) 를나타낸다. 이고도계에서가장긴바늘의단위는 100 feet 이고, 중간길이의바늘의단위는 1000 feet 이다. 그리고가장짧은길이의바늘의단위는 10000 feet 단위이다. 아래의고도계는고도 4,710 feet 를지시하고있다. 그림 5-6 고도표시기 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 73
참고 ) 비행기의고도는 2 가지방법으로나타냅니다. 1) MSL(Mean of Sea Level): 평균해수면고도를나타내며위의 Altimeter 처럼모든아날로그계기들은 MSL로고도를나타냅니다 (( 원리는각고도마다기압차를이용해나타냄 ). 따라서, 비행기가지상에착륙했을때, 착륙한지점이해수면과같은높이에있지않으면고도계는 0을가르키지않는다. 2) AGL(Above Ground Level) 비행기동체하부로부터지상까지의직선거리를나타냅니다. ( 원리는동체하부에서발사한신호를다시수신, 계산하여나타냄 ) AGL은제한된상황 ( 비교적지상과근접한상황 ), 제한된기종 ( 즉해당장비를장착한비행기 ) 에한해서나타낸다. 5.5. Airspeed Indicator (ASI) 비행기의속도를나타낸다. 단위는 knot 이다. 비행기기종에따라각구간들및표시방법은다르며해당구간들 이있다. 그림 5-7 속도표시기 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 74
흰색시작점 (40 knot) : Full Flap Stalling Speed 녹색시작점 (50 knot) : No Flap Stalling Speed 녹색구간 : 허용비행속도구간노랑색구간 : 주의를요하는비행속도구간적색선이후 : 위험비행속도구간 5.6. 전방향시현기 (HUD) 기본적으로각각의전방향시현기 (HUD : HeadUp Display) 의세부모드와관계없이비행기조종을위한기본정 보들은공통적으로아래그림의 HUD 에나타낸다. 5-8 전방향시현기 (HUD) 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 75
그림 5-9 전방향시현기심볼 (HUD) 1) Heading Scale(Heading Indicator) : Compass와동일한기능을하며현재비행기의 Heading을나타냅다. 위의 HUD에서는 080( 거의동쪽 ) 으로비행하고있다. 2) Heading Bug : 선택된비행경로의 Heading을나타낸다. 따라서, 선택된지점으로비행하고자한다면비행기의 Heading과 Heading Bug를일치시키면된다. 3) Gun Cross : 총알이날아가는방향이다. 4) Pitch Ladder : Attitude Indicator에서나타내는 Pitch와동일한것으로비행기의 Pitch를나타냅니다. 중앙의굵은긴선이가상지평선을나타내며그선을기준으로아래에점선으로표시된것은 Pitch Down, 위에실선으로표시된것은 Pitch Up을나타낸다. 또한, Pitch Up에서는양끝의선이아래를향하고 Pitch Down 에서는위를향하고있다는것을확인해두 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 76
세요. 위의 HUD에서는 Pitch Up된상태 ( 약 3도 ) 이다. 5) Flight Path Maker : 비행기가날아가고있는실제방향을나타낸다. 예를들어, Flight Path Maker를지상의어느한지점에고정시키면서계속그지점으로비행한다면, 바로그지점에추락한다. 대체로비행기는기수가지상과평행해서비행하지는않는다. 즉, 비행기는기수가올라간상태 (Pitch Up) 로 Level Flight( 고도가변하지않는비행 ) 를할수있다. 이경우비행기기수가가르키는방향과실제비행기가날아가는방향은다르다. 6) AirSpeed : ASI(Air Speed Indicator) 와동일한기능을하며현재비행기의속도를나타낸다. 7) Mach number : 현재비행기의 Mach( 마하 ) 수치를나타낸다. 8) AoA Indicator : 현재비행기의 AoA( 공격각 ) 을나타낸다. 9) G force Indicator : 현재비행기가받고있는 G Force( 중력 ) 을나타낸다. 10) Peak(Max) G Force Indicator : 이륙후부터현재까지비행기기체에가해진최대 G를표시한다. 11) HUD mode Indicator : 현재의 HUD 모드를나타낸다. 12) Bank Angle Scale(Roll Scale) : Attiude Indicator의 Bank 표시와동일하며현재비행기의 Bank 각을나타낸다. 13) ETA (Estimated Time of Arrival) 또는 ETE(Estimated Time Enroute) : ETA: 선택된지점에도착예정시간 ( 지정된속도로비행하는경우 ) ETE: 선택된지점에도착할때까지걸리는시간 ( 지정된속도로비행하는경우 ) 14) 선택된지점 (Way Point) 및거리 : 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 77
위의 HUD 에서 30.2는선택된지점 (w2) 까지의거리를나타내며, 단위는일반적으로 nautical miles ( 해리 ) 입니다. 또한, w2는선택된지점을나타낸다. 15) AGL(Above Ground Level) Indicator : 지상과비행기동체밑부분까지의직선거리를나타낸다. 16) MSL(Mean of Sea Level) Indicator : Altimeter와동일한기능을하며평균해수면고도를나타낸다 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 78
6. 항공기계기판설계 1 ( 콘솔프로젝트 ) 6.1. 점 모든디지털그래픽의기본은점 (Pixel) 이다. 선이나면도모두점의집합으로표현할수있다. 그러나 3 차원그래 픽의가장원자적인요소는정점 (Vertex) 이다. 정점은색상이나크기에대한정보는없고오로지위치만을가진다 는면에서점과는다르다. 정점은다음두함수블록사이에서정의한다. void glbegin(glenum mode); void glend(void); glbegin ~ glend 블록사이에다양한함수들이호출되는데주로정점을배치하거나속성을바꾸는명령들이다. 정점은다음함수로지정한다. 앞에서설명한대로좌표지정인수를 4 개까지취할수있고인수의타입도다양하 다. 여기서는평면도형을그리는실습을먼저하므로좌표는 x, y 두개만지정한다. glvertex[2,3,4][s,i,f,d][v](x,y,z,w) 블록내의정점들로무엇을어떻게그릴것인가는 glbegin 으로전달되는모드값에의해결정된다. 다음과같은모 드가제공되며모드에따라정점을연결하는방식이달라진다. 이모드들을완벽하게이해하고자유자재로쓸 수있어야한다. 표 6-1 정점 (Vertex) 모드 모드 설명 GL_POINTS GL_LINE_STRIP GL_LINE_LOOP GL_LINES 독립적인점연결된선분시작점과끝점을이은선분두개의정점들을이은선분 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 79
모드 설명 GL_TRIANGLES GL_TRIANGLE_STRIP GL_TRIANGLE_FAN 세개씩연결한삼각형 연결된삼각형 중심을공유하는삼각형 GL_QUADS 정점 4 개씩을연결하여사각형을그린다. GL_QUAD_STRIP GL_POLYGON 연결된사각형 연결된볼록다각형 기하학적으로가장간단한점부터찍어보자. GL_POINTS 모드로시작하고블록내에서정점의좌표를지정하면 정점위치에점들이찍힌다. Dot #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" void DoDisplay() glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 1.0f); glbegin(gl_points); // COURSE DEVIATION SCALE(DOTS) glvertex2f( -40, 0); glvertex2f( -80, 0); glvertex2f( 40, 0); glvertex2f( 80, 0); glend(); glflush(); void main() glutcreatewindow( HSI"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-1 점 (Dot) glbegin ~ glend 사이는하나의도형을정의하는논리적인블록이다. 그래서가독성을높이기위해두블록사이 에 괄호로감싸고들여쓰기를하기도한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 80
void DoDisplay() glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 1.0f); glbegin(gl_points); // COURSE DEVIATION SCALE(DOTS) glvertex2f( -40, 0); glvertex2f( -80, 0); glvertex2f( 40, 0); glvertex2f( 80, 0); glend(); glflush(); 코드 6-2 점 (Dot) Dispay 함수 glbegin과 glend 사이에빈 괄호를두고정점을이블록안에배치하며한칸들여쓴다. 물론이괄호는문법적으로는아무의미가없으며단지블록을읽기쉽게표시할뿐이다. 보기에는좋지만다소번거롭고소스가길어지므로이강좌에서는그냥평이하게쓰기로한다. 네개의정점을정의했으므로입력된위치에점이찍힐것이다. 그림 6-1 점 점의디폴트크기는 1 픽셀이라너무작아서잘보이지않는다. 좌표는위치만가지는데비해점은화면상에표시 되므로크기를변경할수있고색상도지정할수있다. 점크기의변경범위와조정단위는구현에따라다른데 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 81
다음코드로조사한다. GLfloat range[2], granu; glgetfloatv(gl_point_size_range, range); glgetfloatv(gl_point_size_granularity, &granu); 윈도우환경에서는 1.0 ~ 63.375 까지의범위를가지며 0.125 단위로지정할수있다. 범위를벗어나더라도가장 가까운값이선택되며에러는나지않는다. 점크기는다음함수로지정한다. 점크기의디폴트는 1 이다. void glpointsize(glfloat size); size 인수는점을감싸는원의직경을지정한다. 안티알리아싱을하지않으면점은시각형으로출력되는데 size 는사각형의한변길이에해당한다. 다음코드는점을 10 픽셀로확대하여출력한다. void DoDisplay() glclear(gl_color_buffer_bit); glpointsize(10.0); glbegin(gl_points); glvertex2f(0.0, 0.5); glvertex2f(-0.5, -0.5); glvertex2f(0.5, -0.5); glend(); glflush(); glbegin 블록에들어가기전에 glpointsize 함수로점크기를 10 으로지정했다. glbegin 블록안에서지정해도효 과는동일하며중간에라도언제든지점의크기를변경하여크기가각각다른점을찍을수도있다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 82
그림 6-2 점 점을확대하면정사각형형태로출력되는데안티알리아싱을지정하면둥그렇게원모양으로표시된다. 점은가장 기본적인그래픽요소이지만점만으로표현할수있는것이거의없어사용빈도는낮다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 83
6.2. 선 정점들을연결하면선분이된다. 선을그리는모드는 3 가지가있다. 모드를다음과같이변경해보자. #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" void DoDisplay() glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(0.0f, 1.0f, 1.0f); glbegin(gl_triangles); // ARROW glvertex2f(-7,93); glvertex2f(7,93); glvertex2f(0,115); glend(); gllinewidth(4.0f); glbegin(gl_lines); // COURSE ARROW glvertex2f(0,61); glvertex2f(0,93); glvertex2f(-80,40); glvertex2f(-80,-40); glvertex2f(0,-61); glvertex2f(0,-105); glend(); glflush(); void main() glutcreatewindow( HSI"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-3 선 위코드는 HSI 계기판에구성되는선을 Display 하는코드이다. 하나의선은화살표가있는선이며, 나머지 2 개의 선은화살표가없는선이다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 84
그림 6-3 선 선을그리는다양한방법을아래에설명한다. GL_LINE_STRIP 은정점들을연결하여선분을그린다. STRIP 은계속이어서그린다는뜻이다. 첫번째정점과두번 째정점을연결하고이어서두번째정점과세번째정점을연결한다. 그러나처음과끝을연결하지않으므로열린 개곡선이된다. 그려지는선의개수는정점의개수보다하나더적다. 정점이 3 개이므로선분은 2 개만그려진다. GL_LINE_LOOP 는선분을이어서그리고시작점과끝점을자동으로연결하여폐곡선을만든다. 세번째정점과첫번째정점이연 결되어삼각형모양이그려진다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 85
그림 6-4 삼각형 GL_LINES 는정점들을두개씩한쌍으로묶어선을그린다. 여러개의정점을배치해놓으면각각떨어진선분이 그려진다. 다음코드는 6 개의정점을지그재그로배치하고 6 개의선을긋는다. void DoDisplay() glclear(gl_color_buffer_bit); glbegin(gl_lines); GLfloat x = -0.8; GLfloat y = 0.4; for (int i = 0; i < 6; i++) glvertex2f(x, y); x += 0.3; y *= -1; glend(); glflush(); 코드 6-4 선 첫번째, 두번째정점이연결되고세번째, 네번째정점이연결되는식이다. 정점이 6 개이므로두개씩짝을지어 총 3 개의선분이그려진다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 86
그림 6-5 정점의순서 만약정점이홀수개라면마지막정점은대응되는짝이없으므로무시된다. 그림 6-6 선 선의두께는디폴트로 1 이되더굵게그릴수도있다. 점과마찬가지로구현에따라지정가능한범위가다르다. 다음코드로범위를구한다. GLfloat range[2], granu; glgetfloatv(gl_line_width_range, range); glgetfloatv(gl_line_width_granularity, &granu); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 87
윈도우즈환경에서조사한결과 0.5 ~ 10.0 까지 0.125 단위로조정할수있다. 선의두께를변경할때는다음함 수를호출한다. void gllinewidth(glfloat width); 다음예제는 1 부터시작해서선두께를점점증가시켜가며각각다른굵기로수평선을여러개긋는다. void DoDisplay() glclear(gl_color_buffer_bit); GLfloat y; GLfloat w = 1; for (y = 0.8; y > -0.8;y -= 0.2) gllinewidth(w++); glbegin(gl_lines); glvertex2f(-0.8, y); glvertex2f(0.8, y); glend(); glflush(); y 좌표 0.8 부터시작해서 0.2 만큼씩아래로이동하며선을그었다. 한단계내려갈때마다선의굵기는 1 씩증가 한다. 윈도우크기를변경해도선의굵기는유지된다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 88
그림 6-7 선굵기 실선이아닌다른모양의선을그리려면스티플 (Stipple: 점묘법 ) 기능을켜야한다. 특정기능을사용할때는 glenable 함수로사용할기능의이름을전달한다. 스티플기능은다음호출문에의해활성화된다. 대부분의기능 은디폴트로꺼져있으므로사용하려면반드시켜야한다. glenable(gl_line_stipple); 물론이기능이더이상필요없으면 gldisable 함수로언제든지기능을취소할수있다. 선의모양은다음함수 로지정한다. void gllinestipple(glint factor, GLushort pattern); pattern은이진수로표현한선의모양이다. 하위비트부터선의앞쪽부분의점모양을지정한다. 대응되는비트가 1인자리는점이찍히고 0인부분은찍히지않는다. factor 인수는비트하나가점몇개에대응될것인가를지정한다. 이값이 1이면비트하나가점하나에대응되며 2이면비트당 2개의점이그려져좀더긴모양을만들수있다. 다음예제는점섬, 쇄선등을출력한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 89
void DoDisplay() GLushort arpat[]=0xaaaa,0xaaaa,0xaaaa,0xaaaa,0x33ff,0x33ff,0x33ff,0x57ff,0x57ff ; GLint arfac[] = 1, 2, 3, 4, 1, 2, 3, 1, 2; glclear(gl_color_buffer_bit); glenable(gl_line_stipple); GLfloat y; GLint idx = 0; for (y = 0.8; y > -0.8;y -= 0.2) gllinestipple(arfac[idx], arpat[idx]); glbegin(gl_lines); glvertex2f(-0.8, y); glvertex2f(0.8, y); glend(); idx++; glflush(); 코드 6-5 점선 pattern 와 factor 인수에대해 9 개의인수쌍을배열로준비해두고각모양대로선을그려보았다. 배열의앞쪽 요소부터위쪽에서순서대로적용하여그렸다. 그림 6-8 점선 0xaaaa 는이진수로 1010101010101010 이므로점과공백이계속반복되는점선이된다. factor 가 2 면점과공백이 두배로확장되므로더성긴점선이그려진다. factor 를 3, 4 로더크게지정하면점사이의거리가더욱멀어진 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 90
다. 0x33ff 는일점쇄선의패턴을지정하는데각비트가어떻게대응되는지를보자. 그림 6-9 점선의패턴 하위비트부터오른쪽에서순서대로점과대응되므로비트를뒤집어야한다. 왜하위부터앞쪽점에대응시키는가하면기계적연산이간단하기때문이다. 점 10개그리고 2개건너뛰고 2개그리고다시 2개건너뛴다. 긴선, 짧은선이계속반복되므로일점쇄선이된다. 끝부분에여백이있어야반복될때긴선과짧은선이붙지않는다. 0x57ff는이진수로 0101011111111111이되며긴선하나에짧은선두개가계속반복되므로이점쇄선이다. 어떤모양이든간에비트로선모양을만들고 16진수로바꿔서패턴으로사용하면된다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 91
6.3. 삼각형 2 차원그래픽의기본요소는픽셀이지만 3 차원그래픽의기본요소는삼각형이다. 작은삼각형들이모여서모든 물체들이구성된다. 그래서삼각형이아주중요하며자주사용된다. GL_TRIANGLES 모드는정점세개씩을모아서 삼각형을그린다. 제일처음만들었던예제가바로이모드로삼각형을그렸다. #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" void DoDisplay() glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 1.0f); glbegin(gl_triangles); // TO ARROW glvertex2f(-48,40); glvertex2f(-32,40); glvertex2f(-40,55); glend(); glbegin(gl_triangles); // FROM ARROW glvertex2f(-48,-40); glvertex2f(-32,-40); glvertex2f(-40,-55); glend(); glflush(); void main() glutcreatewindow( HSI"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-6 삼각형 6 개의정점에대해삼각형을그리면 2 개의삼각형이만들어진다. 3 개씩짝을지어삼각형하나를그리므로정점 개수를 3 으로나눈개수만큼의삼각형이그려진다. 3 의배수에서남는정점은무시된다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 92
그림 6-10 삼각형 GL_TRIANGLE_STRIP 은삼각형을계속이어서그린다. 첫세개의정점으로삼각형을그리고추가되는정점을새 로운꼭지점으로하는삼각형을계속이어서그린다. void DoDisplay() glclear(gl_color_buffer_bit); glshademodel(gl_flat); glbegin(gl_triangle_strip); GLfloat x = -0.8; GLfloat y = 0.4; for (int i = 0; i < 6; i++) if (i % 2 == 0) glcolor3f(1.0, 0.0, 0.0); else glcolor3f(0.0, 1.0, 0.0); glvertex2f(x, y); x += 0.3; y *= -1; glend(); glflush(); 정점이 6 개이므로삼각형은모두 4 개가그려진다. 색상을지정하지않으면전부흰색으로그려져하나의평행사 변형으로보이므로각정점마다색상을번갈아가며지정하고쉐이드모델을 FLAT 으로지정하여단색으로채색했 다. 쉐이드모델에대해서는차후설명하기로한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 93
그림 6-11 연속삼각형 각삼각형을분리해보면다음과같다. 그림 6-12 연속삼각형의정점순서 v0, v1, v2 세개의정점을연결하여첫번째삼각형을그린다. 그리고 v1, v2를한변으로하고새로추가된 v3를나머지한꼭지점으로하는삼각형을그린다. 계속해서 v2, v3, v4를꼭지점으로하는삼각형을그리고 v3, v4, v5 를꼭지점으로하는삼각형이그려진다. 이런식으로이전의정점들을연결해서그리면적은개수의정점으로도많은삼각형을그릴수있다는이점이있다. n개의삼각형을그리는데 n+2개의정점만있으면된다. 개별적으로삼각형을그리는방법에비해이전정점을 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 94
재활용하므로메모리도절약되고속도도훨씬빠르다. 새로그려지는삼각형은반시계방향으로그려진다. 삼각형을그리는방향 (Winding) 은삼각형의앞뒤를구분하는의미가있는데다음에자세히알아볼것이다. GL_TRIANGLE_FAN은첫삼각형의꼭지점하나를고정해두고새로추가되는두정점을연결하여계속삼각형을그린다. 마치부채살을추가하여부채를만드는방법과비슷해서 FAN이라는이름이붙었다. void DoDisplay() glclear(gl_color_buffer_bit); glshademodel(gl_flat); glbegin(gl_triangle_fan); glcolor3f(1.0, 0.0, 0.0); glvertex2f(0.0, 0.0); glvertex2f(0.0, 0.5); glvertex2f(-0.35, 0.35); glcolor3f(0.0, 1.0, 0.0); glvertex2f(-0.5, 0.0); glcolor3f(1.0, 0.0, 0.0); glvertex2f(-0.35, -0.35); glcolor3f(0.0, 1.0, 0.0); glvertex2f(0.0, -0.5); glend(); glflush(); 중심부에첫정점을찍고 12 시방향부터반시계방향으로돌며삼각형을계속이어그렸다. 삼각형간의구분을위 해색상을교대로바꾸었다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 95
그림 6-13 부채 간단하게작성하기위해정점들을직접찍었는데루프를돌며원주상의점들을순회하면원형이나원뿔처럼꼭 지점을공유하는도형을쉽게만들수있다. 이삼각형들을아주잘게나누면완전한원모양이될것이다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 96
6.4. 사각형 사각형도입체물체를구성하는기본요소이다. 삼각형에비해약간의제약이있지만그리기속도가빠르고적은 개수로도넓은면적을그릴수있어종종사용된다. 사각형은자주사용되므로별도의그리기함수가제공된다. void glrect[i,s,f,d][v](x1, y1, x2, y2) 완전히독립된함수이므로 glbegin ~ glend 블록에포함시키지않고도사각형을그릴수있다. 인수로좌상단좌 표와우하단좌표를주거나또는각좌표값의배열을전달한다. 다음은사각형을그린다. #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" void DoDisplay() glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 0.0f); glrectf(-2.0, 144.0,-8,154); glrectf(2.0, 144.0,8,154); glflush(); void main() glutcreatewindow( HSI"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-7 사각형 왼쪽위와오른쪽아래를꼭지점으로하는사각형이그려진다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 97
그림 6-14 사각형 아주쉽게사각형을그릴수있지만대각선의두점을지정하는식이므로각변이수직인직사각형만그릴수 있다. 평행사변형이나사다리꼴처럼직각이아닌사각형은그릴수없다. 불규칙한사각형은정점을직접지정하 여다각형으로그려야한다. 다음은마름모를그린다. void DoDisplay() glclear(gl_color_buffer_bit); glbegin(gl_quads); glvertex2f(0.0, 0.5); glvertex2f(-0.5, 0.0); glvertex2f(0.0, -0.5); glvertex2f(0.5, 0.0); glend(); glflush(); 코드 6-8 사각형 GL_QUADS 는 4 개씩정점을연결하여사각형을그린다. 제일위의꼭지점을시작으로하여반시계방향으로마름 모를구성하는꼭지점을전달했다. 임의위치의정점을전달할수있으므로직각이아닌사각형을그릴수있다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 98
그림 6-15 마름모 정점을 4 개만지정했으므로사각형은하나만그려진다. 8 개라면 2 개, 12 개라면 3 개의사각형이그려질것이다. GL_QUAD_STRIP 모드는추가되는 2 개의정점으로이전사각형을계속이어서그린다. 6 개의정점으로 2 개의사 각형을연속으로그릴수있다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 99
6.5. 다각형 GL_POLYGON은모든정점을하나로연결하여다각형을그린다. 정점의개수만큼의다각형이만들어지는데 5개면 5각형, 8개면 8각형이그려진다. 삼각형이나사각형도이모드로그릴수있다. 정점이몇개든간에모조리연결해서하나의도형을정의할수있다. 굉장히자유도가높은모드인것같지만아무다각형이나그릴수있는것은아니고까다로운조건이적용된다. GL_POLYGON 모드로그리는다각형음다음세가지조건을반드시만족해야한다. 1 정점의선이교차해서는안된다. 2 다각형은볼록해야한다. 3 모든정점은같은평면내에있어야한다. 첫번째, 두번째조건은다소이해하기쉽다. 다각형은하나의닫힌도형이어야하며어디가안쪽이고어디가바 깥쪽인지명확하게구분되어야한다. 그러나선이교차하거나오목하면이런판단이아주어려워진다. 다음예를 보자. 그림 6-16 다각형의조건 왼쪽은모두 GL_POLYGON 모드로그릴수있는다각형이다. 그러나오른쪽은제대로그려지지않는다. 리본모양의다각형은선분이교차되어두개의다각형으로분할된것처럼보인다. L자모양의다각형은오목해서적법하지않다. 볼록하다는것은내부에서임의의선분을그었을때선분이다각형을벗어나지않아야함을뜻한다. 그러나 L자모양은선분이바깥을벗어날수있어오목하다. 십자형의다각형도같은이유로적법하지않다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 100
앞에서마름모를 GL_QUADS 로그렸는데 4 개의정점을연결하는것이므로 GL_POLYGON 으로모드를바꾸어도정 상적으로잘그려진다. 마름모를구성하는 4 정점이반시계방향으로제대로나열되어있기때문이다. 이코드를 다음과같이수정해보자. #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" void DoDisplay() glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 0.0f); glbegin(gl_line_strip); // 비행기 glvertex2f(0,30); glvertex2f(6,12); glvertex2f(15,7); glvertex2f(15,4); glvertex2f(9,2); glvertex2f(8,-1); glvertex2f(25,-12); glvertex2f(25,-18); glvertex2f(12,-22); glvertex2f(12,-25); glvertex2f(8,-27); glvertex2f(6,-30); glvertex2f(2,-30); glvertex2f(1,-27); glvertex2f(-1,-27); glvertex2f(-2,-30); glvertex2f(-6,-30); glvertex2f(-8,-27); glvertex2f(-12,-25); glvertex2f(-12,-22); glvertex2f(-25,-18); glvertex2f(-25,-12); glvertex2f(-8,-1); glvertex2f(-9,2); glvertex2f(-15,4); glvertex2f(-15,7); glvertex2f(-6,12); glvertex2f(0,30); glend(); glflush(); void main() 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 101
glutcreatewindow( HSI"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-9 다각형을이용한항공기 3 번째정점과 4 번째정점의순서를바꾸었다. 이렇게되면선분이교차하며오목한다각형이그려진다. 그림 6-17 항공기 OpenGL 이인정하는다각형이아니다. 두다각형의차이점은정점의순서이다. 왼쪽마름모는정점을잇는선분 들이만나지않지만순서를바꾸면선분끼리교차할뿐만아니라오목해져버린다. 그림 6-18 정점순서 에러는발생하지않고어쨌든그려지지만이것이과연의도했던다각형이맞는지는애매하다. 만약꼭저런식으 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 102
로다각형을그리고싶다면규칙에맞는두개의다각형으로분할해야한다. void DoDisplay() glclear(gl_color_buffer_bit); glbegin(gl_triangles); glvertex2f(0.0, 0.5); glvertex2f(-0.5, 0.0); glvertex2f(0.0, 0.0); glvertex2f(0.0, 0.0); glvertex2f(0.5, 0.0); glvertex2f(0.0, -0.5); glend(); glflush(); 이경우는리본의아래쪽과위쪽을두개의삼각형으로나누고 GL_TRIANGLES 모드로그리면된다. 볼록한두 개의다각형이그려지며둘다다각형조건에적합하다. 그림 6-19 다각형 3 번째조건은다각형을구성하는모든정점이같은평면에소속되어야한다는것이다. 다음두개의사각형을보 자. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 103
그림 6-20 평면위의정점 2차원화면상에서이두도형의상태를정확하게그리는것은사실무척어려운일이어서약간의상상력이필요하다. 왼쪽사각형은 A4 용지를책상위에반듯하게놓은모양이며용지의꼭지점 4면이책상이라는평면에모두소속되어있는상태이다. 이런도형은적법한다각형으로인정된다. 오른쪽사각형은 A4 용지를책상에놓은후오른쪽아래귀퉁이를위쪽으로약간치켜든상태이다. 한쪽이하늘위로솟아올랐으므로사각형의 4점이모두책상면에소속되지않았다. OpenGL은이런다각형을인정하지않으며제대로그려내지도못한다. 좀더심하게꼬아서뫼비우스의띠처럼비틀어놓으면어디가앞이고어디가뒤인지도헷갈릴것인다. 4각형, 6각형, 8각형등얼마든지많은꼭지점을가지는다각형을정의할수는있다. 그러나반드시모든정점은한면에속해야한다. 위예에서보다시피사각형은항상이조건을만족시키지못한다. 반면삼각형은어떤경우라도한평면에속한다는특징이있다. 왜그런지차원을낮추어생각해보자. 두개의점은무조건 1차원직선에속하지만점이 3개로늘어나면세점이나란히있는특수한경우를제외하고는한선분에속할수없다. 그림 6-21 정점과선분 이제이이론을한차원높여생각해보면삼각형과사각형의특징도분명해진다. 점 3 개는어떤위치에있더라 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 104
도이들을모두포괄하는하나의평면을정의할수있다. 그러나점이하나더늘어나 4개가되면이점들이한평면에속하지않는경우가더많아지며일반적으로같은평면에속하기어렵다. 손가락 3개를편상태에서세손가락을모두책상에붙이는것은언제나가능하지만손가락 4개는그렇지않다는것을생각해보자. 사각형도조건만맞추면다각형이될수있으며삼각형보다처리속도가빠르지만반드시조건을지켜야한다. 이런이유로 3차원그래픽을구성하는기본단위는대부분의경우삼각형이다. 아무리복잡한물체도삼각형의조합으로표현할수있다. 사각형은삼각형 2개를붙이면간단하게정의된다. 참고로모바일환경의 OpenGL ES 는사각형을아예인정하지않으며무조건삼각형만가능하다. OpenGL이다각형에대해이런까다로운제한을두는이유는그래야속도가빠르기때문이다. 이런저런조건들다고려해서다각형을그리자면너무복잡해지고계산양도많아진다. 원자적인다각형이단순해야더효율적이고빠른알고리즘을적용할수있으며하드웨어의도움도받을수있다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 105
6.6. 방위지시계 (Bearing Pointer) EHSI 에서 Bearing Pointer 는오른쪽그림과같이 Display 된다. 그림 6-22 방위지시계 Bearing Pointer 를 Display 하기위한코드는아래와같다. #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" void DoDisplay() glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 1.0f); glbegin(gl_triangles); // BEARING POINTER ARROW glvertex2f(-7,136); glvertex2f(7,136); glvertex2f(0,155); glend(); gllinewidth(4.0f); glbegin(gl_lines); // BEARING POINTER glvertex2f(0,-106); glvertex2f(0,-136); glvertex2f(0,106); glvertex2f(0,148); glend(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 106
glflush(); void main() glutcreatewindow( HSI"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-10 방위지시계 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 107
6.7. 러버라인 (Lubber Line) EHSI 에서 Lubber Line 은오른쪽그림과같이 Display 된다. 러버라인 (Lubber Line) 은항공기의전후방향을표시한눈금으로나침반의테두리밖에붙어있다. 그림 6-23 러버라인 (Lubber Line) Lubber Line 을 Display 하기위한코드는아래와같다. #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" void DoDisplay() glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 1.0f); glrectf(-1.0, 130.0,1,148); // LUBBER LINE for(int i = 0; i < 17 ; i++) glrotatef(-5, 0.0, 0.0, 1.0); glrectf(-1.0, 134.0,1,140); glrotatef(-5, 0.0, 0.0, 1.0); glrectf(-1.5, 130.0,1.5,140); glrotatef(-5, 0.0, 0.0, 1.0); glrectf(-1.0, 134.0,1,140); glrotatef(-10, 0.0, 0.0, 1.0); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 108
glrectf(-1.0, 134.0,1,140); for(int j = 0; j < 17 ; j++) glrotatef(-5, 0.0, 0.0, 1.0); glrectf(-1.5, 130.0,1.5,140); glrotatef(-5, 0.0, 0.0, 1.0); glrectf(-1.0, 134.0,1,140); glrotatef(-5, 0.0, 0.0, 1.0); glrectf(-1.0, -130.0,1,-148); glflush(); void main() glutcreatewindow( HSI"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-11 러버라인 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 109
6.8. 코스방향제어 (Course Arrow Control Box) EHSI 에서 Course Arrow Control Box 는오른쪽그림과같이 Display 된다. 그림 6-24 코스방향제어 Course Arrow Coontrol Box 를 Display 하기위한코드는아래와같다. #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" void DoDisplay() glenable(gl_map1_vertex_3); glenable(gl_blend); glblendfunc(gl_src_alpha,gl_one_minus_src_alpha); glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glenable(gl_line_smooth); glcolor3f(0.0f, 1.0f, 1.0f); CourseArrowSet(); // COURSE ARROW CONTROLL BOX glcolor3f(1.0f, 1.0f, 0.0f); HeadingMarkerSet(); glutswapbuffers(); void main() glutinitdisplaymode(glut_double GLUT_RGBA); glutinitwindowsize(576, 576); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 110
glutcreatewindow("mfd"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-12 코스방향제어 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 111
6.9. 고정표지 (Fixed Marker) EHSI 에서 Fixed Marker 는오른쪽그림과같이 Display 된다. 그림 6-25 고정표지 (Fixed Marker) Fixed Marker 를 Display 하기위한코드는아래와같다. #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" #include <gl/glut.h> void DoDisplay() glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 1.0f); glbegin(gl_triangles); // FIXED MARKER RIGHT glvertex2f(144,0); glvertex2f(154,5); glvertex2f(154,-5); glend(); glbegin(gl_triangles); // FIXED MARKER LEFT glvertex2f(-144,0); glvertex2f(-154,5); glvertex2f(-154,-5); glend(); glpushmatrix(); glrotatef(45,0.0, 0.0, 1.0); // FIXED MARKER LEFT_BOTTOM 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 112
glbegin(gl_triangles); glvertex2f(-144,0); glvertex2f(-154,5); glvertex2f(-154,-5); glend(); glrotatef(-90,0.0, 0.0, 1.0); // FIXED MARKER LEFT_TOP glbegin(gl_triangles); glvertex2f(-144,0); glvertex2f(-154,5); glvertex2f(-154,-5); glend(); glrotatef(90, 0.0, 0.0, 1.0); // FIXED MARKER RIGHT_TOP glbegin(gl_triangles); glvertex2f(144,0); glvertex2f(154,5); glvertex2f(154,-5); glend(); glrotatef(-90, 0.0, 0.0, 1.0); // FIXED MARKER RIGHT_BOTTOM glbegin(gl_triangles); glvertex2f(144,0); glvertex2f(154,5); glvertex2f(154,-5); glend(); glpopmatrix(); glflush(); void main() glutcreatewindow( HSI"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-13 고정표지 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 113
6.10. 각도 (Degree) EHSI 에서 Degree 는오른쪽그림과같이 Display 된다. 그림 6-26 각도 (Degree) Degree 를 Display 하기위한코드는아래와같다. #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" float CircleReverse = 0; void DoDisplay() glenable(gl_map1_vertex_3); glenable(gl_blend); glblendfunc(gl_src_alpha,gl_one_minus_src_alpha); glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glenable(gl_line_smooth); glcolor3f(1.0f,1.0f,1.0f); Degree(-1*CircleReverse); glutswapbuffers(); void main() glutinitdisplaymode(glut_double GLUT_RGBA); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 114
glutinitwindowsize(576, 576); glutcreatewindow("mfd"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-14 각도 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 115
6.11. 기타정보 EHSI 에서방위각, 모드등의기타정보는오른쪽그림과같이 Display 된다. 그림 6-27 기타정보 기타 EHSI 정보를 Display 하기위한코드는아래와같다. #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" #include "main.h" float CircleReverse = 0; void DoDisplay() glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glenable(gl_map1_vertex_3); glenable(gl_blend); glblendfunc(gl_src_alpha,gl_one_minus_src_alpha); glpushmatrix(); glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glenable(gl_line_smooth); gllinewidth(1.0f); glcolor3f(1.0f,1.0f,1.0f); glenable( GL_POINT_SMOOTH); CircleWindow(-1*CircleReverse); glcolor3f(0.0f, 1.0f, 1.0f); Nav(); CourseEng(); RangeIndicator(); glcolor3f(0.0f, 1.0f, 1.0f); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 116
TimeDestination(); glpopmatrix(); glutswapbuffers(); void main() glutinitdisplaymode(glut_double GLUT_RGBA); glutinitwindowsize(576, 576); glutcreatewindow("mfd"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-15 기타정보 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 117
6.12. 전자식수평자세지시계 (EHSI) 전자식수평자세지시계 (EHSI : Electronic Horizontal Situation Indicator) 는조종사가방향을찾는비행에서수행해야할적절한변화를보여주는전기적비행과항법계기이다지금까지 EHSI를구성하는요소를각각구현하였다. 각구성요소를모두종합하여컴파일하면아래와같이 Display 된다.. 그림 6-28 전자식수평자세지시계 (EHSI) GLUT 를이용한 EHSI Project 를 Display 하기위한코드는아래와같다 #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 118
float Heading_Rot = 0.0f; float BearingReverse = 53; float CircleReverse = 0; float ArrowReverse = 0; void EHSI() glenable(gl_line_smooth); gllinewidth(1.0f); glcolor3f(1.0f,1.0f,1.0f); glenable( GL_POINT_SMOOTH); Degree(-1*CircleReverse); FixedMarker();// FIXED MARKER CircleWindow(-1*CircleReverse); glcolor3f(0.0f, 1.0f, 1.0f); Nav();// MODE CourseEng(); CourseArrow(ArrowReverse); if((int)arrowreverse==-1) ArrowReverse=359; else if((int)arrowreverse==360) ArrowReverse=0; else if((int)circlereverse==-1) CircleReverse=359; else if((int)circlereverse==360) CircleReverse=0; glpointsize(1.0f); RangeIndicator(); glcolor3f(0.0f, 1.0f, 1.0f); TimeDestination(); glcolor3f(0.0f, 1.0f, 1.0f); CourseArrowSet(); glcolor3f(1.0f, 1.0f, 0.0f); HeadingMarkerSet(); glcolor3f(1.0f, 1.0f, 0.0f); AirPlane(); glcolor3f(0.0f, 1.0f, 1.0f); glpushmatrix(); glrotatef(-arrowreverse, 0.0, 0.0, 1.0); CourseArrowShape(); glcolor3f(1.0f, 1.0f, 1.0f); glpointsize(7.0f); CourseDeviationScale(); ToFromArrow(); glpopmatrix(); glpushmatrix(); glrotatef(heading_rot, 0.0, 0.0, 1.0); glcolor3f(1.0f, 1.0f, 0.0f);// HEADING MARKER HeadingMarker(); glpopmatrix(); glcolor3f(1.0f, 1.0f, 1.0f); glpushmatrix(); line(); glpopmatrix(); glpushmatrix(); glrotatef(-bearingreverse, 0.0, 0.0, 1.0); BearingPointer(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 119
glpopmatrix(); glpushmatrix(); glscalef(200.0f/254.0f,200.0f/254.0f,0.0f); gltranslatef(220.0f,210.0f,0.0f); //MFDSizeButton(down[HSI],HSI); glpopmatrix(); glpushmatrix(); glscalef(200.0f/254.0f,200.0f/254.0f,0.0f); gltranslatef(220.0f,-210.0f,0.0f); //MFDResizeButton(1); glpopmatrix(); gldisable(gl_line_smooth); void DoDisplay() glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glenable(gl_map1_vertex_3); glenable(gl_blend); glblendfunc(gl_src_alpha,gl_one_minus_src_alpha); glpushmatrix(); glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); EHSI(); glpopmatrix(); glutswapbuffers(); void main() glutinitdisplaymode(glut_double GLUT_RGBA); glutinitwindowsize(576, 576); glutcreatewindow("mfd"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-16 전자식수평자세지시계 (EHSI) 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 120
6.13. 블랜딩 화면에그려진그림은색상버퍼라는메모리에저장된다. 그림이이미그려져있는상태에서같은위치에다른그림을그리면새그림을메모리에기록하므로이전에그려져있던그림은덮여서지워진다. 이당연한현상도블랜딩모드를변경하면달라질수있다. 블랜딩은색상버퍼에이미기록되어있는값과새로그려지는값의논리연산방법을지정한다. 다른프로그래밍언어에서 ROP 모드 (Raster Operation) 라고흔히부르는연산이되그보다는훨씬더상세하다. 디폴트모드가단순한복사이므로이전그림이지워지지만다른모드를사용하면두값을논리적으로연산한결과를써넣음으로써특이한효과를낼수있다. 블랜딩기능을사용하라면다음명령으로이기능을켜야한다. glenable(gl_blend); 블랜딩은색상버퍼에이미기록되어있는값 D 와새로기록되는값 S 와의연산을정의한다. 연산방법은다음 두함수로지정한다. void glblendfunc(glenum sfactor, GLenum dfactor); void glblendequation(glenum mode); sfactor 와 dfactor 는 S 색상과 D 색상에각각적용할연산식을정의하며 mode 는두연산결과를합칠방법을정의 한다. 모드에따른연산식은다음과같다. 디폴트는두연산식을더하는 GL_FUNC_ADD 이다. 표 6-2 블랜딩모드 모드 연산식 GL_FUNC_ADD S*SF + D*DF. 이모드가디폴트이다. GL_FUNC_SUBTRACT GL_FUNC_REVERSE_SUBTRACT GL_MIN GL_MAX S*SF - D*DF D*DF -S*SF S*SF, D*DF 중작은값 S*SF, D*DF 중큰값 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 121
S 와 D 에적용되는연산식의종류는다음과같다. 이해를돕기위해잘사용되지않는일부항을생략했는데더 정확한식은레퍼런스를보기바란다. 표 6-3 블랜딩모드연산식 연산식 색상 (FR, FG, FB, FA) GL_ZERO (0,0,0,0) GL_ONE (1,1,1,1) GL_SRC_COLOR GL_ONE_MINUS_SRC_COLOR GL_DST_COLOR GL_ONE_MINUS_DST_COLOR GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA GL_DST_ALPHA GL_ONE_MINUS_DST_ALPHA GL_CONSTANT_COLOR GL_ONE_MINUS_CONSTANT_COLOR GL_CONSTANT_ALPHA GL_ONE_MINUS_CONSTANT_ALPHA GL_SRC_ALPHA_SATURATE (RS, GS, BS, AS) (1-RS, 1-GS, 1-BS, 1-AS) (RD, GD, BD, AD) (1-RD, 1-GD, 1-BD, 1-AD) (AS, AS, AS, AS) (1-AS, 1-AS, 1-AS, 1-AS) (AD, AD, AD, AD) (1-AD, 1-AD, 1-AD, 1-AD) (RC, GC, BC, AC) (1-RC, 1-GC, 1-BC, 1-AC) (AC, AC, AC, AC) (1-AC, 1-AC, 1-AC, 1-AC) (i,i,i,1) i= min(as, 1-AD) 연산식에의해 R, G, B, A 색상요소각각에곱해지는 FR, FG, FB, FA 함수가정의되고이함수가각색상요소에 적용됨으로써중간식이생성되며두중간식을연산하여최종색상을도출한다. 색상요소가아닌상수와도연산 을하는데이때사용할상수는다음함수로지정한다. void glblendcolor(glclampf red, GLclampf green, GLclampf blue, GLclampf alpha); 디폴트상수는 (0,0,0,0) 인검정색이다. 다음함수는좀더상세한연산방법을지정한다. GLBlendFunc 는 RGB 색 상요소와알파요소를같이연산하는데비해이함수는두요소에대해각각다른블렌딩함수를지정한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 122
void glblendfuncseparate(glenum srcrgb, GLenum dstrgb, GLenum srcalpha, GLenum dstalpha); void glblendequationseparate(glenum modergb, GLenum modealpha); 지정가능한연산의종류는동일하다. 계산식이좀더복잡해지지만대신더다양한기교를부릴수있다. 블랜 딩은설명만으로이해하기는어려우므로예제를분석해보자. Blend #include <gl/glut.h> #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" float Heading_Rot = 0.0f; float BearingReverse = 53; float CircleReverse = 0; float ArrowReverse = 0; void EHSI() glenable(gl_line_smooth); gllinewidth(1.0f); glcolor3f(1.0f,1.0f,1.0f); glenable( GL_POINT_SMOOTH); Degree(-1*CircleReverse); FixedMarker();// FIXED MARKER CircleWindow(-1*CircleReverse); glcolor3f(0.0f, 1.0f, 1.0f); Nav();// MODE CourseEng(); CourseArrow(ArrowReverse); if((int)arrowreverse==-1) ArrowReverse=359; else if((int)arrowreverse==360) ArrowReverse=0; else if((int)circlereverse==-1) CircleReverse=359; else if((int)circlereverse==360) CircleReverse=0; glpointsize(1.0f); RangeIndicator(); glcolor3f(0.0f, 1.0f, 1.0f); TimeDestination(); glcolor3f(0.0f, 1.0f, 1.0f); CourseArrowSet(); glcolor3f(1.0f, 1.0f, 0.0f); HeadingMarkerSet(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 123
glcolor3f(1.0f, 1.0f, 0.0f); AirPlane(); glcolor3f(0.0f, 1.0f, 1.0f); glpushmatrix(); glrotatef(-arrowreverse, 0.0, 0.0, 1.0); CourseArrowShape(); glcolor3f(1.0f, 1.0f, 1.0f); glpointsize(7.0f); CourseDeviationScale(); ToFromArrow(); glpopmatrix(); glpushmatrix(); glrotatef(heading_rot, 0.0, 0.0, 1.0); glcolor3f(1.0f, 1.0f, 0.0f);// HEADING MARKER HeadingMarker(); glpopmatrix(); glcolor3f(1.0f, 1.0f, 1.0f); glpushmatrix(); line(); glpopmatrix(); glpushmatrix(); glrotatef(-bearingreverse, 0.0, 0.0, 1.0); BearingPointer(); glpopmatrix(); glpushmatrix(); glscalef(200.0f/254.0f,200.0f/254.0f,0.0f); gltranslatef(220.0f,210.0f,0.0f); //MFDSizeButton(down[HSI],HSI); glpopmatrix(); glpushmatrix(); glscalef(200.0f/254.0f,200.0f/254.0f,0.0f); gltranslatef(220.0f,-210.0f,0.0f); //MFDResizeButton(1); glpopmatrix(); gldisable(gl_line_smooth); void DoDisplay() glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glenable(gl_map1_vertex_3); glenable(gl_blend); glblendfunc(gl_src_color,gl_one_minus_src_color); glpushmatrix(); glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); EHSI(); glpopmatrix(); glutswapbuffers(); void main() glutinitdisplaymode(glut_double GLUT_RGBA); glutinitwindowsize(576, 576); glutcreatewindow("mfd"); glutdisplayfunc(dodisplay); glutmainloop(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 124
코드 6-17 블랜딩 glblendfunc 의설정에따라아래와같은결과를얻을수있다. 그림 6-29 블랜딩적용전 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 125
그림 6-30 블랜딩적용후 이예제에서반투명출력에사용한블랜드연산식은다음과같다. glblendfunc(gl_src_alpha, GL_ONE_MINUS_SRC_ALPHA); 삼각형의알파값이 0.4라고했을때 GL_SRC_ALPHA의블랜딩함수는 (AS, AS, AS, AS) 이다. 그래서 S의각색상요소에 0.4가곱해진다. GL_ONE_MINUS_SRC_ALPHA의블랜딩함수는모두 1-AS이므로 D의각색상요소에 0.6 이곱해진다. 두연산결과를연산하는모드는디폴트인 GL_FUNC_ADD이므로두값을더해최종색상을결정한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 126
(0.4 * 1 + 0.6 * 0, 0.4 * 0 + 0.6 * 0, 0.4 * 0 + 0.6 * 1, 0.4 * 0.4 + 0.6 * 0.6) (0.4 * (1,0,0,0.4) + 0.6 * (0,0,1,0.6)) 0.4 * 빨간색 + 0.6 * 파란색 수식으로표현하면복잡해보이는데말로설명하면 S 색 40%, D 색 60% 를섞어서새로기록한다는뜻이다. 그래 서두색상이반쯤섞여서출력되며뒤쪽색상이적당히비쳐보이는것이다. 불투명모드일때는다음블랜드 연산식을사용한다. glblendfunc(gl_one, GL_ZERO); 이식은아주쉽다. S의모든색상요소에 1을곱한다는것은곧 S의색상을그대로유지한다는뜻이고 D의모든색상요소에 0을곱한다는것은 D의색상을완전히무시한다는뜻이다. 그러므로 D 색상은 S에덮여서안보이게되는것이다. 블랜딩모드는응용의묘미가있는기술이다. 연산식을잘조합하며유리창에흐릿하게비치는상태나거울에반사된모양을그릴수있다. 정확하게원하는효과를내기위해서는많은연습과테스트가필요하다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 127
6.14. 안티알리아싱 컴퓨터화면은디지털이어서해상도가웬만큼높아도실세계의장면들보다는자연스럽지못하다. 특히색상경계가뚜렷할수록경계면이어색해서이질감이더해보인다. 디지털화면에서나타나는계단현상등을알리아스라고하며이런현상을제거또는감소시키는기술을안티알리아싱 (Anti Aliasing) 이라고한다. 알리아스는여러가지원인으로인해발생하는데너무뚜렷한색상차가주된원인이다. 알리아스를제거하려면두색상의경계면에중간색을삽입하는기법이흔히사용된다. 예를들어흰색과검정색사이에회색을단계적으로삽입하는식이다. 이기능은블랜딩연산을사용하므로블랜딩기능을켜야한다. 그리고다음함수로점, 선, 다각형에대해안티알리아싱을적용한다. glenable(gl_point_smooth); glenable(gl_line_smooth); glenable(gl_polygon_smooth); 블랜딩을켜고알리아싱기능을켜놓으면 OpenGL이알아서알리아스를제거해준다. 물론추가연산을해야하므로시간은좀더걸린다. 다각형에대한안티알리아싱은일부플랫폼에서는제대로지원되지않는다. 컴퓨터의세계에서속도와품질은항상반비례관계에있다. 속도를내려면품질을희생해야하고고품질을얻으려면시간이오래걸릴수밖에없다. 둘다좋을수는없으므로개발자는둘중어떤것에더중점을둘것인지를선택해야한다. 다음함수는 OpenGL 라이브러리에게무엇을더우선시할것인지힌트를제공한다. void glhint(glenum target, GLenum mode); target 은옵션조정의대상이고 mode 는옵션을어떻게조정할것인가를지정한다. 조정가능한옵션목록은다 음과같다. 의미는대부분이름으로부터쉽게알수있도록되어있다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 128
GL_FOG_HINT GL_GENERATE_MIPMAP_HINT GL_LINE_SMOOTH_HINT GL_PERSPECTIVE_CORRECTION_HINT GL_POINT_SMOOTH_HINT GL_POLYGON_SMOOTH_HINT GL_TEXTURE_COMPRESSION_HINT GL_FRAGMENT_SHADER_DERIVATIVE_HINT 각타겟에대해 mode로힌트를준다. 속도가최우선일때는 GL_FASTEST 모드를지정하고품질이중요할때는 GL_NICEST로지정한다. 어느것이나상관없다면 GL_DONT_CARE로지정하며이값이디폴트이다. 그래서별다른지정이없으면 OpenGL이지맘대로속도와품질중하나를선택한다. 힌트는강제적인명령이아니며어디까지나특정기능이어떤식으로구현되었으면좋겠다는희망사항을밝히는것뿐이어서반드시지정한대로동작한다는법은없다. 힌트를실제그리기에적용할것인가아닌가는드라이버가결정한다. 드라이버의능력이되고상황이허락한다면요청을받아줄것이고그렇지않다면무시해버린다. 다음예제는안티알리아싱과힌트기능을테스트한다. AntiAlias #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "EHSISymbol.h" float Heading_Rot = 0.0f; float BearingReverse = 53; float CircleReverse = 0; float ArrowReverse = 0; void EHSI() BOOLEAN balias; BOOLEAN bhint; balias = TRUE; 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 129
bhint = TRUE; // 안티알리아싱 on, off if (balias) glenable(gl_point_smooth); glenable(gl_line_smooth); glenable(gl_polygon_smooth); else gldisable(gl_point_smooth); gldisable(gl_line_smooth); gldisable(gl_polygon_smooth); // 고품질출력을위한힌트 glhint(gl_point_smooth_hint, bhint? GL_NICEST:GL_FASTEST); glhint(gl_line_smooth_hint, bhint? GL_NICEST:GL_FASTEST); glhint(gl_polygon_smooth_hint, bhint? GL_NICEST:GL_FASTEST); //glenable(gl_line_smooth); gllinewidth(1.0f); glcolor3f(1.0f,1.0f,1.0f); //glenable( GL_POINT_SMOOTH); Degree(-1*CircleReverse); FixedMarker();// FIXED MARKER CircleWindow(-1*CircleReverse); glcolor3f(0.0f, 1.0f, 1.0f); Nav();// MODE CourseEng(); CourseArrow(ArrowReverse); if((int)arrowreverse==-1) ArrowReverse=359; else if((int)arrowreverse==360) ArrowReverse=0; else if((int)circlereverse==-1) CircleReverse=359; else if((int)circlereverse==360) CircleReverse=0; glpointsize(1.0f); RangeIndicator(); glcolor3f(0.0f, 1.0f, 1.0f); TimeDestination(); glcolor3f(0.0f, 1.0f, 1.0f); CourseArrowSet(); glcolor3f(1.0f, 1.0f, 0.0f); HeadingMarkerSet(); glcolor3f(1.0f, 1.0f, 0.0f); AirPlane(); glcolor3f(0.0f, 1.0f, 1.0f); glpushmatrix(); glrotatef(-arrowreverse, 0.0, 0.0, 1.0); CourseArrowShape(); glcolor3f(1.0f, 1.0f, 1.0f); glpointsize(7.0f); CourseDeviationScale(); ToFromArrow(); glpopmatrix(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 130
glpushmatrix(); glrotatef(heading_rot, 0.0, 0.0, 1.0); glcolor3f(1.0f, 1.0f, 0.0f);// HEADING MARKER HeadingMarker(); glpopmatrix(); glcolor3f(1.0f, 1.0f, 1.0f); glpushmatrix(); line(); glpopmatrix(); glpushmatrix(); glrotatef(-bearingreverse, 0.0, 0.0, 1.0); BearingPointer(); glpopmatrix(); glpushmatrix(); glscalef(200.0f/254.0f,200.0f/254.0f,0.0f); gltranslatef(220.0f,210.0f,0.0f); //MFDSizeButton(down[HSI],HSI); glpopmatrix(); glpushmatrix(); glscalef(200.0f/254.0f,200.0f/254.0f,0.0f); gltranslatef(220.0f,-210.0f,0.0f); //MFDResizeButton(1); glpopmatrix(); //gldisable(gl_line_smooth); void DoDisplay() glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glenable(gl_map1_vertex_3); glenable(gl_blend); glblendfunc(gl_src_alpha,gl_one_minus_src_alpha); glpushmatrix(); glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); EHSI(); glpopmatrix(); glutswapbuffers(); void main() glutinitdisplaymode(glut_double GLUT_RGBA); glutinitwindowsize(576, 576); glutcreatewindow("mfd"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-18 안티알리아싱 안티알리아싱과힌트기능을설정하여보고출력결과가어떻게달라지는지관찰해보자. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 131
그림 6-31 안티알리아싱적용전 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 132
그림 6-32 안티알리아싱적용후 안티알리아싱을적용하지않은상태에서는점이사각형으로보이고직선도계단현상이심해눈에거슬린다. 검정바탕에흰색이다보니부자연스러움이훨씬더심해보인다. 다각형은원색이라그래도덜어색하다. 안티알리아싱기능을켜면점은동그랗게보이고계단현상도훨씬덜해보인다. 돋보기로화면을확대해보면회색점이흐릿하게삽입되어있는것을볼수있다. 다각형에대해서는안티알리아싱이제대로지원되지않는다. 힌트기능도토글할수있도록해두었는데그림이너무단순해서힌트의효과를실감하기어렵다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 133
6.15. 전방향시현기 (HUD) 전방향시현기 (HUD:Head-up Display) 는조종사로하여금전방캐노피바깥의실제상황을보면서동시에각종 정보를한눈에식별할수있도록한다. HUD 에는항공기조종에필수적인고도, 속도, 자세등항법정보와무장 모드에따른표적조준을위한심볼및정보를표시한다. 그림 6-33 전방향시현기 (HUD) GLUT 를이용한 HUD Project 를 Display 하기위한코드는아래와같다 #include <gl/glut.h> #include <gl/gl.h> #include <gl/glu.h> #include <stdio.h> #include <windows.h> #include "main.h" float Alty = 0; 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 134
float Airy = 0; int Hsrx = 0; void HNum(int num); void FPM(float x, float y); void Air(float Airy); void Alt(float Alty); void EnBox(); void HNumDraw(float Alty,float Airy, int Hsrx); void HSR(int Hsrx); struct PointXY point[4]; struct UserList *listheader=null; int down[4]=0,0,0,0; int i,count; int navselect=off; // select navgation bar int cheak; // swap cheak int navtype=navselecte; // select delete type decision int usercnt=1; // save number count int set; GLbyte *gltloadtga(const char *szfilename, GLint *iwidth, GLint *iheight, GLint *icomponents, GLenum *eformat) FILE *pfile; // File pointer TGAHEADER tgaheader; // TGA file header unsigned long limagesize; // Size in bytes of image short sdepth; // Pixel depth; GLbyte *pbits = NULL; // Pointer to bits // Default/Failed values *iwidth = 0; *iheight = 0; *eformat = GL_BGR_EXT; *icomponents = GL_RGB8; // Attempt to open the fil pfile = fopen(szfilename, "rb"); if(pfile == NULL) return NULL; // Read in header (binary) fread(&tgaheader, 18/* sizeof(tgaheader)*/, 1, pfile); // Do byte swap for big vs little endian #ifdef APPLE BYTE_SWAP(tgaHeader.colorMapStart); BYTE_SWAP(tgaHeader.colorMapLength); BYTE_SWAP(tgaHeader.xstart); BYTE_SWAP(tgaHeader.ystart); BYTE_SWAP(tgaHeader.width); BYTE_SWAP(tgaHeader.height); #endif // Get width, height, and depth of texture *iwidth = tgaheader.width; 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 135
*iheight = tgaheader.height; sdepth = tgaheader.bits / 8; // Put some validity checks here. Very simply, I only understand // or care about 8, 24, or 32 bit targa's. if(tgaheader.bits!= 8 && tgaheader.bits!= 24 && tgaheader.bits!= 32) return NULL; // Calculate size of image buffer limagesize = tgaheader.width * tgaheader.height * sdepth; // Allocate memory and check for success pbits = (signed char *)malloc(limagesize * sizeof(glbyte)); if(pbits == NULL) return NULL; // Read in the bits // Check for read error. This should catch RLE or other // weird formats that I don't want to recognize if(fread(pbits, limagesize, 1, pfile)!= 1) free(pbits); return NULL; // Set OpenGL format expected switch(sdepth) case 3: // Most likely case *eformat = GL_BGR_EXT; *icomponents = GL_RGB8; break; case 4: *eformat = GL_BGRA_EXT; *icomponents = GL_RGBA8; break; case 1: *eformat = GL_LUMINANCE; *icomponents = GL_LUMINANCE8; break; ; // Done with File fclose(pfile); // Return pointer to image data return pbits; void HUD2(float Alty,float Airy,float Hsrx) GLubyte *pimage = NULL; GLint iwidth, iheight, icomponents; GLenum eformat; 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 136
// Clear the window with current clearing color glclear(gl_color_buffer_bit); // Targa's are 1 byte aligned glpixelstorei(gl_unpack_alignment, 1); // Load the TGA file, get width, height, and component/format information pimage = (unsigned char *)gltloadtga("sky.tga", &iwidth, &iheight, &icomponents, &eformat); glpixelzoom((glfloat) point[hud].endxp / (GLfloat)iWidth, (GLfloat) point[hud].endyp / (GLfloat)iHeight); // Use Window coordinates to set raster position glrasterpos2i(-254, -254); // Draw the pixmap if(pimage!= NULL) gldrawpixels(iwidth, iheight, eformat, GL_UNSIGNED_BYTE, pimage); // Don't need the image data anymore free(pimage); /* 초기설정 ( 곡선, 화면초기화 ) */ gllinewidth(2.0f); /* 선의색설정 */ glcolor3f(0.0f, 1.0f, 0.0f); gldisable(gl_line_smooth); /* Digital Air&Alt Enclosure Box */ EnBox(); /* FPM Video (x 좌표, y 좌표 ) -> 현재비행기가향하는방향 */ FPM(0.0, 0.0); /* 시저박스활성화 ( 설정된부분만 Display) */ glenable(gl_scissor_test); // glscissor(149, 80, 210, 60); if(point[hud].endxp == 288) glscissor(point[hud].startxp+80, point[hud].startyp+45, 127,33 ); else glscissor(point[hud].startxp+163, point[hud].startyp+90, 250,65 ); /* Heading Scale Reference Point ( 각도 ) */ HSR(Hsrx); // glscissor(0, 84, 508, 210); if(point[hud].endxp == 288) glscissor(point[hud].startxp, point[hud].startyp+84, point[hud].endxp,120 ); else glscissor(point[hud].startxp, point[hud].startyp+169, point[hud].endxp,223 ); /* AirSpeed Scale Mark ( 속도값 ) */ Air(Airy); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 137
/* Altitude Scale Mark ( 고도값 ) */ Alt(Alty); HNumDraw(Airy, Alty, Hsrx); /* 시저박스비활성화 */ gldisable(gl_scissor_test); #if 0 glpushmatrix(); gltranslatef(220.0f,210.0f,0.0f); MFDSizeButton(down[HUD],HUD); glpopmatrix(); glpushmatrix(); gltranslatef(220.0f,-210.0f,0.0f); MFDResizeButton(3); glpopmatrix(); gldisable(gl_line_smooth); #endif // CrossLine(); void DoDisplay() glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glenable(gl_map1_vertex_3); glenable(gl_blend); glblendfunc(gl_src_alpha,gl_one_minus_src_alpha); point[hud].startxp=0; point[hud].startyp=0; point[hud].endxp=576; point[hud].endyp=576; point[hud].type=hud; point[hud].size=large; point[hud].position=left; glpushmatrix(); glortho(-254.0f,254.0f,-254.0f,254.0f,1.0f,-1.0f); HUD2(Alty, Airy,Hsrx); glpopmatrix(); glutswapbuffers(); void main() glutinitdisplaymode(glut_double GLUT_RGBA); glutinitwindowsize(576, 576); glutcreatewindow("mfd"); glutdisplayfunc(dodisplay); glutmainloop(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 138
코드 6-19 전방향시현기 (HUD) HUD 를구현하기위해 HUD 의함수외에아래의파일이추가된다. 그림 6-34 전방향시현기 (HUD) 추가코드 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 139
6.16. 전자식수평위치방향계 (EHSD) 전자식수평위치방향계 (EHSD : Electornic Horizontal Situation Director) 는항공기위치정보를보여주는계기이다 그림 6-35 전자식수평위치방향계 (EHSD) GLUT 를이용한 HSD Project 를 Display 하기위한코드는아래와같다 #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "main.h" void HSD2(); struct PointXY point[4]; struct UserList *listheader=null; 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 140
float HSDSize = 1; float HSDd = 0; float HSDx = 0; float HSDy = 0; float HSDr = 0; int HSDROUT = 0; int HSDBARE = 0; int HSDAA = 0; int HSDAG = 0; int TANK = 0; GLint cout=0; void HSD2() if(point[hsd].endyp == 576) glenable(gl_line_smooth); HSDSelectArea(HSDx,HSDy, HSDr); glcolor3f(1.0f,1.0f,1.0f); HSDScale(); glpushmatrix(); gltranslatef(0.0f, -144.0f,0.0f); HSDRangeRingTics(); HSDMagSens(HSDr); HSDRoute(HSDx, HSDy, HSDr); HSDOwnShip(); glpopmatrix(); HSDCusor(); #if 0 glpushmatrix(); glscalef(288.0f/254.0f,288.0f/254.0f,0.0f); gltranslatef(220.0f,210.0f,0.0f); MFDSizeButton(down[HSD],HSD); glpopmatrix(); glpushmatrix(); glscalef(288.0f/254.0f,288.0f/254.0f,0.0f); gltranslatef(220.0f,-210.0f,0.0f); MFDResizeButton(0); glpopmatrix(); #endif gldisable(gl_line_smooth); #if 0 glpushmatrix(); glscalef(288.0f/254.0f,288.0f/254.0f,0.0f); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 141
CrossLine(); glpopmatrix(); #endif void DoDisplay() glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glenable(gl_map1_vertex_3); glenable(gl_blend); glblendfunc(gl_src_alpha,gl_one_minus_src_alpha); point[hsd].startxp=864; point[hsd].startyp=0; point[hsd].endxp=576; point[hsd].endyp=576; point[hsd].type=hsd; point[hsd].size=large; point[hsd].position=right; glpushmatrix(); glortho(-288.0f,288.0f,-288.0f,288.0f,1.0f,-1.0f); HSD2(); glpopmatrix(); glutswapbuffers(); void main() glutinitdisplaymode(glut_double GLUT_RGBA); glutinitwindowsize(576, 576); glutcreatewindow("mfd"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-20 전자식수평위치방향계 HSD 를구현하기위해 HSD 의함수외에아래의파일이추가된다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 142
그림 6-36 전자식수평위치방향계추가코드 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 143
6.17. 전자식자세방향지시계 (EADI) 전자식자세방향지시계 (EADI : Electronic Attitude Director Indicator) 는항공기의상승각 후퇴각 회전각등전후좌 우의수평상태를알려주는계기로, 항공기의핵심계기이다. 그림 6-37 전자식자세방향지시계 (EADI) GLUT 를이용한 EADI Project 를 Display 하기위한코드는아래와같다 #include <glut.h> #include <gl.h> #include <glu.h> #include <stdio.h> #include <windows.h> #include "main.h" struct PointXY point[4]; struct UserList *listheader=null; 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 144
extern float Pitch; extern float Roll; extern int mode_select; extern int cout; void PitchLadder(int xpitch, int xroll); void neddlebar(int xpitch, int xroll); void SkyLand(int xpitch, int xroll); void Rollscale(); void aircraft(); void modechange(); void EADI(void) int xpitch, xroll; if(roll>=180) Roll = Roll-360; else if(roll<=-180) Roll = Roll+360; xroll = Roll; xpitch = -Pitch; if((xpitch/1890)>0) xpitch = 630; Pitch = 630; if((xpitch/1890)<0) xpitch = -630; Pitch = -630; gllinewidth(2.0f); if(xpitch<=630 && xpitch>=-630) glpushmatrix(); SkyLand(xPitch, xroll); glcolor3f(1.0, 1.0, 1.0); PitchLadder(xPitch, xroll); glpopmatrix(); else if(xpitch>0) glpushmatrix(); glrotatef(180,0,0,1); SkyLand((xPitch-(xPitch-630)*2), xroll); glcolor3f(1.0, 1.0, 1.0); PitchLadder((xPitch-(xPitch-630)*2), xroll); glpopmatrix(); else if(xpitch<0) glpushmatrix(); glrotatef(180,0,0,1); SkyLand((xPitch-(xPitch+630)*2), xroll); glcolor3f(1.0, 1.0, 1.0); PitchLadder((xPitch-(xPitch+630)*2), xroll); glpopmatrix(); neddlebar(xpitch, xroll); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 145
glcolor3f(1.0, 1.0, 1.0); glpopmatrix(); modechange(); Rollscale(); aircraft(); glenable(gl_line_smooth); #if 0 glpushmatrix(); gltranslatef(220.0f,210.0f,0.0f); MFDSizeButton(down[ADI],ADI); glpopmatrix(); glpushmatrix(); gltranslatef(220.0f,-210.0f,0.0f); MFDResizeButton(2); glpopmatrix(); #endif gldisable(gl_line_smooth); //CrossLine(); void DoDisplay() glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glenable(gl_map1_vertex_3); glenable(gl_blend); glblendfunc(gl_src_alpha,gl_one_minus_src_alpha); glpushmatrix(); glortho(-254.0f,254.0f,-254.0f,254.0f,10.0f,-10.0f); EADI(); glpopmatrix(); glutswapbuffers(); void main() glutinitdisplaymode(glut_double GLUT_RGBA); glutinitwindowsize(576, 576); glutcreatewindow("mfd"); glutdisplayfunc(dodisplay); glutmainloop(); 코드 6-21 전자식자세방향지시계 EADI 를구현하기위해 EADI 의함수외에아래의파일이추가된다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 146
그림 6-38 전자식자세방향지시계추가코드 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 147
7. 항공기계기판설계 2 ( 윈도우프로젝트 ) 7.1. MFC 프로그램소개 마이크로소프트파운데이션클래스라이브러리 (Microsoft Foundation Class Library, MFC) 는마이크로소프트에서 만든윈도 API 를 C++ 로둘러싼라이브러리이다. 클래스들은윈도의공용컨트롤과스마트포인터를사용하는 창개체이다. MFC는 1992년 16비트윈도용마이크로소프트 C/C++ 7.0 컴파일러에서처음도입되었다. 그당시에는 C++ 이소프트웨어제품개발언어로활용되기시작하던때였다. 마이크로소프트는개발도구시장에서경쟁력을얻기위해 C++ 을활용하여 MFC를만들었다. MFC의구조는후에시맨틱사에매각된매킨토시의 TCL(Think Class Library) 에서영향을받았다. 볼랜드의터보 C++ 과터보파스칼에서는 OWL(Object Windows Library) 이란경쟁제품이있었다. 객체지향모델을더엄격하게따르고있었기때문에, OWL은한때 MFC보다인기있었다. 하지만윈도의새로운기능에대한업데이트가늦어지게되면서, 시장지배력을잃어버렸다. 그이후볼랜드는 OWL의개발을중단하고, 이를대체하는 VCL을개발하여델파이와 C++ 빌더에서사용하고있다. C++ 빌더는 MFC를라이선스받아포함하고있다. 마이크로소프트에서 MFC가만들어졌음에도많은프로그래머들에게 MFC는너무복잡했기때문에, 마이크로소프트는상용소프트웨어개발에비주얼베이직을쓰라고권장하였다. MFC와비주얼베이직의후속작으로 Windows Forms가출시되었으며 C++ 관리모드확장으로쓸수있다. 비주얼스튜디오 2005 출시와함께닷넷프레임워크의기능들을더쉬운문법으로쓸수있게되었다. 비주얼베이직을강조하면서도새버전의비주얼스튜디오에는항상 MFC 가공급되었다. 그래서많은프로그래머 들이 MFC 를사용하게되었다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 148
MFC 가처음도입되었을때마이크로소프트는기본적인 C++ 문법에메시지처리, 예외처리, 런타임처리, 동적 클래스객체생성을위한매크로를추가해 C++ 언어를확장하려했다. 이런매크로를활용한시스템은컴파일러 의타입검사를무시하므로버그를가져올수있었다. 32 비트버전의 MFC 부터이것이개선되었다. MFC 의가장큰장점은윈도 API 를객체지향적으로프로그래밍할수있다는것이다. 또한윈도의자원과연관된 형들은그들을생성한객체가죽게되면자동으로핸들을해제해준다는장점도있다. 게다가 MFC 의문서 / 뷰프 레임워크는데이터모델과유저인터페이스, 제어로직을분리한다는 MVC 디자인을자연스럽게만들어준다. 하지만 MFC 는다중운영체제를지원하지않는다는약점이있다. Mainsoft 가만든유닉스용 MFC 가있으며, 1990 년대마이크로소프트는맥 OS 용 MFC 를만들기도했지만, 계속개발하지않았다. MFC Feature Pack 을지원하여, 리본메뉴등의 UI 를 IDE 에서자동으로작성해준다. 7-1 컴파일러버전에따른 MFC 버전 컴파일러버전 MFC 버전 Microsoft C/C++ 7.0 MFC 1.0 Visual C++ 1.0 MFC 2.0 Visual C++ 1.5 MFC 2.5 Visual C++ 2.0 MFC 3.0 Visual C++ 2.1 MFC 3.1 Visual C++ 2.2 MFC 3.2 Visual C++ 4.0 MFC 4.0 Visual C++ 4.1 MFC 4.1 Visual C++ 4.2 MFC 4.2 Visual C++ 5.0 Visual C++ 6.0 Visual C++.NET 2002 Visual C++.NET 2003 Visual C++ 2005 MFC 4.21 (mfc42.dll) MFC 6.0 (mfc42.dll) MFC 7.0 (mfc70.dll) MFC 7.1 (mfc71.dll) MFC 8.0 (mfc80.dll) 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 149
Visual C++ 2008 Visual C++ 2010 MFC 9.0 (mfc90.dll) MFC 10.0 (mfc100.dll 7.2. 프로젝트생성 1) 파일 새로만들기 프로젝트 2) MFC 에서 MFC 응용프로그램 을선택하고이름을입력후확인을선택한다. 그림 7-1 MFC 프로젝트생성 3) 다음클릭한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 150
그림 7-2 MFC 응용프로그램마법사 4) 단일문서선택후마침 그림 7-3 MFC 응용프로그램종류 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 151
7.3. OpenGL 설정 1) include stdafx.h 파일을열고다음코드를입력한다. stdafx.h // Include OpenGL header files #include <gl\gl.h>// opengl32.lib #include <gl\glaux.h>// glaux.lib #include <gl\glu.h>// glu32.lib #include "math.h" #pragma comment(lib, "OPENGL32.LIB") #pragma comment(lib, "GLAUX.LIB") #pragma comment(lib, "GLU32.LIB") 코드 7-1 stdafx.h 파일설정 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 152
그림 7-4 stdafx.h 파일설정 2) view 클래스멤버함수와멤버변수명세 프로젝트명 view.h 파일을열고다음멤버변수와멤버함수를추가한다. MFDview.h // 사용자정의 public: HDCm_hDC; // GDI Device Context HGLRCm_hglRC;// Rendering Context void InitGL(); void ReSizeGLScene(GLsizei width, GLsizei height); void CopenglView::DrawGLScene(); BOOL SetPixelformat(HDC hdc); 코드 7-2 멤버변수멤버함수추가 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 153
그림 7-5 멤버변수멤버함수추가 3) 멤버함수세부내용작성 프로젝트명 view.cpp 파일을열고다음멤버함수를추가한다. MFDview.cpp BOOL CmfdView::SetPixelformat(HDC hdc) int pixelformat; PIXELFORMATDESCRIPTOR pfd = sizeof(pixelformatdescriptor), // size of this pfd 1, // default version PFD_DRAW_TO_WINDOW // support window PFD_SUPPORT_OPENGL // support OpenGL PFD_GENERIC_FORMAT 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 154
// choose best matching pixel format if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == FALSE ) //MessageBox( "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 32, // 32-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 8, // no alpha buffer 0, // shift bit ignored 8, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 16, // 16-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored ; // set pixel format to device context if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE) //MessageBox( "SetPixelFormat failed", "Error", MB_OK); return FALSE; return TRUE; void CmfdView::InitGL() glclearcolor(0.0f, 0.0f, 0.0f, 0.5f); glcleardepth(1.0f); glenable(gl_depth_test); gldepthfunc(gl_lequal); glhint(gl_perspective_correction_hint, GL_NICEST); void CmfdView::ReSizeGLScene(GLsizei width, GLsizei height) // don't want a divede by zero if (height==0) height=1; // reset the viewport to new dimensions glviewport(0,0,width,height); glmatrixmode(gl_projection); glloadidentity(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 155
// calculate aspect ratio of the window gluperspective(45.0f,(glfloat)width/(glfloat)height,0.1f,1000.0f); // set modelvew matrix glmatrixmode(gl_modelview); glloadidentity(); void CmfdView::DrawGLScene() // clear screen and depth buffer glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glloadidentity(); // camera view configuration glulookat(0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); // draw EHSI(); // swap buffer SwapBuffers(m_hDC); 코드 7-3 MFC OpenGL 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 156
그림 7-6 MFC OpenGL 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 157
7.4. 메시지핸들러추가 1) OnCreate 클래스뷰 C 프로젝트명 View 오른쪽버튼클릭 속성 메시지 WM_CREATE ADD CREATE 를추가한다. 그림 7-7 메시지핸들러추가 - 1 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 158
그림 7-8 메시지핸들러추가 - 2 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 159
그림 7-9 메시지핸들러추가 - 3 클릭시새로운코드가생성되는데아래코드를삽입한다. MFDview.cpp m_hdc = GetDC()->m_hDC ; // set the pixel format if(!setpixelformat(m_hdc)) return -1; // create rendering context and make it current m_hglrc = wglcreatecontext(m_hdc); wglmakecurrent(m_hdc,m_hglrc); InitGL(); 코드 7-4 메시지핸들러추가 - 1 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 160
그림 7-10 메시지핸들러추가 - 4 2)OnDestroy 같은방법으로 WM_DESTROY 를생성해아래코드를입력한다. MFDview.cpp // deselect rendering context and delete it wglmakecurrent(m_hdc, NULL); wgldeletecontext(m_hglrc) 코드 7-5 메시지핸들러추가 - 2 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 161
그림 7-11 메시지핸들러추가 - 5 3)OnSize 같은방법으로 WM_SIZE 를생성해아래코드를입력한다. MFDview.cpp ReSizeGLScene(cx, cy); 코드 7-6 메시지핸들러추가 - 3 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 162
그림 7-12 메시지핸들러추가 - 6 4)OnDraw OnDraw 는이미생성되어있으므로다음코드만삽입한다. MFDview.cpp DrawGLScene(); 코드 7-7 메시지핸들러추가 - 4 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 163
그림 7-13 메시지핸들러추가 - 7 여기까지작성된코드를컴파일하면아래와같이 Display 된다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 164
그림 7-14 메시지핸들러적용된 EHSI 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 165
7.5. 점 MFD 의 EHSI 계기판을구성하는요소중점을 display 한다. 그림 7-15 점 점을 Display 하기위한코드는아래와같다. MFDview.cpp BOOL CmfdView::SetPixelformat(HDC hdc) int pixelformat; PIXELFORMATDESCRIPTOR pfd = sizeof(pixelformatdescriptor), // size of this pfd 1, // default version PFD_DRAW_TO_WINDOW // support window PFD_SUPPORT_OPENGL // support OpenGL PFD_GENERIC_FORMAT 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 166
// choose best matching pixel format if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == FALSE ) //MessageBox( "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 32, // 32-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 8, // no alpha buffer 0, // shift bit ignored 8, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 16, // 16-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored ; // set pixel format to device context if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE) //MessageBox( "SetPixelFormat failed", "Error", MB_OK); return FALSE; return TRUE; void CmfdView::InitGL() glclearcolor(0.0f, 0.0f, 0.0f, 0.5f); glcleardepth(1.0f); glenable(gl_depth_test); gldepthfunc(gl_lequal); glhint(gl_perspective_correction_hint, GL_NICEST); void CmfdView::ReSizeGLScene(GLsizei width, GLsizei height) // don't want a divede by zero if (height==0) height=1; // reset the viewport to new dimensions glviewport(0,0,width,height); glmatrixmode(gl_projection); glloadidentity(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 167
// calculate aspect ratio of the window gluperspective(45.0f,(glfloat)width/(glfloat)height,0.1f,1000.0f); // set modelvew matrix glmatrixmode(gl_modelview); glloadidentity(); void CmfdView::DrawGLScene() // clear screen and depth buffer glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glloadidentity(); // camera view configuration glulookat(0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); // draw glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 1.0f); glbegin(gl_points); // COURSE DEVIATION SCALE(DOTS) glvertex2f( -40, 0); glvertex2f( -80, 0); glvertex2f( 40, 0); glvertex2f( 80, 0); glend(); glflush(); // swap buffer SwapBuffers(m_hDC); 코드 7-8 점 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 168
7.6. 선 MFD 에서선을 display 한다. 그림 7-16 선 선을 Display 하기위한코드는아래와같다. MFDview.cpp BOOL CmfdView::SetPixelformat(HDC hdc) int pixelformat; PIXELFORMATDESCRIPTOR pfd = sizeof(pixelformatdescriptor), // size of this pfd 1, // default version PFD_DRAW_TO_WINDOW // support window 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 169
// choose best matching pixel format if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == FALSE ) //MessageBox( "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; PFD_SUPPORT_OPENGL // support OpenGL PFD_GENERIC_FORMAT PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 32, // 32-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 8, // no alpha buffer 0, // shift bit ignored 8, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 16, // 16-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored ; // set pixel format to device context if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE) //MessageBox( "SetPixelFormat failed", "Error", MB_OK); return FALSE; return TRUE; void CmfdView::InitGL() glclearcolor(0.0f, 0.0f, 0.0f, 0.5f); glcleardepth(1.0f); glenable(gl_depth_test); gldepthfunc(gl_lequal); glhint(gl_perspective_correction_hint, GL_NICEST); void CmfdView::ReSizeGLScene(GLsizei width, GLsizei height) // don't want a divede by zero if (height==0) height=1; // reset the viewport to new dimensions glviewport(0,0,width,height); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 170
glmatrixmode(gl_projection); glloadidentity(); // calculate aspect ratio of the window gluperspective(45.0f,(glfloat)width/(glfloat)height,0.1f,1000.0f); // set modelvew matrix glmatrixmode(gl_modelview); glloadidentity(); void CmfdView::DrawGLScene() // clear screen and depth buffer glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glloadidentity(); // camera view configuration glulookat(0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); // draw glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 1.0f); glbegin(gl_triangles); // ARROW glvertex2f(-7,93); glvertex2f(7,93); glvertex2f(0,115); glend(); gllinewidth(4.0f); glbegin(gl_lines); // COURSE ARROW glvertex2f(0,61); glvertex2f(0,93); glvertex2f(-80,40); glvertex2f(-80,-40); glvertex2f(0,-61); glvertex2f(0,-105); glend(); glflush(); // swap buffer SwapBuffers(m_hDC); 코드 7-9 선 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 171
7.7. 삼각형 MFD 의 EHSI 계기판을구성하는요소중삼각형을 display 한다. 그림 7-17 삼각형 삼각형을 Display 하기위한코드는아래와같다. MFDview.cpp BOOL CmfdView::SetPixelformat(HDC hdc) int pixelformat; PIXELFORMATDESCRIPTOR pfd = sizeof(pixelformatdescriptor), // size of this pfd 1, // default version PFD_DRAW_TO_WINDOW // support window 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 172
// choose best matching pixel format if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == FALSE ) //MessageBox( "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; PFD_SUPPORT_OPENGL // support OpenGL PFD_GENERIC_FORMAT PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 32, // 32-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 8, // no alpha buffer 0, // shift bit ignored 8, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 16, // 16-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored ; // set pixel format to device context if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE) //MessageBox( "SetPixelFormat failed", "Error", MB_OK); return FALSE; return TRUE; void CmfdView::InitGL() glclearcolor(0.0f, 0.0f, 0.0f, 0.5f); glcleardepth(1.0f); glenable(gl_depth_test); gldepthfunc(gl_lequal); glhint(gl_perspective_correction_hint, GL_NICEST); void CmfdView::ReSizeGLScene(GLsizei width, GLsizei height) // don't want a divede by zero if (height==0) height=1; // reset the viewport to new dimensions glviewport(0,0,width,height); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 173
glmatrixmode(gl_projection); glloadidentity(); // calculate aspect ratio of the window gluperspective(45.0f,(glfloat)width/(glfloat)height,0.1f,1000.0f); // set modelvew matrix glmatrixmode(gl_modelview); glloadidentity(); void CmfdView::DrawGLScene() // clear screen and depth buffer glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glloadidentity(); // camera view configuration glulookat(0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); // draw glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 1.0f); glbegin(gl_triangles); // TO ARROW glvertex2f(-48,40); glvertex2f(-32,40); glvertex2f(-40,55); glend(); glbegin(gl_triangles); // FROM ARROW glvertex2f(-48,-40); glvertex2f(-32,-40); glvertex2f(-40,-55); glend(); glflush(); // swap buffer SwapBuffers(m_hDC); 코드 7-10 삼각형 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 174
7.8. 사각형 MFD 의 EHSI 계기판을구성하는요소중사각형을 display 한다. 그림 7-18 사각형 사각형을 Display 하기위한코드는아래와같다. MFDview.cpp BOOL CmfdView::SetPixelformat(HDC hdc) int pixelformat; PIXELFORMATDESCRIPTOR pfd = sizeof(pixelformatdescriptor), // size of this pfd 1, // default version PFD_DRAW_TO_WINDOW // support window 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 175
// choose best matching pixel format if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == FALSE ) //MessageBox( "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; PFD_SUPPORT_OPENGL // support OpenGL PFD_GENERIC_FORMAT PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 32, // 32-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 8, // no alpha buffer 0, // shift bit ignored 8, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 16, // 16-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored ; // set pixel format to device context if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE) //MessageBox( "SetPixelFormat failed", "Error", MB_OK); return FALSE; return TRUE; void CmfdView::InitGL() glclearcolor(0.0f, 0.0f, 0.0f, 0.5f); glcleardepth(1.0f); glenable(gl_depth_test); gldepthfunc(gl_lequal); glhint(gl_perspective_correction_hint, GL_NICEST); void CmfdView::ReSizeGLScene(GLsizei width, GLsizei height) // don't want a divede by zero if (height==0) height=1; // reset the viewport to new dimensions glviewport(0,0,width,height); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 176
glmatrixmode(gl_projection); glloadidentity(); // calculate aspect ratio of the window gluperspective(45.0f,(glfloat)width/(glfloat)height,0.1f,1000.0f); // set modelvew matrix glmatrixmode(gl_modelview); glloadidentity(); void CmfdView::DrawGLScene() // clear screen and depth buffer glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glloadidentity(); // camera view configuration glulookat(0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); // draw glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 0.0f); glrectf(-2.0, 144.0,-8,154); glrectf(2.0, 144.0,8,154); glflush(); // swap buffer SwapBuffers(m_hDC); 코드 7-11 사각형 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 177
7.9. 다각형 MFD 의 EHSI 계기판을구성하는요소중다각형을 display 한다. 그림 7-19 다각형 다각형을 Display 하기위한코드는아래와같다. MFDview.cpp BOOL CmfdView::SetPixelformat(HDC hdc) int pixelformat; PIXELFORMATDESCRIPTOR pfd = sizeof(pixelformatdescriptor), // size of this pfd 1, // default version PFD_DRAW_TO_WINDOW // support window 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 178
// choose best matching pixel format if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == FALSE ) //MessageBox( "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; PFD_SUPPORT_OPENGL // support OpenGL PFD_GENERIC_FORMAT PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 32, // 32-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 8, // no alpha buffer 0, // shift bit ignored 8, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 16, // 16-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored ; // set pixel format to device context if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE) //MessageBox( "SetPixelFormat failed", "Error", MB_OK); return FALSE; return TRUE; void CmfdView::InitGL() glclearcolor(0.0f, 0.0f, 0.0f, 0.5f); glcleardepth(1.0f); glenable(gl_depth_test); gldepthfunc(gl_lequal); glhint(gl_perspective_correction_hint, GL_NICEST); void CmfdView::ReSizeGLScene(GLsizei width, GLsizei height) // don't want a divede by zero if (height==0) height=1; // reset the viewport to new dimensions glviewport(0,0,width,height); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 179
glmatrixmode(gl_projection); glloadidentity(); // calculate aspect ratio of the window gluperspective(45.0f,(glfloat)width/(glfloat)height,0.1f,1000.0f); // set modelvew matrix glmatrixmode(gl_modelview); glloadidentity(); void CmfdView::DrawGLScene() // clear screen and depth buffer glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glloadidentity(); // camera view configuration glulookat(0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); // draw glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 0.0f); glbegin(gl_line_strip); // 비행기 glvertex2f(0,30); glvertex2f(6,12); glvertex2f(15,7); glvertex2f(15,4); glvertex2f(9,2); glvertex2f(8,-1); glvertex2f(25,-12); glvertex2f(25,-18); glvertex2f(12,-22); glvertex2f(12,-25); glvertex2f(8,-27); glvertex2f(6,-30); glvertex2f(2,-30); glvertex2f(1,-27); glvertex2f(-1,-27); glvertex2f(-2,-30); glvertex2f(-6,-30); glvertex2f(-8,-27); glvertex2f(-12,-25); glvertex2f(-12,-22); glvertex2f(-25,-18); glvertex2f(-25,-12); glvertex2f(-8,-1); glvertex2f(-9,2); glvertex2f(-15,4); glvertex2f(-15,7); glvertex2f(-6,12); glvertex2f(0,30); glend(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 180
glflush(); // swap buffer SwapBuffers(m_hDC); 코드 7-12 다각형 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 181
7.10. 방위지시계 (Bearing Pointer) MFD 의 EHSI 계기판을구성하는요소중방위지시계 (Bearing Pointer) 를 display 한다. 그림 7-20 방위지시계 Bearing Pointer 를 Display 하기위한코드는아래와같다. MFDview.cpp BOOL CmfdView::SetPixelformat(HDC hdc) int pixelformat; PIXELFORMATDESCRIPTOR pfd = sizeof(pixelformatdescriptor), // size of this pfd 1, // default version PFD_DRAW_TO_WINDOW // support window PFD_SUPPORT_OPENGL // support OpenGL PFD_GENERIC_FORMAT 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 182
// choose best matching pixel format if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == FALSE ) //MessageBox( "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 32, // 32-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 8, // no alpha buffer 0, // shift bit ignored 8, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 16, // 16-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored ; // set pixel format to device context if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE) //MessageBox( "SetPixelFormat failed", "Error", MB_OK); return FALSE; return TRUE; void CmfdView::InitGL() glclearcolor(0.0f, 0.0f, 0.0f, 0.5f); glcleardepth(1.0f); glenable(gl_depth_test); gldepthfunc(gl_lequal); glhint(gl_perspective_correction_hint, GL_NICEST); void CmfdView::ReSizeGLScene(GLsizei width, GLsizei height) // don't want a divede by zero if (height==0) height=1; // reset the viewport to new dimensions glviewport(0,0,width,height); glmatrixmode(gl_projection); glloadidentity(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 183
// calculate aspect ratio of the window gluperspective(45.0f,(glfloat)width/(glfloat)height,0.1f,1000.0f); // set modelvew matrix glmatrixmode(gl_modelview); glloadidentity(); void CmfdView::DrawGLScene() // clear screen and depth buffer glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glloadidentity(); // camera view configuration glulookat(0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); // draw glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 1.0f); glrectf(-1.0, 130.0,1,148); // LUBBER LINE for(int i = 0; i < 17 ; i++) glrotatef(-5, 0.0, 0.0, 1.0); glrectf(-1.0, 134.0,1,140); glrotatef(-5, 0.0, 0.0, 1.0); glrectf(-1.5, 130.0,1.5,140); glrotatef(-5, 0.0, 0.0, 1.0); glrectf(-1.0, 134.0,1,140); glrotatef(-10, 0.0, 0.0, 1.0); glrectf(-1.0, 134.0,1,140); for(int j = 0; j < 17 ; j++) glrotatef(-5, 0.0, 0.0, 1.0); glrectf(-1.5, 130.0,1.5,140); glrotatef(-5, 0.0, 0.0, 1.0); glrectf(-1.0, 134.0,1,140); glrotatef(-5, 0.0, 0.0, 1.0); glrectf(-1.0, -130.0,1,-148); glflush(); // swap buffer SwapBuffers(m_hDC); 코드 7-13 방위지시계 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 184
7.11. 러버라인 (Lubber Line) MFD 의 EHSI 계기판을구성하는요소중러버라인 (Lubber Line) 을 display 한다. 그림 7-21 러버라인 (Lubber Line) Lubber Line 를 Display 하기위한코드는아래와같다. MFDview.cpp BOOL CmfdView::SetPixelformat(HDC hdc) int pixelformat; PIXELFORMATDESCRIPTOR pfd = sizeof(pixelformatdescriptor), // size of this pfd 1, // default version PFD_DRAW_TO_WINDOW // support window PFD_SUPPORT_OPENGL // support OpenGL PFD_GENERIC_FORMAT 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 185
// choose best matching pixel format if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == FALSE ) //MessageBox( "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 32, // 32-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 8, // no alpha buffer 0, // shift bit ignored 8, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 16, // 16-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored ; // set pixel format to device context if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE) //MessageBox( "SetPixelFormat failed", "Error", MB_OK); return FALSE; return TRUE; void CmfdView::InitGL() glclearcolor(0.0f, 0.0f, 0.0f, 0.5f); glcleardepth(1.0f); glenable(gl_depth_test); gldepthfunc(gl_lequal); glhint(gl_perspective_correction_hint, GL_NICEST); void CmfdView::ReSizeGLScene(GLsizei width, GLsizei height) // don't want a divede by zero if (height==0) height=1; // reset the viewport to new dimensions glviewport(0,0,width,height); glmatrixmode(gl_projection); glloadidentity(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 186
// calculate aspect ratio of the window gluperspective(45.0f,(glfloat)width/(glfloat)height,0.1f,1000.0f); // set modelvew matrix glmatrixmode(gl_modelview); glloadidentity(); void CmfdView::DrawGLScene() // clear screen and depth buffer glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glloadidentity(); // camera view configuration glulookat(0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); // draw glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 1.0f); glbegin(gl_triangles); // BEARING POINTER ARROW glvertex2f(-7,136); glvertex2f(7,136); glvertex2f(0,155); glend(); gllinewidth(4.0f); glbegin(gl_lines); // BEARING POINTER glvertex2f(0,-106); glvertex2f(0,-136); glvertex2f(0,106); glvertex2f(0,148); glend(); glflush(); // swap buffer SwapBuffers(m_hDC); 코드 7-14 러버라인 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 187
7.12. 코스방향제어 (Course Arrow Control Box) MFD 의 EHSI 계기판을구성하는요소중 Course Arrow Control Box 를 display 한다. 그림 7-22 코스방향제어 Fixed Marker 를 Display 하기위한코드는아래와같다. MFDview.cpp #include "EHSISymbol.h" BOOL CmfdView::SetPixelformat(HDC hdc) int pixelformat; PIXELFORMATDESCRIPTOR pfd = sizeof(pixelformatdescriptor), // size of this pfd 1, // default version PFD_DRAW_TO_WINDOW // support window PFD_SUPPORT_OPENGL // support OpenGL PFD_GENERIC_FORMAT 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 188
// choose best matching pixel format if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == FALSE ) //MessageBox( "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 32, // 32-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 8, // no alpha buffer 0, // shift bit ignored 8, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 16, // 16-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored ; // set pixel format to device context if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE) //MessageBox( "SetPixelFormat failed", "Error", MB_OK); return FALSE; return TRUE; void CmfdView::InitGL() glclearcolor(0.0f, 0.0f, 0.0f, 0.5f); glcleardepth(1.0f); glenable(gl_depth_test); gldepthfunc(gl_lequal); glhint(gl_perspective_correction_hint, GL_NICEST); void CmfdView::ReSizeGLScene(GLsizei width, GLsizei height) // don't want a divede by zero if (height==0) height=1; // reset the viewport to new dimensions glviewport(0,0,width,height); glmatrixmode(gl_projection); glloadidentity(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 189
// calculate aspect ratio of the window gluperspective(45.0f,(glfloat)width/(glfloat)height,0.1f,1000.0f); // set modelvew matrix glmatrixmode(gl_modelview); glloadidentity(); void CmfdView::DrawGLScene() EHSIsymbol EHI; // clear screen and depth buffer glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glloadidentity(); // camera view configuration glulookat(0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); // draw glenable(gl_map1_vertex_3); glenable(gl_blend); glblendfunc(gl_src_alpha,gl_one_minus_src_alpha); glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glenable(gl_line_smooth); glcolor3f(0.0f, 1.0f, 1.0f); EHSI.CourseArrowSet(); // COURSE ARROW CONTROLL BOX glcolor3f(1.0f, 1.0f, 0.0f); EHSI.HeadingMarkerSet(); // swap buffer SwapBuffers(m_hDC); 코드 7-15 코스방향제어 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 190
7.13. 고정표지 (Fixed Marker) MFD 의 EHSI 계기판을구성하는요소중 Fixed Marker 를 display 한다. 그림 7-23 고정표지 Fixed Marker 를 Display 하기위한코드는아래와같다. MFDview.cpp BOOL CmfdView::SetPixelformat(HDC hdc) int pixelformat; PIXELFORMATDESCRIPTOR pfd = sizeof(pixelformatdescriptor), // size of this pfd 1, // default version PFD_DRAW_TO_WINDOW // support window PFD_SUPPORT_OPENGL // support OpenGL PFD_GENERIC_FORMAT 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 191
// choose best matching pixel format if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == FALSE ) //MessageBox( "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 32, // 32-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 8, // no alpha buffer 0, // shift bit ignored 8, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 16, // 16-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored ; // set pixel format to device context if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE) //MessageBox( "SetPixelFormat failed", "Error", MB_OK); return FALSE; return TRUE; void CmfdView::InitGL() glclearcolor(0.0f, 0.0f, 0.0f, 0.5f); glcleardepth(1.0f); glenable(gl_depth_test); gldepthfunc(gl_lequal); glhint(gl_perspective_correction_hint, GL_NICEST); void CmfdView::ReSizeGLScene(GLsizei width, GLsizei height) // don't want a divede by zero if (height==0) height=1; // reset the viewport to new dimensions glviewport(0,0,width,height); glmatrixmode(gl_projection); glloadidentity(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 192
// calculate aspect ratio of the window gluperspective(45.0f,(glfloat)width/(glfloat)height,0.1f,1000.0f); // set modelvew matrix glmatrixmode(gl_modelview); glloadidentity(); void CmfdView::DrawGLScene() // clear screen and depth buffer glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glloadidentity(); // camera view configuration glulookat(0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); // draw glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 1.0f, 1.0f); glbegin(gl_triangles); // FIXED MARKER RIGHT glvertex2f(144,0); glvertex2f(154,5); glvertex2f(154,-5); glend(); glbegin(gl_triangles); // FIXED MARKER LEFT glvertex2f(-144,0); glvertex2f(-154,5); glvertex2f(-154,-5); glend(); glpushmatrix(); glrotatef(45,0.0, 0.0, 1.0); // FIXED MARKER LEFT_BOTTOM glbegin(gl_triangles); glvertex2f(-144,0); glvertex2f(-154,5); glvertex2f(-154,-5); glend(); glrotatef(-90,0.0, 0.0, 1.0); // FIXED MARKER LEFT_TOP glbegin(gl_triangles); glvertex2f(-144,0); glvertex2f(-154,5); glvertex2f(-154,-5); glend(); glrotatef(90, 0.0, 0.0, 1.0); // FIXED MARKER RIGHT_TOP glbegin(gl_triangles); glvertex2f(144,0); glvertex2f(154,5); glvertex2f(154,-5); glend(); glrotatef(-90, 0.0, 0.0, 1.0); // FIXED MARKER RIGHT_BOTTOM glbegin(gl_triangles); glvertex2f(144,0); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 193
glvertex2f(154,5); glvertex2f(154,-5); glend(); glpopmatrix(); glflush(); // swap buffer SwapBuffers(m_hDC); 코드 7-16 고정표지 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 194
7.14. 각도 (Degree) MFD 의 EHSI 계기판을구성하는요소중 Degree 를 display 한다. 그림 7-24 각도 (Degree) Fixed Marker 를 Display 하기위한코드는아래와같다. MFDview.cpp #include "EHSISymbol.h" BOOL CmfdView::SetPixelformat(HDC hdc) int pixelformat; PIXELFORMATDESCRIPTOR pfd = sizeof(pixelformatdescriptor), // size of this pfd 1, // default version 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 195
// choose best matching pixel format if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == FALSE ) //MessageBox( "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; PFD_DRAW_TO_WINDOW // support window PFD_SUPPORT_OPENGL // support OpenGL PFD_GENERIC_FORMAT PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 32, // 32-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 8, // no alpha buffer 0, // shift bit ignored 8, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 16, // 16-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored ; // set pixel format to device context if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE) //MessageBox( "SetPixelFormat failed", "Error", MB_OK); return FALSE; return TRUE; void CmfdView::InitGL() glclearcolor(0.0f, 0.0f, 0.0f, 0.5f); glcleardepth(1.0f); glenable(gl_depth_test); gldepthfunc(gl_lequal); glhint(gl_perspective_correction_hint, GL_NICEST); void CmfdView::ReSizeGLScene(GLsizei width, GLsizei height) // don't want a divede by zero if (height==0) height=1; // reset the viewport to new dimensions 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 196
glviewport(0,0,width,height); glmatrixmode(gl_projection); glloadidentity(); // calculate aspect ratio of the window gluperspective(45.0f,(glfloat)width/(glfloat)height,0.1f,1000.0f); // set modelvew matrix glmatrixmode(gl_modelview); glloadidentity(); void CmfdView::DrawGLScene() EHSIsymbol EHSI; float CircleReverse = 0; // clear screen and depth buffer glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glloadidentity(); // camera view configuration glulookat(0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); // draw glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f,1.0f,1.0f); glenable(gl_line_smooth); gllinewidth(1.0f); glcolor3f(1.0f,1.0f,1.0f); glenable( GL_POINT_SMOOTH); EHSI.Degree(-1*CircleReverse); // swap buffer SwapBuffers(m_hDC); 코드 7-17 각도 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 197
7.15. 기타정보 MFD 의 EHSI 계기판을구성하는요소중기타정보를 display 한다. 그림 7-25 기타정보 Fixed Marker 를 Display 하기위한코드는아래와같다. MFDview.cpp #include EHSIsymbol.h BOOL CmfdView::SetPixelformat(HDC hdc) int pixelformat; PIXELFORMATDESCRIPTOR pfd = sizeof(pixelformatdescriptor), // size of this pfd 1, // default version PFD_DRAW_TO_WINDOW // support window PFD_SUPPORT_OPENGL // support OpenGL 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 198
// choose best matching pixel format if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == FALSE ) //MessageBox( "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; PFD_GENERIC_FORMAT PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 32, // 32-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 8, // no alpha buffer 0, // shift bit ignored 8, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 16, // 16-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored ; // set pixel format to device context if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE) //MessageBox( "SetPixelFormat failed", "Error", MB_OK); return FALSE; return TRUE; void CmfdView::InitGL() glclearcolor(0.0f, 0.0f, 0.0f, 0.5f); glcleardepth(1.0f); glenable(gl_depth_test); gldepthfunc(gl_lequal); glhint(gl_perspective_correction_hint, GL_NICEST); void CmfdView::ReSizeGLScene(GLsizei width, GLsizei height) // don't want a divede by zero if (height==0) height=1; // reset the viewport to new dimensions glviewport(0,0,width,height); glmatrixmode(gl_projection); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 199
glloadidentity(); // calculate aspect ratio of the window gluperspective(45.0f,(glfloat)width/(glfloat)height,0.1f,1000.0f); // set modelvew matrix glmatrixmode(gl_modelview); glloadidentity(); void CmfdView::DrawGLScene() EHSIsymbol EHSI; float CircleReverse = 0; // clear screen and depth buffer glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glloadidentity(); // camera view configuration glulookat(0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); // draw glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glenable(gl_line_smooth); gllinewidth(1.0f); glcolor3f(1.0f,1.0f,1.0f); glenable(gl_point_smooth); EHSI.CircleWindow(-1*CircleReverse); glcolor3f(0.0f, 1.0f, 1.0f); EHSI.Nav(); EHSI.CourseEng(); EHSI.RangeIndicator(); glcolor3f(0.0f, 1.0f, 1.0f); EHSI.TimeDestination(); // swap buffer SwapBuffers(m_hDC); 코드 7-18 기타정보 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 200
7.16. 타이머를이용한이벤트처리 OnTime 타이머를이용하여외부로부터입력받은값을실시간으로반영할수있다. 1) 클래스뷰탭 속성 WM_TIMER OnTimer 를선택한다. 그림 7-26 타이머 - 1 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 201
그림 7-27 타이머 - 2 2) 클래스뷰탭 속성 WM_TIMER OnTimer 를선택한다. WM_ 를생성해아래코드를입력합니다. MFDview.cpp // Global 변수선언 float Heading_Rot = 0.0f; float BearingReverse = 53; float CircleReverse = 0; float ArrowReverse = 0; switch(nidevent) case 1: UpdateData(TRUE); Heading_Rot = Heading_Rot - 1; BearingReverse = BearingReverse + 0.5; CircleReverse = CircleReverse + 0.5; ArrowReverse = ArrowReverse - 1; 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 202
DrawGLScene(); UpdateData(FALSE); break; default: break; 코드 7-19 타이머 - 1 여기서 Heading_Rot, BearingReverse, CircleReverse, ArrowReverse 변수는동작을확인하기위해단순하게일정 값을증가 / 감소시키도록했다. 외부인터페이스를이용해외부로부터값을받는다면이부분에값을연결시키면, 실시간구현이가능하다. 그림 7-28 타이머 - 3 3) Timer 를아래와같이 CMFDView::OnDraw() 에아래와같이코드를추가한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 203
MFDview.cpp KillTimer(1); SetTimer(1, 100, NULL); 코드 7-20 타이머 - 2 그림 7-29 타이머 - 4 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 204
7.17. Menu 를이용한 Color 속성변경 Menu 를이용하여 Color 를변경할수있다. 1) 리소스뷰 Menu IDR_MAIINFAME 을선택하여아래와같이 Menu 를구성한다. 그림 7-30 Color 속성변경 - 1 2) 각메뉴별로마우스오른쪽버튼을클릭하여이벤트처리기추가 (A) 을선택한다.. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 205
그림 7-31 Color 속성변경 - 2 3) 이벤트처리기마법사를통해함수처리기를아래와같이추가한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 206
그림 7-32 Color 속성변경 - 3 4) 아래와같이매서드가추가되고아래와같이코드를입력한다.. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 207
그림 7-33 Color 속성변경 - 4 MFDview.cpp // Global 변수선언 BOOL Red = FALSE; BOOL Green = FALSE; BOOL Blue = FALSE; BOOL Yellow = FALSE; Red = FALSE; Green = FALSE; Blue = FALSE; Yellow = TRUE; 코드 7-21 Color 속성변경 - 1 Red, Green, Blue, Yellow 변수는 MFDView.cpp 에서 Global 변수로선언한다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 208
그림 7-34 Color 속성변경 - 5 나머지 Red, Green, Blue 부분도위와같은방법으로추가한다. 5) CMFDView::EHSI() 매서드에 Menu 의이벤트를처리하도록비행기를그리기전에색을결정하도록 EHSI.AirPlane(); 윗부분에아래와같이입력한다. MFDview.cpp void CMFDView::OnAirplaneRed() // TODO: 여기에명령처리기코드를추가합니다. Red = TRUE; Green = FALSE; Blue = FALSE; Yellow = FALSE; DrawGLScene(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 209
void CMFDView::OnAirplaneGreen() // TODO: 여기에명령처리기코드를추가합니다. Red = FALSE; Green = TRUE; Blue = FALSE; Yellow = FALSE; DrawGLScene(); void CMFDView::OnAirplaneBlue() // TODO: 여기에명령처리기코드를추가합니다. Red = FALSE; Green = FALSE; Blue = TRUE; Yellow = FALSE; DrawGLScene(); void CMFDView::OnAirplaneYellow() // TODO: 여기에명령처리기코드를추가합니다. Red = FALSE; Green = FALSE; Blue = FALSE; Yellow = TRUE; DrawGLScene(); 코드 7-22 Color 속성변경 - 2 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 210
그림 7-35 Color 속성변경 - 6 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 211
7.18. 전자식수평자세지시계 (EHSI) MFC 를이용한전자식수평자세지시계 (EHSI : Electronic Horizontal Situation Indicator) 프로젝트를컴파일하여실 행하면아래와같은결과를얻을수있다. 그림 7-36 전자식수평자세지시계 (EHSI) EHSI 멤버함수는아래와같다. MFDview.cpp float Heading_Rot = 0.0f; 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 212
float BearingReverse = 53; float CircleReverse = 0; float ArrowReverse = 0; BOOL Red = FALSE; BOOL Green = FALSE; BOOL Blue = FALSE; BOOL Yellow = FALSE; void CMFDView::EHSI() EHSIsymbol EHSI; glortho(-200.0f,200.0f,-200.0f,200.0f,1.0f,-1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f,1.0f,1.0f); glenable(gl_line_smooth); gllinewidth(1.0f); //gllinewidth(2.0f); glcolor3f(1.0f,1.0f,1.0f); glenable( GL_POINT_SMOOTH); EHSI.Degree(-1*CircleReverse); EHSI.FixedMarker(); EHSI.CircleWindow(-1*CircleReverse); glcolor3f(0.0f, 1.0f, 1.0f); EHSI.Nav(); EHSI.CourseEng(); EHSI.CourseArrow(ArrowReverse); // 방위각 // FIXED MARKER // 방위각출력 // MODE // COURSE WINDOW 에서영어철자 (COURSE) // COURSE ARROW if((int)arrowreverse==-1) ArrowReverse=359; else if((int)arrowreverse==360) ArrowReverse=0; else if((int)circlereverse==-1) CircleReverse=359; else if((int)circlereverse==360) CircleReverse=0; glpointsize(1.0f); EHSI.RangeIndicator(); glcolor3f(0.0f, 1.0f, 1.0f); EHSI.TimeDestination(); glcolor3f(0.0f, 1.0f, 1.0f); EHSI.CourseArrowSet(); // RANGE INDICATOR // TIME TO DESTINATION // COURSE ARROW CONTROLL BOX glcolor3f(1.0f, 1.0f, 0.0f); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 213
EHSI.HeadingMarkerSet(); if (Red == TRUE) glcolor3f(1.0f, 0.0f, 0.0f); else if(green == TRUE) glcolor3f(0.0f, 1.0f, 0.0f); else if(blue == TRUE) glcolor3f(0.0f, 0.0f, 1.0f); else if(yellow == TRUE) glcolor3f(1.0f, 1.0f, 0.0f); else glcolor3f(1.0f, 1.0f, 1.0f); EHSI.AirPlane(); // COURSE ARROW CONTROLL BOX // 비행기그림 glcolor3f(0.0f, 1.0f, 1.0f); /* COURSE ARROW & COURSE DEVIATIONRoll & TO/FROM ARROW 회전 */ glpushmatrix(); glrotatef(-arrowreverse, 0.0, 0.0, 1.0); EHSI.CourseArrowShape(); glcolor3f(1.0f, 1.0f, 1.0f); glpointsize(7.0f); EHSI.CourseDeviationScale(); EHSI.ToFromArrow(); glpopmatrix(); /* HEADING MARKER 회전 */ glpushmatrix(); glrotatef(heading_rot, 0.0, 0.0, 1.0); glcolor3f(1.0f, 1.0f, 0.0f); // HEADING MARKER EHSI.HeadingMarker(); glpopmatrix(); glcolor3f(1.0f, 1.0f, 1.0f); glpushmatrix(); EHSI.line(); // 원의나눔선 glpopmatrix(); /* BEARING POINTER 회전 */ glpushmatrix(); glrotatef(-bearingreverse, 0.0, 0.0, 1.0); EHSI.BearingPointer(); glpopmatrix(); glend(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 214
코드 7-23 전자식수평지시계 (EHSI) 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 215
7.19. 전방향시현기 (HUD) MFC 를이용한전방향시현기 (HUD : Head-up Display) 프로젝트를컴파일하여실행하면아래와같은결과를얻을 수있다. 그림 7-37 전방향시현기 (HUD) HUD 를구현하기위해 HUD 의함수외에아래의파일이추가된다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 216
그림 7-38 HUD 추가파일 HUD 멤버함수는아래와같다. MFDview.cpp GLbyte *gltloadtga(const char *szfilename, GLint *iwidth, GLint *iheight, GLint *icomponents, GLenum *eformat) FILE *pfile; // File pointer TGAHEADER tgaheader; // TGA file header unsigned long limagesize; // Size in bytes of image short sdepth; // Pixel depth; GLbyte *pbits = NULL; // Pointer to bits // Default/Failed values *iwidth = 0; *iheight = 0; *eformat = GL_BGR_EXT; *icomponents = GL_RGB8; // Attempt to open the fil pfile = fopen(szfilename, "rb"); if(pfile == NULL) return NULL; // Read in header (binary) fread(&tgaheader, 18/* sizeof(tgaheader)*/, 1, pfile); // Do byte swap for big vs little endian #ifdef APPLE BYTE_SWAP(tgaHeader.colorMapStart); BYTE_SWAP(tgaHeader.colorMapLength); BYTE_SWAP(tgaHeader.xstart); BYTE_SWAP(tgaHeader.ystart); BYTE_SWAP(tgaHeader.width); BYTE_SWAP(tgaHeader.height); #endif // Get width, height, and depth of texture 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 217
*iwidth = tgaheader.width; *iheight = tgaheader.height; sdepth = tgaheader.bits / 8; // Put some validity checks here. Very simply, I only understand // or care about 8, 24, or 32 bit targa's. if(tgaheader.bits!= 8 && tgaheader.bits!= 24 && tgaheader.bits!= 32) return NULL; // Calculate size of image buffer limagesize = tgaheader.width * tgaheader.height * sdepth; // Allocate memory and check for success pbits = (signed char *)malloc(limagesize * sizeof(glbyte)); if(pbits == NULL) return NULL; // Read in the bits // Check for read error. This should catch RLE or other // weird formats that I don't want to recognize if(fread(pbits, limagesize, 1, pfile)!= 1) free(pbits); return NULL; // Set OpenGL format expected switch(sdepth) case 3: // Most likely case *eformat = GL_BGR_EXT; *icomponents = GL_RGB8; break; case 4: *eformat = GL_BGRA_EXT; *icomponents = GL_RGBA8; break; case 1: *eformat = GL_LUMINANCE; *icomponents = GL_LUMINANCE8; break; ; // Done with File fclose(pfile); // Return pointer to image data return pbits; void HUD2(float Alty,float Airy,float Hsrx) GLubyte *pimage = NULL; GLint iwidth, iheight, icomponents; GLenum eformat; // Clear the window with current clearing color 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 218
glclear(gl_color_buffer_bit); // Targa's are 1 byte aligned glpixelstorei(gl_unpack_alignment, 1); // Load the TGA file, get width, height, and component/format information pimage = (unsigned char *)gltloadtga("sky.tga", &iwidth, &iheight, &icomponents, &eformat); glpixelzoom((glfloat) point[hud].endxp / (GLfloat)iWidth, (GLfloat) point[hud].endyp / (GLfloat)iHeight); // Use Window coordinates to set raster position //glrasterpos2i(-254, -254); glrasterpos2i(-300, -300); // Draw the pixmap if(pimage!= NULL) gldrawpixels(iwidth, iheight, eformat, GL_UNSIGNED_BYTE, pimage); // Don't need the image data anymore free(pimage); /* 초기설정 ( 곡선, 화면초기화 ) */ gllinewidth(2.0f); /* 선의색설정 */ glcolor3f(0.0f, 1.0f, 0.0f); gldisable(gl_line_smooth); /* Digital Air&Alt Enclosure Box */ EnBox(); /* FPM Video (x 좌표, y 좌표 ) -> 현재비행기가향하는방향 */ FPM(0.0, 0.0); /* 시저박스활성화 ( 설정된부분만 Display) */ glenable(gl_scissor_test); //glscissor(149, 80, 210, 60); if(point[hud].endxp == 288) glscissor(point[hud].startxp+80, point[hud].startyp+45, 127,33 ); else glscissor(point[hud].startxp+163, point[hud].startyp+90, 250,65 ); /* Heading Scale Reference Point ( 각도 ) */ HSR(Hsrx); //glscissor(0, 84, 508, 210); if(point[hud].endxp == 288) glscissor(point[hud].startxp, point[hud].startyp+84, point[hud].endxp,120 ); else glscissor(point[hud].startxp, point[hud].startyp+169, point[hud].endxp,223 ); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 219
/* AirSpeed Scale Mark ( 속도값 ) */ Air(Airy); /* Altitude Scale Mark ( 고도값 ) */ Alt(Alty); HNumDraw(Airy, Alty, Hsrx); /* 시저박스비활성화 */ gldisable(gl_scissor_test); //glpushmatrix(); // gltranslatef(220.0f,210.0f,0.0f); // MFDSizeButton(down[HUD],HUD); //glpopmatrix(); //glpushmatrix(); // gltranslatef(220.0f,-210.0f,0.0f); // MFDResizeButton(3); //glpopmatrix(); //gldisable(gl_line_smooth); //CrossLine(); void CMFDView::DrawGLScene() // clear screen and depth buffer glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glloadidentity(); // camera view configuration glulookat(0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); set=0; glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glenable(gl_map1_vertex_3); glenable(gl_blend); glblendfunc(gl_src_alpha,gl_one_minus_src_alpha); point[hud].startxp=0; point[hud].startyp=0; point[hud].endxp=576; point[hud].endyp=576; point[hud].type=hud; point[hud].size=large; point[hud].position=left; // draw glpushmatrix(); glortho(-254.0f,254.0f,-254.0f,254.0f,1.0f,-1.0f); HUD2(Alty, Airy,Hsrx); glpopmatrix(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 220
// swap buffer SwapBuffers(m_hDC); 코드 7-24 HUD 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 221
7.20. 전자식수평위치방향계 (EHSD) MFC 를이용한전자식수평위치방향계 (HSD : Electronic Horizontal Situation Director) 프로젝트를컴파일하여실 행하면아래와같은결과를얻을수있다. 그림 7-39 전자식수평위치방향계 (EHSD) HSD 를구현하기위해 HSD 의함수외에아래의파일이추가된다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 222
그림 7-40 전자식수평위치방향계 (EHSD) 추가파일 HSD 멤버함수는아래와같다. MFDview.cpp void HSD2() if(point[hsd].endyp == 576) glenable(gl_line_smooth); HSDSelectArea(HSDx,HSDy, HSDr); glcolor3f(1.0f,1.0f,1.0f); HSDScale(); glpushmatrix(); gltranslatef(0.0f, -144.0f,0.0f); HSDRangeRingTics(); HSDMagSens(HSDr); HSDRoute(HSDx, HSDy, HSDr); HSDOwnShip(); glpopmatrix(); HSDCusor(); #if 0 glpushmatrix(); glscalef(288.0f/254.0f,288.0f/254.0f,0.0f); gltranslatef(220.0f,210.0f,0.0f); MFDSizeButton(down[HSD],HSD); glpopmatrix(); glpushmatrix(); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 223
glscalef(288.0f/254.0f,288.0f/254.0f,0.0f); gltranslatef(220.0f,-210.0f,0.0f); MFDResizeButton(0); glpopmatrix(); #endif gldisable(gl_line_smooth); #if 0 glpushmatrix(); glscalef(288.0f/254.0f,288.0f/254.0f,0.0f); CrossLine(); glpopmatrix(); #endif //------------------------------------------------------------------ void CMFDView::DrawGLScene() // clear screen and depth buffer glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glloadidentity(); // camera view configuration glulookat(0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); set=0; glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glenable(gl_map1_vertex_3); glenable(gl_blend); glblendfunc(gl_src_alpha,gl_one_minus_src_alpha); point[hsd].type=hsd; point[hsd].size=small; point[hsd].position=right; // draw glpushmatrix(); glortho(-288.0f,288.0f,-288.0f,288.0f,1.0f,-1.0f); HSD2(); glpopmatrix(); // swap buffer SwapBuffers(m_hDC); 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 224
코드 7-25 전자식수평위치방향계 (EHSD) 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 225
7.21. 전자식자세방향지시계 (EADI) MFC 를이용한전자식자세방향지시계 (EADI : Electronic Attitude Director Indicator) 프로젝트를컴파일하여실행 하면아래와같은결과를얻을수있다. 그림 7-41 전자식자세방향지시계 (EADI) EADI 를구현하기위해 EADI 의함수외에아래의파일이추가된다. 그림 7-42 전자식자세방향지시계 (EADI) 추가파일 EADI 멤버함수는아래와같다. 한국폴리텍대학항공캠퍼스항공제어시스템과페이지 226