Direct X Demo 따라하기 Direct X Wizard를 이용하여 프로젝트를 생성한다

Slides:



Advertisements
Similar presentations
YES C 제 1 장 C 언어의 개요 1/34 제 1 장 C 언어의 개요 문봉근. YES C 제 1 장 C 언어의 개요 2/34 제 1 장 C 언어의 개요 1.1 프로그램과 C 언어의 특징 1.2 C 언어의 프로그램 구성 1.3 비주얼 C++ 통합 환경 들어가기.
Advertisements

메시지 처리의 기본 개념 메시지 발생된 이벤트의 종류와 정보를 전달하는 일종의 상수 값 윈도우 프로그래밍 가장 중요한 것은 메시지를 처리하는 것 윈도우 시스템 Application 이벤트 발생 메시지 전송 메시지 처리 화면에 출력.
강의 내용 : DirectX 개요 DirectX 9 을 이용한 시각화. 목 차 DirectX 출현 배경 DirectX 현재 버전 DirectX 장점 DirectX 구성요소 DirectX SDK 다운로드 및 설치 DirectX SDK 폴더 구성 및 역할 샘플 코드 브라우저.
2장. 윈도우즈 입출력 1/211 1.
7장. MDI 프로그래밍 MDI 프로그래밍에 대한 내용을 배우도록 한다. 지금까지 배운 것은 생성된 윈도우에 단일 화면이 존재하는 형태였다. 이것을 SDI라고 부르고 Single Document Interface의 약자이다. 하나의 문서를 하나의 화면에 보여주는 형태의.
03장 영상처리를 위한 Visual C++ 디지털 영상 파일 포맷 MFC 응용 프로그램 마법사를 이용한 MFC 프로젝트 작성
제 11 장 구조체.
Implement of Input and Interaction
명품 C++ 프로그래밍 3장. 클래스와 객체.
명품 C++ 4장. 객체 포인터와 객체 배열, 객체의 동적 생성.
Windows Programming Chapter 1. Introduction to SDK
윈도우 운영체제와 윈도우 응용 프로그램의 특징을 이해한다.
2장 렌더링 파이프라인 목표 Direct3D에서 3D 물체를 표현하는 방법을 배운다. 가상카메라를 모델링하는 방법을 배운다.
C++ Espresso 제1장 기초 사항.
제1장 윈도우 프로그래밍 1.1 윈도우 프로그래밍의 개념 1.2 윈도우 프로그램의 기본 구조
Visual C++ Programming Document/View Architecture 3
5장. 단축키와 비트맵 윈도우 프로그램에는 화면에서 사용자들의 입력을 받아 들이고 출력을 위한 코드 외 부분이 존재한다. 이 부분을 주로 리소스라고 부르고 이들은 주로 화면에 나타난다. 메뉴, 툴바, 비트맵, 단축키, 대화상자 등이 여기에 속한다. 이 부분들은 우리의 프로그램의.
Chapter 09. 소켓 입출력 모델(I).
DirectX9를 이용한 3D GAME 프로그래밍 입문
Internet Computing KUT Youn-Hee Han
Chapter 02 JAVA 프로그래밍 시작하기 01 실무에서 사용하는 JAVA 개발 환경 02 JAVA 프로그램 작성
Lab 3 Guide: 교재 4장 대화상자 예제. - 프로파일 입력 ( 쪽)
제 8 장  파서 생성기 YACC 사용하기.
제12장 유연한 카메라 클래스 만들기 학기 컴퓨터게임(DirectX).
제13장 기본적인 지형 렌더링 학기 컴퓨터게임(DirectX).
실전 프로젝트 2 : 숫자야구 숫자 야구를 구현해보자.
윤 홍 란 MFC 기초 윤 홍 란
5장. 리스트 리스트 학습목표 목록이나 도표처럼 여러 데이터를 관리할 수 있는 자료형을 추상화
8. 객체와 클래스 (기본).
DirectX Audio 2002년 3월 최윤석 작성.
쉽게 풀어쓴 C언어 Express 제17장 동적 메모리와 연결 리스트 C Express.
C++ Espresso 제9장 다형성.
Choi, Namseok Java 기초 (Java의 제어문과 배열) Choi, Namseok
9장 글꼴.
문 성 원 3D Game Programming QuadTree Culling 문 성 원 KoreaIT 전문학교 게임학과.
9장 글꼴.
윤성우의 열혈 C++ 프로그래밍 윤성우 저 열혈강의 C++ 프로그래밍 개정판 Chapter 03. 클래스의 기본.
FND (Flexible Numeric Display)
MFC Application Frameworks (AFX)
MFC 프로그래밍에 관한 팁 / Keyboard / Timer
제6장 텍스처링 학기 컴퓨터게임(DirectX).
제8장 스텐실.
제 14 장 파티클 시스템.
12장 유연한 카메라 클래스 만들기 한성대학교 멀티미디어공학과 게임 프로그래밍-I 강의노트
Chapter 05. 클래스 완성. chapter 05. 클래스 완성 01. 복사 생성자 복사 생성(Copy Construction) 생성될 때 자신과 같은 타입의 객체를 변수로 받아, 이 객체와 같은 값을 갖는 새로운 객체를 생성하는 것 명시적인 생성 과정뿐만.
C ++ 프로그래밍 시작.
C++ 개요 객체지향 윈도우즈 프로그래밍 한국성서대학교 유일선
주소록 프로그램.
프로그래밍2 및 실습 C언어 기반의 C++ 2.
제 3 장 상수와 변수
제 16 장 고수준 셰이딩 언어 소개.
Chapter 3 클래스. 최호성.
Real-time Tactics Game
Chapter 09. 소켓 입출력 모델(I).
컴퓨터의 기초 제 2강 - 변수와 자료형 , 연산자 2006년 3월 27일.
가상함수와 추상 클래스.
Terrain.
WSAAsync Select 김대열 Bit - Academy Sunmoon University, Korea.
DirectX 9을 이용한 게임 개발 기본 코스 강의 내용 : blending.
3장. 변수와 연산자. 3장. 변수와 연산자 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, / 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, /
Direct 3D Direct 3D 프로그래밍의 흐름 Direct3D8 객체 생성 Direct3D8 객체 사용
Lab 9 Guide: 인터넷 프로그래밍 예제 * 일대일 채팅 프로그램 (교재 27장, 쪽)
DirectSound 프로그래밍 DirectSound를 사용하면 매우 짧은 지연 시간에 사운드를 재생해, 애플리케이션으로 하드웨어 리소스를 치밀하게 제어할 수 있다. DirectSound 인터페이스를 사용하여 다음과 같은 처리가 가능하게 된다. WAV 포맷의 파일 또는.
3장. 제어 메시지 처리하기 1/211 1.
제 7장 이벤트.
제 8장. 클래스의 활용 학기 프로그래밍언어및실습 (C++).
04장 ㅎㅎ 화소점 처리 화소 점 처리의 개념 디지털 영상의 산술연산과 논리연산 디지털 영상의 다양한 화소 점 처리 기법
게임과 1학년 Flipping - 파일을 읽어서 출력하는 프로그램
DirectX 9 Ch1. Direct3D 초기화.
제 4장 Visual C++ COM 컴파일러.
Presentation transcript:

Direct X Demo 따라하기 Direct X Wizard를 이용하여 프로젝트를 생성한다 File -> New -> Project ->DirectX 9 AppWizard 프로젝트 경로 및 프로젝트 이름 설정 후 OK -> Direct Music 제거 후 Next -> Triangle 선택 후 Next -> DirectInput Keyboard device 선택 후 Finish multimedia.bmp, multi2.wav, multi3.wav 화일을 프로젝트 디렉토리에 복사한다.

