利用D3D8的IDirect3DSurface8 & IDirect3DTexture8 模拟出一个简单的表面类。
利用这个类可以去完成图片的局部BLT及图片与图片的BLT,也就是一个进似于IDirectDrawSurface7的东西,当然了,功能没有它的强的,而且是非常的简单。
功能: 一个表面分成:静态表面(IDirect3DTexture8)、动态表面(IDirect3DSurface8),因为静态表面不支持静态拷贝到静态或静态拷贝到动态,最终只好使用动态拷贝到动态再由动态拷贝到静态。 静态表面时只有一个功能可以改变表面数据CreFileToTex();但是静态表面BLT的速度相对动态而言就快了一些(静态:纹理->后备缓存,动态:表面->纹理->后备缓存);这里使用专门提供这个功能是因为平常要去改变表面数据的机会不会太多,最常见的是:建立一个表面,把图像数据放到里面去,再去建立另一个再放图像数据……,最后把这个表面里面的图像的某一块BLT到后备缓存,那块表面里面的图像BLT到后备缓存,从这里可以看到,一个静态的表面是很常用的,所以尽可以的使用静态表面,如果要使用动态也最好少更新数据,另外Updata最好多次更新表面数据后(在一帧时间内)再调用(不过这样的话多次更新的中间是不能使用ALPHA功能的,ALPHA功能只在Updata才能使用)。表面数据建立可以直接去文件里面读取(静态时,只有去文件里面读取,当要完成从虽的功能处来读取,你可以让动态表面帮忙一下)。
好了,口水不多流了,自己看源代码吧,看源代码比看我的口水好多了。 ……不好意思,再流一下,这里面的ColorKey修改功能还没有完成还用品质模式修改(ColorKey可以在建立一张图片的时候指定的,使用动态表面与动态表面之间的数据拷贝也可以设定ColorKey[BltSurToSur()]),哪位有空帮忙写一下好了,其实也不怎么用到的,所以就懒了……
#if !defined(__AFX_GESURFACE_H__)
#define __AFX_GESURFACE_H__
#if _MSC_VER > 1000
#pragma once
#endif
#include <windows.h>
#include <d3d8.h>
#pragma comment (lib, "d3d8.lib")
#include <d3dx8.h>
#pragma comment (lib, "d3dx8.lib")
#pragma comment (lib, "dxguid.lib")
typedef enum _GEBLTMODE
{
GESUR_DISABLE =0, //关闭所有效果
GESUR_EXTERIOR =1, //使用外部定义的效果
GESUR_INTERIOR =2, //使用内部定义的效果
}GEBLTMODE;
typedef enum _GEMEMMODE
{
GEVIEMEM = 1, //显卡内存
GEMANMEM = 2, //管理内存
GESYSMEM = 3 //系统内存
}GEMEMMODE;
//-----------------
//功能:虚拟D3D表面缓冲使其成为2D里面的表面
//备注:将表面建立在显卡缓存是提供给显示缓冲使用的
// (主表面/屏后缓冲),平常的图形都应建立在系统缓存
//-----------------
class GESurface
{
private:
bool C_bAnimate;//表面是否建立
DWORD C_dwBasicColor;//表面基础颜色值
DWORD C_dwColorKey;//表面颜色键值
int C_iWidth,C_iHeight;//表面宽高
D3DFORMAT C_d3dFormat;//表面数据模式
GEMEMMODE C_geMemoryMode;//表面存储器模式
LPDIRECT3DDEVICE8 C_pd3dDev;//D3D设备指针
LPDIRECT3DTEXTURE8 C_pd3dTexture;//D3D纹理指针
LPDIRECT3DSURFACE8 C_pd3dSurface;//D3D表面指针
struct GEVertex
{
float x,y,z,rhw;
DWORD color;
float u, v;
};
enum {GEFVF = D3DFVF_XYZRHW | D3DFVF_TEX1 | D3DFVF_DIFFUSE};
typedef enum _GESURSTATE
{
GESUR_STATIC = 0,
GESUR_DYNAMIC = 1
}GESURSTATE;
GESURSTATE C_SurfaceState;//表面状态(动态或静态)
//初始化
Init(LPDIRECT3DDEVICE8 fpd3dDev,int fiw,int fih,D3DFORMAT fd3dFormat,GEMEMMODE fgeMemoryMode);
public:
GESurface();
~GESurface();
//数据操作
LockRect(RECT *fprLockRect,UCHAR **fppucData, INT *fpiPitch);//矩形锁定
UnlockRect();//矩形解锁
//ALPHA
SetBasicColor(DWORD fdwBasicColor);
GetBasicColor(DWORD *fdwBasicColor);
//颜色键
SetColorKey(DWORD fdwColorKey);
GetColorKey(DWORD *fdwColorKey);
//宽高
int GetWidth(){return C_iWidth;};
int GetHeight(){return C_iHeight;};
//表面数据品质模式(ARGB8888/RGB888/RGB565/ARGB4444...)
SetQualityFormat(D3DFORMAT fd3dFormat);
GetQualityFormat(D3DFORMAT *fd3dFormat);
//表面指针
GetSurToTex(LPDIRECT3DTEXTURE8 *fppd3dTex);//取静态表面指针
GetSurToSur(LPDIRECT3DSURFACE8 *fppd3dSur);//取动态表面指针
//建立表面
CreFileToTex(LPDIRECT3DDEVICE8 fpd3dDev,char fpcFileName[],RECT *fprDestRect,D3DFORMAT fd3dFormat,GEMEMMODE fgeMemoryMode,DWORD fdwColorKey);
CreFileToSur(LPDIRECT3DDEVICE8 fpd3dDev,char fpcFileName[],RECT *fprDestRect,D3DFORMAT fd3dFormat,GEMEMMODE fgeMemoryMode,DWORD fdwColorKey);
CreSur(LPDIRECT3DDEVICE8 fpd3dDev,int fiw,int fih,D3DFORMAT fd3dFormat,GEMEMMODE fgeMemoryMode);
//BLT
Blt(RECT *fprSrcRect,RECT *fprDestRect,GEBLTMODE fgeFlags=GESUR_INTERIOR);
BltSurToSur(RECT *fprSrcRect,RECT *fprDestRect,DWORD fdwColorKey,GESurface *fpgeSur);
ClearSur();//用于将动态表面数据清零
//动态指针要求:修改了表面数据之后应Updata,要不然,不能更新
//可以多次更新数据,再于最后要显示的时候Updata,这样能提高利用率
Updata();
//释放
Release();
};
#endif
#include <windows.h>
#include <d3d8.h>
#include <d3dx8.h>
#include "GESurface.h"
//因为在2D里面不使用多层次纹理,所以将其设定为第一层
const int M_iTextLevel = 1;
GESurface::
GESurface():
C_bAnimate(false),
C_dwBasicColor(0x7fffffff),
C_dwColorKey(0xff000000),
C_iWidth(0),
C_iHeight(0),
C_pd3dDev(NULL),
C_pd3dSurface(NULL),
C_pd3dTexture(NULL)
{
}
GESurface::
~GESurface()
{
Release();
}
//初始化
GESurface::
Init(
LPDIRECT3DDEVICE8 fpd3dDev,
int fiw,int fih,
D3DFORMAT fd3dFormat,
GEMEMMODE fgeMemoryMode)
{
//属性初始化
C_bAnimate = true;
C_iWidth = fiw;
C_iHeight = fih;
C_d3dFormat = fd3dFormat;
C_geMemoryMode = fgeMemoryMode;
C_pd3dDev = fpd3dDev;
//动态纹理建立在AGP(图形加速接口)
//如果是动态纹理,使用D3DPOOL_DEFAULT,并在系统内存中创建一个后备纹理用于恢复设备
//因为动态纹理不能使用D3DPOOL_MANAGED,D3DPOOL_SYSTEMMEM
//静态纹理,使用D3DPOOL_MANAGED
return true;
}
//动态表面锁定
//当矩形值为NULL时,锁定整个动态表面
GESurface::
LockRect(
RECT *fprLockRect,
UCHAR **fppucData,
INT *fpiPitch)
{
if(C_SurfaceState != GESUR_DYNAMIC)
return false;
HRESULT hr;
D3DLOCKED_RECT d3dLockRect;
hr=C_pd3dSurface->LockRect(&d3dLockRect,fprLockRect,0);
if(FAILED(hr))return false;
*fppucData = (UCHAR*)d3dLockRect.pBits;
*fpiPitch = d3dLockRect.Pitch;
return true;
}
//动态表面解锁
GESurface::
UnlockRect()
{
if(C_SurfaceState != GESUR_DYNAMIC)
return false;
C_pd3dSurface->UnlockRect();
return true;
}
//基础颜色(色含背景色和ALPHA)
//当一张图片使用了这个基础色之后,
//将会使这张图片与这个基础色进行混合,混合比率使用设定的ALPHA值
//(ALPHA值对目的图片依然有效)
GESurface::
SetBasicColor(
DWORD fdwBasicColor)
{
C_dwBasicColor = fdwBasicColor;
}
GESurface::
GetBasicColor(
DWORD *fdwBasicColor)
{
*fdwBasicColor = C_dwBasicColor;
}
//颜色键
//该功能没有完成
GESurface::
SetColorKey(
DWORD fdwColorKey)
{
if(C_SurfaceState != GESUR_DYNAMIC)
return false;
return true;
}
GESurface::
GetColorKey(
DWORD *fdwColorKey)
{
*fdwColorKey = C_dwColorKey;
}
//表面数据品质模式(ARGB8888/RGB888/RGB565/ARGB4444...)
//该功能没有完成
GESurface::
SetQualityFormat(
D3DFORMAT fd3dFormat)
{
if(C_SurfaceState != GESUR_DYNAMIC)
return false;
// memcpy(&C_d3dFormat,&fd3dFormat,sizeof(D3DFORMAT));
return true;
}
GESurface::
GetQualityFormat(
D3DFORMAT *fd3dFormat)
{
memcpy(fd3dFormat,&C_d3dFormat,sizeof(D3DFORMAT));
}
//-------------------------
//取静态表面指针
GESurface::
GetSurToTex(
LPDIRECT3DTEXTURE8 *fppd3dTex)
{
*fppd3dTex = C_pd3dTexture;
}
//取动态表面指针
GESurface::
GetSurToSur(
LPDIRECT3DSURFACE8 *fppd3dSur)
{
if(C_SurfaceState != GESUR_DYNAMIC)
{
*fppd3dSur = NULL;
return false;
}
*fppd3dSur = C_pd3dSurface;
return true;
}
//BLT动态表面数据区去另一个动态表面数据区
GESurface::
BltSurToSur(
RECT *fprSrcRect,
RECT *fprDestRect,
DWORD fdwColorKey,
GESurface *fpgeSur)
{
if(C_SurfaceState != GESUR_DYNAMIC)
return false;
LPDIRECT3DSURFACE8 pd3dSrcSur;
HRESULT hr;
//取源动态表面指针
fpgeSur->GetSurToSur(&pd3dSrcSur);
//拷贝数据
hr=D3DXLoadSurfaceFromSurface(C_pd3dSurface,NULL,fprDestRect,
pd3dSrcSur,NULL,fprSrcRect,D3DX_FILTER_NONE,fdwColorKey);
if(FAILED(hr))return false;
//因为这里使用的源指针是直接从表面拷过来的,不能使用Release()
pd3dSrcSur = NULL;
return true;
}
//BLT静态表面上某一区域到后备缓存
GESurface::
Blt(
RECT *fprSrcRect,
RECT *fprDestRect,
GEBLTMODE fgeFlags)
{
D3DSURFACE_DESC d3dDesc;
D3DDISPLAYMODE d3dDisMod;
RECT rSrcRect,rDestRect;
float fDestWP = 1,fDestHP = 1;
C_pd3dTexture->GetLevelDesc(0,&d3dDesc);
C_pd3dDev->GetDisplayMode(&d3dDisMod);
//正规化RECT数据
if(fprSrcRect)
{
rSrcRect = *fprSrcRect;
if((long)d3dDesc.Width <= rSrcRect.left ||
(long)d3dDesc.Height <= rSrcRect.top ||
rSrcRect.right <= rSrcRect.left ||
rSrcRect.bottom <= rSrcRect.top)
return false;
//调整非法数据
if(0 > rSrcRect.left)
rSrcRect.left = 0;
if(0 > rSrcRect.top)
rSrcRect.top = 0;
if((long)d3dDesc.Width < rSrcRect.right)
{
fDestWP -= (rSrcRect.right - d3dDesc.Width)/
(rSrcRect.right - rSrcRect.left);
rSrcRect.right = d3dDesc.Width;
}
if((long)d3dDesc.Height < rSrcRect.bottom)
{
fDestHP -= (rSrcRect.bottom - d3dDesc.Height)/
(rSrcRect.bottom - rSrcRect.top);
rSrcRect.bottom = d3dDesc.Height;
}
}
else
{
rSrcRect.left = 0;
rSrcRect.top = 0;
rSrcRect.right = d3dDesc.Width;
rSrcRect.bottom = d3dDesc.Height;
}
if(fprDestRect)
{
rDestRect = *fprDestRect;
if((long)d3dDisMod.Width <= rDestRect.left ||
(long)d3dDisMod.Height <= rDestRect.top ||
rDestRect.right <= rDestRect.left ||
rDestRect.bottom <= rDestRect.top)
return false;
//调整非法数据
//显示系统自动调整
}
else
{
rDestRect.left = 0;
rDestRect.top = 0;
rDestRect.right = d3dDisMod.Width;
rDestRect.bottom = d3dDisMod.Height;
}
//设定BLT位置及数据源位置
//x/y代表BLT位置
//tu/tv代表数据源位置
float fVLeft,fVTop,fVRight,fVBottom,fTLeft,fTTop,fTRight,fTBottom;
fTLeft = (float)((float)rSrcRect.left / (float)d3dDesc.Width);
fTTop = (float)((float)rSrcRect.top / (float)d3dDesc.Height);
fTRight = (float)((float)rSrcRect.right / (float)d3dDesc.Width);
fTBottom = (float)((float)rSrcRect.bottom / (float)d3dDesc.Height);
fVLeft = (float)rDestRect.left;
fVTop = (float)rDestRect.top;
fVRight = (float)rDestRect.right * fDestWP;
fVBottom = (float)rDestRect.bottom * fDestHP;
float z = 0,rhw = 1.f;
//建立顶点
GEVertex geVertex[]={
{ fVLeft, fVTop, z, rhw, C_dwBasicColor, fTLeft, fTTop },
{ fVRight, fVTop, z, rhw, C_dwBasicColor, fTRight, fTTop },
{ fVRight, fVBottom, z, rhw, C_dwBasicColor, fTRight, fTBottom },
{ fVLeft, fVBottom, z, rhw, C_dwBasicColor, fTLeft, fTBottom }
};
//设定显示状态
C_pd3dDev->SetRenderState(D3DRS_LIGHTING, false);
if(fgeFlags != GESUR_DISABLE)
{
//是否使用默认ALPHA状态(不使用的话就使用外部定义的ALPHA状态)
if(fgeFlags == GESUR_INTERIOR)
{
//关闭CULLMODE使图像两面都为可见
C_pd3dDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
//开启ALPHABlend,混合方式使用按源ALPHA值,线性上升或下降
C_pd3dDev->SetRenderState(D3DRS_ALPHABLENDENABLE,true);
C_pd3dDev->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
C_pd3dDev->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
//Colorkey有效,BasicColor有效
C_pd3dDev->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_MODULATE);
C_pd3dDev->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
C_pd3dDev->SetTextureStageState(0,D3DTSS_ALPHAARG2,D3DTA_DIFFUSE);
}
}
else
{
C_pd3dDev->SetRenderState(D3DRS_ALPHABLENDENABLE,false);
}
HRESULT hr;
//画图
hr=C_pd3dDev->SetRenderState(D3DRS_LIGHTING,false);
if(FAILED(hr))return false;
hr=C_pd3dDev->SetTexture(0,C_pd3dTexture);
if(FAILED(hr))return false;
hr=C_pd3dDev->SetVertexShader(GEFVF);
if(FAILED(hr))return false;
hr=C_pd3dDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN,2,geVertex,sizeof(GEVertex));
if(FAILED(hr))return false;
return true;
}
//动态表面清零
GESurface::
ClearSur()
{
if(C_SurfaceState != GESUR_DYNAMIC)
return false;
HRESULT hr;
D3DLOCKED_RECT d3dlockRect;
D3DSURFACE_DESC d3dsurDesc;
hr=C_pd3dSurface->GetDesc(&d3dsurDesc);
if(FAILED(hr))return false;
hr=C_pd3dSurface->LockRect(&d3dlockRect,NULL,0);
if(FAILED(hr))return false;
memset((BYTE*)d3dlockRect.pBits,0,(d3dsurDesc.Height * d3dlockRect.Pitch));
C_pd3dSurface->UnlockRect();
return true;
}
//建立一个动态表面并清零
GESurface::
CreSur(
LPDIRECT3DDEVICE8 fpd3dDev,
int fiw,int fih,
D3DFORMAT fd3dFormat,
GEMEMMODE fgeMemoryMode)
{
if(C_bAnimate)
Release();
C_SurfaceState = GESUR_DYNAMIC;
HRESULT hr;
D3DPOOL d3dPool;
if(fgeMemoryMode == GEMANMEM ||fgeMemoryMode == GESYSMEM)
d3dPool = D3DPOOL_MANAGED;
else if(fgeMemoryMode == GEVIEMEM)
d3dPool = D3DPOOL_DEFAULT;
else return false;
//建立动态表面
hr=fpd3dDev->CreateImageSurface(fiw,fih,fd3dFormat,&C_pd3dSurface);
if(FAILED(hr))return false;
//建立用于显示的静态表面
hr=D3DXCreateTexture(fpd3dDev,fiw,fih,1,0,fd3dFormat,d3dPool,&C_pd3dTexture);
if(FAILED(hr))return false;
//对动态表面清零
ClearSur();
Init(fpd3dDev,fiw,fih,fd3dFormat,fgeMemoryMode);
return true;
}
//初始化静态表面(从文件中读图形数据)
//支持ColorKey(只能在初始化的时候使用)
GESurface::
CreFileToTex(
LPDIRECT3DDEVICE8 fpd3dDev,
char fpcFileName[],
RECT *fprDestRect,
D3DFORMAT fd3dFormat,
GEMEMMODE fgeMemoryMode,
DWORD fdwColorKey)
{
if(C_bAnimate)
Release();
C_SurfaceState = GESUR_STATIC;
D3DXIMAGE_INFO d3dImgInfo;
D3DPOOL d3dPool;
if(fgeMemoryMode == GEMANMEM ||fgeMemoryMode == GESYSMEM)
d3dPool = D3DPOOL_MANAGED;
else if(fgeMemoryMode == GEVIEMEM)
d3dPool = D3DPOOL_DEFAULT;
else return false;
HRESULT hr;
hr=D3DXCreateTextureFromFileEx(fpd3dDev,fpcFileName,
D3DX_DEFAULT,D3DX_DEFAULT,1,0,fd3dFormat,d3dPool,
D3DX_FILTER_NONE,D3DX_FILTER_NONE,fdwColorKey,
&d3dImgInfo,NULL,&C_pd3dTexture);
if(FAILED(hr))
{
return false;
}
Init(fpd3dDev,d3dImgInfo.Width,d3dImgInfo.Height,fd3dFormat,fgeMemoryMode);
return true;
}
//初始化动态表面(从文件中读图形数据)
//支持ColorKey(只能在初始化的时候使用)
GESurface::
CreFileToSur(
LPDIRECT3DDEVICE8 fpd3dDev,
char fpcFileName[],
RECT *fprDestRect,
D3DFORMAT fd3dFormat,
GEMEMMODE fgeMemoryMode,
DWORD fdwColorKey)
{
D3DXIMAGE_INFO d3dImgInfo;
D3DPOOL d3dPool;
HRESULT hr;
if(fgeMemoryMode == GEMANMEM ||fgeMemoryMode == GESYSMEM)
d3dPool = D3DPOOL_MANAGED;
else if(fgeMemoryMode == GEVIEMEM)
d3dPool = D3DPOOL_DEFAULT;
else return false;
//快速取得图像宽高
LPDIRECT3DSURFACE8 pd3dSur;
hr=fpd3dDev->CreateImageSurface(1,1,fd3dFormat,&pd3dSur);
if(FAILED(hr))return false;
hr=D3DXLoadSurfaceFromFile(pd3dSur, NULL, NULL, fpcFileName,
NULL, D3DX_FILTER_NONE, 0, &d3dImgInfo);
if(FAILED(hr))return false;
pd3dSur->Release();
pd3dSur=NULL;
//建立动态表面
CreSur(fpd3dDev,d3dImgInfo.Width,d3dImgInfo.Height,fd3dFormat,fgeMemoryMode);
//读取图像数据去动态表面
hr=D3DXLoadSurfaceFromFile(C_pd3dSurface,NULL,NULL,fpcFileName,
NULL,D3DX_FILTER_NONE,fdwColorKey,&d3dImgInfo);
if(FAILED(hr))return false;
C_pd3dDev = fpd3dDev;
return true;
}
//拷贝动态表面数据去静态表面
//动态表面最终BLT还是要转成静态表面,
//所以当使用动态表面时(图像数据->动态表面->静态表面)
//当使用静态表面时(图像数据->静态表面)
//比较可知动态表面速度比静态表面速度慢多了
//现在还没有找到好的方法,只好先用这个了
GESurface::
Updata()
{
if(C_SurfaceState != GESUR_DYNAMIC)
return false;
HRESULT hr;
LPDIRECT3DSURFACE8 pd3dTexSur;
hr=C_pd3dTexture->GetSurfaceLevel(0,&pd3dTexSur);
if(FAILED(hr))return false;
hr=C_pd3dDev->CopyRects(C_pd3dSurface,0,0,pd3dTexSur,0);
if(FAILED(hr))return false;
pd3dTexSur->Release();
return true;
}
//释放
GESurface::
Release()
{
if(C_pd3dSurface){C_pd3dSurface->Release(); C_pd3dSurface=NULL;}
if(C_pd3dTexture){C_pd3dTexture->Release(); C_pd3dTexture=NULL;}
}
|