CreateVertexBuffer() [FIXED]

Started by
11 comments, last by MrDoomMaster 18 years, 8 months ago
Is there a way to change the FVF flags initially specified in the call to CreateVertexBuffer()? I would like to use the same vertex buffer for both textured quads and regular non-textured quads. In order to do this, I need to add/remove the D3DFVF_TEX1 flag depending on my needs. I think it would be rather slow to create/destroy a new vertex buffer for everytime my needs change! Thanks! [Edited by - MrDoomMaster on July 30, 2005 11:38:59 PM]
Advertisement
For the non-textured quads you can just set the texture to 0:
g_pDevice->SetTexture(0, 0);


Other than that, I can't find a way to change the FVF.
I've also just noticed IDirect3DDevice9::SetFVF()

Yet, you specify your FVF flags in both CreateVertexBuffer() *and* in SetFVF(). Must these remain the same? Can I use SetFVF to change flags? Why must you specify the flags in two different places?
I have no idea, I'll look into it though.

You probably do need to keep them the same. The device needs to know the FVF for drawing and the vertex buffer needs to know the FVF to allocate enough memory.
A few possible solutions to consider:

1) As Programmer16 suggests, simply disable texturing when rendering the untextured stuff; this is actually the simplest method.

2) create a non-FVF vertex buffer instead, pass NULL for the FVF, and create two vertex declarations instead, remembering that the stride for both should be the same (so that the texture coordinates are simply skipped). Declarations should still work with the old fixed function pipeline if that's you're reason for using FVFs.

3) create two vertex buffers, one for the position, and one for the texture coordinates, then use multiple vertex streams; you'll need to create two declarations as with solution 2, but it should also still work with the fixed function pipe IIRC.


SetFVF just sets the currently used FVF, IIRC the D3D runtime won't be happy if the FVF doesn't match the vertex buffer.

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

Well I modified my function to allow a user to specify NULL for the texture, in order to simply blitter a non-textured quad. The thing is, DrawPrimitive() Fails!

Here is my function, it's rather long, but very readable:

int DrawTexQuad(IDirect3DTexture9* Texture, DWORD Blend, int dest_x, int dest_y, Rect* source){    Rect tRect;    D3DSURFACE_DESC sd;    TexQuadVertex* Quad = 0;    if(!source)    {        tRect.x = 0;        tRect.y = 0;        if(!Texture)        {            tRect.width = m_DisplayInfo.Resolution.x;            tRect.height = m_DisplayInfo.Resolution.y;        }        else        {            if(Texture->GetLevelDesc(0, &sd) != D3D_OK)                return 0;            tRect.width = sd.Width;            tRect.height = sd.Height;        }        source = &tRect;    }    if(m_VertexBuffer->Lock(0, 0, (void**)&Quad, 0) != D3D_OK)        return 0;    memset(Quad, 0, sizeof(TexQuadVertex) * 4);    Quad[0].x       = (float)dest_x;    Quad[0].y       = (float)dest_y;    Quad[0].z       = 0.0;    Quad[0].rhw     = 1.0;    Quad[0].Color   = Blend;    Quad[1].x       = (float)dest_x + source->width;    Quad[1].y       = (float)dest_y;    Quad[1].z       = 0.0;    Quad[1].rhw     = 1.0;    Quad[1].Color   = Blend;    Quad[2].x       = (float)dest_x + source->width;    Quad[2].y       = (float)dest_y + source->height;    Quad[2].z       = 0.0;    Quad[2].rhw     = 1.0;    Quad[2].Color   = Blend;    Quad[3].x       = (float)dest_x;    Quad[3].y       = (float)dest_y + source->height;    Quad[3].z       = 0.0;    Quad[3].rhw     = 1.0;    Quad[3].Color   = Blend;    if(Texture)    {        Quad[0].tu      = (float)source->x / sd.Width;        Quad[0].tv      = (float)source->y / sd.Height;        Quad[1].tu      = (float)(source->x + source->width) / sd.Width;        Quad[1].tv      = (float)source->y / sd.Height;        Quad[2].tu      = (float)(source->x + source->width) / sd.Width;        Quad[2].tv      = (float)(source->y + source->height) / sd.Height;        Quad[3].tu      = (float)source->x / sd.Width;        Quad[3].tv      = (float)(source->y + source->height) / sd.Height;    }    m_VertexBuffer->Unlock();    if(m_Device->SetStreamSource(0, m_VertexBuffer, 0, sizeof(TexQuadVertex)) != D3D_OK)        return 0;    if(m_Device->SetFVF(m_VertexFormat) != D3D_OK)        return 0;    if(!SetTexture(Texture))        return 0;    if(m_Device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2) != D3D_OK)        return 0;    return 1;}