Direct X Demo 따라하기 우선 배경공간을 만든다 텍스쳐를 사용하기 위하여 텍스쳐 구조체를 선언한다. 프로젝트이름.h 에 버텍스 정보(위치, 법선, 텍스쳐 좌표)를 만든다. 코드 struct CUSTOMVERTEX { D3DXVECTOR3 position; // vertex position D3DXVECTOR3 normal; // vertex normal float tu,tv; }; #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1) 텍스쳐를 사용하기 위하여 텍스쳐 구조체를 선언한다. 프로젝트이름.h 에 CMyD3DApplication의 멤버변수로 다음을 추가한다. LPDIRECT3DTEXTURE9 g_pTexture1;

Direct X Demo 따라하기 텍스쳐와 버텍스를 생성한다. 프로젝트이름.cpp에 InitDeviceObjects()함수의 내용을 다음과 같이 변경한다. 배경을 그리기 위하여 사각형 4개( 삼각형 8개 – 점 24개)를 생성하며 multimedia.bmp화일을 텍스쳐로 생성한다. 코드 HRESULT hr; // Init the font m_pFont->InitDeviceObjects( m_pd3dDevice ); if( FAILED( D3DXCreateTextureFromFile( m_pd3dDevice, "multimedia.bmp", &g_pTexture1 ) ) ) { return E_FAIL; } // Create the vertex buffer if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( 24*sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_MANAGED, &m_pVB, NULL ) ) ) return DXTRACE_ERR( "CreateVertexBuffer", hr ); // Fill the vertex buffer with 2 triangles CUSTOMVERTEX* pVertices; //버텍스를 통하여 벽생성 사각형 4개를 생성 if( FAILED( hr = m_pVB->Lock( 0, 0, (VOID**)&pVertices, 0 ) ) ) return DXTRACE_ERR( "Lock", hr );

텍스쳐와 버텍스를 생성한다. 프로젝트이름.cpp에 InitDeviceObjects()함수의 내용을 다음과 같이 변경한다. 배경을 그리기 위하여 사각형 4개( 삼각형 8개 – 점 24개)를 생성하며 multimedia.bmp화일을 텍스쳐로 생성한다. 코드 HRESULT hr; // Init the font m_pFont->InitDeviceObjects( m_pd3dDevice ); if( FAILED( D3DXCreateTextureFromFile( m_pd3dDevice, "multimedia.bmp", &g_pTexture1 ) ) ) { return E_FAIL; } // Create the vertex buffer if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( 24*sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_MANAGED, &m_pVB, NULL ) ) ) return DXTRACE_ERR( "CreateVertexBuffer", hr ); // Fill the vertex buffer with 2 triangles CUSTOMVERTEX* pVertices; //버텍스를 통하여 벽생성 사각형 4개를 생성 if( FAILED( hr = m_pVB->Lock( 0, 0, (VOID**)&pVertices, 0 ) ) ) return DXTRACE_ERR( "Lock", hr ); pVertices[0].position = D3DXVECTOR3( -10.0f, -2.0f, 80.0f ); pVertices[0].normal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); pVertices[0].tu = 0.0f; pVertices[0].tv = 0.0f; pVertices[1].position = D3DXVECTOR3( 10.0f, -2.0f, 80.0f ); pVertices[1].normal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); pVertices[1].tu = 1.0f; pVertices[1].tv = 0.0f;

pVertices[2].position = D3DXVECTOR3( 10.0f, -2.0f, -10.0f ); pVertices[2].normal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); pVertices[2].tu = 1.0f; pVertices[2].tv = 1.0f; pVertices[3].position = D3DXVECTOR3( -10.0f, -2.0f, 80.0f ); pVertices[3].normal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); pVertices[3].tu = 0.0f; pVertices[3].tv = 0.0f; pVertices[4].position = D3DXVECTOR3( 10.0f, -2.0f, -10.0f ); pVertices[4].normal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); pVertices[4].tu = 1.0f; pVertices[4].tv = 1.0f; pVertices[5].position = D3DXVECTOR3( -10.0f, -2.0f, -10.0f ); pVertices[5].normal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); pVertices[5].tu = 0.0f; pVertices[5].tv = 1.0f; pVertices[6].position = D3DXVECTOR3( -10.0f, 5.0f, -10.0f ); pVertices[6].normal = D3DXVECTOR3( 1.0f, 0.0f, 0.0f ); pVertices[6].tu = 0.0f; pVertices[6].tv = 0.0f; pVertices[7].position = D3DXVECTOR3( -10.0f, -2.0f, 80.0f ); pVertices[7].normal = D3DXVECTOR3( 1.0f, 0.0f, 0.0f ); pVertices[7].tu = 1.0f; pVertices[7].tv = 1.0f; pVertices[8].position = D3DXVECTOR3( -10.0f, -2.0f, -10.0f ); pVertices[8].normal = D3DXVECTOR3( 1.0f, 0.0f, 0.0f ); pVertices[8].tu = 0.0f; pVertices[8].tv = 1.0f; pVertices[9].position = D3DXVECTOR3( -10.0f, 5.0f, -10.0f ); pVertices[9].normal = D3DXVECTOR3( 1.0f, 0.0f, 0.0f ); pVertices[9].tu = 0.0f; pVertices[9].tv = 0.0f; pVertices[10].position = D3DXVECTOR3( -10.0f, 5.0f, 80.0f ); pVertices[10].normal = D3DXVECTOR3( 1.0f, 0.0f, 0.0f ); pVertices[10].tu = 1.0f; pVertices[10].tv = 0.0f; pVertices[11].position = D3DXVECTOR3( -10.0f, -2.0f, 80.0f );

pVertices[11].normal = D3DXVECTOR3( 1.0f, 0.0f, 0.0f ); pVertices[11].tu = 1.0f; pVertices[11].tv = 1.0f; pVertices[12].position = D3DXVECTOR3( -10.0f, 5.0f, 80.0f ); pVertices[12].normal = D3DXVECTOR3( -1.0f, 0.0f, 0.0f ); pVertices[12].tu = 0.0f; pVertices[12].tv = 0.0f; pVertices[13].position = D3DXVECTOR3( 10.0f, -2.0f, 80.0f ); pVertices[13].normal = D3DXVECTOR3( -1.0f, 0.0f, 0.0f ); pVertices[13].tu = 1.0f; pVertices[13].tv = 1.0f; pVertices[14].position = D3DXVECTOR3( -10.0f, -2.0f, 80.0f ); pVertices[14].normal = D3DXVECTOR3( -1.0f, 0.0f, 0.0f ); pVertices[14].tu = 0.0f; pVertices[14].tv = 1.0f; pVertices[15].position = D3DXVECTOR3( -10.0f, 5.0f, 80.0f ); pVertices[15].normal = D3DXVECTOR3( -1.0f, 0.0f, 0.0f ); pVertices[15].tu = 0.0f; pVertices[15].tv = 0.0f; pVertices[16].position = D3DXVECTOR3( 10.0f, 5.0f, 80.0f ); pVertices[16].normal = D3DXVECTOR3( -1.0f, 0.0f, 0.0f ); pVertices[16].tu = 1.0f; pVertices[16].tv = 0.0f; pVertices[17].position = D3DXVECTOR3( 10.0f, -2.0f, 80.0f ); pVertices[17].normal = D3DXVECTOR3( -1.0f, 0.0f, 0.0f ); pVertices[17].tu = 1.0f; pVertices[17].tv = 1.0f; pVertices[18].position = D3DXVECTOR3( 10.0f, 5.0f, 80.0f ); pVertices[18].normal = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); pVertices[18].tu = 0.0f; pVertices[18].tv = 0.0f; pVertices[19].position = D3DXVECTOR3( 10.0f, -2.0f, -10.0f ); pVertices[19].normal = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); pVertices[19].tu = 1.0f; pVertices[19].tv = 1.0f; pVertices[20].position = D3DXVECTOR3( 10.0f, -2.0f, 80.0f );

pVertices[20].normal = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); pVertices[20].tu = 0.0f; pVertices[20].tv = 1.0f; pVertices[21].position = D3DXVECTOR3( 10.0f, 5.0f, 80.0f ); pVertices[21].normal = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); pVertices[21].tu = 0.0f; pVertices[21].tv = 0.0f; pVertices[22].position = D3DXVECTOR3( 10.0f, 5.0f, -10.0f ); pVertices[22].normal = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); pVertices[22].tu = 1.0f; pVertices[22].tv = 0.0f; pVertices[23].position = D3DXVECTOR3( 10.0f, -2.0f, -10.0f ); pVertices[23].normal = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); pVertices[23].tu = 1.0f; pVertices[23].tv = 1.0f; m_pVB->Unlock(); return S_OK;

