本項ではビュー上に形状を描画できるようにするための準備を行います。【補足:ドキュメント/ビューアーキテクチャ】
MFCにはクラスウィザードと呼ばれる簡単にクラスの追加/編集が行える機能があります。クラスウィザードを使ってOpenGLでの描画に必要な準備を行い、ビュー上に座標軸を描画してみましょう。【補足:クラス、コードウィザード】
クラスウィザードを使って OpenGL 関連の変数/メソッド/ハンドラーの追加を行います。
1. メニューの [プロジェクト(P)]-[クラスウィザード(Z)...] を選択し、『クラスウィザード』ダイアログを開きます。
2. 「プロジェクト(P)」コンボボックスで "STLViewer" を選択します。
3. 「クラス名(N)」コンボボックスで "CSTLViewerView" を選択します。
4. 「メンバー変数」タブを選択します。
5. 「カスタムの追加(U)...」ボタンを押下し、『メンバー変数の追加』ダイアログを開きます。
6. 「変数の型(T)」コンボボックスに "HGLRC" を入力します。
7. 「変数名(N)」エディットボックスに "m_hGLRC" を入力します。
8. 「アクセス」のラジオボタンから "プライベート(V)" を選択します。
9. 「OK」ボタンを押下します。
続けてクラスウィザードを使い、メソッドを追加します。
1. 「メソッド」タブを選択します。
2. 「メソッドの追加(A)...」ボタンを押下し、『関数の追加』ダイアログを開きます。
3. 「関数名(U)」エディットボックスに "InitGL" を入力します。
4. 「戻り値の型(Y)」コンボボックスで "bool" を選択します。
5. 「アクセス(A)」コンボボックスで "private" を選択します。
6. 「OK」ボタンを押下します。
7. 『クラスウィザード』ダイアログで「メソッドの追加(A)...」ボタンを押下し、『関数の追加』ダイアログを開きます。
8. 「関数名(U)」エディットボックスに "DrawGL" を入力します。
9. 「戻り値の型(Y)」コンボボックスで "void" を選択します。
10. 「アクセス(A)」コンボボックスで "private" を選択します。
11. 「OK」ボタンを押下します。
12. 『クラスウィザード』ダイアログで「メソッドの追加(A)...」ボタンを押下し、『関数の追加』ダイアログを開きます。
13. 「関数名(U)」エディットボックスに "SetDCPixelFormat" を入力します。
14. 「戻り値の型(Y)」コンボボックスで "bool" を選択します。
15. 「アクセス(A)」コンボボックスで "private" を選択します。
16. 「+」ボタンを押下します。
17. 「パラメータ(P)」リストボックスのアイテムに "HDC hdc" を入力します。
18. 「OK」ボタンを押下します。
正しく実行できていれば【STLViewerView.h】,【STLViewerView.cpp】のように変更されています。
ここではクラスウィザードで追加したメソッドやハンドラーに処理を追加します。
gl*, glu*, glut* などの OpenGL 関連の API を呼び出すためのヘッダーファイルを追加しておきます。
【STLViewerView.cpp】
// STLViewerView.cpp : CSTLViewerView クラスの実装
//
#include "pch.h"
#include "framework.h"
#include <GL/glut.h>
// SHARED_HANDLERS は、プレビュー、縮小版、および検索フィルター ハンドラーを実装している ATL プロジェクトで定義でき、
// そのプロジェクトとのドキュメント コードの共有を可能にします。
#ifndef SHARED_HANDLERS
#include "STLViewer.h"
#endif
#include "STLViewerDoc.h"
#include "STLViewerView.h"
念のためレンダリングコンテキストハンドラー(m_hGLRC)を初期化しておきます。
【STLViewerView.cpp】
CSTLViewerView::CSTLViewerView() noexcept
: m_hGLRC(nullptr)
{
// TODO: 構築コードをここに追加します。
}
ビューが破棄されるときにレンダリングコンテキストに使用したデバイスコンテキストの解放とレンダリングコンテキストの削除を行います。
【STLViewerView.cpp】
CSTLViewerView::~CSTLViewerView()
{
wglMakeCurrent(NULL, NULL); // free current context
wglDeleteContext(m_hGLRC); // Delete rendering context
}
この関数で OpenGL 関連の初期化を行います。
【STLViewerView.cpp】
bool CSTLViewerView::InitGL()
{
// デバイスコンテキスト取得
CClientDC dc(this);
// ピクセルフォーマット設定
if (!SetDCPixelFormat(dc.m_hDC)) {
return false;
}
// レンダリングコンテキスト生成
m_hGLRC = wglCreateContext(dc.m_hDC);
if (!m_hGLRC) {
return false;
}
// カレントコンテキスト設定
if (!wglMakeCurrent(dc.m_hDC, m_hGLRC)) {
return false;
}
// 描画クリア時の色指定
glClearColor(1.0, 1.0, 1.0, 1.0);
return true;
}
ビューの描画が必要になったときに呼び出される関数です。
【STLViewerView.cpp】
void CSTLViewerView::DrawGL()
{
// カレントコンテキスト設定
CClientDC dc(this);
wglMakeCurrent(dc.m_hDC, m_hGLRC);
// バッファーのクリア
glClear(GL_COLOR_BUFFER_BIT);
// X軸線描画
glBegin(GL_LINES);
glColor3d(1.0, 0.0, 0.0);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(100.0, 0.0, 0.0);
glEnd();
// Y軸線描画
glBegin(GL_LINES);
glColor3d(0.0, 1.0, 0.0);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, 100.0, 0.0);
glEnd();
// Z軸線描画
glBegin(GL_LINES);
glColor3d(0.0, 0.0, 1.0);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, 0.0, 100.0);
glEnd();
// OpenGL関数の実行強制
glFlush();
// オンスクリーンバッファーへのコピー
SwapBuffers(dc.m_hDC);
}
この関数では OpenGL 描画を行うデバイス(ここではビュー)のピクセルフォーマットを設定します。
【STLViewerView.cpp】
bool CSTLViewerView::SetDCPixelFormat(HDC hdc)
{
// デバイスコンテキストに適したピクセルフォーマットを設定する
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // Size of this structure
1, // Version number
PFD_DRAW_TO_WINDOW | // Flags
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA, // RGBA pixel values
24, // 24-bit color
0, 0, 0, 0, 0, 0, // Don't care about these
0, 0, // No alpha buffer
0, 0, 0, 0, 0, // No accumulation buffer
32, // 32-bit depth buffer
0, // No stencil buffer
0, // No auxiliary buffers
PFD_MAIN_PLANE, // Layer type
0, // Reserved (must be 0)
0, 0, 0 // No layer masks
};
const int nPixelFormat = ChoosePixelFormat(hdc, &pfd);
// デバイスコンテキストにピクセルフォーマットを設定する
if (!SetPixelFormat(hdc, nPixelFormat, &pfd)) {
return false;
}
// 使用するピクセルフォーマットの情報を取得する
return (DescribePixelFormat(hdc, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd) != 0);
}
ビューが作成されるときの処理をここに記述します。
【STLViewerView.cpp】
int CSTLViewerView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// OpenGL初期化
if (!InitGL()) {
return -1;
}
return 0;
}
ビューのサイズが変更されるときの処理をここに記述します。
【STLViewerView.cpp】
void CSTLViewerView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// カレントコンテキスト設定
CClientDC dc(this);
wglMakeCurrent(dc.m_hDC, m_hGLRC);
// 描画領域設定
glViewport(0, 0, cx, cy);
glLoadIdentity();
gluPerspective(30.0, (double)cx / (double)cy, 1.0, 1000.0);
gluLookAt(200.0, 200.0, 200.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}
ビューの描画が必要になったときに呼び出される関数です。
【STLViewerView.cpp】
void CSTLViewerView::OnDraw(CDC* /*pDC*/)
{
CSTLViewerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// OpenGL描画
DrawGL();
}