www.pudn.com > 3DEarth.rar > 3DWND.CPP


// 3dwnd1.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include "3dwnd.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
 
 
#define  BALLFVF	D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_SPECULAR|D3DFVF_TEX1 
 
 
///////////////////////////////////////////////////////////////////////////// 
// C3dwnd 
 
C3dwnd::C3dwnd() 
{ 
	g_pD3D=NULL; 
	g_pD3DDevice=NULL; 
	bpin=FALSE; 
 
 
	g_pFont=NULL; 
	hFont=CreateFont( 15, 0, 0, 0, 
		FW_NORMAL, FALSE, FALSE, FALSE, 
		GB2312_CHARSET, 
		OUT_DEFAULT_PRECIS, 
		CLIP_DEFAULT_PRECIS, 
		DEFAULT_QUALITY, 
		VARIABLE_PITCH, 
		"宋体" ); 
		 
	pBallTex=NULL; 
	pBallData=NULL; 
	pAirTex=NULL; 
	pAirData=NULL; 
 
	g_ti=0; 
	anglight=0; 
	danglight=23*D3DX_PI/(90*365); 
} 
 
C3dwnd::~C3dwnd() 
{ 
} 
 
 
BEGIN_MESSAGE_MAP(C3dwnd, CWnd) 
	//{{AFX_MSG_MAP(C3dwnd) 
	ON_WM_DESTROY() 
	ON_WM_CREATE() 
	ON_WM_MOUSEMOVE() 
	ON_WM_LBUTTONDOWN() 
	ON_WM_LBUTTONUP() 
	ON_WM_TIMER() 
	ON_COMMAND(US_DRAW, DrawScene) 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
 
///////////////////////////////////////////////////////////////////////////// 
// C3dwnd message handlers 
 
BOOL C3dwnd::CreateWnd(CWnd* parent,RECT& rect) 
{ 
	CString clsstr=AfxRegisterWndClass(0,LoadCursor(0,IDC_ARROW), 
									  (HBRUSH)(COLOR_WINDOW+5),0); 
	g_rect=rect; 
	BOOL res; 
	if (parent==NULL) 
		res=CWnd::CreateEx(0,clsstr,"My Direct3D",WS_POPUPWINDOW|WS_CAPTION ,rect,parent,0); 
	else res=CWnd::CreateEx(0,clsstr,"",WS_CHILD|WS_VISIBLE,rect,parent,0); 
	return res; 
} 
 
void C3dwnd::OnDestroy()  
{ 
	CWnd::OnDestroy(); 
	 
	// TODO: Add your message handler code here 
	KillTimer(1); 
 
	if(g_pD3DDevice != NULL) 
        g_pD3DDevice->Release(); 
 
    if(g_pD3D != NULL) 
        g_pD3D->Release(); 
 
    if(g_pFont != NULL) 
        g_pFont->Release(); 
 
    if(pBallData != NULL) 
        pBallData->Release(); 
 
    if(pBallTex != NULL) 
        pBallTex->Release(); 
 
    if(pAirData != NULL) 
        pAirData->Release(); 
 
    if(pAirTex != NULL) 
        pAirTex->Release(); 
 
} 
 
int C3dwnd::OnCreate(LPCREATESTRUCT lpCreateStruct)  
{ 
	if (CWnd::OnCreate(lpCreateStruct) == -1) 
		return -1; 
	 
	srand( (unsigned)time( NULL ) ); 
 
	// TODO: Add your specialized creation code here 
	if (InitialiseD3D()==S_OK) 
	{ 
		pBallData=PrepairBallData(30);		//准备物点坐标 
		pAirData=PrepairBallData(32);		//准备物点坐标 
 
		D3DXCreateFont(g_pD3DDevice,hFont,&g_pFont); 
 
		PrepairLight();				//准备光照 
		PrepairVertex();			//准备观察、投影矩阵(世界矩阵另设) 
		PrepairMaterial();			//准备材质 
		PrepairTexture();			//准备纹理 
 
		SetTimer(1,50,NULL); 
 
	} 
 
	return 0; 
} 
 
