3D研究室

Back to Title Page(OpenLab)タイトルページへ戻る

最終更新日: 1999年 04月 09日 金曜日

ダイアログボックスでも3DをPart2

 3D研究室へようこそ。ようやく公開できる程度のコードを作成 しましたので早速公開開始することにします。

 今回は、Direct3DRMのエミュレーションモードを使用した ワイヤーフレーム三角形の表示をダイアログボックス内のコントロールに 張り付け表示を行う基本プログラムです。

 今回あえてダイアログボックス形式を選んだのは、多くのサンプル プログラムが標準的なWindowを使用してチャイルドWindows などで表示するサンプルは発表していますが、ダイアログボックスに対し て行っている物はなく、ダイアログボックス形式なら、機能の拡張テスト やパラメータの変更を直感的にインプリメントしやすいため最近の私の ソフトのほとんどはダイアログボックス形式を使用しています。また、 MFCのダイアログボックス形式実行ファイルの作成は新規作成にて 簡単に行えるため、MFCからのDirect3Dの利用をよりはっきり 際だたせることになると思います。

 今回使用しているソースコードのすべてはこちらからダウンロードできます。必要な環境は、

Visual C++ 6.0 Professional Edition
作成時にはVisual Studio 6.0 Enterprizeで行いましたが VC++ 6.0 Proで十分です。
DirectX SDK 6.0 以降
DirectX SDK 6.1 をお勧めします。コンパイラー・リンカーがSDKに含まれる
ヘッダーファイル及びライブラリーを適切に見つけられるようにしておいてください。

 サンプルコードを以下に記載しておきます。手動で手を加えた主なところはで表しておきます。ソースコードとにらめっこするときに参考にしてください。

 PartUでの拡張

 今回は、カメラの移動・回転オブジェクトの選択に焦点をあてて拡張しました。カメラの移動回転はAddRotationとAddTranslateをカメラフレームに行うことで対応しました。これぐらいは、DirectXのマニュアルを少し理解すればできますが、実際に表示してるオブジェクトをダブルクリックして選択する方法も掲載しておきました。厳密な計算はしていませんので、若干ポインターが左上にずれますが、表示位置の調整をきちんと補正すればこの点は解消されますが今回は省略しました。

 追加した物にメッシュデータを保存・読込する機能も追加しておきました。ソースコードを参照してください。

 

 くわしくは、実際にコンパイルして実行しながらソースを眺めてみてください。


 具体的なインプリメント例としてソースコードを掲載しておきます。

// Test01Dlg.h : ヘッダー ファイル
//

#if !defined(AFX_TEST01DLG_H__0D547F07_ECDB_11D2_8DD3_0090CCA04D48__INCLUDED_)
#define AFX_TEST01DLG_H__0D547F07_ECDB_11D2_8DD3_0090CCA04D48__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

/////////////////////////////////////////////////////////////////////////////
// CTest01Dlg ダイアログ

#include "..\..\DXD3DRM.h"

class CTest01Dlg : public CDialog
{
// 構築
private:
    CDxD3DRm *c3c;

public:
    CTest01Dlg(CWnd* pParent = NULL);    // 標準のコンストラクタ

// ダイアログ データ
    //{{AFX_DATA(CTest01Dlg)
    enum { IDD = IDD_TEST01_DIALOG };
    CListBox    m_list1;
    CButton    m_window;
    //}}AFX_DATA

    // ClassWizard は仮想関数のオーバーライドを生成します。
    //{{AFX_VIRTUAL(CTest01Dlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV のサポート
    //}}AFX_VIRTUAL

// インプリメンテーション
protected:
    HICON m_hIcon;