Direct X Demo 따라하기 3차원 환경을 변경한다. 프로젝트이름.cpp의 RestoreDeviceObjects()함수안의 내용에 다음과 같이 수정한다 코드 // 모든 빛을 반사한다. D3DMATERIAL9 mtrl; D3DUtil_InitMaterial( mtrl, 1.0f, 1.0f, 1.0f ); m_pd3dDevice->SetMaterial( &mtrl ); //전체적인 밝기를 밝게 한다. m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x001F1F1F ); //바라보는 위치를 좀더 뒤로 하고 위쪽에서 바라보도록 한다. D3DXVECTOR3 vFromPt = D3DXVECTOR3( 0.0f, 10.0f, -20.0f );

Direct X Demo 따라하기 온라인상 움직임의 동기화를 위하여 FrameMove를 사용하지 않겠다. 렌더링하기 프로젝트이름.cpp 의 FrameMove()의 내용을 return S_OK; 를 제외하고 모두 제거한다. 렌더링하기 프로젝트이름.cpp의 Render()의 내용을 다음의 코드와 교체한다. 코드

// Clear the viewport m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0x000000ff, 1.0f, 0L ); //공간의 메테리얼 설정 D3DMATERIAL9 mtrl; D3DUtil_InitMaterial( mtrl, 0.9f, 0.9f, 0.9f ); m_pd3dDevice->SetMaterial( &mtrl ); if( SUCCEEDED( m_pd3dDevice->BeginScene() ) ) { //공간 렌더링을 위하여 월드 메트릭스 원점으로 이동 D3DXMATRIX matWorld; D3DXMATRIX matRotX; D3DXMATRIX matRotY; D3DXMatrixRotationX( &matRotX, m_fWorldRotX ); D3DXMatrixRotationY( &matRotY, m_fWorldRotY ); D3DXMatrixMultiply( &matWorld, &matRotX, &matRotY); m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); m_pd3dDevice->SetTexture( 0, g_pTexture1 ); // Render the vertex buffer contents m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(CUSTOMVERTEX) ); m_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX ); m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 8 ); RenderText(); // End the scene. m_pd3dDevice->EndScene(); } return S_OK;

Direct X Demo 따라하기 자원을 해제한다.. 이상으로 배경을 모두 만들었다. 사용자를 만들어보도록 하겠다. 프로젝트이름.cpp의 DeleteDeviceObjects()함수안의 내용에 다음과 같이 추가한다 코드 if( g_pTexture1 != NULL ) g_pTexture1->Release(); 이상으로 배경을 모두 만들었다. 사용자를 만들어보도록 하겠다.

Direct X Demo 따라하기 새로운 클래스를 생성한다. VC++ 메뉴에 Project -> Add to Project -> New 선택 C++ Header 선택 화일이름 = XUser로 하여 파일을 만든다 같은 방법으로 C++ Source File 화일이름 = XUser로 하여 파일을 만든다.

Direct X Demo 따라하기 XUser.h에 다음과 같이 추가한다. 코드 (자세한 내용은 주석을 참조) #include <d3dx9.h> //삼각형의 법선벡터 추출.. void Get_Normal(const D3DXVECTOR3 *p1 ,const D3DXVECTOR3 *p2 ,const D3DXVECTOR3 *p3 , D3DXVECTOR3 *normal); typedef struct _tagMapVertex { D3DXVECTOR3 p; D3DXVECTOR3 n; float tu,tv; }UCUSTOMVERTEX; //커스텀 버텍스 유형 설정 #define D3DFVF_UCUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1) //오브젝트 내용 위치 회전값 칼라 물체 위치 저장.. struct UserStatus D3DXVECTOR3 vLoc; D3DXVECTOR3 vR; FLOAT fR,fG,fB; D3DMATRIX matLocal; };

