• Advertisement
Sign in to follow this  

[MDX] Invalid stride size for CustomVertex.PositionOnly?

This topic is 4254 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm mostly doing 2D stuff in MDX, but I need to draw a selection rectangle for my RTS, and I figured, doing it as a LineStrip would be most efficient. I created a class for this, and ended up with this:
    public class SelectionRectangle
    {
        private VertexBuffer vb;
        private Engine2D engine;
        private Point topLeft;
        private Point bottomRight;

        public SelectionRectangle(Engine2D engine)
        {
            this.engine = engine;

            // Spawn our VertexBuffer
            vb = new VertexBuffer(typeof(CustomVertex.PositionOnly), 3, engine.Device,
                                    Usage.WriteOnly, CustomVertex.PositionOnly.Format, Pool.Default);
            vb.Created += new EventHandler(OnVertexBufferCreated);

            SetRectangle(new Point(10, 10), new Point(20, 20));
        }

        public void SetRectangle(Point topLeft, Point bottomRight)
        {
            this.topLeft = topLeft;
            this.bottomRight = bottomRight;

            fillVertexBuffer(vb);
        }

        public void Render()
        {
            engine.Device.SetStreamSource(0, vb, 0);
            engine.Device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
        }

        private void OnVertexBufferCreated(object sender, EventArgs e)
        {
            VertexBuffer vb = (VertexBuffer)sender;

            fillVertexBuffer(vb);
        }

        private void fillVertexBuffer(VertexBuffer vb)
        {
            // Now fill our vertexbuffer
            CustomVertex.PositionOnly[] verts = new CustomVertex.PositionOnly[3];
            verts[0].Position = new Vector3(topLeft.X, topLeft.Y, 1.0f);
            verts[1].Position = new Vector3(topLeft.X, bottomRight.Y, 1.0f);
            verts[2].Position = new Vector3(bottomRight.X, bottomRight.Y, 1.0f);
            //verts[3].Position = new Vector3(bottomRight.X, topLeft.Y, 1.0f);
            //verts[3].Color = Color.Red.ToArgb();

            vb.SetData(verts, 0, LockFlags.None);            
        }
    }

It throws an InvalidCallException on the DrawPrimitives() call, and in DebugView it shows this:
[4056] Direct3D9: (ERROR) :Vertex stride in stream 0 is less than in the declaration 
[4056] Direct3D9: (ERROR) :DrawPrimitive failed. 
From what I understand, is that the FVF size is invalid with what is stored in the VB. However, looking at the code, I can't see why that is, since I do use the same vertexformat all over the place. What is wrong here? Note: The above code uses a trianglelist for testing purposes. Toolmaker

Share this post


Link to post
Share on other sites
Advertisement

I believe it's pretty much mandatory to specify the vertex format prior to drawing any primitives. You shouldn't count on the vertex format being already set in previous code fragment or retained from a previous frame, since rendering meshes and sprites or a device reset may implicitly alter the vertex format. Try adding the following line at the beginning of your render method:

engine.Device.VertexFormat = CustomVertex.PositionOnly.Format;

Share this post


Link to post
Share on other sites
1 more question tho: I'm now also rendering my map again, and it seems odd: Without my map, it shows the line perfectly:


However, when I do render my map aswell, the line is gone:


I tried changing the z position of the line to 0.9f or 1.0f, but that doesn't help much. Any ideas why this happens?

Toolmaker

Share this post


Link to post
Share on other sites
An alternative would be to use CustomVertex.Transformed for the rectangle's vertices. This would make sense, since the rectangle is in clip/view/screen space anyway and it would make sure there aren't any shady clip space transformations applied to your vertices. A little hack would be to disable the ZBuffer by calling engine.Device.ZBufferEnable = false; (don't forget to turn it back on after you're done with the rectangle!).

