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);
}