class XUser { private: //디바이스 포인터를 넘겨받아 저장 LPDIRECT3DDEVICE9 m_pd3dDevice; //사용자 정점버퍼 LPDIRECT3DVERTEXBUFFER9 m_pUserVB; //사용자 인덱스 버퍼 LPDIRECT3DINDEXBUFFER9 m_pUserIB; //상태 저장 구조체 사용 UserStatus userstatus; //사용자 이름 삽입. char name[256]; public: XUser(); ~XUser(); //공동 프레임워크. HRESULT InitDeviceObjects(LPDIRECT3DDEVICE9 pDevice); HRESULT DeleteDeviceObjects(); HRESULT RestoreDeviceObjects(); HRESULT Render(); //사용자의 움직임에 따른 회전량 계산을 위함 HRESULT UserRotate(float Rot); //사용자 움직임에 따른 좌표 변환을 위함. HRESULT set_Move(float x, float y, float z); //사용자의 이름을 저장하기 위함 HRESULT set_Name(char* name); //사용자의 이름을 얻어오기 위함 char* get_Name(); //디바이스를 수동으로 연결하기 위함 사용하지 않음 HRESULT setDevice(LPDIRECT3DDEVICE9 pDevice); //사용자의 색을 선택하기 위함 HRESULT setColor(float r, float g, float b); //사용자의 움직임을 절대적으로 이동 HRESULT set_InitMove(float x, float y, float z); //사용자의 움직인 좌표를 얻어 옴.. float get_x(); float get_y(); float get_z(); };

Direct X Demo 따라하기 XUser.cpp에 다음과 같이 추가한다. 생성자 / 소멸자 코드 (자세한 내용은 주석을 참조) #include "XUser.h" #include <dxerr9.h> #include "dxutil.h" #include "D3DUtil.h" //생성자 XUser::XUser() { userstatus.vLoc = D3DXVECTOR3(0.0f, 0.0f, 0.0f); userstatus.vR.x = 0.0f; userstatus.vR.y = 0.0f; userstatus.vR.z = 0.0f; //색 선정. userstatus.fR = 1.0f; userstatus.fG = 0.92f; userstatus.fB = 0.0f; //사용자의 위치(정가운데) 를 설정. D3DXMATRIX matWorld; D3DXMatrixTranslation(&matWorld, 0.0f, 0.0f, 0.0f); userstatus.matLocal = matWorld; } XUser::~XUser()

Direct X Demo 따라하기 XUser.cpp에 다음과 같이 추가한다. 코드 (자세한 내용은 주석을 참조) HRESULT XUser::setDevice(LPDIRECT3DDEVICE9 pDevice) { //디바이스를 전달받음 this->m_pd3dDevice = pDevice; return 1; } HRESULT XUser::InitDeviceObjects(LPDIRECT3DDEVICE9 pDevice) //사용자의 3차원 객체를 세팅 //버텍스를 통하여 점을 찍고 인덱스 버퍼를 통하여 그림 m_pUserVB = NULL; m_pUserIB = NULL; //디바이스 포인터를 저장. HRESULT hr; //버텍스 생성 6개의 점을 생성 if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( 6*sizeof(UCUSTOMVERTEX), 0, D3DFVF_UCUSTOMVERTEX, D3DPOOL_MANAGED, &m_pUserVB, NULL ) ) ) return DXTRACE_ERR( "CreateVertexBuffer", hr );

UCUSTOMVERTEX* pVertices; D3DXVECTOR3 normal; if( FAILED( hr = m_pUserVB->Lock( 0, 0, (VOID**)&pVertices, 0 ) ) ) return DXTRACE_ERR( "VertexLock", hr ); //todo : 여따가 그림 그리기.. pVertices[0].p = D3DXVECTOR3(0.0f, 2.0f, 0.0f); pVertices[0].n = D3DXVECTOR3(0.0f, 0.0f, 0.0f); pVertices[0].tu = 0; pVertices[0].tv = 0; pVertices[1].p = D3DXVECTOR3(0.0f, -2.0f, 0.0f); pVertices[1].n = D3DXVECTOR3(0.0f, 0.0f, 0.0f); pVertices[1].tu = 0; pVertices[1].tv = 0; pVertices[2].p = D3DXVECTOR3(-1.0f, 0.0f, 0.0f); pVertices[2].n = D3DXVECTOR3(0.0f, 0.0f, 0.0f); pVertices[2].tu = 0; pVertices[2].tv = 0; pVertices[3].p = D3DXVECTOR3(1.0f, 0.0f, 0.0f); pVertices[3].n = D3DXVECTOR3(0.0f, 0.0f, 0.0f); pVertices[3].tu = 0; pVertices[3].tv = 0; pVertices[4].p = D3DXVECTOR3(0.0f, 0.0f, -1.0f); pVertices[4].n = D3DXVECTOR3(0.0f, 0.0f, 0.0f); pVertices[4].tu = 0; pVertices[4].tv = 0; pVertices[5].p = D3DXVECTOR3(0.0f, 0.0f, 1.0f); pVertices[5].n = D3DXVECTOR3(0.0f, 0.0f, 0.0f); pVertices[5].tu = 0; pVertices[5].tv = 0;

//삼각형의 노벌값을 계산하여 삽입. Get_Normal(&pVertices[0].p, &pVertices[3].p, &pVertices[4].p, &normal); pVertices[0].n += normal; pVertices[3].n += normal; pVertices[4].n += normal; Get_Normal(&pVertices[0].p, &pVertices[5].p, &pVertices[3].p, &normal); pVertices[5].n += normal; Get_Normal(&pVertices[0].p, &pVertices[2].p, &pVertices[5].p, &normal); pVertices[2].n += normal; Get_Normal(&pVertices[0].p, &pVertices[4].p, &pVertices[2].p, &normal); Get_Normal(&pVertices[1].p, &pVertices[4].p, &pVertices[3].p, &normal); pVertices[1].n += normal; Get_Normal(&pVertices[1].p, &pVertices[3].p, &pVertices[5].p, &normal); Get_Normal(&pVertices[1].p, &pVertices[5].p, &pVertices[2].p, &normal); Get_Normal(&pVertices[1].p, &pVertices[2].p, &pVertices[4].p, &normal); m_pUserVB->Unlock();

//인덱스를 삽입 //인덱스는 인덱스 순서대로 버텍스를 삽입한것과 같다. WORD Userindex[24] = {0}; Userindex[0] = 0; Userindex[1] = 3; Userindex[2] = 4; Userindex[3] = 0; Userindex[4] = 5; Userindex[5] = 3; Userindex[6] = 0; Userindex[7] = 2; Userindex[8] = 5; Userindex[9] = 0; Userindex[10] = 4; Userindex[11] = 2; Userindex[12] = 1; Userindex[13] = 4; Userindex[14] = 3; Userindex[15] = 1; Userindex[16] = 3; Userindex[17] = 5; Userindex[18] = 1; Userindex[19] = 5; Userindex[20] = 2; Userindex[21] = 1; Userindex[22] = 2; Userindex[23] = 4; DWORD pSizeUserIndex = sizeof(Userindex); if( FAILED(hr = m_pd3dDevice->CreateIndexBuffer(pSizeUserIndex, 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &m_pUserIB, NULL))) return DXTRACE_ERR( "CreateIndexBuffer", hr ); WORD* pIndices; if (FAILED( m_pUserIB->Lock(0, pSizeUserIndex, (VOID**)&pIndices, 0))) return DXTRACE_ERR( "IndexLock", hr ); memcpy(pIndices, Userindex, pSizeUserIndex); m_pUserIB->Unlock(); return 1; }

Direct X Demo 따라하기 XUser.cpp에 다음과 같이 추가한다. 코드 (자세한 내용은 주석을 참조) HRESULT XUser::DeleteDeviceObjects() { //버텍스와 인덱스의 자원을 해제한다. SAFE_RELEASE(m_pUserVB); SAFE_RELEASE(m_pUserIB); return 1; } HRESULT XUser::RestoreDeviceObjects() HRESULT XUser::Render() //자신의 메테리얼로 설정후 좌표이동 및 렌더링 D3DMATERIAL9 mtrl; D3DUtil_InitMaterial( mtrl, userstatus.fR, userstatus.fG, userstatus.fB ); m_pd3dDevice->SetMaterial( &mtrl ); //현재 유저의 위치로 변경. m_pd3dDevice->SetTransform(D3DTS_WORLD, &userstatus.matLocal); //그림. m_pd3dDevice->SetStreamSource( 0, m_pUserVB, 0, sizeof(UCUSTOMVERTEX) ); m_pd3dDevice->SetFVF(D3DFVF_UCUSTOMVERTEX); m_pd3dDevice->SetIndices(m_pUserIB); m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 6, 0, 24/3);

Direct X Demo 따라하기 XUser.cpp에 다음과 같이 추가한다. //사용자 움직임에 따라 화전 코드 (자세한 내용은 주석을 참조) //사용자 움직임에 따라 화전 HRESULT XUser::UserRotate(float Rot) { userstatus.vR.x += Rot*0.5; D3DXMATRIX matTemp; D3DXMATRIX matWorld = userstatus.matLocal; D3DXMatrixRotationY(&matTemp, userstatus.vR.x); D3DXMatrixMultiply(&matWorld,&matTemp,&matWorld); userstatus.matLocal=matWorld; return 1; } //사용자의 움직임 HRESULT XUser::set_Move(float x, float y, float z) userstatus.vLoc.x += x*0.5; userstatus.vLoc.y += y*0.5; userstatus.vLoc.z += z*0.5; D3DXMATRIX matWorld; D3DXMatrixTranslation(&matWorld, userstatus.vLoc.x, userstatus.vLoc.y, userstatus.vLoc.z); userstatus.matLocal = matWorld;

return 1; } //사용자의 이름 세팅 HRESULT XUser::set_Name(char* name) { strcpy(this->name, name); return S_OK; //사용자의 이름 얻기 char* XUser::get_Name() return name; //색갈 세팅 HRESULT XUser::setColor(float r, float g, float b) userstatus.fR = r; userstatus.fG = g; userstatus.fB = b; //초기값으로 받은 경우 월드 메트릭스 계산 HRESULT XUser::set_InitMove(float x, float y, float z) userstatus.vLoc.x = x; userstatus.vLoc.y = y; userstatus.vLoc.z = z; D3DXMATRIX matWorld; D3DXMatrixTranslation(&matWorld, userstatus.vLoc.x, userstatus.vLoc.y, userstatus.vLoc.z); userstatus.matLocal = matWorld;

//위치 X좌표 float XUser::get_x() { return userstatus.vLoc.x; } //위치 Y좌표 float XUser::get_y() return userstatus.vLoc.y; //위치 Z좌표 float XUser::get_z() return userstatus.vLoc.z; //법선벡터값 계산을 위한 함수 void Get_Normal(const D3DXVECTOR3 *p1 ,const D3DXVECTOR3 *p2 ,const D3DXVECTOR3 *p3 , D3DXVECTOR3 *normal) D3DXVECTOR3 temp1, temp2; temp1.x = p1->x - p2->x; temp1.y = p1->y - p2->y; temp1.z = p1->z - p2->z; temp2.x = p2->x - p3->x; temp2.y = p2->y - p3->y; temp2.z = p2->z - p3->z; D3DXVec3Cross(normal , &temp1, &temp2); D3DXVec3Normalize(normal,normal);

Direct X Demo 따라하기 새로운 클래스를 생성한다. 이상으로 사용자를 만들었으며 여러 사용자를 위하여 사용자 매니저를 만들도록 하겠다. 새로운 클래스를 생성한다. VC++ 메뉴에 Project -> Add to Project -> New 선택 C++ Header 선택 화일이름 = ListManager로 하여 파일을 만든다 같은방법으로 C++ Sourse File 화일이름 = ListManager로 하여 파일을 만든다.

Direct X Demo 따라하기 ListManager.h에 다음과 같이 추가한다. 코드 (자세한 내용은 주석참조) #include "XUser.h" //자신포함 최대 8명이 접속할수 있으며 자신을 제외하고 7명을 관리하게 된다. #define MAXUSER 7 class ListManager { private: XUser userlist[MAXUSER]; int usercount[MAXUSER]; public: ListManager(); ~ListManager(); HRESULT userAdd(char *name); HRESULT userRemove(char *name); HRESULT allRander(); HRESULT initListmanager(LPDIRECT3DDEVICE9 pDevice); HRESULT DeleteDeviceObjects(); HRESULT userMove(char *act, char *name); HRESULT setInitMove(float x, float y, float z, char *name); };

Direct X Demo 따라하기 ListManager.cpp에 다음과 같이 추가한다. 코드 (자세한 내용은 주석참조) #include "ListManager.h" ListManager::ListManager() { } ListManager::~ListManager() //생성시 3개의 사용자 3차원 객체 초기화 HRESULT ListManager::initListmanager(LPDIRECT3DDEVICE9 pDevice) int a=0; for (a=0 ; a<MAXUSER ; a++) userlist[a].InitDeviceObjects(pDevice); userlist[a].set_Name(""); //사용자마다 다른 색을 선정. userlist[0].setColor(1.0f, 0.0f, 0.0f); userlist[1].setColor(0.0f, 1.0f, 0.0f); userlist[2].setColor(0.0f, 0.0f, 1.0f); userlist[3].setColor(0.5f, 1.0f, 0.0f); userlist[4].setColor(0.0f, 0.5f, 1.0f); userlist[5].setColor(1.0f, 0.0f, 0.5f); userlist[6].setColor(0.5f, 0.1f, 0.5f); return 1;

//사용자 추가 아이디가 "" 공백을 통하여 사용자 검색 //공백은 사용자가 없는것으로 인식. HRESULT ListManager::userAdd(char *name) { int a=0; for (a=0 ; a<MAXUSER ; a++) if (strcmp(userlist[a].get_Name(), "") == 0) userlist[a].set_Name(name); break; } return 0; //사용자 제거 HRESULT ListManager::userRemove(char *name) if ( strcmp(userlist[a].get_Name(), name) == 0) userlist[a].set_Name(""); return 1; //모든 3차원 객체 렌더링 //접속죽인 사용자만 렌더링. HRESULT ListManager::allRander() if ( strcmp(userlist[a].get_Name(), "") != 0) userlist[a].Render(); //소멸시 모든 3차원 객체 해제 HRESULT ListManager::DeleteDeviceObjects() userlist[a].DeleteDeviceObjects(); //사용자 움직임 에 따른 검색및 이동 HRESULT ListManager::userMove(char *name, char *act) if (strcmp(name,userlist[a].get_Name())==0) if (strcmp(act, "UP")==0) userlist[a].set_Move(0.0f, 0.0f, 1.0f); userlist[a].UserRotate(-1.0f); else if (strcmp(act, "DOWN")==0) userlist[a].set_Move(0.0f, 0.0f, -1.0f); userlist[a].UserRotate(1.0f); else if (strcmp(act, "LEFT")==0) userlist[a].set_Move(-1.0f, 0.0f, 0.0f); else if (strcmp(act, "RIGHT")==0) userlist[a].set_Move(1.0f, 0.0f, 0.0f); //초기값 설정을 위한 벡터값 세팅 HRESULT ListManager::setInitMove(float x, float y, float z, char *name) userlist[a].set_InitMove(x, y, z);

Direct X Demo 따라하기 이상으로 사용자 매니저를 만들었으며 메뉴에 호스트 및 접속 메뉴를 추가하고 접속을 위한 다이얼로그를 생성한다. Resource view창을 통하여 메뉴에 Host 와 connect를 추가하고 각각의 ID를 INET_HOST와 INET_CONNECT 라고 적어준다. 두개의 다이얼로그를 생성한다. Host다이얼로그 -> 에디트 상자를 삽입하여 ID를 IDC_CHATID라고 적어준다. 또 다이얼로그의 Properties 선택하여 IDD_HOST로 이름 붙인다. Connect다이얼로그 -> 에디트 상자 2개를 삽입하여 다음과 같이 ID를 IDC_IPADDR, IDC_CHATID와 INET_CONNECT로 적어준다. 또 다이얼로그의 Properties 선택하여 IDD_CONNECT로 이름 붙인다.

Direct X Demo 따라하기 채팅을 위하여 채팅창을 만든다. 새로운 클래스를 생성한다. VC++ 메뉴에 Project -> Add to Project -> New 선택 C++ Header 선택 화일이름 = Chating로 하여 파일을 만든다 같은방법으로 C++ Sourse File 화일이름 = Chating로 하여 파일을 만든다.

Direct X Demo 따라하기 Chating.h에 다음과 같이 추가한다. 코드 (자세한 내용은 주석 참조) #include <windows.h> #define ID_EDIT 100 #define ID_LISTBOX 101 //채팅내용을 보내는 메시지 선언 #define WM_UCHATSEND WM_USER+6 class Chating { private: char str[256]; public: Chating(); ~Chating(); HRESULT chat_SetText(char *p); HRESULT init_Chating(HWND hWnd, HINSTANCE g_hInst); HRESULT set_Focus(); };

Direct X Demo 따라하기 Chating.cpp에 다음과 같이 추가한다. #include "Chating.h" 코드 (자세한 내용은 주석 참조) #include "Chating.h" //메시지 가로채기 복구를 위한 프로시져 WNDPROC OldEditProc; //리스트와 에디트 헨들 HWND hlist; HWND hEdit_input; //에디트의 메시지 가로채기 LRESULT CALLBACK EditSubProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { char str[256]; switch (iMessage) case WM_KEYDOWN: if (wParam==VK_RETURN) //에디트 포커스 상태에서 엔터 입력시 WM_UCHATSEND 이벤트 발생 후 포커스 부모에게 넘김 GetWindowText(hWnd, str, 256); SetWindowText(hWnd, ""); if (strlen(str) != 0) SendMessage(GetParent(hWnd), WM_UCHATSEND, 0, (LPARAM)str); } SetFocus(GetParent(hWnd));

} return CallWindowProc(OldEditProc, hWnd, iMessage, wParam, lParam); Chating::Chating() { //소멸시 가로챈 메시지 복구 Chating::~Chating() SetWindowLong(hEdit_input, GWL_WNDPROC, (LONG)OldEditProc); //생성시 리스트와 에디트 생성 HRESULT Chating::init_Chating(HWND hWnd, HINSTANCE g_hInst) hEdit_input=CreateWindow("edit", "대화내용 입력", WS_CHILD | WS_VISIBLE | WS_CAPTION, 0, 200, 300, 50, hWnd, (HMENU)ID_EDIT, g_hInst, NULL); OldEditProc = (WNDPROC)SetWindowLong(hEdit_input, GWL_WNDPROC, (LONG)EditSubProc); hlist=CreateWindow("listBox", "채팅 창", WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_CAPTION, 0, 0, 300, 200, hWnd, (HMENU)ID_EDIT, g_hInst, NULL); return 1; //리스트에 내용 삽입 HRESULT Chating::chat_SetText(char *p) int a; a = SendMessage(hlist, LB_ADDSTRING, 0, (LPARAM)p); SendMessage(hlist, LB_SETCURSEL, (WPARAM)a, (LPARAM)a); HRESULT Chating::set_Focus() SetFocus(hEdit_input); return 0;

Direct X Demo 따라하기 이상으로 채팅관련 클래스를 만들었으며 따로 만들어 놓은 사운드와 플레이 클래스를 로드 한다. 새로운 클래스를 생성한다. VC++ 메뉴에 Project -> Add to Project -> File 선택 dsdemo.cpp, dsdemo.h dsutil.cpp, dsutil.h DPSocket.cpp. DPSockt.h 를 로드 한다.

Direct X Demo 따라하기 DPSocket은 메시지(채팅, 움직임)처리를 위하여 수정하였으므로 다음의 코드를 덮는다. 코드 (DPSocket.h) /******************************************************************** created:2003/05/10 created:10:5:2003 0:55 filename: M:\MYSTUDY\DIRECTPLAY\DPSOCKET\DPSocket.h file path:M:\MYSTUDY\DIRECTPLAY\DPSOCKET file base:DPSocket file ext:h author:JAXAL purpose:DirectPlay를 캡슐화한 클래스 *********************************************************************/ #ifndef _DPSOCKET_H #define _DPSOCKET_H #include<windows.h> #include<dplay8.h> #include"dxutil.h" //각각의 메시지에 해당하는 메시지를 정의한다. #define WM_UCHAT WM_USER+1 #define WM_UMOVE WM_USER+2 #define WM_UCONNECT WM_USER+3 #define WM_UDISCON WM_USER+4 #define WM_USTARTM WM_USER+5 // {DA342589-D8A5-46af-866E-5D1C8F1375AF} static const GUID DP_SOCKET = { 0xda342589, 0xd8a5, 0x46af, { 0x86, 0x6e, 0x5d, 0x1c, 0x8f, 0x13, 0x75, 0xaf } };

#define MAX_PLAYERS 8 #define CHAT_MESSAGE 1000 #define MOVE_MESSAGE 1001 #define START_MESSAGE 1002 struct PACKET_OBJECT { UINTprotocol; charszMsg[256]; charszName[32]; }; class CDPSocket protected: CDPSocket(); static CDPSocket* pDPSocket; public: virtual ~CDPSocket(); static CDPSocket* getInstance() if(pDPSocket == NULL) return new CDPSocket(); return pDPSocket; } private: DPNHANDLEm_hConnectAsyncOp; HWNDm_hWnd; charm_szPeerName[256]; void SetHWnd(HWND hWnd);

HRESULT InitializeDirectPlay(); void SetMessageHandler(const PFNDPNMESSAGEHANDLER pfn); virtual HRESULT Host(char* strPeerName, DWORD dwPort); virtual HRESULT Connect(char* strIP, DWORD dwPort, char* strPeerName); virtual HRESULT SendMessage(UINT nProtocol, int player, char* message); private: static HRESULT WINAPI DirectPlayMessageHandler(PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer); static HRESULT CreatePlayer(PVOID pvUserContenxt, PVOID pMsgBuffer); static HRESULT DestoryPlayer(PVOID pvUserContext, PVOID pMsgBuffer); }; #endif

Direct X Demo 따라하기 DPSocket은 메시지(채팅, 움직임)처리를 위하여 수정하였음으로 다음의 코드를 덮는다. 코드 (DPSocket.cpp) /******************************************************************** created:2003/05/10 created:10:5:2003 1:14 filename: M:\MYSTUDY\DIRECTPLAY\DPSOCKET\DPSocket.cpp file path:M:\MYSTUDY\DIRECTPLAY\DPSOCKET file base:DPSocket file ext:cpp author:JAXAL purpose:DPSocket 구현 *********************************************************************/ //#include"stdafx.h" #include<stdio.h> #include"DPSocket.h" IDirectPlay8Peer*g_pDP; IDirectPlay8Address*g_pDeviceAddress; IDirectPlay8Address*g_pHostAddress; DPNIDg_dpnidLocalPlayer = 0; boolbHost = 0; struct PLAYER_INFORMATION { boolbActive; DPNIDdpnidPlayer; charszPlayerName[32]; };

struct PLAYER_INFORMATIONPlayerInfo[MAX_PLAYERS]; CDPSocket* CDPSocket::pDPSocket = new CDPSocket(); CDPSocket::CDPSocket() { g_pDP = NULL; g_pDeviceAddress = NULL; g_pHostAddress = NULL; } CDPSocket::~CDPSocket() if(g_pHostAddress) g_pHostAddress->Release(); if(g_pDeviceAddress) g_pDeviceAddress->Release(); if(g_pDP) g_pDP->Release(); void CDPSocket::SetHWnd(HWND hWnd) m_hWnd = hWnd; HRESULT CDPSocket::InitializeDirectPlay() HRESULT ret; ret = CoInitialize(NULL); if(FAILED(ret)) MessageBox(m_hWnd, "Error Initializing COM", "DirectPlayError", MB_ICONERROR); return ret;

ret = CoCreateInstance(CLSID_DirectPlay8Peer, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Peer, (LPVOID*)&g_pDP); if(FAILED(ret)) { MessageBox(m_hWnd, "Error Can't Create DirectPlay8Peer", "DirectPlayError", MB_ICONERROR); return ret; } ret = CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, (LPVOID*)&g_pDeviceAddress); MessageBox(m_hWnd, "Error Can't Create DeviceAddress", "DirectPlayError", MB_ICONERROR); ret = g_pDP->Initialize(NULL, DirectPlayMessageHandler, 0); MessageBox(m_hWnd, "Error Initialize MessageHandler", "DirectPlayError", MB_ICONERROR); ret = g_pDeviceAddress->SetSP(&CLSID_DP8SP_TCPIP); MessageBox(m_hWnd, "Error Device Service Provider", "DirectPlayError", MB_ICONERROR); ret = CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, (LPVOID*)&g_pHostAddress);