Nice to see some progress on your Dune2 clone again, multiple unit selection was indeed one of the few things the original missed. In your 2nd screenshot it looks like there shouldn't be any rectangle visible anyway btw, since the Cross and the Quad sprite are in the same place. Guess that's just nitpicking though [smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by remigius
An alternative would be to use CustomVertex.Transformed for the rectangle's vertices. This would make sense, since the rectangle is in clip/view/screen space anyway and it would make sure there aren't any shady clip space transformations applied to your vertices. A little hack would be to disable the ZBuffer by calling engine.Device.ZBufferEnable = false; (don't forget to turn it back on after you're done with the rectangle!).

Nice to see some progress on your Dune2 clone again, multiple unit selection was indeed one of the few things the original missed. In your 2nd screenshot it looks like there shouldn't be any rectangle visible anyway btw, since the Cross and the Quad sprite are in the same place. Guess that's just nitpicking though [smile]


Right now, the rectangle is hard-coded from 10,10 to 100,100. It doesn't respond to the mouse as of yet. I just wanted to make it work first, before adding responding to the mouse.

I tried disabling the ZBuffer before rendering the linestrip, and re-enabling it when done, but that doesn't seem to do much(ie. the rect still isn't there).

How much of a difference would the CustomVertex.Transformed make in this case? And could this all be a camera problem? Would it help if I change the world view/world transform?

Toolmaker

Share this post


Link to post
Share on other sites
It could be some setting you're setting to draw the terrain, but not unsetting afterwards. Theres lots of options here, just have a look at the terrain rendering code and see what might affect the rectangle code.

Hope this helps :).

Share this post


Link to post
Share on other sites
The terrain is rendered using the (D3DX)Sprite class, so I have no idea what settings it changes.

Everything is rendered using Sprite, except the rectangle, which is done by rendering a primitive.

Toolmaker

Share this post


Link to post
Share on other sites
All I can think of is these two possibilities:
1) You're drawing the terrain over the line. Are you sure you're rendering the line last?

2) Sprite is messing with one of your matrices. It shouldn't, really, unless you use the ObjectSpace flag anywhere, but it would be worth checking anyways. Try resetting you matrices to their old values before drawing again. Maybe that'll help :)

[EDIT] I also see you're using the 3 parameter overload of SetStreamSource. I'm not exactly sure about MDX1.1, but in 2.0 that one causes some "problems" :). If there's a 4 parameter overload, one with the stride in it, you might want to try that one instead.

Also, someone else might have more ideas :).

Share this post


Link to post
Share on other sites
Quote:
Original post by sirob
[EDIT] I also see you're using the 3 parameter overload of SetStreamSource. I'm not exactly sure about MDX1.1, but in 2.0 that one causes some "problems" :). If there's a 4 parameter overload, one with the stride in it, you might want to try that one instead.


You have to use the 4-parameter version if you have a type less vertex buffer. If your vertex buffer contains a format the 3-parameter version calculate the stride from this format. This is the same for MDX 1.1 and MDX 2.0

An additional reason I can see is that after drawing the map the pixel pipeline (texture, stage setup, shader) is not set correctly to render a white line.


Share this post


Link to post
Share on other sites
Quote:
Original post by Demirug
You have to use the 4-parameter version if you have a type less vertex buffer. If your vertex buffer contains a format the 3-parameter version calculate the stride from this format. This is the same for MDX 1.1 and MDX 2.0


Just ran a quick test under MDX2. Even when providing an FVF to the vertex buffer, if I don't supply a stride to the SetStreamSource, it won't render right (nothing shows, in my case).

I'm not sure what's up with it, but I havn't yet been able to get an overload other than the 4 parameter one to work.

Share this post


Link to post
Share on other sites
See the above 3 replies [smile]

Quote:
How much of a difference would the CustomVertex.Transformed make in this case? And could this all be a camera problem?


