FreeType을 이용한 Font 처리

FreeType의 주된 용도는 Anti-Aliasing 처리가 된 세련된 폰트의 출력에 있습니다. FreeType은 Windows는 물론이고, Linux나 MacOS에서 특히 더 많이 사용되고 있는 오픈소스 라이브러리입니다. 3D에서 한글출력을 위해 FreeType을 사용하는데, 류광님의 주도하에 개발된 glan이라는 한글출력 라이브러리도 안티알리아싱 처리된 문자의 출력을 위해서 FreeType을 활용하고 있는 것으로 알고 있습니다. OpenGL에서 한글출력을 고민하고 계시다면 반드시 glan에 관심을 가져보시길 바랍니다.

저 역시 FreeType에 관심을 가지게 된 이유도 3D에서의 한글출력 문제 때문이였습니다. 하지만 기존의 한글출력 방식은 하나의 이미지에 한글을 그려 놓고, 출력하고자 하는 문자을 텍스쳐 맵핑 방식으로 출력하는 방법을 사용합니다. 장점은 속도가 무척 빠르기 때문에 게임에서 주로 사용됩니다. 하지만 단점은 큰 크기의 한글을 출력하고자 할때 텍스쳐 이미지가 그에 따라 확대되어 커지게 되므로 뭉개지는 결과가 발생하게 되고, 다양한 한글 폰트를 사용하기 위해서 그 다양한 한글 폰트의 종류만큼 한글 맵핑 이미지를 미리 생성해 놓아야 합니다.


그러나 어찌되었든지 게임이라는 장르에서는 한글을 크게 출력할 필요가 없고 다양한 폰트를 사용할 필요가 없기때문에 이러한 단점이 문제가 되지 않습니다. 그러나 게임이 아닌 경우에 다양한 한글 포트와 한글의 크기에 상관없이 미려한 한글 출력을 원할 경우에 다른 방법은 없을지 고민이였습니다.

쉽게 생각할 수 있는 것이 한글을 구성하는 좌표를 구해서 Mesh 형태로 뿌리는 것이였습니다. 물론 속도면에서의 희생이 따르는 방법이긴 합니다만, 경험상 화면상에 문제 출력은 사실 수십자 정도에 불과합니다. 즉, 많아봐야 수백자라는 이야기이지요. 하지만 여려운 점은 글자를 구성하는 좌표를 얻어오는 방법이였습니다. 방법은 2가지인데, 하나는 Windows API를 이용하는 방법과 앞서 언급한 FreeType을 이용하는 방법이 있습니다.

저는 FreeType을 사용하기로 결정하였는데, OpenGL과 같은 플렛폼 독립적인 라이브러리와 궁합이 정확히 맞아 떨어진다는 생각에서 였습니다. 제가 시험삼에 작성한 코드의 그 결과 화면은 위와 같습니다.

지정된 폰트의 글자에 대한 Anti-Aliasing 처리된 한글 표시와 그 글자의 구성 좌표를 표시하고 있습니다. 구성좌표는 박스로 나타내었는데, 빨강색 박스는 곡선처리를 위한 제어점(Control Point)입니다.

FreeType의 초기화, 안티알리아싱 처리된 글자의 출력, 글자의 구성 좌표를 얻는 방법에 대한 전체 코드가 담긴 첨부파일을 참고하시길 바랍니다. 2006년이라는 시대에 한글처리 문제로 고민해야 하는 웃지 못할 상황에 도움이 되길 바라는 마음에서 글을 올립니다.

ActiveX가 삽입된 IE의 URL 구하기

http://www.delmadang.com에서 “마린”님이 올린 글입니다. 추후에 유용하게 사용될 듯 해서 Keep해 둡니다. 참고로 Delphi로 된 코드입니다.

uses SHDocVw;

function Get_IE_URL:string;
var
  ClientSite: IOleClientSite;
  WebBrowserApp: IWebBrowserApp;
  ServiceProvider: IServiceProvider;
  WebBrowser2: IWebBrowser2;