ret = g_pHostAddress->SetSP(&CLSID_DP8SP_TCPIP); if(FAILED(ret)) { MessageBox(m_hWnd, "Error Host Service Provider", "DirectPlayError", MB_ICONERROR); return ret; } return S_OK; HRESULT CDPSocket::Host(char* strPeerName, DWORD dwPort) charstrSessionName[256]; WCHARwszPeerName[256]; WCHARwszSessionName[256]; DPN_APPLICATION_DESCdnAppDesc; DPN_PLAYER_INFOdpPlayerInfo; HRESULTret; strcpy(m_szPeerName, strPeerName); DXUtil_ConvertGenericStringToWideCch(wszPeerName, strPeerName, 256); ZeroMemory(&dpPlayerInfo, sizeof(DPN_PLAYER_INFO)); dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO); dpPlayerInfo.dwInfoFlags = DPNINFO_NAME; dpPlayerInfo.pwszName = wszPeerName; ret = g_pDP->SetPeerInfo(&dpPlayerInfo, NULL, NULL, DPNSETPEERINFO_SYNC); MessageBox(m_hWnd, "Error SetPeerInfo", "DirectPlayError", MB_ICONERROR); sprintf(strSessionName, "%s's room", strPeerName); DXUtil_ConvertGenericStringToWideCch(wszSessionName, strSessionName, 256); ZeroMemory(&dnAppDesc, sizeof(DPN_APPLICATION_DESC)); dnAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC); dnAppDesc.guidApplication = DP_SOCKET; dnAppDesc.pwszSessionName = wszSessionName; dnAppDesc.dwMaxPlayers = MAX_PLAYERS; dnAppDesc.dwFlags = DPNSESSION_MIGRATE_HOST;

