'direct3d'에 해당되는 글 1건

  1. wx파이썬 d3d 연동하기 (2) 2007/05/13

wx파이썬 d3d 연동하기

Posted at 2007/05/13 20:00// Posted in wxPython/wxApp
0. 다운로드

wxPython.direct3d.tutorial.vertices



1. 프로젝트 만들기

사용하는 컴파일러는 vc2005 express 버전입니다.

vc2005 express 는 dll 프로젝트를 만들 수 있는 위자드가 없으므로
첨부 파일에 포함된 Direct3DProjectMaker.py 를 사용합니다.

from ctypes import *
import os

VCPROJ_FORM         = open("project_template/template.vcproj").read()
PROJECT_DEF_FORM    = open("project_template/project.def").read()
PROJECT_CPP_FORM    = open("project_template/project.cpp").read()
PROJECT_PY_FORM     = open("project_template/project.py").read()
PROJECT_H_FORM      = open("project_template/project.h").read()
STDAFX_CPP_FORM     = open("project_template/stdafx.cpp").read()
STDAFX_H_FORM       = open("project_template/stdafx.h").read()


class GUID(Structure):
    _fields_ = [
            ("data1", c_ulong),
            ("data2", c_ushort),
            ("data3", c_ushort),
            ("data4", c_ubyte * 2),
            ("data5", c_ubyte * 6),
        ]

    def __init__(self):
        windll.ole32.CoCreateGuid(byref(self))

    def __str__(self):
        return "%X-%X-%X-%s-%s" % (self.data1, self.data2, self.data3,
            "".join("%X" % (c) for c in self.data4),
            "".join("%X" % (c) for c in self.data5))

    def __repr__(self):
        return "{%s}" % self.__str__()

def MakeProject(name):

    PROJECT_GUID = str(GUID())
    PROJECT_NAME = name
    PROJECT_EXPORT      = "%s_EXPORT" % (PROJECT_NAME.upper())
    PROJECT_INC         = "$(DXSDK_DIR)/include"
    PROJECT_DEBUG_LIB   = "$(DXSDK_DIR)/Lib/x86"
    PROJECT_RELEASE_LIB = "$(DXSDK_DIR)/Lib/x86"

    os.mkdir(name)
    open("%s/%s.vcproj"     % (name, name), "w").write(VCPROJ_FORM % locals())
    open("%s/%s.def"        % (name, name), "w").write(PROJECT_DEF_FORM % (locals()))
    open("%s/%s.cpp"        % (name, name), "w").write(PROJECT_CPP_FORM)
    open("%s/%s.py"         % (name, name), "w").write(PROJECT_PY_FORM % (locals()))
    open("%s/%s.h"          % (name, name), "w").write(PROJECT_H_FORM)
    open("%s/stdafx.cpp"    % (name),       "w").write(STDAFX_CPP_FORM)
    open("%s/stdafx.h"      % (name),       "w").write(STDAFX_H_FORM)

if __name__ == "__main__":
    MakeProject("temp")


MakeProject 에 프로젝트 이름을 적고 실행하면 해당 이름을 가진 vc2005 dll 프로젝트가 만들어집니다.

D3D SDK 위치는 $(DXSDK_DIR) 를 사용하며, 환경변수로 DXSDK_DIR 를 만들어주거나, 해당 위치에 직접 경로를 적어주면 됩니다.



2. d3d 코드 작성

d3d 코드를 작성 합니다. 여기서는 d3d 예제인 vertices.cpp 파일을 복사한 후
WinMain 과 MsgProc 부분을 제거했습니다.

#include "stdafx.h"
//-----------------------------------------------------------------------------
// File: Vertices.cpp
//
// Desc: In this tutorial, we are rendering some vertices. This introduces the
//       concept of the vertex buffer, a Direct3D object used to store
//       vertices. Vertices can be defined any way we want by defining a
//       custom structure and a custom FVF (flexible vertex format). In this
//       tutorial, we are using vertices that are transformed (meaning they
//       are already in 2D window coordinates) and lit (meaning we are not
//       using Direct3D lighting, but are supplying our own colors).
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#include <d3d9.h>
#pragma warning( disable : 4996 ) // disable deprecated warning
#include <strsafe.h>
#pragma warning( default : 4996 )




//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
LPDIRECT3D9             g_pD3D       = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9       g_pd3dDevice = NULL; // Our rendering device
LPDIRECT3DVERTEXBUFFER9 g_pVB        = NULL; // Buffer to hold vertices

// A structure for our custom vertex type
struct CUSTOMVERTEX
{
    FLOAT x, y, z, rhw; // The transformed position for the vertex
    DWORD color;        // The vertex color
};

// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)




//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: Initializes Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
    // Create the D3D object.
    if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
        return E_FAIL;

    // Set up the structure used to create the D3DDevice
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

    // Create the D3DDevice
    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                      &d3dpp, &g_pd3dDevice ) ) )
    {
        return E_FAIL;
    }

    // Device state would normally be set here

    return S_OK;
}




