Пример #1
0
//-----------------------------------------------------------------------------
// Name: XBUtil_DeclaratorFromFVF()
// Desc: Create a vertex declaration from an FVF. Registers are assigned as
//       follows:
//          v0     = Vertex position
//          v1     = Vertex blend weights
//          v2     = Vertex normal
//          v3     = Vertex diffuse color
//          v4     = Vertex specular color
//       // v5     = Vertex fog (no FVF code)
//       // v6     = Vertex pointsize (no FVF code)
//       // v7     = Vertex back diffuse color (no FVF code)
//       // v8     = Vertex back specular color (no FVF code)
//          v9-v12 = Vertex texture coords
//-----------------------------------------------------------------------------
HRESULT XBUtil_DeclaratorFromFVF( DWORD dwFVF, 
                                  DWORD Declaration[MAX_FVF_DECL_SIZE] )
{
    // Start the declaration
    DWORD decl = 0;
    Declaration[decl++] = D3DVSD_STREAM(0);

    // Handle position
    DWORD dwPositionFVF = ( dwFVF & D3DFVF_POSITION_MASK );
    if( dwPositionFVF == D3DFVF_XYZRHW ) Declaration[decl++] = D3DVSD_REG( 0, D3DVSDT_FLOAT4 ); 
    else                                 Declaration[decl++] = D3DVSD_REG( 0, D3DVSDT_FLOAT3 ); 

    // Handle blend weights
    if( dwPositionFVF == D3DFVF_XYZB1 )  Declaration[decl++] = D3DVSD_REG( 1, D3DVSDT_FLOAT1 ); 
    if( dwPositionFVF == D3DFVF_XYZB2 )  Declaration[decl++] = D3DVSD_REG( 1, D3DVSDT_FLOAT2 ); 
    if( dwPositionFVF == D3DFVF_XYZB3 )  Declaration[decl++] = D3DVSD_REG( 1, D3DVSDT_FLOAT3 ); 
    if( dwPositionFVF == D3DFVF_XYZB4 )  Declaration[decl++] = D3DVSD_REG( 1, D3DVSDT_FLOAT4 ); 

    // Handle normal, diffuse, and specular
    if( dwFVF & D3DFVF_NORMAL )          Declaration[decl++] = D3DVSD_REG( 2, D3DVSDT_FLOAT3 );
    if( dwFVF & D3DFVF_DIFFUSE )         Declaration[decl++] = D3DVSD_REG( 3, D3DVSDT_D3DCOLOR );
    if( dwFVF & D3DFVF_SPECULAR )        Declaration[decl++] = D3DVSD_REG( 4, D3DVSDT_D3DCOLOR );

    // Handle texture coordinates
    DWORD dwNumTextures = (dwFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;

    for( DWORD i=0; i<dwNumTextures; i++ )
    {
        DWORD dwTexCoordSize = ( dwFVF & (0x00030000<<(i*2)) );

        DWORD dwNumTexCoords = 0;
        if( dwTexCoordSize == D3DFVF_TEXCOORDSIZE1(i) ) dwNumTexCoords = D3DVSDT_FLOAT1;
        if( dwTexCoordSize == D3DFVF_TEXCOORDSIZE2(i) ) dwNumTexCoords = D3DVSDT_FLOAT2;
        if( dwTexCoordSize == D3DFVF_TEXCOORDSIZE3(i) ) dwNumTexCoords = D3DVSDT_FLOAT3;
        if( dwTexCoordSize == D3DFVF_TEXCOORDSIZE4(i) ) dwNumTexCoords = D3DVSDT_FLOAT4;

        Declaration[decl++] = D3DVSD_REG( 9 + i, dwNumTexCoords );
    }

    // End the declarator
    Declaration[decl++] = D3DVSD_END();

    return S_OK;
}
Пример #2
0
/* Explanation of texture copying via drawShadedTexQuad and drawShadedTexSubQuad:
	From MSDN: "When rendering 2D output using pre-transformed vertices,
				care must be taken to ensure that each texel area correctly corresponds
				to a single pixel area, otherwise texture distortion can occur."
	=> We need to subtract 0.5 from the vertex positions to properly map texels to pixels.
	HOWEVER, the MSDN article talks about D3DFVF_XYZRHW vertices, which bypass the programmable pipeline.
	Since we're using D3DFVF_XYZW and the programmable pipeline though, the vertex positions
	are normalized to [-1;+1], i.e. we need to scale the -0.5 offset by the texture dimensions.
	For example see a texture with a width of 640 pixels:
	"Expected" coordinate range when using D3DFVF_XYZRHW: [0;640]
	Normalizing this coordinate range for D3DFVF_XYZW: [0;640]->[-320;320]->[-1;1]
		i.e. we're subtracting width/2 and dividing by width/2
	BUT: The actual range when using D3DFVF_XYZRHW needs to be [-0.5;639.5] because of the need for exact texel->pixel mapping.
	We can still apply the same normalizing procedure though:
		[-0.5;639.5]->[-320-0.5;320-0.5]->[-1-0.5/320;1-0.5/320]

	So generally speaking the correct coordinate range is [-1-0.5/(w/2);1-0.5/(w/2)]
	which can be simplified to [-1-1/w;1-1/w].

	Note that while for D3DFVF_XYZRHW the y coordinate of the bottom of the screen is positive,
		it's negative for D3DFVF_XYZW. This is why we need to _add_ 1/h for the second position component instead of subtracting it.

	For a detailed explanation of this read the MSDN article "Directly Mapping Texels to Pixels (Direct3D 9)".
*/
void drawShadedTexQuad(IDirect3DTexture9 *texture,
	const RECT *rSource,
	int SourceWidth,
	int SourceHeight,
	int DestWidth,
	int DestHeight,
	IDirect3DPixelShader9 *PShader,
	IDirect3DVertexShader9 *Vshader,
	float Gamma)
{
	float sw = 1.0f / (float)SourceWidth;
	float sh = 1.0f / (float)SourceHeight;
	float dw = 1.0f / (float)DestWidth;
	float dh = 1.0f / (float)DestHeight;
	float u1 = 0.0f;
	float u2 = 1.0f;
	float v1 = 0.0f;
	float v2 = 1.0f;
	if (rSource != nullptr)
	{
		u1 = ((float)rSource->left) * sw;
		u2 = ((float)rSource->right) * sw;
		v1 = ((float)rSource->top) * sh;
		v2 = ((float)rSource->bottom) * sh;
	}
	float g = 1.0f / Gamma;

	const struct Q2DVertex
	{
		float x, y, z, rhw, u, v, w, h, G;
	} coords[4] = {
{-1.0f - dw,-1.0f + dh, 0.0f,1.0f, u1, v2, dw, dh, g},
{-1.0f - dw, 1.0f + dh, 0.0f,1.0f, u1, v1, dw, dh, g},
{ 1.0f - dw,-1.0f + dh, 0.0f,1.0f, u2, v2, dw, dh, g},
{ 1.0f - dw, 1.0f + dh, 0.0f,1.0f, u2, v1, dw, dh, g}
	};
	D3D::ChangeVertexShader(Vshader);
	D3D::ChangePixelShader(PShader);
	D3D::SetTexture(0, texture);
	D3D::ChangeVertexDeclaration(0);
	dev->SetFVF(D3DFVF_XYZW | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE1(2));
	dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coords, sizeof(Q2DVertex));
	RestoreShaders();
}
Пример #3
0
void drawShadedTexSubQuad(IDirect3DTexture9 *texture,
	const MathUtil::Rectangle<float> *rSource,
	int SourceWidth,
	int SourceHeight,
	const MathUtil::Rectangle<float> *rDest,
	int DestWidth,
	int DestHeight,
	IDirect3DPixelShader9 *PShader,
	IDirect3DVertexShader9 *Vshader,
	float Gamma)
{
	float sw = 1.0f / (float)SourceWidth;
	float sh = 1.0f / (float)SourceHeight;
	float dw = 1.0f / (float)DestWidth;
	float dh = 1.0f / (float)DestHeight;
	float u1 = rSource->left * sw;
	float u2 = rSource->right * sw;
	float v1 = rSource->top * sh;
	float v2 = rSource->bottom * sh;
	float g = 1.0f / Gamma;

	struct Q2DVertex
	{
		float x, y, z, rhw, u, v, w, h, G;
	} coords[4] = {
{ rDest->left - dw , rDest->top + dh, 1.0f,1.0f, u1, v2, dw, dh, g},
{ rDest->left - dw , rDest->bottom + dh, 1.0f,1.0f, u1, v1, dw, dh, g},
{ rDest->right - dw , rDest->top + dh, 1.0f,1.0f, u2, v2, dw, dh, g},
{ rDest->right - dw , rDest->bottom + dh, 1.0f,1.0f, u2, v1, dw, dh, g}
	};
	D3D::ChangeVertexShader(Vshader);
	D3D::ChangePixelShader(PShader);
	D3D::SetTexture(0, texture);
	D3D::ChangeVertexDeclaration(0);
	dev->SetFVF(D3DFVF_XYZW | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE1(2));
	dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coords, sizeof(Q2DVertex));
	RestoreShaders();
}
Пример #4
0
static void D3DXGetFVFVertexSizeTest(void)
{
    UINT got;

    compare_vertex_sizes (D3DFVF_XYZ, 12);

    compare_vertex_sizes (D3DFVF_XYZB3, 24);

    compare_vertex_sizes (D3DFVF_XYZB5, 32);

    compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_NORMAL, 24);

    compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_DIFFUSE, 16);

    compare_vertex_sizes (
        D3DFVF_XYZ |
        D3DFVF_TEX1 |
        D3DFVF_TEXCOORDSIZE1(0), 16);
    compare_vertex_sizes (
        D3DFVF_XYZ |
        D3DFVF_TEX2 |
        D3DFVF_TEXCOORDSIZE1(0) |
        D3DFVF_TEXCOORDSIZE1(1), 20);

    compare_vertex_sizes (
        D3DFVF_XYZ |
        D3DFVF_TEX1 |
        D3DFVF_TEXCOORDSIZE2(0), 20);

    compare_vertex_sizes (
        D3DFVF_XYZ |
        D3DFVF_TEX2 |
        D3DFVF_TEXCOORDSIZE2(0) |
        D3DFVF_TEXCOORDSIZE2(1), 28);

    compare_vertex_sizes (
        D3DFVF_XYZ |
        D3DFVF_TEX6 |
        D3DFVF_TEXCOORDSIZE2(0) |
        D3DFVF_TEXCOORDSIZE2(1) |
        D3DFVF_TEXCOORDSIZE2(2) |
        D3DFVF_TEXCOORDSIZE2(3) |
        D3DFVF_TEXCOORDSIZE2(4) |
        D3DFVF_TEXCOORDSIZE2(5), 60);

    compare_vertex_sizes (
        D3DFVF_XYZ |
        D3DFVF_TEX8 |
        D3DFVF_TEXCOORDSIZE2(0) |
        D3DFVF_TEXCOORDSIZE2(1) |
        D3DFVF_TEXCOORDSIZE2(2) |
        D3DFVF_TEXCOORDSIZE2(3) |
        D3DFVF_TEXCOORDSIZE2(4) |
        D3DFVF_TEXCOORDSIZE2(5) |
        D3DFVF_TEXCOORDSIZE2(6) |
        D3DFVF_TEXCOORDSIZE2(7), 76);

    compare_vertex_sizes (
        D3DFVF_XYZ |
        D3DFVF_TEX1 |
        D3DFVF_TEXCOORDSIZE3(0), 24);

    compare_vertex_sizes (
        D3DFVF_XYZ |
        D3DFVF_TEX4 |
        D3DFVF_TEXCOORDSIZE3(0) |
        D3DFVF_TEXCOORDSIZE3(1) |
        D3DFVF_TEXCOORDSIZE3(2) |
        D3DFVF_TEXCOORDSIZE3(3), 60);

    compare_vertex_sizes (
        D3DFVF_XYZ |
        D3DFVF_TEX1 |
        D3DFVF_TEXCOORDSIZE4(0), 28);

    compare_vertex_sizes (
        D3DFVF_XYZ |
        D3DFVF_TEX2 |
        D3DFVF_TEXCOORDSIZE4(0) |
        D3DFVF_TEXCOORDSIZE4(1), 44);

    compare_vertex_sizes (
        D3DFVF_XYZ |
        D3DFVF_TEX3 |
        D3DFVF_TEXCOORDSIZE4(0) |
        D3DFVF_TEXCOORDSIZE4(1) |
        D3DFVF_TEXCOORDSIZE4(2), 60);

    compare_vertex_sizes (
        D3DFVF_XYZB5 |
        D3DFVF_NORMAL |
        D3DFVF_DIFFUSE |
        D3DFVF_SPECULAR |
        D3DFVF_TEX8 |
        D3DFVF_TEXCOORDSIZE4(0) |
        D3DFVF_TEXCOORDSIZE4(1) |
        D3DFVF_TEXCOORDSIZE4(2) |
        D3DFVF_TEXCOORDSIZE4(3) |
        D3DFVF_TEXCOORDSIZE4(4) |
        D3DFVF_TEXCOORDSIZE4(5) |
        D3DFVF_TEXCOORDSIZE4(6) |
        D3DFVF_TEXCOORDSIZE4(7), 180);
}
Пример #5
0
	void DX9Buffer::setNbTexCoords(size_t nb)
	{
		if (nbTexCoords != nb)
		{
			nbTexCoords = nb;
			SAFE_RELEASE( texCoordBuffer );
			if (nbTexCoords > 0)
				DX9Info::getDevice()->CreateVertexBuffer(nbVertices*nbTexCoords*sizeof(float), D3DUSAGE_DYNAMIC, D3DFVF_TEX1|D3DFVF_TEXCOORDSIZE1(nbTexCoords), D3DPOOL_DEFAULT, &texCoordBuffer, NULL);
			currentTexCoordIndex = 0;
		}
	}