ret = g_pDeviceAddress->AddComponent(DPNA_KEY_PORT, &dwPort, sizeof(DWORD), DPNA_DATATYPE_DWORD); if(FAILED(ret)) { MessageBox(m_hWnd, "Error DeviceAddress AddComponent", "DirectPlayError", MB_ICONERROR); return ret; } ret = g_pDP->Host(&dnAppDesc, &g_pDeviceAddress, 1, NULL, NULL, NULL, NULL); MessageBox(m_hWnd, "Error Can't Host", "DirectPlayError", MB_ICONERROR); bHost = 1; return S_OK; HRESULT CDPSocket::Connect(char* strIP, DWORD dwPort, char* strPeerName) HRESULTret = S_OK; WCHARwszHostName[256]; WCHARwszPeerName[256]; DPN_APPLICATION_DESCdpnAppDesc; DPN_PLAYER_INFOdpPlayerInfo; strcpy(m_szPeerName, strPeerName); DXUtil_ConvertGenericStringToWideCch(wszPeerName, strPeerName, 256); ZeroMemory(&dpPlayerInfo, sizeof(DPN_PLAYER_INFO)); dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO); dpPlayerInfo.dwInfoFlags = DPNINFO_NAME; dpPlayerInfo.pwszName = wszPeerName; ret = g_pDP->SetPeerInfo(&dpPlayerInfo, NULL, NULL, DPNSETPEERINFO_SYNC); MessageBox(m_hWnd, "Error fail SetPeerInfo", "DirectPlayError", MB_ICONERROR); return -1;