HRESULT C3dwnd::InitialiseD3D() 
{ 
 
	//首先,创建一个主要的D3D物体。如果它被成功创建了我们就获得了一个指向Idirect3D8接口的指针。 
    g_pD3D = Direct3DCreate8(D3D_SDK_VERSION); 
    if(g_pD3D == NULL) 
    { 
        return E_FAIL; 
    } 
 
 
	//获得当前的显示模式 
    D3DDISPLAYMODE d3ddm; 
    if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))) 
    { 
        return E_FAIL; 
    } 
 
	//创建一个结构来保存我们设备的设置信息 
    D3DPRESENT_PARAMETERS d3dpp;  
    ZeroMemory(&d3dpp, sizeof(d3dpp)); 
 
	//填充结构。 
    d3dpp.Windowed = TRUE;		//我们想要我们的程序用窗口显示, 
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; 
    d3dpp.BackBufferFormat = d3ddm.Format;		//设置back buffer为和我们当前显示模式匹配的格式。 
    d3dpp.EnableAutoDepthStencil = TRUE; 
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16; 
 
	//创建一个Direct3D设备 
    if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,this->GetSafeHwnd(),  
                                   D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice))) 
    { 
        return E_FAIL; 
    } 
 
	//D3DADAPTER_DEFAULT告诉Direct3D使用主显示器,只有当你使用多显示器时才是必须的。你可以使用一个数值 
	//来指定另外一个显示器。调用IDirect3D的GetAdapterCount将返回系统的适配器数目。 
 
	//第二个参数,D3DDEVTYPE_HAL,告诉Direct3D使用硬件加速。其它选项包括D3DDEVTYPE_REF和D3DDEVTYPE_SW, 
	//通常你都会希望使用硬件加速的,但有时侯你可能会使用软件加速进行测试。 
	 
	//指定窗口取得焦点。如果是全屏应用程序,你需要一个最顶层窗口。  
 
	//D3DCREATE_SOFTWARE_VERTEXPROCESSING指定顶点处理类型。你也可以使用硬件加速或是联合类型,我不使用硬 
	//件加速为的是广泛的兼容性。如果你想支持T&L, 则你必须使用硬件加速。 
	 
	//最后两个参数很简单,一个是你以前建立的,而pID3Ddevice是你现在要创建的IDirect3DDevice8接口。 
	 
	//如果方法返回D3DERR_NOTAVAILABLE,则你写的参数是正确的,但你的设备不支持你指定的参数。 
	 
	//最完美的是这个方法自动为你创建后台缓冲(back buffers)和深度缓冲(depth buffers) 。剪裁(Clipping) 
	//作为后台表面(backface culling)被自动激活。 
	 
	//灯光也被自动激活了,直到你定义顶点颜色之前,你可以禁止使用灯光: 
 
//   g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE); 
//	g_pD3DDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT ); 
	g_pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); 
	g_pD3DDevice->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE ); 
 
    // Turn on the zbuffer 
    g_pD3DDevice->SetRenderState( D3DRS_ZENABLE, TRUE ); 
 
	return S_OK; 
 
} 
 
LPDIRECT3DVERTEXBUFFER8 C3dwnd::PrepairBallData(float R) 
{ 
	LPDIRECT3DVERTEXBUFFER8 pStreamData=NULL; 
 
	int num_elems = BALLFACE*(BALLFACE*2+3)/2; 
 
	g_pD3DDevice->CreateVertexBuffer(sizeof(BALLVERTEX) * num_elems, 
									D3DUSAGE_WRITEONLY, 
									BALLFVF, 
									D3DPOOL_DEFAULT,  
									&pStreamData); 
	if (!pStreamData) 
        return NULL; 
 
	BALLVERTEX *vv; 
	pStreamData->Lock(0, 0, (BYTE**)&vv, 0); 
 
	float TH=D3DX_PI*2/BALLFACE;	//(0,2*PI)	 
	float FI1,FI2;	//(0,PI) 
	 
	float x1,x2,y1,y2,z1,z2; 
	int i,j,n=0; 
	DWORD clr=0x40ffffff; 
	 
	for (j=0;jUnlock(); 
 
	g_pD3DDevice->SetVertexShader(BALLFVF); 
	 
	return pStreamData; 
} 
 
HRESULT C3dwnd::PrepairVertex() 
{ 
	angx=0.0; 
	angy=0.0; 
	float R=200; 
    D3DXVECTOR3 vEyePt    = D3DXVECTOR3( 0, 0, R); 
    D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, 0.0f,  0.0f ); 
    D3DXVECTOR3 vUpVec    = D3DXVECTOR3( 0.0f, 1.0f,  0.0f ); 
    D3DXMatrixLookAtLH( &g_matView, &vEyePt, &vLookatPt, &vUpVec ); 
	//观察矩阵:vEyePt视点位置;vLookatPt投视方向;vUpVec向上坐标轴(x?y?z?) 
    g_pD3DDevice->SetTransform( D3DTS_VIEW, &g_matView ); 
 
    D3DXMATRIX matProj; 
	float r=(float)g_rect.right/g_rect.bottom; 
    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/6, r, 1.0f, 1000.0f ); 
	//投影矩阵:视场角(0,PI);纵横比;最近、最远绘制点 
    g_pD3DDevice->SetTransform( D3DTS_PROJECTION, &matProj ); 
 
    D3DXMATRIX matWorld; 
	D3DXMatrixIdentity(&matWorld);	//准备世界矩阵 
    g_pD3DDevice->SetTransform( D3DTS_WORLD, &matWorld); 
 
	return S_OK; 
 
} 
 