    // 生成されたメッセージ マップ関数
    //{{AFX_MSG(CTest01Dlg)
    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    virtual void OnOK();
    virtual void OnCancel();
    afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
    afx_msg void OnOutofmemorySpin1(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnDeltaposSpin1(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnDeltaposSpin2(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnDeltaposSpin3(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnOutofmemorySpin4(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnDeltaposSpin4(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnDeltaposSpin5(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnDeltaposSpin6(NMHDR* pNMHDR, LRESULT* pResult);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ は前行の直前に追加の宣言を挿入します。

#endif // !defined(AFX_TEST01DLG_H__0D547F07_ECDB_11D2_8DD3_0090CCA04D48__INCLUDED_)

 

// Test01Dlg.cpp : インプリメンテーション ファイル
//

#include "stdafx.h"
#include "Test01.h"
#include "Test01Dlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CTest01Dlg ダイアログ


CTest01Dlg::CTest01Dlg(CWnd* pParent /*=NULL*/)
    : CDialog(CTest01Dlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(CTest01Dlg)
        // メモ: この位置に ClassWizard によってメンバの初期化が追加されます。
    //}}AFX_DATA_INIT
    // メモ: LoadIcon は Win32 の DestroyIcon のサブシーケンスを要求しません。
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    c3c = NULL;
}

void CTest01Dlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CTest01Dlg)
    DDX_Control(pDX, IDC_LIST1, m_list1);
    DDX_Control(pDX, IDC_STATIC_WINDOW, m_window);
    //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CTest01Dlg, CDialog)
    //{{AFX_MSG_MAP(CTest01Dlg)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_WM_LBUTTONDBLCLK()
    ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN1, OnDeltaposSpin1)
    ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN2, OnDeltaposSpin2)
    ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN3, OnDeltaposSpin3)
    ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN4, OnDeltaposSpin4)
    ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN5, OnDeltaposSpin5)
    ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN6, OnDeltaposSpin6)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTest01Dlg メッセージ ハンドラ

BOOL CTest01Dlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // このダイアログ用のアイコンを設定します。フレームワークはアプリケーションのメイン
    // ウィンドウがダイアログでない時は自動的に設定しません。
    SetIcon(m_hIcon, TRUE);             // 大きいアイコンを設定
    SetIcon(m_hIcon, FALSE);        // 小さいアイコンを設定
   
    // TODO: 特別な初期化を行う時はこの場所に追加してください。

    c3c = new CDxD3DRm(&m_window); // this

    HRESULT hr = c3c->GetLastErr();
    if(FAILED(hr)){
        AfxMessageBox("D3DRM3インターフェース作成に失敗しました");
        return TRUE;
    }
    //-----------------------
    // MeshBuilder Sample

    {
    D3DVECTOR vertices[ ] = {
        D3DVAL( -1 ), D3DVAL( 0 ), D3DVAL( 0 ),
        D3DVAL( 0 ), D3DVAL( 2 ), D3DVAL( 0 ),
        D3DVAL( 1 ), D3DVAL( 0 ), D3DVAL( 0 ),
    };

    // フェース リスト
    int faces[ ] = {
        3, 0, 1, 2,
        0
    };

        CDxD3DRmMeshBuilder mesh1;
        CDxD3DRmFrame newFrame;
        hr = mesh1.Create(c3c);

        if(FAILED(hr)){     AfxMessageBox("MeshBuilder 作成に失敗しました"); return TRUE;}

//        mesh1.Load("..\\sample.x");
        mesh1.AddFaces(3,vertices,0,NULL,(LPDWORD)faces,NULL);

        c3c->CreateFrame(&newFrame);             // 初期フレームから新しいフレーム生成
        newFrame.AddVisual(mesh1.GetObject()); // フレームにメッシュを割り当て
        newFrame.SetPosition(0,0,0);
        newFrame.SetOrientation(0,0,1,0,1,0);

        mesh1.SetName("Sample Triangle");
//        mesh1.Save("sample.x");

    }
    c3c->ActivateJob();
    //-----------------------
    return TRUE; // TRUE を返すとコントロールに設定したフォーカスは失われません。
}

// もしダイアログボックスに最小化ボタンを追加するならば、アイコンを描画する
// コードを以下に記述する必要があります。MFC アプリケーションは document/view
// モデルを使っているので、この処理はフレームワークにより自動的に処理されます。

void CTest01Dlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 描画用のデバイス コンテキスト

        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

        // クライアントの矩形領域内の中央
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // アイコンを描画します。
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDC *p;
        p = m_window.GetDC();
       
        //-----------------------
        c3c->HandlePaintJob(p);
        c3c->ViewportClear();
        c3c->Render();
        c3c->Update();
        //-----------------------
        m_window.ReleaseDC(p);
        //-----------------------
        CDialog::OnPaint();
    }
}