ZeroMemory(&dpnAppDesc, sizeof(DPN_APPLICATION_DESC)); dpnAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC); dpnAppDesc.guidApplication = DP_SOCKET; DXUtil_ConvertGenericStringToWideCch(wszHostName, strIP, 256); ret = g_pHostAddress->AddComponent(DPNA_KEY_HOSTNAME, wszHostName, (wcslen(wszHostName)+1)*sizeof(WCHAR), DPNA_DATATYPE_STRING); if(FAILED(ret)) { MessageBox(m_hWnd, "Error fail Host Address AddComponent", "DirectPlayError", MB_ICONERROR); return -1; } ret = g_pHostAddress->AddComponent(DPNA_KEY_PORT, &dwPort, sizeof(DWORD), DPNA_DATATYPE_DWORD); MessageBox(m_hWnd, "Error fail Host Port AddComponent", "DirectPlayError", MB_ICONERROR); ret = g_pDP->Connect(&dpnAppDesc, g_pHostAddress, g_pDeviceAddress, NULL, NULL, NULL, 0, NULL, NULL, &m_hConnectAsyncOp, NULL); if(ret != E_PENDING && FAILED(ret)) MessageBox(m_hWnd, "Error fail Connect", "DirectPlayError", MB_ICONERROR); return ret; HRESULT CDPSocket::SendMessage(UINT nProtocol, int player, char* message) PACKET_OBJECTpacket; DPNHANDLEhAsync; DWORDdwLength = strlen(message); DPN_BUFFER_DESCbufferDesc; if(dwLength == 0) return S_OK;

packet.protocol = nProtocol; strcpy(packet.szMsg, message); strcpy(packet.szName, m_szPeerName); bufferDesc.dwBufferSize = sizeof(PACKET_OBJECT); bufferDesc.pBufferData = (BYTE*)&packet; if(player == -1) g_pDP->SendTo(DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1, 0, NULL, &hAsync, 0); else g_pDP->SendTo(PlayerInfo[player].dpnidPlayer, &bufferDesc, 1, 0, NULL, &hAsync, 0); return S_OK; } HRESULT WINAPI CDPSocket::DirectPlayMessageHandler(PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer) { HRESULTret = S_OK; PACKET_OBJECT*receive; intprotocol = 0; charstrMessage[256]; charstrName[256]; switch(dwMessageId) case DPN_MSGID_CREATE_PLAYER: CDPSocket::CreatePlayer(pvUserContext, pMsgBuffer); //MessageBox(pDPSocket->m_hWnd, "CreatePlayer!!!", "음..", MB_OK); break; case DPN_MSGID_DESTROY_PLAYER: CDPSocket::DestoryPlayer(pvUserContext, pMsgBuffer); case DPN_MSGID_HOST_MIGRATE: PDPNMSG_HOST_MIGRATE pHostMigrateMsg; pHostMigrateMsg = (PDPNMSG_HOST_MIGRATE)pMsgBuffer;

if(pHostMigrateMsg->dpnidNewHost == g_dpnidLocalPlayer) { MessageBox(pDPSocket->m_hWnd, "You are the Host!!", "DirectPlay", MB_OK); } break; case DPN_MSGID_TERMINATE_SESSION: MessageBox(pDPSocket->m_hWnd, "Terminating Session!!!", "DirectPlay", MB_OK); PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg; pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer; case DPN_MSGID_RECEIVE: PDPNMSG_RECEIVE pReceiveMsg; pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer; receive = (struct PACKET_OBJECT*)pReceiveMsg->pReceiveData; protocol = receive->protocol; strcpy(strMessage, receive->szMsg); strcpy(strName, receive->szName); //MessageBox(pDPSocket->m_hWnd, strMessage, strName, MB_OK); if (protocol == CHAT_MESSAGE) ::SendMessage(pDPSocket->m_hWnd, WM_UCHAT, (WPARAM)strMessage, (LPARAM)strName); else if (protocol == MOVE_MESSAGE) ::SendMessage(pDPSocket->m_hWnd, WM_UMOVE, (WPARAM)strMessage, (LPARAM)strName); else if (protocol == START_MESSAGE) ::SendMessage(pDPSocket->m_hWnd, WM_USTARTM, (WPARAM)strMessage, (LPARAM)strName);

case DPN_MSGID_CONNECT_COMPLETE: PDPNMSG_CONNECT_COMPLETE pConnectCompleteMsg; pConnectCompleteMsg = (PDPNMSG_CONNECT_COMPLETE)pMsgBuffer; break; } return ret; HRESULT CDPSocket::CreatePlayer(PVOID pvUserContenxt, PVOID pMsgBuffer) { HRESULTret = S_OK; PDPNMSG_CREATE_PLAYERpCreatePlayerMsg; charstrName[256]; DWORDdwSize = 0; DPN_PLAYER_INFO*pdpPlayerInfo = NULL; inti; pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer; ret = g_pDP->GetPeerInfo(pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0); if(FAILED(ret) && ret != DPNERR_BUFFERTOOSMALL) ret = -1; else pdpPlayerInfo = (DPN_PLAYER_INFO*)new BYTE[dwSize]; ZeroMemory(pdpPlayerInfo, dwSize); pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO); if(FAILED(ret)) DXUtil_ConvertWideStringToGenericCch(strName, pdpPlayerInfo->pwszName, 256);

