欢迎阅读指正和转载,但请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com
 
深度探索DxFramework
 
第10章 进入三维的世界 8
 
10.8.构建大厦的基石,3D图元类
 
10.8.1.图元用到的顶点种类和相关操作
 
10.8.2.顶点操作类C_VertexManipunator
 
在很多种情况下,程序员希望能够像使用数组下标访问数组一样,通过指定索引值,能够从顶点缓冲区种获取某一个特定的顶点。上面章节介绍了顶点的种类和它的数据结构,可以发现由dxframework提供的自定义顶点类型,它们的区别仅仅在于顶点的纹理坐标层数的不同而已。而且,从CUSTOMVERTEX1TEXTURE到CUSTOMVERTEX8TEXTURE。它们的结构体数据成员前三项都是完全一样的,只是最后一项的纹理坐标数组随顶点的纹理坐标层数的不同而不同。那意思就是说,从内存结构上来看,CUSTOMVERTEX1TEXTURE到CUSTOMVERTEX8TEXTURE。每一项都可以视为是它后一项的子集。这样一来的话,只要给定正确的每一个顶点在顶点缓冲区的起始位置,只要能返回一个以那起始位置指针指向的,大小为CUSTOMVERTEX8TEXTURE的内存区域的数据。那么这一段数据就肯定能够囊括从CUSTOMVERTEX1EXTURE到STOMVERTEX8TEXTURE这八种类型的顶点。当然啦,里面的一些纹理坐标是否真的有效则需要使用者自己去判断。比如,返回了CUSTOMVERTEX8TEXTURE类型的数据,但是实质上顶点的类型是CUSTOMVERTEX5TEXTURE的话。那么返回的那一段CUSTOMVERTEX8TEXTURE类型的数据,其最后的3个纹理坐标其实是一个无效值来的,它只是下一个顶点的数据而已。示意图如下:
 
 
C_VertexManipulator类正是根据这个思想而实现的。类的声明如下:
 

class C_VertexManipulator 
{
public:
    C_VertexManipulator();  
    ~C_VertexManipulator(); 
    
    //给定顶点缓冲区起始地址处的首指针,并且给定这个顶点的纹理坐标层数
    void SetPointer(BYTE *p_Buffer, int numTexture);

    //给定索引,返回索引指向的顶点的数据
    CUSTOMVERTEX8TEXTURE& operator[](int index); 
    BYTE*    p_Buffer;  //顶点缓冲区起始地址处的首指针
private:
    DWORD    nextChunk; //每一块chunk的大小
};

 
成员变量nextChunk是每个顶点的大小。以字节为单位,这个值在指定了顶点的纹理坐标层数就能确定了,代码如下:
 
#include "vertexmanipulator.h"

C_VertexManipulator::C_VertexManipulator() 
{
    p_Buffer = NULL;
    nextChunk = 0;
}

C_VertexManipulator::~C_VertexManipulator() 
{
}

void C_VertexManipulator::SetPointer(BYTE *p_Buffer, int numTexture) 
{
    this->p_Buffer = p_Buffer;
    //位置坐标和法线向量使用了两个D3DXVECTOR3,漫反射颜色一个DWORD 多少个numTexture就有多少个D3DXVECTOR2来存放纹理坐标
    nextChunk = 2 * sizeof(D3DXVECTOR3) + sizeof(DWORD) +  numTexture * sizeof(D3DXVECTOR2); 
}

CUSTOMVERTEX8TEXTURE& C_VertexManipulator::operator[](int index)
{
    //返回索引为index的顶点数据
    return *(CUSTOMVERTEX8TEXTURE *) (p_Buffer + index * nextChunk);
}
 
经过上面的分析,相信读者已经明白了C_VertexManipulator类的机制了。这个类在图元类中被广泛使用,经常用在初始化顶点信息,以及访问某个特定的顶点。在后面章节分些图元类的实现的时候将能看到C_VertexManipulator类是如何被使用的。
 
10.8.3 各种Alpha混合操作
 
dxframework封装了图元的alpha混合操作。Direct3D中计算alpha混合的颜色的方法如下:
 
Color = (RGBsrc * Ksrc) OP (RGBsrc * Kdst)
 