HRESULT C3dwnd::PrepairMaterial() 
{ 
	ZeroMemory(&ball_mtrl,sizeof(ball_mtrl)); 
 
	//rgb的反射率 
	ball_mtrl.Ambient.r = 0.1f;  
	ball_mtrl.Ambient.g = 0.1f; 
	ball_mtrl.Ambient.b = 0.1f; 
 
	ball_mtrl.Diffuse.r = 1.0f;  
	ball_mtrl.Diffuse.g = 1.0f; 
	ball_mtrl.Diffuse.b = 1.0f; 
 
	ball_mtrl.Specular.r = 1.0f;  
	ball_mtrl.Specular.g = 1.0f; 
	ball_mtrl.Specular.b = 1.0f; 
 
	ball_mtrl.Power = 10.0f;  
 
	g_pD3DDevice->SetMaterial(&ball_mtrl); 
 
	return S_OK; 
} 
 
HRESULT C3dwnd::PrepairLight() 
{ 
//  g_pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE );		//禁止所有光 
 
 
	D3DXVECTOR3 vecDir; 
	D3DLIGHT8 light;  
	ZeroMemory( &light, sizeof(D3DLIGHT8) ); 
 
	light.Type = D3DLIGHT_DIRECTIONAL; 
 
	light.Ambient.r = 1.0f; 
	light.Ambient.g = 1.0f; 
	light.Ambient.b = 1.0f; 
//	light.Ambient.a = 0.5f; 
 
	light.Diffuse.r = 1.0f; 
	light.Diffuse.g = 1.0f; 
	light.Diffuse.b = 1.0f; 
 
	light.Specular.r = 0.5f; 
	light.Specular.g = 0.5f; 
	light.Specular.b = 0.5f; 
 
//	light.Position=D3DXVECTOR3(-30,0,-30); 
 
	vecDir = D3DXVECTOR3(-cosf(anglight),sinf(anglight),0); 
	D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecDir ); 
	light.Range = 1000.0f; 
 
	g_pD3DDevice->SetLight( 0, &light );  
	g_pD3DDevice->LightEnable( 0, TRUE); 
	g_pD3DDevice->SetRenderState( D3DRS_LIGHTING, TRUE ); 
    g_pD3DDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE ); 
 
	g_pD3DDevice->SetRenderState(D3DRS_AMBIENT,0xff404040);		//设置环境光 
 
	return S_OK; 
} 
 
HRESULT C3dwnd::PrepairTexture() 
{ 
	//设置纹理 
	D3DXCreateTextureFromResourceA(g_pD3DDevice,NULL,"EARTH",&pBallTex); 
	D3DXCreateTextureFromResourceA(g_pD3DDevice,NULL,"AIR",&pAirTex); 
 
	return S_OK; 
} 
 
 
HRESULT C3dwnd::DrawScene() 
{ 
	HRESULT hr; 
 
    if(g_pD3D == NULL) 
    { 
        return E_FAIL; 
    } 
	 
	hr = g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,  
							 D3DCOLOR_RGBA(0,0,0,0), 1.0, 0); 
 
	//Clear会填充你指定的缓冲区。你可以填充Z缓冲区、后台缓冲区或摸板缓冲区(stencil buffer)。 
 
	hr = g_pD3DDevice->BeginScene(); 
	if(FAILED(hr)) 
		return hr; 
 
	// Put all drawing code here 
	g_pD3DDevice->SetStreamSource(0, pBallData, sizeof(BALLVERTEX)); 
	g_pD3DDevice->SetRenderState(D3DRS_SPECULARENABLE, TRUE ); 
	g_pD3DDevice->SetTexture(0,pBallTex);  
    g_pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE,   FALSE ); 
	g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0,BALLFACE*(BALLFACE*2+3)/2-2); 
 
	D3DXMATRIX angmat; 
	D3DXMatrixIdentity(&angmat); 
	D3DXMatrixRotationX(&angmat, -3.1415926/4); 