//-----------------------------------------------------------------------------
// Name: InitVB()
// Desc: Creates a vertex buffer and fills it with our vertices. The vertex
//       buffer is basically just a chuck of memory that holds vertices. After
//       creating it, we must Lock()/Unlock() it to fill it. For indices, D3D
//       also uses index buffers. The special thing about vertex and index
//       buffers is that they can be created in device memory, allowing some
//       cards to process them in hardware, resulting in a dramatic
//       performance gain.
//-----------------------------------------------------------------------------
HRESULT InitVB()
{
    // Initialize three vertices for rendering a triangle
    CUSTOMVERTEX vertices[] =
    {
        { 150.0f,  50.0f, 0.5f, 1.0f, 0xffff0000, }, // x, y, z, rhw, color
        { 250.0f, 250.0f, 0.5f, 1.0f, 0xff00ff00, },
        {  50.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },
    };

    // Create the vertex buffer. Here we are allocating enough memory
    // (from the default pool) to hold all our 3 custom vertices. We also
    // specify the FVF, so the vertex buffer knows what data it contains.
    if( FAILED( g_pd3dDevice->CreateVertexBuffer( 3*sizeof(CUSTOMVERTEX),
                                                  0, D3DFVF_CUSTOMVERTEX,
                                                  D3DPOOL_DEFAULT, &g_pVB, NULL ) ) )
    {
        return E_FAIL;
    }

    // Now we fill the vertex buffer. To do this, we need to Lock() the VB to
    // gain access to the vertices. This mechanism is required becuase vertex
    // buffers may be in device memory.
    VOID* pVertices;
    if( FAILED( g_pVB->Lock( 0, sizeof(vertices), (void**)&pVertices, 0 ) ) )
        return E_FAIL;
    memcpy( pVertices, vertices, sizeof(vertices) );
    g_pVB->Unlock();

    return S_OK;
}




//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
VOID Cleanup()
{
    if( g_pVB != NULL )
        g_pVB->Release();

    if( g_pd3dDevice != NULL )
        g_pd3dDevice->Release();

    if( g_pD3D != NULL )
        g_pD3D->Release();
}




//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
//-----------------------------------------------------------------------------
VOID Render()
{
    // Clear the backbuffer to a blue color
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );

    // Begin the scene
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    {
        // Draw the triangles in the vertex buffer. This is broken into a few
        // steps. We are passing the vertices down a "stream", so first we need
        // to specify the source of that stream, which is our vertex buffer. Then
        // we need to let D3D know what vertex shader to use. Full, custom vertex
        // shaders are an advanced topic, but in most cases the vertex shader is
        // just the FVF, so that D3D knows what type of vertices we are dealing
        // with. Finally, we call DrawPrimitive() which does the actual rendering
        // of our geometry (in this case, just one triangle).
        g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) );
        g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
        g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 );

        // End the scene
        g_pd3dDevice->EndScene();
    }

    // Present the backbuffer contents to the display
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}



3. def 파일 작성

def 파일에 파이썬에서 사용할 함수 이름을 적습니다.

LIBRARY tutorial
EXPORTS   
    InitD3D
    InitVB
    Render
    Cleanup


4. 파이썬 코드 작성

ctypes 를 사용해 tutorial.def 의 함수 리스트 정보를 토대로 tutorial.dll 함수를 임포트합니다.

import ctypes

def Import(modName, funcNameList):
    globalDict = globals()

    mod = ctypes.cdll.__getattr__(modName)
    for funcName in funcNameList:
        func = mod.__getattr__(funcName)
        func.restype = None

        globalDict[funcName] = func

Import("tutorial", [funcName
    for funcName in [line.strip() for line in open("tutorial.def").readlines()[2:]] if funcName])



from ctypes.wintypes import HRESULT

InitD3D.restype = HRESULT
InitVB.restype = HRESULT

S_OK = 0


if __name__ == "__main__":
    import wx

    class TestFrame(wx.Frame):
        def __init__(self, parent, title):
            wx.Frame.__init__(self, parent, -1, title, pos=(0, 0), size=(320, 240))
            self.CentreOnScreen(wx.BOTH)

            if self.__Startup():
                self.Bind(wx.EVT_PAINT, self.__OnPaint)

        def __del__(self):
            self.__Cleanup()

        def __Startup(self):
            if InitD3D(self.GetHandle()) != S_OK:
                print "InitD3D.Error"
                return False

            if InitVB() != S_OK:
                print "InitVB.Error"
                return False

            return True

        def __OnPaint(self, event):
            dc = wx.PaintDC(self)

            Render()

        def __Cleanup(self):
            Cleanup()


    class TestApp(wx.App):
        def OnInit(self):
            "OnInit"
            frame = TestFrame(None, "TestApp")
            frame.Show()
            self.SetTopWindow(frame)
            return True

        def OnExit(self):
            "OnExit"
            pass

    TestApp(redirect=False).MainLoop()


wxPython 에서도 OnIdle 을 지원하긴 하지만, Threading 을 사용하는 것이 더 좋은 듯합니다. 이 방법에 대해서는 추후에 다루어 보도록 하겠습니다.
이올린에 북마크하기(0) 이올린에 추천하기(0)
2007/05/13 20:00 2007/05/13 20:00