The bolded line of text is where my function fails. As you can see, if you specify NULL to the Texture parameter, the function simply skips the tu and tv members, which are initially set to 0. If both Texture *and* source parameters are NULL, then the entire quad should be the size of the screen, as you can see. If Texture is NOT null but source is NULL, then the size of the entire texture should be used as the texture coordinates. I hope this isn't too overly complicated.

My SetTexture() Function:
int SetTexture(IDirect3DTexture9* Texture){    if(Texture != m_CurrentTexture)    {        if(m_Device->SetTexture(0, Texture) != D3D_OK)            return 0;        m_CurrentTexture = Texture;    }    return 1;}


This function simply checks to see if you're trying to change the texture to the same texture more than once. If you're changing a new texture, it will change it. Otherwise the function simply returns with no changes made.

My vertex structure:
    struct TexQuadVertex    {        float x;        float y;        float z;        float rhw;        D3DCOLOR Color;        float tu;        float tv;    };


And finally, my call to CreateVertexBuffer, along with my FVF Flags:
DWORD m_VertexFormat = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1;if(m_Device->CreateVertexBuffer(sizeof(TexQuadVertex) * 4, 0, m_VertexFormat,    D3DPOOL_DEFAULT, &m_VertexBuffer, 0) != D3D_OK){    return 0;}


I really apologize for posting so much code, but I'm extremely stumped on why this is failing. Thanks for all of your help guys!
Quote:Original post by MrDoomMaster
The thing is, DrawPrimitive() Fails!


I can't see anything obviously wrong with the code you've posted - have you tried using the debug runtimes with maximum output? They're often pretty good at telling you what/why functions failed [smile]

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

A few things.
1) If I recall correctly, the VB's setting for FVF is used for caching and stuff like that, so it should work okay if you don't set it, however, (which leads me to (2))
2) If the FVF on the VB and the one you set for your device don't match, you get warnings. Since you're only matching you return value to D3D_OK, you'd be counting these warnings as errors. Try using the SUCCEEDED() and FAILED() macros instead, since they count warnings as successful calls.
3) I don't really see why you need to go into so much trouble? I think you should just pump some value into the non-textured vertices' u and v values and then simply set up your texture stages (or vertex shader) to only use diffuse colors (or whatever else you want). It's much more straightforward, and should give you less trouble, and the waste of 8 bytes per vertex seems very reasonable.
Sirob Yes.» - status: Work-O-Rama.
Well first of all, I don't even know what the Debug Runtimes are, much less how to use them. I've always based error checking on return values, nothing more.

Secondly, My FVF flags never change. What you see them set to is what they remain at always. So, having said this, DrawPrimitive() should not return 'warnings'. If it isn't equal to D3D_OK, this must mean something is wrong. Yet, in the DirectX documentation, the only 'reason' listed for failure of DrawPrimitive() is D3DERR_INVALIDCALL, which is absolutely *NO* help at all.

I suspect submitting a NULL texture pointer to IDirect3DDevice9::SetTexture() may be the source of the problem. Can anyone confirm this?
Quote:Original post by MrDoomMaster
Well first of all, I don't even know what the Debug Runtimes are, much less how to use them. I've always based error checking on return values, nothing more.
...
Yet, in the DirectX documentation, the only 'reason' listed for failure of DrawPrimitive() is D3DERR_INVALIDCALL, which is absolutely *NO* help at all.


If a Direct3D function returns an error or is the slightest bit unhappy about something, the debug runtime will tell you *why* its unhappy. Here's some information on how to enable the debug runtimes (they're invaluable!):

http://nexe.gamedev.net/directKnowledge/default.asp?p=Debugging


Quote:I suspect submitting a NULL texture pointer to IDirect3DDevice9::SetTexture() may be the source of the problem. Can anyone confirm this?


NULL is actually a valid value for IDirect3DDevice9::SetTexture(), it simply unsets the currently set texture for that texture stage and decrements its reference count (the SetTexture() call with a non-NULL texture pointer increments the reference count for that texture).

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

This topic is closed to new replies.

Advertisement