MFC 응용 통합
MFC SDI/MDI 응용에서 CView 파생 클래스에 henc 를 통합하는 전형적인 패턴.
헤더 / 멤버 변수
섹션 제목: “헤더 / 멤버 변수”#include "henc.h"#include <gl/GL.h>
class CEncView : public CView{protected: HGLRC m_hRC; // OpenGL 컨텍스트 HDC m_hDC; // 디바이스 컨텍스트 int m_view; // henc 뷰 핸들 bool m_inited;
public: CEncView(); virtual ~CEncView();
protected: afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnDestroy(); afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg BOOL OnEraseBkgnd(CDC* pDC); virtual void OnDraw(CDC* pDC);
DECLARE_MESSAGE_MAP()};메시지 맵 & OnCreate (henc 초기화)
섹션 제목: “메시지 맵 & OnCreate (henc 초기화)”BEGIN_MESSAGE_MAP(CEncView, CView) ON_WM_CREATE() ON_WM_DESTROY() ON_WM_SIZE() ON_WM_LBUTTONDOWN() ON_WM_ERASEBKGND()END_MESSAGE_MAP()
int CEncView::OnCreate(LPCREATESTRUCT lpCreateStruct){ if (CView::OnCreate(lpCreateStruct) == -1) return -1;
m_hDC = ::GetDC(m_hWnd);
// PIXELFORMATDESCRIPTOR 설정 + ChoosePixelFormat + SetPixelFormat 생략 (표준 OpenGL 셋업) PIXELFORMATDESCRIPTOR pfd = {}; pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 32; pfd.cDepthBits = 24;
int pf = ChoosePixelFormat(m_hDC, &pfd); SetPixelFormat(m_hDC, pf, &pfd);
m_hRC = wglCreateContext(m_hDC); wglMakeCurrent(m_hDC, m_hRC);
// henc 초기화 if (hencInit() != 0) { AfxMessageBox(_T("hencInit failed")); return -1; } m_view = hencCreate(); hencSelect(m_view);
// 기본 셀 자동 로딩 (응용에 따라 메뉴에서 호출) hencLoad("S57/KR4A4061.000"); hencSetCenter(m_view, 129.42, 35.10); hencSetZoom(m_view, 12.0);
m_inited = true; return 0;}OnSize: 뷰포트 동기화
섹션 제목: “OnSize: 뷰포트 동기화”void CEncView::OnSize(UINT nType, int cx, int cy){ CView::OnSize(nType, cx, cy); if (!m_inited || cx <= 0 || cy <= 0) return;
hencSetViewport(m_view, 0, 0, cx, cy); Invalidate(FALSE); // 다음 OnDraw 트리거}OnDraw: 매 프레임 렌더링
섹션 제목: “OnDraw: 매 프레임 렌더링”void CEncView::OnDraw(CDC* /*pDC*/){ if (!m_inited) return;
wglMakeCurrent(m_hDC, m_hRC); hencSelect(m_view);
hencClearBackground(m_view); hencRender(m_view); hencSwapBuffer(m_view);}
// CView 가 자체 배경을 그리지 않도록BOOL CEncView::OnEraseBkgnd(CDC* /*pDC*/) { return TRUE; }OnLButtonDown: 객체 선택
섹션 제목: “OnLButtonDown: 객체 선택”void CEncView::OnLButtonDown(UINT nFlags, CPoint point){ if (!m_inited) { CView::OnLButtonDown(nFlags, point); return; }
// 클릭 위치 ± 8 px 영역 내에서 가장 가까운 S-57 객체를 픽킹 int objHandle = hencPickObj(m_view, point.x, point.y, 8); if (objHandle >= 0) { char buf[2048]; hencObjToString(objHandle, buf, sizeof(buf)); CString msg(buf); AfxMessageBox(msg); }
CView::OnLButtonDown(nFlags, point);}OnDestroy: 정리
섹션 제목: “OnDestroy: 정리”void CEncView::OnDestroy(){ if (m_inited) { hencDelete(m_view); hencDeinit(); }
wglMakeCurrent(NULL, NULL); if (m_hRC) wglDeleteContext(m_hRC); if (m_hDC) ::ReleaseDC(m_hWnd, m_hDC);
CView::OnDestroy();}자주 마주치는 문제
섹션 제목: “자주 마주치는 문제”- OnDraw 가 호출돼도 빈 화면:
wglMakeCurrent가 OnDraw 마다 호출되지 않으면 다른 컨텍스트가 현재 상태일 수 있다. 멀티 뷰·다이얼로그가 있으면 매번 명시적으로 컨텍스트 활성화. - OnSize 에서 뷰포트가 0×0: 최초
OnCreate시점에cx == 0인 경우가 있다.m_inited플래그로 가드. - MFC OnEraseBkgnd 깜빡임: 반드시
OnEraseBkgnd에서TRUE반환. 기본 동작은 흰 배경으로 채워 깜빡임 발생. - 객체 선택이 빈 결과:
hencPickObj의 검색 반경(px) 을 8~16 정도로 늘리거나, hencSelectObj 로 사각 영역 선택 사용.
관련 API
섹션 제목: “관련 API”- 라이프사이클: hencInit / hencCreate / hencSelect / hencDelete / hencDeinit
- 렌더링: hencSetViewport / hencClearBackground / hencRender / hencSwapBuffer
- 객체 선택: hencPickObj / hencSelectObj / hencObjToString