Пример #6
0
	DX9Buffer::DX9Buffer(BufferInfo &info) :
		nbVertices(info.nbVertices),
		nbIndices(info.nbIndices),
		nbTexCoords(info.nbTexCoords),
		currentVertexIndex(0),
		currentColorIndex(0),
		currentTexCoordIndex(0),

		currentLock(NO_LOCK),
		vertexBuffer(NULL), colorBuffer(NULL), texCoordBuffer(NULL), indexBuffer(NULL),
		ptrVertexBuffer(NULL), ptrColorBuffer(NULL), ptrTexCoordBuffer(NULL), ptrIndexBuffer(NULL)
	{
		SPK_ASSERT(nbVertices > 0,"DX9Buffer::DX9Buffer(BufferInfo) - The number of vertices cannot be 0");

		DX9Info::getDevice()->CreateVertexBuffer(nbVertices*sizeof(D3DXVECTOR3), D3DUSAGE_DYNAMIC, D3DFVF_XYZ, D3DPOOL_DEFAULT, &vertexBuffer, NULL);
		DX9Info::getDevice()->CreateVertexBuffer(nbVertices*sizeof(D3DCOLOR), D3DUSAGE_DYNAMIC, D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &colorBuffer, NULL);

		// TODO : gérer les indices 32bit
		if( nbIndices > 0 )
		{
			DX9Info::getDevice()->CreateIndexBuffer(nbIndices*sizeof(short), 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &indexBuffer, 0);

			unsigned int offsetIndex = 0;

			lock(INDEX_LOCK);
			// initialisation de l'index buffer
			for(size_t i = 0; i < nbIndices/6; i++)
			{
//#ifdef _DX9QUADRENDERER_CLOCKWISE_
				*(ptrIndexBuffer++) = 0 + offsetIndex;
				*(ptrIndexBuffer++) = 1 + offsetIndex;
				*(ptrIndexBuffer++) = 2 + offsetIndex;
				*(ptrIndexBuffer++) = 0 + offsetIndex;
				*(ptrIndexBuffer++) = 2 + offsetIndex;
				*(ptrIndexBuffer++) = 3 + offsetIndex;
// TODO handle counter clockwise
//#else
//				*(ptrIndexBuffer++) = 0 + offsetIndex;
//				*(ptrIndexBuffer++) = 2 + offsetIndex;
//				*(ptrIndexBuffer++) = 1 + offsetIndex;
//				*(ptrIndexBuffer++) = 0 + offsetIndex;
//				*(ptrIndexBuffer++) = 3 + offsetIndex;
//				*(ptrIndexBuffer++) = 2 + offsetIndex;
//#endif
				offsetIndex += 4;
			}
			unlock();
		}

		// TODO : gérer autre chose que les textures 2D
		if(nbTexCoords > 0)
			DX9Info::getDevice()->CreateVertexBuffer(nbVertices*sizeof(D3DXVECTOR2), D3DUSAGE_DYNAMIC, D3DFVF_TEX1|D3DFVF_TEXCOORDSIZE1(nbTexCoords), D3DPOOL_DEFAULT, &texCoordBuffer, NULL);
	}