//    g_pD3DDevice->SetTransform( D3DTS_WORLD,  &angmat ); 
 
	g_pD3DDevice->SetStreamSource(0, pAirData, sizeof(BALLVERTEX)); 
	g_pD3DDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE ); 
	g_pD3DDevice->SetTexture(0,pAirTex);  
    g_pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE,   TRUE ); 
    g_pD3DDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA ); 
    g_pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); 
	g_pD3DDevice->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_BLENDCURRENTALPHA );  
//	g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0,BALLFACE*(BALLFACE*2+3)/2-2); 
 
	hr = g_pD3DDevice->EndScene(); 
	if(FAILED(hr)) 
		return hr; 
 
//	g_pFont->DrawTextA(s_fps,-1,&r,DT_TOP|DT_LEFT|DT_NOCLIP,0xffffffff); 
 
	// 翻转后台表面。 
	hr = g_pD3DDevice->Present(NULL, NULL, NULL, NULL); 
	g_fps++; 
 
	return hr; 
} 
 
void C3dwnd::OnMouseMove(UINT nFlags, CPoint point)  
{ 
	// TODO: Add your message handler code here and/or call default 
 
	if (!bpin) 
		return; 
 
	angx-=(float)(curx-point.x)/100; 
	curx=point.x; 
 
	angy+=(float)(cury-point.y)/100; 
	cury=point.y; 
 
 
 
 
	CWnd::OnMouseMove(nFlags, point); 
} 
 
 
void C3dwnd::OnLButtonDown(UINT nFlags, CPoint point)  
{ 
	// TODO: Add your message handler code here and/or call default 
	SetCapture(); 
	bpin=TRUE; 
	curx=point.x; 
	cury=point.y; 
	CWnd::OnLButtonDown(nFlags, point); 
} 
 
void C3dwnd::OnLButtonUp(UINT nFlags, CPoint point)  
{ 
	// TODO: Add your message handler code here and/or call default 
	ReleaseCapture(); 
	bpin=FALSE; 
	CWnd::OnLButtonUp(nFlags, point); 
} 
 
void C3dwnd::OnTimer(UINT nIDEvent)  
{ 
	// TODO: Add your message handler code here and/or call default 
 
	angx+=D3DX_PI/20; 
	D3DXMATRIX angmat,angmatX,angmatY; 
	D3DXMatrixIdentity(&angmatX); 
	D3DXMatrixRotationY(&angmatX, -angx); 
	D3DXMatrixIdentity(&angmatY); 
	D3DXMatrixRotationX(&angmatY, -angy); 
 
	angmat=angmatX*angmatY; 
 
    g_pD3DDevice->SetTransform( D3DTS_WORLD,  &angmat ); 
 
 
	g_ti++; 
	if (g_ti>=40) 
	{ 
		g_ti=0; 
		D3DLIGHT8 light;  
		ZeroMemory( &light, sizeof(D3DLIGHT8) ); 
		g_pD3DDevice->GetLight( 0, &light );  
 
		anglight+=danglight; 
		if (anglight>23*D3DX_PI/180) 
			anglight=23*D3DX_PI/180,danglight=-23*D3DX_PI/(90*365); 
		else if (anglight<-23*D3DX_PI/180) 
			anglight=-23*D3DX_PI/180,danglight=23*D3DX_PI/(90*365); 
 
		D3DXVECTOR3 vecDir; 
		vecDir = D3DXVECTOR3(-cosf(anglight),sinf(anglight),0); 
		D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecDir ); 
 
		g_pD3DDevice->SetLight( 0, &light ); 
	} 
 
	CWnd::OnTimer(nIDEvent); 
}