begin
  Result := '';
  if (ComObject as IOleObject).GetClientSite(ClientSite) = S_OK then
  begin
    if (ClientSite <> nil) then
    begin
      ClientSite.QueryInterface(IServiceProvider, ServiceProvider);
      if (ServiceProvider <> nil) then
      begin
        ServiceProvider.QueryService( IWebBrowserApp, IWebBrowserApp, WebBrowserApp);
        if (WebBrowserApp <> nil) then
        begin
          WebBrowser2 := IWebBrowser2(WebBrowserApp);
          Result := WebBrowser2.Get_LocationURL;
        end;
      end;
    end;
  end;
end;

Windows Vista에서 ActiveX의 행보는 어떻게 되는걸까요? 혹자는 ActiveX는 없어질 것이다라고 말하지만.. Vista에 기본으로 탑재되는 IE의 시험버전이 기존의 Windows에서 잘.. 돌아가며, 당연이 여기에 ActiveX를 삽입하여 잘 작동하고 있고.. 아직까지 .NET의 하부단에서 ActiveX가 사용되고 있습니다. 물론 .NET에서 사용하는 ActiveX는 조금씩 제거 되겠지만요. 또한 Flash와 같은 컨트롤 역시 여전이 ActiveX이구요. 또…. 물론 추후에는 .NET용 Flash가 나오겠지요. 곰곰이.. 곰곰이 생각을 해보면… ActiveX는 Windows Vista에서도 여전이 잘사용되리라 의심치 않습니다. 아마도… Vista 이후의 Windows에서나 ActiveX가 Disable되지 않을까 짐작됩니다..

MFC7.0 계층도


급작스레, Dialog기반의 Utility Tool을 만들려던 중, 머리속에 까막까막해진 MFC 때문에 버벅대다가 일단 클래스 계층도부터 찾아보자 해서 찾은 것. 출처는 MSDN. 그리고 내가 필요했던 class는 파일을 열기 위한 대화창을 위한 “CFileDialog”. 이제 다시 CFileDialog에 대한 MSDN 도움말(F1)을 통한 Copy & Paste 그리고 MSDN에서 불충분한 정보는 Devpia를 통해 검색, 다시 Copy & Paste.