Пример #7
0
static void test_fvf_decl_conversion(IDirect3DDevice9 *pDevice)
{

    HRESULT hr;
    unsigned int i;

    IDirect3DVertexDeclaration9* default_decl = NULL;
    DWORD default_fvf = D3DFVF_SPECULAR | D3DFVF_DIFFUSE;
    D3DVERTEXELEMENT9 default_elements[] =
        { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 },
          { 0, 4, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() };

    /* Create a default declaration and FVF that does not match any of the tests */
    hr = IDirect3DDevice9_CreateVertexDeclaration( pDevice, default_elements, &default_decl );
    ok(SUCCEEDED(hr), "CreateVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
    if (FAILED(hr)) goto cleanup;

    /* Test conversions from vertex declaration to an FVF.
     * For some reason those seem to occur only for POSITION/POSITIONT,
     * Otherwise the FVF is forced to 0 - maybe this is configuration specific */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, D3DFVF_XYZ, TRUE));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, D3DFVF_XYZRHW, TRUE));
    }
    for (i = 0; i < 4; i++) {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT1+i, 0, D3DDECLUSAGE_BLENDWEIGHT, 0}, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] = 
            { { 0, 0, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0}, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }

    /* Make sure textures of different sizes work */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }

    /* Make sure the TEXCOORD index works correctly - try several textures */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 },
              { 0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 },
              { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2 },
              { 0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }

    /* No FVF mapping available */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }

    /* Try empty declaration */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] = { D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }

    /* Now try a combination test */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITIONT, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 },
              { 0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 },
              { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 },
              { 0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 },
              { 0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1 }, D3DDECL_END() };
        VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0, FALSE));
    }

    /* Test conversions from FVF to a vertex declaration 
     * These seem to always occur internally. A new declaration object is created if necessary */

    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZ, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZW, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
          { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZRHW, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
              { 0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
              { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
           D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
              { 0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB5, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB1, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
    }
    {
         CONST D3DVERTEXELEMENT9 test_buffer[] =
             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
               { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB2, test_buffer, 1));
    }
    {
         CONST D3DVERTEXELEMENT9 test_buffer[] =
             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
               { 0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
               { 0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
             D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
     }
     {
         CONST D3DVERTEXELEMENT9 test_buffer[] =
             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
               { 0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
               { 0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
             D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
     }
     {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB3, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
              { 0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
              { 0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB4, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
              { 0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
              { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
              { 0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_NORMAL, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_PSIZE, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_DIFFUSE, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_SPECULAR, test_buffer, 1));
    }

    /* Make sure textures of different sizes work */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1, test_buffer, 1));
    }
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1, test_buffer, 1));
    }

    /* Make sure the TEXCOORD index works correctly - try several textures */
    {
        CONST D3DVERTEXELEMENT9 test_buffer[] =
            { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 },
              { 0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 },
              { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2 },
              { 0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3 }, D3DDECL_END() };
        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
            D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1) | D3DFVF_TEXCOORDSIZE2(2) |
            D3DFVF_TEXCOORDSIZE4(3) | D3DFVF_TEX4, test_buffer, 1));
    }

    /* Now try a combination test  */
    {
       CONST D3DVERTEXELEMENT9 test_buffer[] =
                { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
                  { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
                  { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 },
                  { 0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 },
                  { 0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 },
                  { 0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 }, D3DDECL_END() };
       VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB4 | D3DFVF_SPECULAR | D3DFVF_DIFFUSE |
           D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1) | D3DFVF_TEX2, test_buffer, 1));
    }

    /* Setting the FVF to 0 should result in no change to the default decl */
    VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, 0, default_elements, 0));

    cleanup:
    IDirect3DDevice9_SetVertexDeclaration ( pDevice, NULL );
    if ( default_decl ) IUnknown_Release (default_decl);
}