在上式中,Color表示经过alpha混合操作后的颜色值;RGBsrc表示源颜色值,即是将要绘制的图元的颜色值。Ksrc表示源混合系数,一般地赋值为半透明度的alpha值,当然也可以是枚举类型D3DBLEND中的任意值,这个值用来和RGBsrc相乘;RGBdst表示目标颜色值,即当前颜色缓冲区中的颜色值;Kdst表示目标系数,可以是属于枚举类型D3DBLEND中的值,用来和RGBdst相乘。OP则表示源计算结果和目标计算(即当前颜色缓冲区计算)结果的混合方法。
 
举个简单的例子,当把Ksrc设置为D3DBLEND_SRCALPHA,即当前要绘制的像素的alpha值。把Kdst设置为D3DBLEND_INVSRCALPHA,即用1减去当前绘制像素的alpha值;把OP设置为D3DBLENDOP_ADD,使得源计算结果和目标计算结果相加。这样子的话,上述的计算方法就是:
 
Color = (RGBsrc * ALPHAsrc) + [RGBdst * (1-ALPHAsrc)]
 
示例的代码如下:
 
IDirect3DDevice8* pDevice;
//启动alpha混合
pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE , TRUE );
//指定使用当前要绘制的像素的alpha值做为源计算的alpha值
pDevice->SetRenderState( D3DRS_SRCBLEND ,D3DBLEND_SRCALPHA );
//指定当前颜色缓冲区中像素的alpha值作为目标计算的alpha值
pDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
//把源计算结果和目标计算结果相加,得到最终的颜色值
pDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD);
//和枚举值D3DBLEND类似,DxFrameWork定义了一系列的常数用以表示alpha的混合系数的取值,如下:
const DWORD BLEND_ZERO               =  1;
const DWORD BLEND_ONE                =  2;
const DWORD BLEND_SRCCOLOR           =  3;
const DWORD BLEND_INVSRCCOLOR        =  4;
const DWORD BLEND_SRCALPHA           =  5; 
const DWORD BLEND_INVSRCALPHA        =  6;
const DWORD BLEND_DESTALPHA          =  7; 
const DWORD BLEND_INVDESTALPHA       =  8;
const DWORD BLEND_DESTCOLOR          =  9;
const DWORD BLEND_INVDESTCOLOR       = 10;
const DWORD BLEND_SRCALPHASAT        = 11;
 
各常量的意义如下表:
 
常量名
说明
BLEND_ZERO
1
alpha混合系数为0
BLEND_ONE
2
alpha混合系数为1
BLEND_SRCCOLOR
3
alpha混合系数为当前要绘制的像素的颜色值,即(Rs,Gs,Bs,As)
BLEND_INVSRCCOLOR
4
alpha混合系数为1减去当前要绘制的像素的颜色值(1-Rs,1-Gs,1-Bs,1-As)
BLEND_SRCALPHA
5
alpha混合系数为当前要绘制的像素的alpha值
BLEND_INVSRCALPHA
6
alpha混合系数为1减去当前要绘制的像素的alpha值
BLEND_DESTALPHA
7
alpha混合系数为当前颜色缓冲区中像素的alpha值
BLEND_INVDESTALPHA
8
alpha混合系数为1减去当前颜色缓冲区中像素的alpha值
BLEND_DESTCOLOR
9
alpha混合系数为当前颜色缓冲区中像素的颜色值,即(Rd,Gd,Bd,As)
BLEND_INVDESTCOLOR
10
alpha混合系数为1减去当前颜色缓冲区中像素的颜色值(1-Rs,1-Gs,1-Bs,1-As)
BLEND_SRCALPHASAT
11
 
 
Direct3D通过alpha测试(alpha test)来判定是否绘制当前的像素。所谓的alpha测试是指检查是指比较当前颜色缓冲器中的像素和即将要绘制的像素,看这两者是否满足某些比较条件。
 
和alpha混合相比alpha测试不将当前的像素颜色和颜色缓冲器中的像素做混合操作,而是直接就判断要么绘制当前像素,要么就不绘制。因为alpha测试不需要对颜色缓冲器的数据进行读操作,所以其速度要优于alpha混合。
 