The default Sprites also use pre-transformed vertices for rendering (when you're not using SpriteFlags.ObjectSpace). These vertices are in view space at z=0, so they're drawn on top of everything else. So this isn't a camera problem, but rather a z-buffering problem.

Switching to pretransformed vertices for your line might help (and make sense conceptually), but disabling the z-buffer should also have solved the problem. For the z-buffer trick to work, you should render the line last (after rendering the terrain) as Sirob pointed out, because otherwise the terrain will just be drawn over it, since the sprites are at z=0, which should always be closer than your object-space line.

Quote:
You have to use the 4-parameter version if you have a type less vertex buffer.


This case and instancing are the only times I ever needed to use the 4-parameter overload in MDX1.1. IIRC using the 3-parameter overload doesn't generate a Direct3D debug warning or anything, so using it shouldn't be a problem.

Quote:
Just ran a quick test under MDX2. Even when providing an FVF to the vertex buffer, if I don't supply a stride to the SetStreamSource, it won't render right (nothing shows, in my case).


Strange... are you also setting the FVF on the device?

Share this post


Link to post
Share on other sites
Quote:
Original post by remigius
Quote:
Just ran a quick test under MDX2. Even when providing an FVF to the vertex buffer, if I don't supply a stride to the SetStreamSource, it won't render right (nothing shows, in my case).


Strange... are you also setting the FVF on the device?


You bet.

this thread is getting out of hand, quickly

Share this post


Link to post
Share on other sites
Quote:
Original post by sirob
Quote:
Original post by Demirug
You have to use the 4-parameter version if you have a type less vertex buffer. If your vertex buffer contains a format the 3-parameter version calculate the stride from this format. This is the same for MDX 1.1 and MDX 2.0


Just ran a quick test under MDX2. Even when providing an FVF to the vertex buffer, if I don't supply a stride to the SetStreamSource, it won't render right (nothing shows, in my case).

I'm not sure what's up with it, but I havn't yet been able to get an overload other than the 4 parameter one to work.


Sorry I had should be clearer. With “contains a format” I meant a buffer that was created with the CreateGeneric method.

Share this post


Link to post
Share on other sites
Quote:
Original post by Demirug
Quote:
Original post by sirob
Quote:
Original post by Demirug
You have to use the 4-parameter version if you have a type less vertex buffer. If your vertex buffer contains a format the 3-parameter version calculate the stride from this format. This is the same for MDX 1.1 and MDX 2.0


Just ran a quick test under MDX2. Even when providing an FVF to the vertex buffer, if I don't supply a stride to the SetStreamSource, it won't render right (nothing shows, in my case).

I'm not sure what's up with it, but I havn't yet been able to get an overload other than the 4 parameter one to work.


Sorry I had should be clearer. With “contains a format” I meant a buffer that was created with the CreateGeneric method.


Aha! That does indeed work. Looks like I've finally found a use for the 3 argument overload, and another generic class other than the GraphicsBuffer. Sweet day it is :).

Toolmaker, really sorry for throwing this completely off course ;).

Share this post


Link to post
Share on other sites
No results with the Transformed, and I'm kind of puzzled to why it doesn't work. I don't seem to be using the StencilBuffer, so that shouldn't be a problem. This is my initialization code:

public override void Initialize(System.Windows.Forms.Control owner, int screenWidth, int screenHeight, bool windowed)
{
this.owner = owner;
PresentParameters presentParams = new PresentParameters();
presentParams.SwapEffect = SwapEffect.Discard;

Format current = Manager.Adapters[0].CurrentDisplayMode.Format;

if (!windowed && Manager.CheckDeviceType(0, DeviceType.Hardware, current, current, false))
{
presentParams.Windowed = false;
presentParams.BackBufferFormat = current;
presentParams.BackBufferCount = 1;
presentParams.BackBufferWidth = screenWidth;
presentParams.BackBufferHeight = screenHeight;
}
else
{
presentParams.Windowed = true;
}

// Get default adapter
int adapter = Manager.Adapters.Default.Adapter;
Caps caps = Manager.GetDeviceCaps(adapter, DeviceType.Hardware);
CreateFlags createFlags;

// Check if the device supports TnL and is a pure device
if (caps.DeviceCaps.SupportsHardwareTransformAndLight)
{
createFlags = CreateFlags.HardwareVertexProcessing;
}
else
{
createFlags = CreateFlags.SoftwareVertexProcessing;
}

if (caps.DeviceCaps.SupportsPureDevice)
createFlags |= CreateFlags.PureDevice;

device = new Device(adapter, DeviceType.Hardware, owner, createFlags, presentParams);
sprite = new Sprite(device);
}



And this is my Rect creation and filling code:

private void fillVertexBuffer(VertexBuffer vb)
{
// Now fill our vertexbuffer
CustomVertex.Transformed[] verts = new CustomVertex.Transformed[5];
verts[0].Position = new Vector4(topLeft.X, topLeft.Y, 1.0f, 1.0f);
verts[1].Position = new Vector4(topLeft.X, bottomRight.Y, 1.0f, 1.0f);
verts[2].Position = new Vector4(bottomRight.X, bottomRight.Y, 1.0f, 1.0f);
verts[3].Position = new Vector4(bottomRight.X, topLeft.Y, 1.0f, 1.0f);
verts[4].Position = new Vector4(topLeft.X, topLeft.Y, 1.0f, 1.0f);

vb.SetData(verts, 0, LockFlags.None);
}