// システムは、ユーザーが最小化ウィンドウをドラッグしている間、
// カーソルを表示するためにここを呼び出します。
HCURSOR CTest01Dlg::OnQueryDragIcon()
{
    return (HCURSOR) m_hIcon;
}

void CTest01Dlg::OnOK()
{
    // TODO: この位置にその他の検証用のコードを追加してください
    if(c3c!=NULL)delete c3c;
    CDialog::OnOK();
}

void CTest01Dlg::OnCancel()
{
    // TODO: この位置に特別な後処理を追加してください。
    if(c3c!=NULL)delete c3c;
    CDialog::OnCancel();
}


void CTest01Dlg::OnDeltaposSpin1(NMHDR* pNMHDR, LRESULT* pResult) {
    NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
    // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
    NM_UPDOWN p = *pNMUpDown;
    c3c->d3Camera.AddRotation(D3DVALUE(0.1 * p.iDelta),0,0,D3DVALUE(0.1));
    InvalidateRect(NULL,FALSE);
    *pResult = 0;
}

void CTest01Dlg::OnDeltaposSpin2(NMHDR* pNMHDR, LRESULT* pResult) {
    NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
    // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
    NM_UPDOWN p = *pNMUpDown;
    c3c->d3Camera.AddRotation(0,D3DVALUE(0.1 * p.iDelta),0,D3DVALUE(0.1));
    InvalidateRect(NULL,FALSE);
    *pResult = 0;
}

void CTest01Dlg::OnDeltaposSpin3(NMHDR* pNMHDR, LRESULT* pResult) {
    NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
    // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
    NM_UPDOWN p = *pNMUpDown;
    c3c->d3Camera.AddRotation(0,0,D3DVALUE(0.1 * p.iDelta),D3DVALUE(0.1));
    InvalidateRect(NULL,FALSE);
    *pResult = 0;
}

void CTest01Dlg::OnDeltaposSpin4(NMHDR* pNMHDR, LRESULT* pResult)
{
    NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
    // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
    NM_UPDOWN p = *pNMUpDown;
    c3c->d3Camera.AddTranslation(D3DVALUE(0.1 * p.iDelta),0,0);
    InvalidateRect(NULL,FALSE);
    *pResult = 0;
}

void CTest01Dlg::OnDeltaposSpin5(NMHDR* pNMHDR, LRESULT* pResult)
{
    NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
    // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
    NM_UPDOWN p = *pNMUpDown;
    c3c->d3Camera.AddTranslation(0,D3DVALUE(0.1 * p.iDelta),0);
    InvalidateRect(NULL,FALSE);
    *pResult = 0;
}

void CTest01Dlg::OnDeltaposSpin6(NMHDR* pNMHDR, LRESULT* pResult)
{
    NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
    // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
    NM_UPDOWN p = *pNMUpDown;
    c3c->d3Camera.AddTranslation(0,0,D3DVALUE(0.1 * p.iDelta));
    InvalidateRect(NULL,FALSE);
    *pResult = 0;
}
//---------------------------------------------------------------
void CTest01Dlg::OnLButtonDblClk(UINT nFlags, CPoint point)
{
    // TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォルトの処理を呼び出してください
    LPDIRECT3DRMPICKEDARRAY lpPicked;
    c3c->d3Viewport.Pick((LONG)point.x,(LONG)point.y,&lpPicked);
    DWORD i,d = lpPicked->GetSize();
    LPDIRECT3DRMVISUAL         lplpVisual;
    LPDIRECT3DRMFRAMEARRAY    lplpFrameArray;
    D3DRMPICKDESC lpD3DRMPickDesc;

    char name[512];
    DWORD dw=512;
    m_list1.ResetContent();
    for(i=0;i<d;i++){
        lpPicked->GetPick(i,&lplpVisual,&lplpFrameArray,&lpD3DRMPickDesc);
        lplpVisual->GetName(&dw,(LPSTR)name);
        if(strlen(name)==0)continue;
        m_list1.AddString(name);
    }
    CDialog::OnLButtonDblClk(nFlags, point);
}


Copyright (C) Kitaro 1999