alpha测试通过渲染状态D3DRS_ALPHATESTENABLE设置启动与否。通过渲染状态D3DRS_ALPHATESTREF指定参考值。alpha测试函数就是比较当前要绘制的像素的alpha值和指定的参考值。如果测试通过则绘制这将要绘制的像素,否则不绘制。alpha测试参考值的取值范围是0x00000000-0x000000FF。通过渲染状态则可以设定alpha测试函数。alpha测试函数是为D3DCMPFUNC类型。下面的示例代码说明如何进行alpha测试:
 
IDirect3DDevice8* pDevice
//启动alpha测试
pDevice->SetRenderState( D3DRS_ALPHATESTENABLE , TRUE);
//指定alpha测试参考值
pDevice->SetRenderState( D3DRS_ALPHAREF , 0x00000002 );
//指定alpha测试函数
pDevice->SetRenderState( D3DRS_ALPHAFUNC , D3DCMP_LESS );
// dxframework封装了图元的alpha测试操作,dxframework中对alpha测试函数设定常量的定义如下
const DWORD CMP_NEVER                = 1;
const DWORD CMP_LESS                 = 2;
const DWORD CMP_EQUAL                = 3;
const DWORD CMP_LESSEQUAL            = 4;
const DWORD CMP_GREATER              = 5;
const DWORD CMP_NOTEQUAL             = 6;
const DWORD CMP_GREATEREQUAL         = 7;
const DWORD CMP_ALWAYS               = 8;
 
各常量的意义如下表:
 
常量名
说明
CMP_NEVER
1
一直都测试不通过
CMP_LESS
2
小于参考值的时候测试通过
CMP_EQUAL
3
等于参考值的时候测试通过
CMP_LESSEQUAL
4
等于或小于参考值的时候测试通过
CMP_GREATER
5
大于参考值的时候测试通过
CMP_NOTEQUAL
6
不等于参考值的时候测试通过
CMP_GREATEREQUAL
7
等于或大于参考值的时候测试通过
CMP_ALWAYS
8
一直都测试通过
 
10.8.4 各种颜色操作
 
正如上面谈到的图元的顶点可以支持多个纹理坐标。这也就意味图元类要支持并且封装了Direct3D的多纹理映射(multi-texture mapping)操作。到目前为止,Direct3D支持最多八层(stage)的纹理映射。这也就是说每个多边形可以同时拥有1到8张不同的纹理贴图;也即是上面介绍的自定义顶点最多只能有8个纹理坐标的原因。Direct3D渲染流水线可以在一个渲染过程(render pass)中把这些纹理颜色依次进行操作混合,使之渲染到一个表面。每一个纹理层对应从0到7的顺序编号。Direct3D多纹理混合过程如下图:
 
 
应用程序将自由地选择是否应用多纹理,但是如果应用了多纹理操作的话。各个纹理层必须是从最低索引值开始,而且必须要连续。也就是说,不允许不使用第i层纹理层,而直接使用第i+1层纹理层。缺省地,Direct3D只是使用了单层纹理映射来进行渲染。纹理层第0层是缺省打开的,第1到7层则默认关闭。要启动某一层纹理层的示例代码如下:
 
// IDirect3DDevice8* pDevice;
pDevice->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_DISABLE);
 
IDirect3DDevice8::SetTextureStageState函数用来设置纹理层状态。它将从0到7的其中一个值作为参数表示纹理层索引号。把D3DTSS_COLOROP作为第二个参数,表示将要设置纹理层的颜色混合运算;把D3DTOP_DISABLE作为第三个参数。表示禁用当前纹理层颜色操作。
 