public void Render()
{
engine.Device.RenderState.ZBufferEnable = false;
engine.Device.VertexFormat = CustomVertex.Transformed.Format;
engine.Device.SetStreamSource(0, vb, 0);
engine.Device.DrawPrimitives(PrimitiveType.LineStrip, 0, 4);
engine.Device.RenderState.ZBufferEnable = true;
}

Share this post


Link to post
Share on other sites
As I don’t see any pixel pipeline setup code in your render function I have to ask.

In which state is the pixel part of the render pipeline?

Share this post


Link to post
Share on other sites
I have no idea. I'm far from experienced with Direct3D, and I do not manipulate any renderstates unless specified.

What state does the pipeline has to be in?

Toolmaker

Share this post


Link to post
Share on other sites
Look for SetTexture, SetTextureStageState and SetPixelshader calls or the collections for these states.

Additional you can find a list of the renderstates in the documentation: „Saving Pixel State With a StateBlock“ The names can differ a little bit in MDX.

Share this post


Link to post
Share on other sites
Why is the state of the pixel pipeline so important for this call?

And does D3DXSprite change it before rendering? Do I need to unset the texture?

Toolmaker

Share this post


Link to post
Share on other sites
The pixel pipeline is the part of the chip that is responsible for the color of every pixel. This makes it important for every single draw call.

D3DXSprite will manage the state if you use Begin und End.

A texture can make a difference but you should config the pixel pipeline in a way that it does not try to access a texture in the case you don’t need.

Share this post


Link to post
Share on other sites
I see...

In what state do I have to set the pixel pipeline in order for my rect to show up properly? That means, above the map.

When I look at Device.RenderState, there are A LOT of options, which mostly make no sense to me.

Toolmaker

Share this post


Link to post
Share on other sites
Setting a white material on your device and setting the texture on the 1st stage to null should work out (unless your sprites are doing something really exotic). Some purists might argue that setting the texture to null isn't the right way (and they'd be right), so you could go with this instead to draw your line with the desired color:


device.RenderState.TextureFactor = Color.White.ToArgb();
device.TextureState[0].ColorArgument1 = TextureArgument.TFactor;
device.TextureState[0].ColorOperation = TextureOperation.SelectArg1;


And this to reset the pipeline to default (IIRC):


device.TextureState[0].ColorArgument1 = TextureArgument.Diffuse;
device.TextureState[0].ColorArgument2 = TextureArgument.TextureColor;
device.TextureState[0].ColorOperation = TextureOperation.Modulate;


Hope this does the trick :) A bit obvious, but you also might want to make sure you're rendering your line outside of any Sprite.Begin - Sprite.End blocks and within the device.BeginScene - device.EndScene block.

Share this post


Link to post
Share on other sites
Quote:
Original post by remigius
Hope this does the trick :) A bit obvious, but you also might want to make sure you're rendering your line outside of any Sprite.Begin - Sprite.End blocks and within the device.BeginScene - device.EndScene block.


Why do people always come with such genious replies after 22 replies...
And why wasn't I smart enough to discover it myself?

I discarded all suggestions and changed my code into:

public void Render()
{
engine.Sprite.End();

engine.Device.VertexFormat = CustomVertex.Transformed.Format;
engine.Device.SetStreamSource(0, vb, 0);
engine.Device.DrawPrimitives(PrimitiveType.LineStrip, 0, 4);

engine.Sprite.Begin(SpriteFlags.AlphaBlend);
}


On a sidenote, I'm using Sprite atm because it's simple to do. Would it be faster/more efficient if I wrote my own sprite renderer(I don't plan to atm)? It would be a good experience to write my own, but if it's not necessary, I'll might do it later.

I am thinking: Do pixelshaders and such work with the Sprite? Because those might be usefull for adding effects, such as day/night(And units with lights).

Toolmaker

Share this post


Link to post
Share on other sites
Quote:
Original post by Toolmaker
On a sidenote, I'm using Sprite atm because it's simple to do. Would it be faster/more efficient if I wrote my own sprite renderer(I don't plan to atm)? It would be a good experience to write my own, but if it's not necessary, I'll might do it later.

I am thinking: Do pixelshaders and such work with the Sprite? Because those might be usefull for adding effects, such as day/night(And units with lights).

Toolmaker


In general doing something by your own can be faster because you can optimize for your special case. But as long as the D3DX functions works for you I would put such optimizations to the end of my list.

As the sprite methods configured the pixel pipeline you can’t use it with a custom pixel shader.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement