继续接上回,上次说完了绘图相关的函数(Gfx前缀的)
接下来是目标相关的。
HTARGET CALL HGE_Impl::Target_Create(int width, int height, bool zbuffer)
{
CRenderTargetList *pTarget;
D3DSURFACE_DESC TDesc;//表面描述
pTarget = new CRenderTargetList;//新建的目标节点
pTarget->pTex=0;
pTarget->pDepth=0;
if(FAILED(D3DXCreateTexture(pD3DDevice, width, height, 1, D3DUSAGE_RENDERTARGET,//使用传入参数创建纹理
d3dpp->BackBufferFormat, D3DPOOL_DEFAULT, &pTarget->pTex)))//由pTex传出值
{
_PostError("Can't create render target texture");
delete pTarget;
return 0;
}
pTarget->pTex->GetLevelDesc(0, &TDesc);//识别纹理等级并且返回一个表面描述,格式,类型,范围,内存模式,使用类型,
pTarget->width=TDesc.Width;
pTarget->height=TDesc.Height;
if(zbuffer)//z缓存可用就创建深度表面
{
if(FAILED(pD3DDevice->CreateDepthStencilSurface(pTarget->width, pTarget->height,
D3DFMT_D16, D3DMULTISAMPLE_NONE, &pTarget->pDepth)))//创建后的表面直接存在新创建的目标的深度里
{
pTarget->pTex->Release();
_PostError("Can't create render target depth buffer");
delete pTarget;
return 0;
}
}
pTarget->next=pTargets;
pTargets=pTarget;
return (HTARGET)pTarget;
}
整个函数做的事情是创建一个新的Target,把它的属性设定完整,然后通过返回值返回,并且和所有的Target链在一起。
每个目标对象都是链表里的一个节点,它由主要的两部分组成,一个是纹理一个是深度,分别创建了这两个就完成了Target的创建。
void CALL HGE_Impl::Target_Free(HTARGET target)
{
CRenderTargetList *pTarget=pTargets, *pPrevTarget=NULL;
while(pTarget)
{
if((CRenderTargetList *)target == pTarget)
{
if(pPrevTarget)
pPrevTarget->next = pTarget->next;
else
pTargets = pTarget->next;
if(pTarget->pTex) pTarget->pTex->Release();
if(pTarget->pDepth) pTarget->pDepth->Release();
delete pTarget;
return;
}
pPrevTarget = pTarget;
pTarget = pTarget->next;
}
}
释放一个节点,是一个链表节点删除操作,遍历整个链表,找到要删除的那个,分别Release这个目标里的纹理和深度表面,然后再把节点delete就完成了FREE操作。
最后一个关于目标的函数,用来获取某个目标的纹理,如果有就返回纹理,没有就返回0(NULL)HTEXTURE CALL HGE_Impl::Target_GetTexture(HTARGET target) { CRenderTargetList *targ=(CRenderTargetList *)target; if(target) return (HTEXTURE)targ->pTex; else return 0; }
源码里基本都用0来表示NULL,从可读性来说没有用NULL好。
下面是Texture部分,纹理相关函数
HTEXTURE CALL HGE_Impl::Texture_Create(int width, int height)
{
LPDIRECT3DTEXTURE8 pTex;
if( FAILED( D3DXCreateTexture( pD3DDevice, width, height,
1, // Mip levels
0, // Usage
D3DFMT_A8R8G8B8, // Format
D3DPOOL_MANAGED, // Memory pool
&pTex ) ) )
{
_PostError("Can't create texture");
return NULL;
}
return (HTEXTURE)pTex;
}
木有什么说的。
HTEXTURE CALL HGE_Impl::Texture_Load(const char *filename, DWORD size, bool bMipmap)
{
void *data;
DWORD _size;
D3DFORMAT fmt1, fmt2;//文件解析格式
LPDIRECT3DTEXTURE8 pTex;//d3d8的纹理
D3DXIMAGE_INFO info;
CTextureList *texItem;//纹理载入后也会同时添加到纹理列表,返回值也单独返回载入的纹理
if(size) { data=(void *)filename; _size=size; }
else
{
data=pHGE->Resource_Load(filename, &_size);
if(!data) return NULL;
}
//DDX文件头判断,判断成功就设定DDX文件解析格式,否则就是普通32位位图的格式
if(*(DWORD*)data == 0x20534444) // Compressed DDS format magic number
{
fmt1=D3DFMT_UNKNOWN;
fmt2=D3DFMT_A8R8G8B8;
}
else
{
fmt1=D3DFMT_A8R8G8B8;
fmt2=D3DFMT_UNKNOWN;
}
//这里尝试两遍,分别用不同的格式尝试
// if( FAILED( D3DXCreateTextureFromFileInMemory( pD3DDevice, data, _size, &pTex ) ) ) pTex=NULL;
if( FAILED( D3DXCreateTextureFromFileInMemoryEx( pD3DDevice, data, _size,
D3DX_DEFAULT, D3DX_DEFAULT,
bMipmap ? 0:1, // Mip levels
//第一遍 0, // Usage
fmt1, // Format
D3DPOOL_MANAGED, // Memory pool
D3DX_FILTER_NONE, // Filter
D3DX_DEFAULT, // Mip filter
0, // Color key
&info, NULL,
&pTex ) ) )
if( FAILED( D3DXCreateTextureFromFileInMemoryEx( pD3DDevice, data, _size,
D3DX_DEFAULT, D3DX_DEFAULT,
bMipmap ? 0:1, // Mip levels
0, // Usage
//第二遍 fmt2, // Format
D3DPOOL_MANAGED, // Memory pool
D3DX_FILTER_NONE, // Filter
D3DX_DEFAULT, // Mip filter
0, // Color key
&info, NULL,
&pTex ) ) )
{
_PostError("Can't create texture");
if(!size) Resource_Free(data);
return NULL;
}
//已经载入到ptex里了,就释放存文件名的空间
if(!size) Resource_Free(data);
//加入纹理列表
texItem=new CTextureList;
texItem->tex=(HTEXTURE)pTex;
texItem->width=info.Width;
texItem->height=info.Height;
texItem->next=textures;
textures=texItem;
return (HTEXTURE)pTex;
}
纹理载入,适应各种各样的文件,用纹理列表单独来管理纹理,保证同一个纹理只载入一次。
void CALL HGE_Impl::Texture_Free(HTEXTURE tex)
{
LPDIRECT3DTEXTURE8 pTex=(LPDIRECT3DTEXTURE8)tex;
CTextureList *texItem=textures, *texPrev=0;
while(texItem)
{
if(texItem->tex==tex)
{
if(texPrev) texPrev->next=texItem->next;
else textures=texItem->next;
delete texItem;
break;
}
texPrev=texItem;
texItem=texItem->next;
}
if(pTex != NULL) pTex->Release();
}
纹理释放,和Target释放一样,也是从纹理链表里去掉就OK
int CALL HGE_Impl::Texture_GetWidth(HTEXTURE tex, bool bOriginal)
{
D3DSURFACE_DESC TDesc;
LPDIRECT3DTEXTURE8 pTex=(LPDIRECT3DTEXTURE8)tex;
CTextureList *texItem=textures;
if(bOriginal)
{
while(texItem)
{
if(texItem->tex==tex) return texItem->width;
texItem=texItem->next;
}
return 0;
}
else
{
if(FAILED(pTex->GetLevelDesc(0, &TDesc))) return 0;
else return TDesc.Width;
}
}
int CALL HGE_Impl::Texture_GetHeight(HTEXTURE tex, bool bOriginal)
{
D3DSURFACE_DESC TDesc;
LPDIRECT3DTEXTURE8 pTex=(LPDIRECT3DTEXTURE8)tex;
CTextureList *texItem=textures;
if(bOriginal)
{
while(texItem)
{
if(texItem->tex==tex) return texItem->height;
texItem=texItem->next;
}
return 0;
}
else
{
if(FAILED(pTex->GetLevelDesc(0, &TDesc))) return 0;
else return TDesc.Height;
}
}
两个函数写法一样,一起说。
先说用法,后面有个参数bOriginal,表示是否返回源纹理的长/宽,如果这个参数是缺省或者false,就返回当前视图纹理的长/宽(这个数值会因为遮挡,裁剪等等改变)
返回源的话,还是遍历然后找到后返回就行
返回视图的话,先查一遍表面描述,然后得到相应长/宽
返回的数值都是像素数量
DWORD * CALL HGE_Impl::Texture_Lock(HTEXTURE tex, bool bReadOnly, int left, int top, int width, int height)
{
LPDIRECT3DTEXTURE8 pTex=(LPDIRECT3DTEXTURE8)tex;
D3DSURFACE_DESC TDesc;
D3DLOCKED_RECT TRect;
RECT region, *prec;
int flags;
pTex->GetLevelDesc(0, &TDesc);
if(TDesc.Format!=D3DFMT_A8R8G8B8 && TDesc.Format!=D3DFMT_X8R8G8B8) return 0;
if(width && height)//都有值才能构成rect
{
region.left=left;
region.top=top;
region.right=left+width;
region.bottom=top+height;
prec=®ion;
}
else prec=0;
if(bReadOnly) flags=D3DLOCK_READONLY;
else flags=0;
if(FAILED(pTex->LockRect(0, &TRect, prec, flags)))
{
_PostError("Can't lock texture");
return 0;
}
return (DWORD *)TRect.pBits;
}
void CALL HGE_Impl::Texture_Unlock(HTEXTURE tex)
{
LPDIRECT3DTEXTURE8 pTex=(LPDIRECT3DTEXTURE8)tex;
pTex->UnlockRect(0);
}
给一块纹理加锁的操作是通过DX里的
IDirect3DCubeTexture9::LockRect method
就是锁住一块RECT,rect就是由这里传入的参数构造的。
锁住的目的是在访问的时候确保它们不会改变。
第二个参数bReadOnly如果为true,在unlock后这块区域不会被刷新,可以减少渲染量加快速度。
返回值会指向被锁住的纹理内存,可以直接访问纹理像素的值(readonly)。
解锁直接解。
剩下的实现模型函数下次说。