const DWORD TOP_DISABLE                      = 1;
const DWORD TOP_SELECTARG1                  = 2;
const DWORD TOP_SELECTARG2                  = 3;
const DWORD TOP_MODULATE                      = 4;
const DWORD TOP_MODULATE2X                  = 5;
const DWORD TOP_MODULATE4X                  = 6;
const DWORD TOP_ADD                              = 7;
const DWORD TOP_ADDSIGNED                      = 8;
const DWORD TOP_ADDSIGNED2X                  = 9;
const DWORD TOP_SUBTRACT                      = 10;
const DWORD TOP_ADDSMOOTH                      = 11;
const DWORD TOP_BLENDDIFFUSEALPHA          = 12;
const DWORD TOP_BLENDTEXTUREALPHA          = 13;
const DWORD TOP_BLENDCURRENTALPHA          = 16;
const DWORD TOP_MODULATEALPHA_ADDCOLOR      = 18;
const DWORD TOP_MODULATECOLOR_ADDALPHA   = 19;
const DWORD TOP_MODULATEINVALPHA_ADDCOLOR = 20;
const DWORD TOP_MODULATEINVCOLOR_ADDALPHA = 21;
const DWORD TOP_BUMPENVMAP                   = 22;
const DWORD TOP_BUMPENVMAPLUMINANCE           = 23;
const DWORD TOP_LERP                            = D3DTOP_LERP;
 
dxframework也定义了一系列的颜色混合计算式子。下面的计算式中,将由D3DTSS_COLORARG1或者是由D3DTSS_ALPHAARG1指定的第一个混合参数用ARG1表示。由D3DTSS_COLORARG2或者是由D3DTSS_ALPHAARG2指定的第一个混合参数用ARG2表示。最终计算结果用COLOR表示。
 
操作算子
操作解释
计算公式
TOP_DISABLE
禁止该纹理层的颜色输出
TOP_SELECTARG1
将当前纹理层的第一个混合参数直接输出。如果使用了D3DTSS_COLOROP,则输出由D3DTSS_ALPHAARG1指定的第一个表示RGB的参数。如果使用了D3DTSS_ALPHAOP,则输出由D3DTSS_ALPHAARG1指定的第一个表示alpha的参数。
COLOR=ARG1
TOP_SELECTARG2
将当前纹理层的第二个混合参数直接输出。如果使用了D3DTSS_COLOROP,则输出由D3DTSS_COLORARG2指定的第二个表示RGB的参数。如果使用了D3DTSS_ALPHAOP,则输出由D3DTSS_ALPHAARG2指定的第二个表示alpha的参数。
COLOR = ARG2
TOP_MODULATE
将两个混合参数相乘后输出
COLOR = ARG1 * ARG2
TOP_MODULATE2X
将两个混合参数相乘后左移动一位(即乘以2)
COLOR = (ARG1 * ARG2)<<1
TOP_MODULATE4X
将两个混合参数相乘后左移动两位(即乘以4)
COLOR = (ARG1 * ARG2)<<2
TOP_ADD
将两混合参数相加
COLOR = ARG1 + ARG2
TOP_ADDSIGNED
将两混合参数相加后各分量减去0.5
COLOR = ARG1 + ARG2 - 0.5
TOP_ADDSIGNED2X
将两混合参数相加后各分量减去0.5,然后再乘以1
COLOR = (ARG1 + ARG2 - 0.5)<<1
D3DTOP_SUBTRACT
将两混合参数相减
COLOR = ARG1 - ARG2
D3D_ADDSMOOTH
两混合参数相加,然后再减去两混合参数之积
COLOR = ARG1 + ARG2 - ARG1*ARG2
TOP_BLENDDIFFUSEALPHA
混合参数1乘以alpha值,混合参数2乘以1减去alpha的差值。然后再将其结果相加。这里的这个alpha值,是在做Gouraud着色时对顶点做插值时产生的漫反射颜色中的alpha分量。
COLOR= ARG1 * alpha + ARG2 * (1 - alpha)
TOP_BLENDTEXTUREALPHA
混合参数1乘以alpha值,混合参数2乘以1减去alpha的差值。然后再将其结果相加。这里的这个alpha值,是在texel中的alpha分量。
COLOR= ARG1 * alpha + ARG2 * (1 - alpha)
TOP_BLENDCURRENTALPHA
混合参数1乘以alpha值,混合参数2乘以1减去alpha的差值。然后再将其结果相加。这里的这个alpha值,是上一次状态中所保留的alpha分量。
COLOR= ARG1 * alpha + ARG2 * (1 - alpha)
TOP_MODULATEALPHA_ADDCOLOR
混合参数2乘以混合参数1的alpha分量后,再加上混合参数1。注意此计算式仅仅用于颜色操作
COLOR = ARG1 + ARG1.alpha * ARG2
TOP_MODULATECOLOR_ADDALPHA
混合参数1乘以混合参数2后,再加上混合参数1的alpha分量。注意此计算式仅仅用于颜色操作。
COLOR = ARG1 * ARG2 + ARG1.alpha
TOP_MODULATEINVALPHA_ADDCOLOR
混合参数2乘以1减去混合参数1的alpha分量的差,然后再加上混合参数1
COLOR = (1 – ARG1.alpha) * ARG2 + ARG1
TOP_MODULATEINVCOLOR_ADDALPHA
混合参数2乘以1减去混合参数1的alpha分量的差,然后再加上混合参数1的alpha分量。计
COLOR = (1 – ARG1.alpha) * ARG2 + ARG1.alpha
TOP_BUMPENVMAP
 
TOP_BUMPENVMAPLUMINANCE
 
TOP_LERP
 
 
10.8.5 图元含有的属性和相关的读写操作
 
一个图元由顶点组成。顶点有着它的格式,大小。顶点具有颜色,纹理坐标等属性。图元有着它的填充模式、拣选模式和渲染模式。图元有着它的alpha混合方法和颜色混合方法。图元还具有包围盒用以在空间中进行相交判断……等等。下面的代码则详细地列举了一个图元所具备的各种属性。
 
//primitive.h
class C_Primitive
{
public:
    int  numVertices;//图元的顶点缓冲区中的顶点个数
    int  numIndices; //图元的索引缓冲区中的索引个数

protected:
    //包含了所有图元实例指针的静态成员数据
    static vector<C_Primitive*> allPrimitives;
    DWORD renderMode; //当前的渲染模式
    bool  updateMemory;   //是否已更新内存的标志   
    bool  updateVertices; //是否已经更新顶点的标志    
    unsigned int    quality;           //图元的质量,必须是严格的正数。
    D3DMATERIAL8    material;    //图元的材质信息

    //是否允许改变图元所使用的纹理数量的标志
    bool    allowChangeNumTexture;    
    int      numTexture;    //图元所使用的纹理个数,最多为8个
    C_Texture*        p_Texture[8]; //图元使用的纹理对象    
    D3DXVECTOR2        textureScale[8];    //图元纹理的大小    
    D3DXVECTOR2        textureOffset[8];
    DWORD    colorArgument0[8];//用在多纹理阶段的图元的颜色参数0 
    DWORD    colorArgument1[8];//用在多纹理阶段的图元的颜色参数1
    DWORD    colorArgument2[8];//用在多纹理阶段的图元的颜色参数2
    DWORD    alphaArgument0[8];//用在多纹理阶段的图元的alpha参数0
    DWORD    alphaArgument1[8];//用在多纹理阶段的图元的alpha参数1
    DWORD    alphaArgument2[8];//用在多纹理阶段的图元的alpha参数2
    DWORD    colorOperation[8];//每一纹理阶段的颜色操作。
    DWORD    alphaOperation[8];//每一个纹理阶段的alpha混合操作。
    bool    useArgument0;    //是否使用参数0

    //是否使用顶点漫反射颜色,否的话用材质的漫反射颜色
    bool        useVertexDiffuse;
    bool        alphaTestEnable;//是否使用alpha测试功能
    DWORD        alphaTestReference;//alpha测试的测试比较值
    DWORD        alphaTestFunction;//alpha测试的测试函数
    bool        alphaBlendEnable; //是否启动alpha混合
    DWORD        alphaSourceBlendFactor;    //alpha混合的源混合因子

    //alpha混合的目标混合因子
    DWORD        alphaDestinationBlendFactor;  
    DWORD        alphaBlendOperation; //alpha混合的混合方式
    DWORD        cullMode;                //本图元的拣选模式 
    DWORD        vertexFormat; //顶点格式                
    int         vertexSize;//图元中顶点的大小 
    IDirect3DVertexBuffer8*        p_DeviceVB;//顶点缓冲
    IDirect3DIndexBuffer8*        p_DeviceIB; //索引缓冲
    C_BoundingBox*                p_BoundingBox;//图元的包围盒 
    C_VertexManipulator* p_VertexManipulator;//图元的顶点操作器 
    CommandType*             commands;        //图元的渲染命令 
    int        numCommands;    //图元的渲染命令个数
    bool    createVertexBuffer;    //是否图元自己创建顶点缓冲
    bool    createIndexBuffer;//是否图元自己创建索引缓冲
    bool    createCommandList;//是否图元自己创建渲染命令列表
    unsigned char*  p_VertexBufferData; //用来恢复顶点数据               
    unsigned char*  p_IndexBufferData;   //用来恢复顶点索引数据
};

void C_Primitive::SetRenderMode(DWORD renderMode){this->renderMode = renderMode;}
DWORD C_Primitive::GetRenderMode(){return renderMode;}

void C_Primitive::SetQuality(unsigned int quality)
{
    if (quality <= 0)    // Quality of <= 0 is undefined
        quality = 1;
    this->quality = quality;
    updateMemory = TRUE;
    updateVertices = TRUE;
}

unsigned int C_Primitive::GetQuality(){return quality;}

void C_Primitive::SetCullMode(DWORD cullMode)
{
    this->cullMode = cullMode;
    updateVertices = TRUE;
}

DWORD C_Primitive::GetCullMode(){return cullMode;}

// Appearance Properties
void C_Primitive::SetMaterial(D3DMATERIAL8 material){this->material = material; }
D3DMATERIAL8 C_Primitive::GetMaterial(){return material;}
void C_Primitive::SetDiffuseReflection(D3DCOLORVALUE diffuse) {this->material.Diffuse = diffuse; }
D3DCOLORVALUE C_Primitive::GetDiffuseReflection(){return material.Diffuse;}
void C_Primitive::SetAmbientReflection(D3DCOLORVALUE ambient) {this->material.Ambient = ambient; }
D3DCOLORVALUE C_Primitive::GetAmbientReflection(){return material.Ambient;}
void C_Primitive::SetSpecularHighlight(D3DCOLORVALUE specular) { this->material.Specular = specular; }
D3DCOLORVALUE C_Primitive::GetSpecularHighlight(){return material.Specular;}
void C_Primitive::SetLightEmissive(D3DCOLORVALUE emissive){this->material.Emissive = emissive; }
D3DCOLORVALUE C_Primitive::GetLightEmissive(){return material.Emissive;}
void C_Primitive::SetSpecularPower(float specularPower){this->material.Power = specularPower; }
float C_Primitive::GetSpecularPower(){return material.Power;}

void C_Primitive::SetDefaultMaterialAndTextureProperties() 
{
    //设置缺省的材质,缺省地材质的漫反射系数和环境光反射系数都为
    //{1.0f, 1.0f, 1.0f, 1.0f}。缺省地图元不使用镜面反射和漫反射
    D3DMATERIAL8 tempMaterial;
    D3DCOLORVALUE rgbaDiffuse = {1.0f, 1.0f, 1.0f, 1.0f};
D3DCOLORVALUE rgbaAmbient = {1.0f, 1.0f, 1.0f, 1.0f};      D3DCOLORVALUE rgbaSpecular = {0.0f, 0.0f, 0.0f, 0.0f};    D3DCOLORVALUE rgbaEmissive = {0.0, 0.0, 0.0, 0};       
    // Change the material
    tempMaterial.Diffuse = rgbaDiffuse;
    tempMaterial.Ambient = rgbaAmbient;
    tempMaterial.Specular = rgbaSpecular;
    tempMaterial.Emissive = rgbaEmissive;
    tempMaterial.Power = 0;        
    
    //设置材质
    SetMaterial(tempMaterial);

    //设置每一阶段的纹理的大小和偏移量,缺省地纹理没有偏移量
    int i;
    for (i = 0; i < 8; i++) 
    {
        SetTextureScalingXY(i, D3DXVECTOR2(1.0f, 1.0f));
    SetTextureOffsetXY(i, D3DXVECTOR2(0.0f, 0.0f));
    }
}

void C_Primitive::SetAlphaTestEnable(bool alphaTestEnable){this->alphaTestEnable = alphaTestEnable;}
bool C_Primitive::GetAlphaTestEnable(){return alphaTestEnable;}
void C_Primitive::SetAlphaTestReference(DWORD alphaTestReference){this->alphaTestReference = alphaTestReference;}
DWORD C_Primitive::GetAlphaTestReference(){return alphaTestReference;}
void C_Primitive::SetAlphaTestFunction(DWORD alphaTestFunction){this->alphaTestFunction = alphaTestFunction;}
DWORD C_Primitive::GetAlphaTestFunction(){return alphaTestFunction;}
void C_Primitive::SetAlphaBlendEnable(bool alphaBlendEnable){this->alphaBlendEnable = alphaBlendEnable;}
bool C_Primitive::GetAlphaBlendEnable(){return alphaBlendEnable;}
void C_Primitive::SetAlphaSourceBlendFactor(DWORD alphaSourceBlendFactor){ this->alphaSourceBlendFactor = alphaSourceBlendFactor;}
DWORD C_Primitive::GetAlphaSourceBlendFactor(){return alphaSourceBlendFactor;}
void C_Primitive::SetAlphaDestinationBlendFactor(DWORD alphaDestinationBlendFactor){this->alphaDestinationBlendFactor = alphaDestinationBlendFactor;}
DWORD C_Primitive::GetAlphaDestinationBlendFactor(){return alphaDestinationBlendFactor;}
void C_Primitive::SetAlphaBlendOperation(DWORD alphaBlendOperation){this->alphaBlendOperation = alphaBlendOperation;}
DWORD C_Primitive::GetAlphaBlendOperation(){return alphaBlendOperation;    }
void C_Primitive::SetVertexDiffuseColorEnable(bool enable){useVertexDiffuse = enable;}
bool C_Primitive::GetVertexDiffuseColorEnable(){return useVertexDiffuse;}

void C_Primitive::SetNumberofTextureStage(DWORD numTexture) 
{
    if (allowChangeNumTexture) 
    {
        if ((numTexture == 0) || (numTexture > 8)) 
            return;
        if (this->numTexture != numTexture)
        {
            this->numTexture = numTexture;
            if (numTexture == 1) 
            {
                vertexFormat = D3DFVF_CUSTOMVERTEX1TEXTURE; 
                vertexSize = sizeof(CUSTOMVERTEX1TEXTURE);
            } 
            else if (numTexture == 2) 
            { 
                vertexFormat = D3DFVF_CUSTOMVERTEX2TEXTURE; 
                vertexSize = sizeof(CUSTOMVERTEX2TEXTURE);
            } 
            else if (numTexture == 3) 
            {
                vertexFormat = D3DFVF_CUSTOMVERTEX3TEXTURE; 
                vertexSize = sizeof(CUSTOMVERTEX3TEXTURE);
            } 
            else if (numTexture == 4) 
            { 
                vertexFormat = D3DFVF_CUSTOMVERTEX4TEXTURE; 
                vertexSize = sizeof(CUSTOMVERTEX4TEXTURE);
            } 
            else if (numTexture == 5) 
            {
                vertexFormat = D3DFVF_CUSTOMVERTEX5TEXTURE; 
                vertexSize = sizeof(CUSTOMVERTEX5TEXTURE);
            } 
            else if (numTexture == 6) 
            {
                vertexFormat = D3DFVF_CUSTOMVERTEX6TEXTURE; 
                vertexSize = sizeof(CUSTOMVERTEX6TEXTURE);
            } 
            else if (numTexture == 7) 
            { 
                vertexFormat = D3DFVF_CUSTOMVERTEX7TEXTURE; 
                 vertexSize = sizeof(CUSTOMVERTEX7TEXTURE);
            } 
            else if (numTexture == 8) 
            {
                vertexFormat = D3DFVF_CUSTOMVERTEX8TEXTURE; 
                vertexSize = sizeof(CUSTOMVERTEX8TEXTURE);
            } 
            
            updateMemory = TRUE;
            updateVertices = TRUE;
        }
    }
}

// 返回纹理阶段数
DWORD C_Primitive::GetNumberofTextureStage(){return numTexture;}