for(i = 0 ; i < MAX_PLAYERS ; i++) { if(!PlayerInfo[i].bActive) PlayerInfo[i].bActive = 1; PlayerInfo[i].dpnidPlayer = pCreatePlayerMsg->dpnidPlayer; strcpy(PlayerInfo[i].szPlayerName, strName); ::SendMessage(pDPSocket->m_hWnd, WM_UCONNECT, (WPARAM)0, (LPARAM)strName); //MessageBox(pDPSocket->m_hWnd, strName, " ", MB_OK); break; } if(i == MAX_PLAYERS) MessageBox(pDPSocket->m_hWnd, "No free slots!!", "DirectPlay", MB_OK); else if(pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL) g_dpnidLocalPlayer = pCreatePlayerMsg->dpnidPlayer; char temp[24]; sprintf(temp, "<Slot%d> Added Ourselves", i); MessageBox(pDPSocket->m_hWnd, temp, "DirectPlay", MB_OK); else sprintf(temp, "<Slot%d><%s> Is In the room", i, strName); if(bHost) sprintf(temp, "Welcome to the room, %s!", strName); pDPSocket->SendMessage(CHAT_MESSAGE, i, temp); delete pdpPlayerInfo;

return ret; } HRESULT CDPSocket::DestoryPlayer(PVOID pvUserContext, PVOID pMsgBuffer) { PDPNMSG_DESTROY_PLAYERpDestroyPlayerMsg; HRESULTret = S_OK; pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer; if(pDestroyPlayerMsg->dwReason == DPNDESTROYPLAYERREASON_NORMAL) //그냥 나갔다 else if(pDestroyPlayerMsg->dwReason == DPNDESTROYPLAYERREASON_CONNECTIONLOST) //연결이 끊겼다 else if(pDestroyPlayerMsg->dwReason == DPNDESTROYPLAYERREASON_SESSIONTERMINATED) //세션이 끝나다 else if(pDestroyPlayerMsg->dwReason == DPNDESTROYPLAYERREASON_HOSTDESTROYEDPLAYER) //짤렸다 DPN_PLAYER_INFO*pdpPlayerInfo = NULL; DWORDdwSize = 0; PDPNMSG_CREATE_PLAYERpCreatePlayerMsg; charstrName[256]; pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer; g_pDP->GetPeerInfo(pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0); pdpPlayerInfo = (DPN_PLAYER_INFO*)new BYTE[dwSize]; ZeroMemory(pdpPlayerInfo, dwSize); pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO); DXUtil_ConvertWideStringToGenericCch(strName, pdpPlayerInfo->pwszName, 256);

return ret; ::SendMessage(pDPSocket->m_hWnd, WM_UDISCON, (WPARAM)0, (LPARAM)strName); delete pdpPlayerInfo; //::SendMessage(pDPSocket->m_hWnd, WM_UDISCON, (WPARAM)0, (LPARAM)strName); for(int i = 0 ; i < MAX_PLAYERS ; i++) { if(PlayerInfo[i].bActive) if(PlayerInfo[i].dpnidPlayer == pDestroyPlayerMsg->dpnidPlayer) PlayerInfo[i].bActive = 0; //나갔다는 메시지 뿌리고 break; } return ret;

Direct X Demo 따라하기 모든 클래스가 준비 되었으니 프로젝트이름.h 와 프로젝트이름.cpp를 수정하도록 하겠다. #include"Chating.h" #include"dsdemo.h" #include"dpsocket.h" #include"ListManager.h" CMyD3DApplication클래스의 멤버변수로 다음과 같이 추가한다. XUser user1; Chating chat; DSDemo Multi_Sound; ListManager user_lManager; CDPSocket *pDPSocket;

Direct X Demo 따라하기 프로젝트이름.cpp에 다음과 같이 수정한다. CMyD3DApplication()안에 다음을 추가한다. pDPSocket = NULL; InitDeviceObjects()안(return()직전)에 다음을 추가한다. //자신과 접속자 모두의 3차원 객체 생성 user1.InitDeviceObjects(m_pd3dDevice); user_lManager.initListmanager(m_pd3dDevice); Render()안(EndScene()전)에 다음을 추가한다. //자신과 모든 사용자 렌더링 user1.Render(); user_lManager.allRander(); DeleteDeviceObjects()에 다음을 추가한다. user1.DeleteDeviceObjects(); user_lManager.DeleteDeviceObjects();

Direct X Demo 따라하기 다음으로 다이얼로그(Host, Connect)다이얼로그 처리를 위한 프로시저를 MsgProc() 직전에 삽입한다 다음의 코드를 프로젝트이름.cpp에 삽입한다. //다이얼로그 박스에 의한 전달값 char d_str1[128]; // Connect시 아이피값 char d_str2[128]; // Connect시 아이디값 char d_str3[128]; // Host시 아이디값 BOOL CALLBACK ConnectDlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam) { switch(iMessage) case WM_COMMAND: switch(wParam) case IDOK: GetDlgItemText(hDlg, IDC_IPADDR, d_str1, 128); GetDlgItemText(hDlg, IDC_CHATID, d_str2, 128); EndDialog(hDlg, IDOK); break; } case IDCANCEL: EndDialog(hDlg, IDCANCEL);

} break; return 0; BOOL CALLBACK HostDlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam) { switch(iMessage) case WM_COMMAND: switch(wParam) case IDOK: GetDlgItemText(hDlg, IDC_CHATID, d_str3, 128); EndDialog(hDlg, IDOK); case IDCANCEL: EndDialog(hDlg, IDCANCEL);

Direct X Demo 따라하기 다음으로 프로그램의 모든 이벤트를 다루기 위한 MsgProc를 수정해야 하나 양이 많음으로 삭제 후 다음과 같이 삽입한다. 자세한 내용은 주석을 참조한다 코드 LRESULT CMyD3DApplication::MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { char temp[256]; switch( msg ) case WM_UCHAT: {//메시지 화면에 찍기 sprintf(temp, "%s %s", (char *)lParam, (char *)wParam); chat.chat_SetText(temp); break; } case WM_UMOVE: {//사용자 이동 //이동에 따른 효과음 출력 Multi_Sound.PlayFGSound(); user_lManager.userMove((char *)lParam, (char *)wParam); case WM_UCHATSEND: {//메시지 보내기 pDPSocket->SendMessage(CHAT_MESSAGE, -1, (char *)lParam);

case WM_UCONNECT: {//처음 접속시 //자신을 제외하고 접속이 들어왔을경우 접속한 사용자들에게 //자신의 최초좌표를 전송한다. if (strcmp(user1.get_Name(),(char *)lParam) != 0) { user_lManager.userAdd((char *)lParam); sprintf(temp, "%f %f %f", user1.get_x(), user1.get_y(), user1.get_z()); pDPSocket->SendMessage(START_MESSAGE, -1, temp); } break; case WM_UDISCON: {//사용자 접속 해제시 사용자 제거 user_lManager.userRemove((char *)lParam); case WM_USTARTM: {//사용자의 초기 위치값을 받았을 경우 세팅 float vx, vy, vz; sscanf((char *)wParam, "%f%f%f", &vx, &vy, &vz); user_lManager.setInitMove(vx, vy, vz, (char *)lParam); case WM_COMMAND: switch(wParam) case INET_HOST: //호스트 다이얼로그 박스 Pause(true); if (DialogBox(g_hInst, MAKEINTRESOURCE(IDD_HOST), hWnd, HostDlgProc) == IDOK) pDPSocket = CDPSocket::getInstance(); pDPSocket->InitializeDirectPlay(); pDPSocket->SetHWnd(hWnd);

user1.set_Name(d_str3); pDPSocket->Host(d_str3, 5150); } Pause(false); break; case INET_CONNECT: // 컨넥트 다이얼로그 박스 Pause(true); if (DialogBox(g_hInst, MAKEINTRESOURCE(IDD_CONNECT), hWnd, ConnectDlgProc) == IDOK) { pDPSocket = CDPSocket::getInstance(); pDPSocket->InitializeDirectPlay(); pDPSocket->SetHWnd(hWnd); user1.set_Name(d_str2); pDPSocket->Connect(d_str1, 5150, d_str2); case WM_CREATE: //chat클래스와 사운드 클레스 생성및 세팅 //백그라운드 음악 출력 chat.init_Chating(hWnd, g_hInst); Multi_Sound.Initialize(hWnd); Multi_Sound.CreateBGSound("Multi3.wav"); Multi_Sound.CreateFGSound("Multi2.wav"); Multi_Sound.PlayBGSound(); case WM_KEYDOWN: //네트워크 상태가 아닐경우 아무 변화도 일어나지 않게 함

if (pDPSocket == NULL) { MessageBox(hWnd, "네트워크 연결(HOST, CONNECT)을 하십시오.", "경고", MB_OK); break; } switch (wParam) //사용자 키 입력에 따른 메시지 처리 //엔터키를 입력하였을 경우 채팅창으로 포커스 이동. case VK_RETURN: chat.set_Focus(); //사용자 키 입력에 따른 이동내용 모든 사용자에게 통보 case VK_UP: user1.set_Move(0.0f, 0.0f, 1.0f); user1.UserRotate(-1.0f); pDPSocket->SendMessage(MOVE_MESSAGE, -1, "UP"); case VK_DOWN: user1.set_Move(0.0f, 0.0f, -1.0f); user1.UserRotate(1.0f); pDPSocket->SendMessage(MOVE_MESSAGE, -1, "DOWN"); case VK_LEFT: user1.set_Move(-1.0f, 0.0f, 0.0f); pDPSocket->SendMessage(MOVE_MESSAGE, -1, "LEFT"); case VK_RIGHT: user1.set_Move(1.0f, 0.0f, 0.0f); pDPSocket->SendMessage(MOVE_MESSAGE, -1, "RIGHT");

case WM_PAINT: { if( m_bLoadingApp ) // Draw on the window tell the user that the app is loading // TODO: change as needed HDC hDC = GetDC( hWnd ); TCHAR strMsg[MAX_PATH]; wsprintf( strMsg, TEXT("Loading... Please wait") ); RECT rct; GetClientRect( hWnd, &rct ); DrawText( hDC, strMsg, -1, &rct, DT_CENTER|DT_VCENTER|DT_SINGLELINE ); ReleaseDC( hWnd, hDC ); } break; case WM_CLOSE: delete pDPSocket; return CD3DApplication::MsgProc( hWnd, msg, wParam, lParam );

Direct X Demo 따라하기 Direct 3D로 인하여 화면의 채팅 에디트 박스와, 리스트 박스를 지워버림으로 부득이하게 d3dapp.cpp를 다음과 같이 수정 HRESULT CD3DApplication::Create( HINSTANCE hInstance )안에 WS_CLIPCHILDREN 속성 추가 m_dwWindowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE | WS_CLIPCHILDREN; 전체화면에서는 불가능