|
|
发表于 2006-7-27 00:27:00
|
显示全部楼层
Re:请问:纹理是否必须从图形文件载入?能不能在程序中
我写了一个用GDI动态映射纹理的一个小例子,
就是说用GDI再如图片,然后再图片上面画画,textout,lineto等等
然后再映到纹理
#include <d3d8.h>
#include <d3dx8.h>
#include <mmsystem.h>
#pragma comment(lib,"d3d8.lib")
#pragma comment(lib,"d3dx8.lib")
#pragma comment(lib,"winmm.lib")
LPDIRECT3D8 g_pD3D = NULL; // 用来创建D3D设备
LPDIRECT3DDEVICE8 g_pd3dDevice = NULL; // D3D设备
LPDIRECT3DVERTEXBUFFER8 g_pVB = NULL; // 顶点缓冲区
LPDIRECT3DTEXTURE8 g_pTexture = NULL; // 纹理
HWND hWnd = NULL;
HBITMAP texturebmp = NULL;
// 自定义顶点结构
struct CUSTOMVERTEX
{
D3DXVECTOR3 position; // 顶点坐标
D3DCOLOR color; // 顶点颜色
FLOAT tu, tv; // 贴图坐标
};
// 我们自定义的FVF,定义了顶点的结构,
// D3DFVF_XYZ : 表示顶点坐标
// D3DFVF_DIFFUSE : 表示顶点的颜色
// D3DFVF_TX! : 表示有图
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
// 初始化D3D
HRESULT InitD3D( HWND hWnd )
{
// 创建D3D对象
if( NULL == ( g_pD3D = Direct3DCreate8( D3D_SDK_VERSION ) ) )
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; // 设置背景缓冲区格式为当前左面格式
d3dpp.EnableAutoDepthStencil = TRUE; // 打开深度缓冲zbuffer
d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // 深度缓冲格式
// 创建D3D设备
// 第一个参数:使用默认的显卡适配器
// 第二个参数:请求使用硬件抽象层(HAL)
// 第三个参数:窗口句柄
// 第四个参数:使用软件处理顶点
// 第五个参数:创建的参数
// 第六个参数:创建的D3D设备指针
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&g_pd3dDevice ) ) )
{
return E_FAIL;
}
// 关闭culling,让我们能看到3角型的正反面
g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
// 打开ZBUFFER
g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
// Turn off D3D lighting
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
return S_OK;
}
//提取内存~
char * HBtoMe(HBITMAP hBitmap,int *length) // 函数 从HBITMAP 中得到内存
{
char* buffer;
//设备描述表
HDC hDC;
//当前分辨率下每象素所占字节数
int iBits;
//位图中每象素所占字节数
WORD wBitCount;
//定义调色板大小, 位图中像素字节大小 ,位图文件大小 , 写入文件字节数
DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0;
//位图属性结构
BITMAP Bitmap;
//位图文件头结构
BITMAPFILEHEADER bmfHdr;
//位图信息头结构
BITMAPINFOHEADER bi;
//指向位图信息头结构
LPBITMAPINFOHEADER lpbi;
//定义文件,分配内存句柄,调色板句柄
HANDLE hDib, hPal,hOldPal=NULL;
//计算位图文件每个像素所占字节数
hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
DeleteDC(hDC);
if (iBits <= 1) wBitCount = 1;
else if (iBits <= 4) wBitCount = 4;
else if (iBits <= 8) wBitCount = 8;
else wBitCount = 24;
GetObject(hBitmap, sizeof(Bitmap), (LPSTR)&Bitmap);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = Bitmap.bmWidth;
bi.biHeight = Bitmap.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = wBitCount;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrImportant = 0;
bi.biClrUsed = 0;
dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight;
//为位图内容分配内存
hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi;
// 处理调色板
hPal = GetStockObject(DEFAULT_PALETTE);
if (hPal)
{
hDC = ::GetDC(NULL);
hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE);
RealizePalette(hDC);
}
// 获取该调色板下新的像素值
GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)
+dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS);
//恢复调色板
if (hOldPal)
{
::SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);
RealizePalette(hDC);
::ReleaseDC(NULL, hDC);
}
// 设置位图文件头
bmfHdr.bfType = 0x4D42; // "BM"
dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize;
//strncpy(buffer,(char*)&bmfHdr,sizeof(bmfHdr)); //内存copy
*length = dwDIBSize;
buffer = new char[dwDIBSize];
memcpy(buffer,(char*)lpbi,dwDIBSize);
memcpy(buffer,(char*)lpbi,sizeof(bmfHdr));
GlobalUnlock(hDib);
GlobalFree(hDib);
return buffer;
}
// 填充顶点缓区
HRESULT InitGeometry()
{
HDC hdc,MemDC;
HBITMAP bmp;
bmp = (HBITMAP)LoadImage( 0,"3dgame.bmp", IMAGE_BITMAP,256,256,LR_LOADFROMFILE);
MemDC = CreateCompatibleDC(hdc);
SelectObject(MemDC,bmp);
TextOut(MemDC,10,10,"Hello World",11);
char* bmpArr;
int length;
bmpArr = HBtoMe(bmp,&length);
DeleteObject(bmp);
DeleteObject(MemDC);
//add by ajohn 创建GDI对象 bitmap 然后利用该对象映射纹理
/* HDC hdc,MemDC;
hdc = GetDC(hWnd);
MemDC = CreateCompatibleDC(hdc);
HANDLE hfile = CreateFile("3dgame.bmp",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);//创建文件句柄
HBITMAP bmp = NULL;
int width,height;
DWORD length = GetFileSize(hfile,NULL); //打开文件
char* bmpArr = new char[length+1];
char *bmpArr1;
DWORD read;
ReadFile(hfile,bmpArr,length,&read,NULL);//读取二进制文件到内存~~~
if(read !=length) //如果读取不成功
return E_FAIL;
BITMAPFILEHEADER bmfHeader; //位图文件头信息
DWORD bmfHeaderLen = sizeof(bmfHeader);
strncpy((LPSTR)&bmfHeader, (LPSTR)bmpArr, bmfHeaderLen);//填充头信息 -------1
if (bmfHeader.bfType == (*(WORD*)"BM") )//BM代表位图必须为BM
{
char* lpDIB = bmpArr + bmfHeaderLen; //内存指针的+运算
BITMAPINFOHEADER &bmiHeader = *(LPBITMAPINFOHEADER)lpDIB;//读内存 强制装换 -------2
width = bmiHeader.biWidth;
height = bmiHeader.biHeight;
BITMAPINFO &bmInfo = *(LPBITMAPINFO)lpDIB; //这两块内存嵌套? -------3
LPVOID lpDIBBits = bmpArr + ((BITMAPFILEHEADER *)bmpArr)->bfOffBits;
bmp = CreateDIBitmap(MemDC,&bmiHeader,CBM_INIT,lpDIBBits,&bmInfo,DIB_RGB_COLORS);
SelectObject(MemDC,bmp);
TextOut(MemDC,10,10,"Hello World",11);
bmpArr1 = new char[length+1];
HBtoMe(bmp,bmpArr1);
}
// 从一个文件创建我们的纹理
/*该函数是d3dx8tex.h中定义,参数为,1 设备,2 地址 3,字节 4,纹理
D3DXCreateTextureFromFileInMemory(
LPDIRECT3DDEVICE8 pDevice,
LPCVOID pSrcData,
UINT SrcDataSize,
LPDIRECT3DTEXTURE8* ppTexture);*/
if( FAILED( D3DXCreateTextureFromFileInMemory(g_pd3dDevice,bmpArr,length,&g_pTexture)))
return E_FAIL;
delete bmpArr;
//if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, "3dgame.bmp",
// &g_pTexture ) ) )
// return E_FAIL;
// 创建顶点缓冲区
if( FAILED( g_pd3dDevice->CreateVertexBuffer( 50*2*sizeof(CUSTOMVERTEX),
0, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVB ) ) )
{
return E_FAIL;
}
// 填充顶点缓冲区
CUSTOMVERTEX* pVertices;
if( FAILED( g_pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 ) ) )
return E_FAIL;
// 这是一个上下各50个点的圆筒,每个顶点都有其颜色和贴图坐标
for( DWORD i=0; i<50; i++ )
{
FLOAT theta = (2*D3DX_PI*i)/(50-1);
pVertices[2*i+0].position = D3DXVECTOR3( sinf(theta),-1.0f, cosf(theta) );
pVertices[2*i+0].color = 0xffffffff;
pVertices[2*i+0].tu = ((FLOAT)50-i)/(50-1);
pVertices[2*i+0].tv = 1.0f;
pVertices[2*i+1].position = D3DXVECTOR3( sinf(theta), 1.0f, cosf(theta) );
pVertices[2*i+1].color = 0xff808080;
pVertices[2*i+1].tu = ((FLOAT)50-i)/(50-1);
pVertices[2*i+1].tv = 0.0f;
}
g_pVB->Unlock();
DeleteObject(MemDC);
DeleteObject(bmp);
return S_OK;
}
// 释放D3D
VOID Cleanup()
{
// 释放纹理
if( g_pTexture != NULL )
g_pTexture->Release();
// 释放地点缓冲区
if( g_pVB != NULL )
g_pVB->Release();
// 释放D3D设备
if( g_pd3dDevice != NULL)
g_pd3dDevice->Release();
// 释放D3D
if( g_pD3D != NULL)
g_pD3D->Release();
}
// 设置世界矩阵和摄象机
VOID SetupMatrices()
{
// 让世界矩阵绕Y轴旋转
D3DXMATRIX matWorld;
D3DXMatrixIdentity( &matWorld );
D3DXMatrixRotationY( &matWorld, timeGetTime()/1000.f );
g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
// 设置摄象机的位置
D3DXMATRIX matView;
D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0.0f, 1.5f,-5.0f ),
&D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
&D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );
g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
// 设置摄象机的放射参数
D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}
// 渲染
VOID Render()
{
if( NULL == g_pd3dDevice )
return;
// 清除背景为兰色
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
// 开始绘制场景
g_pd3dDevice->BeginScene();
// --渲染图形--
// 设置摄象机位置
SetupMatrices();
// 指定贴图
g_pd3dDevice->SetTexture( 0, g_pTexture );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
g_pd3dDevice->SetStreamSource( 0, g_pVB, sizeof(CUSTOMVERTEX) );
g_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX );
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2*50-2 );
g_pd3dDevice->EndScene();
g_pd3dDevice-> resent( NULL, NULL, NULL, NULL );
}
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY: // 退出消息
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
"D3D Tutorial", NULL };
RegisterClassEx( &wc );
hWnd = CreateWindow( "D3D Tutorial", "GDI映射纹理",
WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
GetDesktopWindow(), NULL, wc.hInstance, NULL );
if( SUCCEEDED( InitD3D( hWnd ) ) )
{
if( SUCCEEDED( InitGeometry() ) )
{
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
MSG msg;
ZeroMemory( &msg, sizeof(msg) );
while( msg.message!=WM_QUIT )
{
if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
Render();
}
}
}
Cleanup();
UnregisterClass( "D3D Tutorial", wc.hInstance );
return 0;
}
|
|