void C_Primitive::DisableChangeNumberofTextureStage()
{
    allowChangeNumTexture = false;
}
void C_Primitive::SetTexture(DWORD textureNum, tstring fileName, bool mutipleResolution, D3DCOLOR colorKey) 
{
    //如果纹理已经存在,则删除之
    if (p_Texture[textureNum]) {
        SAFE_DELETE(p_Texture[textureNum]);
    }
    p_Texture[textureNum] = new C_Texture(fileName,
                                mutipleResolution, colorKey);
}

C_Texture* C_Primitive::GetTextureContainer(int textureNum){return p_Texture[textureNum];}
void C_Primitive::SetTextureScalingXY(DWORD textureNum,D3DXVECTOR2 scale) 
{
    this->textureScale[textureNum] = scale;
    updateVertices = TRUE;
}
D3DXVECTOR2    C_Primitive::GetTextureScalingXY(DWORD textureNum) {return textureScale[textureNum];}

void C_Primitive::SetTextureOffsetXY(DWORD texturenum,D3DXVECTOR2 offset) 
{
    this->textureOffset[texturenum] = offset;
    updateVertices = TRUE;
}

D3DXVECTOR2 C_Primitive::GetTextureOffsetXY( DWORD textureNum) {return textureOffset[textureNum];}
void C_Primitive::SetColorArgument1( int textureNum, DWORD argumentType) {colorArgument1[textureNum] = argumentType;}
DWORD C_Primitive::GetColorArgument1(int textureNum) {return colorArgument1[textureNum];}
void C_Primitive::SetColorArgument2(int textureNum, DWORD argumentType) {colorArgument2[textureNum] = argumentType;}
DWORD C_Primitive::GetColorArgument2(int textureNum){return colorArgument2[textureNum];}
void C_Primitive::SetAlphaArgument1(int textureNum, DWORD argumentType){alphaArgument1[textureNum] = argumentType;}
DWORD C_Primitive::GetAlphaArgument1(int textureNum){return alphaArgument1[textureNum];}
void C_Primitive::SetAlphaArgument2(int textureNum, DWORD argumentType){alphaArgument2[textureNum] = argumentType;}
DWORD C_Primitive::GetAlphaArgument2(int textureNum){return alphaArgument2[textureNum];}
void C_Primitive::SetColorArgument0(int textureNum, DWORD argumentType){colorArgument0[textureNum] = argumentType;}
DWORD C_Primitive::GetColorArgument0(int textureNum){return colorArgument0[textureNum];}
void C_Primitive::SetAlphaArgument0(int textureNum, DWORD argumentType){alphaArgument0[textureNum] = argumentType;}
DWORD C_Primitive::GetAlphaArgument0(int textureNum){return alphaArgument0[textureNum];}
void C_Primitive::SetColorOperation(int textureNum, DWORD operationType){colorOperation[textureNum] = operationType;}
DWORD C_Primitive::GetColorOperation(int textureNum){return colorOperation[textureNum];}
void C_Primitive::SetAlphaOperation(int textureNum, DWORD operationType){alphaOperation[textureNum] = operationType;}
DWORD C_Primitive::GetAlphaOperation(int textureNum){return alphaOperation[textureNum];}
void C_Primitive::SetUseArgument0Enable(bool use) {useArgument0 = use;}
bool C_Primitive::GetUseArgument0Enable() {return useArgument0;}
void C_Primitive::SetVertexBuffer(IDirect3DVertexBuffer8*p_DeviceVB) {this->p_DeviceVB = p_DeviceVB;}
IDirect3DVertexBuffer8* C_Primitive::GetVertexBuffer() {return p_DeviceVB;}
void C_Primitive::SetIndexBuffer(IDirect3DIndexBuffer8* p_DeviceIB) {this->p_DeviceIB = p_DeviceIB;}
IDirect3DIndexBuffer8* C_Primitive::GetIndexBuffer() {return p_DeviceIB;}
DWORD C_Primitive::GetVertexFormat() {return vertexFormat;}
DWORD C_Primitive::GetVertexSize() {return vertexSize;}
C_BoundingBox * C_Primitive::GetBoundingBox() {return p_BoundingBox;}