여기서 잠깐 MS의 우두머리인 회장 스티브 발머가 마이크로소프트가 현재 가장 중요시 여기고 있는 프로젝트는 온라인 서비스인 윈도우 라이브(http://www.live.com)라고  가트너 심포지엄/IT 엑스포에서 밝혔다고 한다. 다음의 http://www.kbench.com/news/?cc=0&no=34378&pg=2에서 [펀] 글이다. (갑작이 MFC7.0에서 엄청난 삼천포로.. ㅡ_ㅡ;)

발머는 라이브닷컴에 대해서 웹사이트같이 클릭만으로 구동되는 서비스로 소프트웨어가 이전되는 단계를 거치고 있다고 밝혔다. 현재 베타 서비스중인 라이브에는 윈도우 라이브 메신저, 레이브 엑스포 온라인 광고등의 다양한 서비스를 테스트중이다. 발머는 현재 가장 중요한 것이 바로 라이브 플랫폼이며 다음 세대의 수익은 인터넷 서비스와 제공에서 나오게 될 것이라고 밝혔다. 이는 가트너의 애널리스트가 곧 검색, 팟캐스팅, 주문형 비디오, 블로그와 같은 인터넷 서비스가 기업의 IT 인프라로 수년이내에 급속히 흡수될 것이라고 전망한 것과 일맥 상통하는 이야기다. 하지만 발머는 온라인으로 전환되는 과정에서도 강력한 클라이언트 시스템의 필요성도 여전히 줄지 않을 것으로 전망했다. 현재 마이크로소프트는 대부분의 소프트웨어 수익을 이러한 클라이언트 시스템에서 거두고 있다. 한편 비스타의 잦은 연기 후 늦장 출시에 대해서 발머는 개발과정 상의 복잡성을 줄여야할 필요성을 배웠다고 답변했다.

내가 여기서 흥미있게 느낀 요지는, 분명이 대세는 웹이기는 하지만, 그럼에도 불구하고 클라이언트 시스템의 필요성은 줄지 않을 것이라는 점… 그러나 역시 대세는 웹이다.

끝으로 웃으개 상황. 좋은 화상카메라를 하나 사려고 daum에서 검색해 보았다. 그런데 검색 결과가 황당했다.


성인 키워드.. ㅡ_ㅜ 난 황당하고 웃겼는데.. 이런 내가 황당하고 웃긴건지.. 여튼 지금도 난 황당하다. 어째서 화상 카메라가 성인 키워드가 되어 버린거지?

MFC에서 성인키워드까지… 지금까지 잡스런 글이였습니다.. ㅋ

ExampleFrameListener의 개념

ExampleFrameListener는 ExampleApplication 클래스와 마찬가지로 Ogre에서 기본적으로 제공하는 Framework 클래스 중 하나이다. KeyListener와 FrameListener로부터 다중상속을 받는 구조이며 기본적으로 갖는 책임 중에 가장 중요한 것은 마우스나 키보드로부터 입력을 받아 처리하고 Frame을 렌더링하데는 필요한 상태정보를 갱신하고, 렌더링을 계속할 것인지의 여부의 결정이다. 아래는 ExampleFrameListener 클래스 관계도이다.

또한 Overlay 클래스를 이용하여 FPS 정보 등을 나타내준다. 사용자가 마우스나 키보드의 입력을 buffer 방식인지, unbuffered 방식인지의 결정에 따라 buffered 방식인 경우, 사용자 입력에 대한 처리를 Event 방식(Callback 방식)으로 하기 위해 EventProcessor 클래스의 인스턴스를 생성해준다.

unbuffered 방식인 경우에는 InputReader 클래스의 인스턴스를 생성해서 사용자가 필요한 시점에서 InputReader의 인스턴스를 이용해서 키보드나 마우스의 상태를 Query할 수 있다. buffer 방식인 경우에도 InputerReader 인스턴스를 사용할 수 있다는 점도 알아 두길 바란다.

기본적으로 ExampleFrameListener 클래스는 unbuffered 방식의 경우에 대해 마우스와 키보드 입력에 대한 처리를 해 놓았다. 예를 들어 커서키를 누르면 화면이 이동한다든지, 마우스를 이용해 확대나 이동을 한다든지 말이다. 하지만 사용자가 원할 경우 이러한 처리를 재정의해서 쉽게 변경할 수 있다.

buffered 방식인지, unbuffered 방식인지의 결정은 ExampleFrameListener 클래스 생성자의 인자를 통해 결정한다.

사용자 입력 이외에 ExampleFrameListener 클래스에서 중요한 것은 FrameListener 클래스의 상속에 있다. FrameListener 클래스는 단지 frameStarted와 frameEnd 가상함수만을 가지고 있다. frameStarted는 하나의 frame을 렌더링 하기 직전에 호출하고 frameEnd는 하나의 frame에 대한 렌더링이 끝났을때 호출된다. 두개의 함수 모두 bool을 반환하는데, false일 경우 다음 frame을 렌더링하지 않는다. 즉, 계속 렌더링하려면 true를 반환해야 한다.

위의 말대로라면 Ogre3D의 main loop인 Root::startRendering 함수의 내용은 다음과 같을 것이고, 실제로 같다.

  1. Root 객체는 자신에 등록된 모든 FrameListener 객체의 frameStarted 함수를 호출
  2. Root 객체는 하나의 frame을 렌더링 함
  3. Root 객체는 자신에 등록된 모든 FrameListener 객체의 frameEnd 함수를 호출

입력이 unbuffered 방식일때 frameStarted나 frameEnd 함수안에서 InputReader 인스턴스를 이용해 키보드나 마우스의 상태를 Query 해서 회전상태나, 이동상태값들을 변경해서 물체를 회전시키고 이동시킬 수 있다. 클래스 관계도에서 ExampleFrameListener 클래스가 Camera 클래스와 관계를 맺고 있는 이유가 여기에 있는데, 입력에 따라 상태정보를 변경하고 다시 이 상태정보를 통해 Camera를 제어하기 위해서이다. RenderWindow와 연관을 맺는 이유는 다음과 같다.

  • FPS를 얻기
  • 개발을 위한 Debug 기능을 이용
  • 화면을 캡쳐화여 png 파일로 저장

마지막으로, 여러분들이 ExampleFrameListener 클래스의 소스를 열어놓고 기본적으로 입력에 대해서 구현해 놓은 것이 무엇인지를 살펴보길 바란다. 이 글을 읽은 후에 소스를 살펴보면 조금이라도 이해가 수월할 것이다.

[펌] 아키텍처 체크 리스트

1. 아키텍처의 개요와 설명을 포함해서 프로그램의 구조가 명확한가?
2. 기능과 다른 모듈과의 인터페이스를 고려해서 모듈이 잘 정의되었나?
3. 모든 기능들이 너무 많거나 적지않은 모듈에 의해 적절히 수행되는가?
4. 설계된 아키텍처가 변화에 적절히 대응할 수 있는가?
5. 구매와 개발에 대한 비교와 결정을 포함하는가?
6. 아키텍처가 다른 목적을 위해 만들어진 코드를 재사용할지를 기술하는가?
7. 중요 데이터 구조가 기술되고 확인되었는가?
8. 중요 데이터 구조가 루틴 액서스 뒤에 은폐되었는가?
9. 데이터베이스 구조와 내용은 설명되었나?
10. 중요 알고리즘이 기술되고 확인됐는가?
11. 중요 대상들이 기술된 것을 확인했는가?
12. 사용자 입력을 처리하는 방법이 기술되었나?
13. 사용자 인터페이스의 중요관점이 정의 되었나?
14. 변경시 프로그램의 다른부분에 영향을 끼치지 않게 사용자 인터페이스가 모듈화되었는가?
15. 메모리관리에 대한 메모리 사용량의 예측과 방법이 기술되고 확인됐는가?
16. 아키텍처는 각 모듈의 용량과 속도를 설정했는가?
17. 문자열 처리에 대해 기술했으며 문자-문자열-저장량에 대해 평가했는가?
18. 에러처리 방법에 대해 기술하는가?
19. 에러메시지는 명확한 사용자 인터페이스를 나타내기 위한 부분으로 처리되는가?
20. 견고성의 정도를 설명하는가?
21. 정도에 지나치거나 부족하게 설계되었나? 이 부분에 대해 명확하게 설명하는가?
22. 시스템의 중요목표가 명확하게 기술되었나?
23. 전체 아키텍처가 개념적으로 일치되었나?
24. 기본 설계가 앞으로 구현될 기종과 언어에 독립적으로 쓰여졌는가?
25. 모든 중요 결정에 대한 동기가 명시되었는가?
26. 시스템을 구현할 프로그래머로써 당신은 아키텍처에 만족하는가?

출처: Steve McConnell의 Code Complete(MS Press 1995)

이 체크 리스트를 읽은 후, 실제 Code Complete 책을 읽고 내가 느낀 아키텍쳐를 세가지로 나타낸다면 다음과 같다.

  1. 아키텍쳐는 산출물이기 이전에 실무 개발자가 코딩하는 매 순간 순간 마다 참고하고, 참고 해야만 하는 유연한(때로 아키텍쳐도 수정되어야 한다) 성서이여야 한다.
  2. 아키텍쳐는 DBMS와 Web Server 그리고 방화벽 등의 시스템의 구성도와 같은 A2 용지 크기의 한장짜리 문서를 포함해서, 시스템을 개발하기 위해 고려해야할 사항을 세부적으로 기술하거나 묘술하는 것이다.
  3. 아키텍쳐에서 어떤 선택 사항에 대한 이유가 반드시 있어야 한다. “예전에 그랬으므로..” 또는 “다른 시스템도 그랬으므로..” 라는 것은 이유가 될 수 없다.