本項では視点変更するための処理を追加していきます。
先ずメニューから視点変更ダイアログを呼び出せるようにします。ビューに視点座標と注目点座標を保持するようにして、その座標を元に視点変更する処理を追加します。視点変更ダイアログのメッセージハンドラーにスライダーの値を視点座標と注視点座標としてビューに渡す処理を追加すれば、スライダーに変更があるとメッセージハンドラーが呼ばれ、値がビューに渡され視点が変更されるはずです。
視点変更コマンドのメニューを追加します。
1. メニューの[表示]-[その他のウィンドウ]-[リソースビュー]を選択し、『リソースビュー』を開きます。
2. リソースビューの "Menu" を展開後、"IDR_MAINFRAME" をダブルクリックし、『IDR_MAINFRAME』メニュービューを開きます。
3. "表示(V)" を展開後、”ステータスバー(S)”の下の ”ここに入力” をクリックし、"視点変更(&C)..." を追加します。
4. "視点変更(C)..." を右クリックし、ポップアップメニューを開き「プロパティ」を選択します。
5. 「ID」 を "ID_VIEW_CHANGE" に変更します。
6. 「プロンプト」に "視点変更ダイアログの表示/非表示\n視点変更ダイアログの表示切り替え" と入力します。
正しく実行できていれば【resource.h】,【STLViewer.rc】のように変更されています。
1. メニューの [プロジェクト(P)]-[クラスウィザード(Z)...] を選択し、『クラスウィザード』ダイアログを開きます。
2. 「クラス名(N)」コンボボックスで "CSTLViewerView" を選択します。
3. 「オブジェクトID(B)」リストボックスで "ID_VIEW_CHANGE" を選択します。
4. 「ハンドラーの追加(A)...」ボタンを押下します。
5. 『メンバー関数の追加』ダイアログが開いたら、「OK」ボタンを押下します。
6. 「メッセージ(S)」で "UPDATE_COMMAND_UI" を選択します。
7. 「ハンドラーの追加(A)...」ボタンを押下します。
8. 『メンバー関数の追加』ダイアログが開いたら、「OK」ボタンを押下します。
9. 『クラスウィザード』ダイアログの「OK」ボタンを押下します。
正しく実行できていれば【STLViewerView.h】,【STLViewerView.cpp】のように変更されています。
視点変更ダイアログの表示と視点変更処理を追加します。
1. モードレスダイアログを保持するため CViewChangeDlg の前方宣言を行います。
【STLViewerView.h】
// STLViewerView.h : CSTLViewerView クラスのインターフェイス
//
#pragma once
class CViewChangeDlg;
2. メンバー変数に視点座標, 注目点座標, 視点変更ダイアログを追加します。
【STLViewerView.h】
class CSTLViewerView : public CView
{
/* 長くなるので一部省略、ここより上は変更なし */
public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnViewChange();
afx_msg void OnUpdateViewChange(CCmdUI* pCmdUI);
private:
CgsPoint m_cpEye; // 視点座標
CgsPoint m_cpCenter; // 注目点座標
CAutoPtr<CViewChangeDlg> m_ptrViewChangeDlg; // 視点変更ダイアログ
};
3. 視点座標, 注目点座標を取得/設定する関数を追加します。
【STLViewerView.h】
class CSTLViewerView : public CView
{
/* 長くなるので一部省略、ここより上は変更なし */
private:
CgsPoint m_cpEye; // 視点座標
CgsPoint m_cpCenter; // 注目点座標
CAutoPtr<CViewChangeDlg> m_ptrViewChangeDlg; // 視点変更ダイアログ
public:
const CgsPoint& GetEyePoint() const { return m_cpEye; }
const CgsPoint& GetCenterPoint() const { return m_cpCenter; }
void SetEyePoint(const CgsPoint& p) { m_cpEye = p; }
void SetCenterPoint(const CgsPoint& p) { m_cpCenter = p; }
};
4. 視点変更ダイアログ破棄関数を宣言します。
【STLViewerView.h】
class CSTLViewerView : public CView
{
/* 長くなるので一部省略、ここより上は変更なし */
public:
const CgsPoint& GetEyePoint() const { return m_cpEye; }
const CgsPoint& GetCenterPoint() const { return m_cpCenter; }
void SetEyePoint(const CgsPoint& p) { m_cpEye = p; }
void SetCenterPoint(const CgsPoint& p) { m_cpCenter = p; }
void DestroyViewChangeDlg();
};
1. 視点変更ダイアログを呼び出すのでインクルードファイルを追加します。
【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"
#include "CViewChangeDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
2. 視点座標を初期化します。
【STLViewerView.cpp】
CSTLViewerView::CSTLViewerView() noexcept
: m_hGLRC(nullptr)
, m_cpEye({200.0, 200.0, 200.0})
{
// TODO: 構築コードをここに追加します。
}
3. 視点変更で視点座標と注目点座標を渡すように変更します。
gluLookAt(200.0, 200.0, 200.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); の青字で書かれた引数を書き換えます。
【STLViewerView.cpp】
void CSTLViewerView::DrawGL()
{
/* 長くなるので一部省略、ここより上は変更なし */
// 視点等変更
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(
m_cpEye.GetX(), m_cpEye.GetY(), m_cpEye.GetZ(),
m_cpCenter.GetX(), m_cpCenter.GetY(), m_cpCenter.GetZ(),
0.0, 1.0, 0.0);
/* 長くなるので一部省略、ここより下は変更なし */
}
4. 光源設定の座標値に視点座標を渡すように変更します。
const GLfloat position[4] = { 200.0f, 200.0f, 200.0f, 1.0f }; の青字で書かれた値を書き換えます。
【STLViewerView.cpp】
void CSTLViewerView::SetLight() const
{
const GLfloat ambient[4] = { 0.8f, 0.8f, 0.8f, 1.0f };
const GLfloat diffuse[4] = { 0.6f, 0.6f, 0.6f, 1.0f };
const GLfloat specular[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
const GLfloat position[4] = {
(float)m_cpEye.GetX(), (float)m_cpEye.GetY(), (float)m_cpEye.GetZ(), 1.0f
};
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); // 環境光設定
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); // 拡散光設定
glLightfv(GL_LIGHT0, GL_SPECULAR, specular); // 鏡面光設定
glLightfv(GL_LIGHT0, GL_POSITION, position); // 光源座標
}
5. メニューの [表示(V)]-[視点変更(C)...] が選択された時の処理を追加します。
【STLViewerView.cpp】
void CSTLViewerView::OnViewChange()
{
if (m_ptrViewChangeDlg) {
// 視点変更ダイアログ破棄
DestroyViewChangeDlg();
}
else {
// 視点変更ダイアログ作成
m_ptrViewChangeDlg.Attach(new CViewChangeDlg(this));
if (m_ptrViewChangeDlg) {
m_ptrViewChangeDlg->Create(IDD_VIEW_CHANGE);
m_ptrViewChangeDlg->ShowWindow(SW_SHOW);
}
}
}
6. メニューの [表示(V)]-[視点変更(C)...] が表示された時の処理を追加します。
【STLViewerView.cpp】
void CSTLViewerView::OnUpdateViewChange(CCmdUI* pCmdUI)
{
// 視点変更ダイアログが表示中にチェックON
pCmdUI->SetCheck(m_ptrViewChangeDlg != nullptr);
}
7. 視点変更ダイアログを破棄する時の処理を追加します。
【STLViewerView.cpp】
void CSTLViewerView::DestroyViewChangeDlg()
{
if (m_ptrViewChangeDlg) {
// 視点変更ダイアログ破棄とオブジェクト破壊
m_ptrViewChangeDlg->DestroyWindow();
m_ptrViewChangeDlg.Free();
}
}
視点変更ダイアログとビュー間で視点座標と注目点座標の受け渡し処理を追加します。
視点変更ダイアログの起動時に視点と注目点を設定します。
【CViewChangeDlg.cpp】
BOOL CViewChangeDlg::OnInitDialog()
{
/* 長くなるので一部省略、ここより上は変更なし */
m_ctrlSliderCenterZ.SetRange(-1000, 1000, TRUE);
if (m_pView) {
// 視点設定
const CgsPoint& eye = m_pView->GetEyePoint();
m_ctrlSliderEyeX.SetPos((int)eye.GetX());
m_ctrlSliderEyeY.SetPos((int)eye.GetY());
m_ctrlSliderEyeZ.SetPos((int)eye.GetZ());
// 注目点設定
const CgsPoint& center = m_pView->GetCenterPoint();
m_ctrlSliderCenterX.SetPos((int)center.GetX());
m_ctrlSliderCenterY.SetPos((int)center.GetY());
m_ctrlSliderCenterZ.SetPos((int)center.GetZ());
}
return TRUE; // return TRUE unless you set the focus to a control
// 例外 : OCX プロパティ ページは必ず FALSE を返します。
}
視点変更ダイアログを閉じるときの処理を追加します。
【CViewChangeDlg.cpp】
void CViewChangeDlg::OnCancel()
{
if (m_pView) {
// 視点変更ダイアログはビューで寿命管理しているので
// ビューに作成した関数を使って破棄する
m_pView->DestroyViewChangeDlg();
}
}
スライダー変更を検知した時の処理を追加します。
【CViewChangeDlg.cpp】
void CViewChangeDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// スライダー変更検知
switch (pScrollBar->GetDlgCtrlID()) {
case IDC_SLIDER_EYE_X:
case IDC_SLIDER_EYE_Y:
case IDC_SLIDER_EYE_Z:
case IDC_SLIDER_CENTER_X:
case IDC_SLIDER_CENTER_Y:
case IDC_SLIDER_CENTER_Z:
const CgsPoint eye = {
(double)m_ctrlSliderEyeX.GetPos(),
(double)m_ctrlSliderEyeY.GetPos(),
(double)m_ctrlSliderEyeZ.GetPos()
};
const CgsPoint center = {
(double)m_ctrlSliderCenterX.GetPos(),
(double)m_ctrlSliderCenterY.GetPos(),
(double)m_ctrlSliderCenterZ.GetPos()
};
if (m_pView) {
// ビューに視点と注目点を設定し再描画
m_pView->SetEyePoint(eye);
m_pView->SetCenterPoint(center);
m_pView->RedrawWindow();
}
break;
}
CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}