Sign in to follow this  
u235

[MDX] Almost there....

Recommended Posts

I am oh so close to getting my first terrain rendered, I can feel it. Problem is, I get a GraphicsException thrown when I call Present(), which, after looking on MSDN, I found is far too general to be much help to me. I was hoping some of you MDX gurus could take a look at my code and tell me what's up. I've tried to eliminate what I feel is irrelevant code, but I also want to make sure the code that matters is there, so I apologize if there is a bit too much code. Anyway, here it is:
namespace TerrainGen
{
    public partial class Visualize : Form
    {
        Device device = null;
        VertexBuffer vb = null;
        IndexBuffer ib = null;
        PresentParameters pp = new PresentParameters();
        CustomVertex.PositionNormal[] verts;
        int[] indices;
        short x, y;

        public Visualize()
        {
            InitializeComponent();
        }

        private void Visualize_Load(object sender, EventArgs e)
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);
            InitGFX();
            LoadVertexBufferLOT();
            LoadIndexBuffer();
        }

        public void InitGFX()
        {
            pp.Windowed = true;
            pp.SwapEffect = SwapEffect.Discard;
            pp.AutoDepthStencilFormat = DepthFormat.D16;
            pp.EnableAutoDepthStencil = true;

            device = new Device(0, DeviceType.Hardware, this, CreateFlags.HardwareVertexProcessing, pp);

            device.RenderState.FillMode = FillMode.WireFrame;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            device.Clear(ClearFlags.Target, Color.Black, 1.0f, 0);
            device.Present();
            this.Invalidate();
        }

        private void LoadVertexBufferLOT()
        {
            StreamReader reader = new StreamReader("temp.lot");

            x = Int16.Parse(reader.ReadLine());
            y = Int16.Parse(reader.ReadLine());

            verts = new CustomVertex.PositionNormal[x * y];

            for (int i = 0; i < y; i++)
            {
                for (int n = 0; n < x; n++)
                {
                    verts[n * i].Nx = 0;
                    verts[n * i].Ny = 1;
                    verts[n * i].Nz = 0;
                    verts[n * i].Position = new Vector3((float)n, float.Parse(reader.ReadLine()), (float)i);
                }
            }

            reader.Close();

            ComputeNormals();

            vb = new VertexBuffer(typeof(CustomVertex.PositionNormal), x*y, device, Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionNormal.Format, Pool.Default);
            vb.SetData(verts, 0, LockFlags.None);

        }

        private void ComputeNormals()
        {
            for (int i = 1; i < y - 1; i++)
            {
                for (int n = 1; n < x - 1; n++)
                {
                    Vector3 X = Vector3.Subtract(verts[i * (y - 1) + n + 1].Position, verts[i * (y - 1) + n - 1].Position);
                    Vector3 Z = Vector3.Subtract(verts[(i + 1) * (y - 1) + n].Position, verts[(i - 1) * (y - 1) + n].Position);
                    Vector3 Normal = Vector3.Cross(Z, X);
                    Normal.Normalize();
                    verts[n * i].Normal = Normal;
                }
            }
        }

        private void LoadIndexBuffer()
        {
            indices = new int[(x * y * 6)];
            int i = 0;
            for (int b = 0; b < y - 1; b++)
            {
                for (int n = 0; n < x - 1; n++)
                {
                    indices[i] = b * x + n;
                    indices[i + 1] = b * x + n + 1;
                    indices[i + 2] = (b + 1) * x + n;
                    indices[i + 3] = (b + 1) * x + n;
                    indices[i + 4] = b * x + n + 1;
                    indices[i + 5] = (b + 1) * x + n + 1;

                    i += 6;
                }
            }

            ib = new IndexBuffer(typeof(int), indices.Length, device, Usage.WriteOnly, Pool.Default);
            ib.Created += new EventHandler(this.OnIndexBufferCreate);
            OnIndexBufferCreate(ib, null);
        }

        private void OnIndexBufferCreate(object sender, EventArgs e)
        {
            IndexBuffer buffer = (IndexBuffer)sender;
            buffer.SetData(indices, 0, LockFlags.None);
        }

        private void SetupCamera()
        {
            device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 1.0f, 3000.0f);
            device.Transform.View = Matrix.LookAtLH(new Vector3(0, 0, 5.0f), new Vector3(), new Vector3(0, 1, 0));
        }

        public void Render()
        {
            device.BeginScene();
            device.VertexFormat = CustomVertex.PositionNormal.Format;
            device.SetStreamSource(0, vb, 0);
            device.Indices = ib;
            device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, x * y, 0, indices.Length / 3);
            device.EndScene();
            device.Present();
        }
    }
}

And if it helps, this takes place in a child window of my main form for which the code in the main form is:
using (Visualize vis = new Visualize())
{
    vis.ShowDialog();
    while (!vis.Disposing)
    {
        vis.Render();
    }
}
Thanks. -AJ

Share this post


Link to post
Share on other sites
Usually some of the problems I see with rendering to child windows is the handle not being passed. Try and pass this.Handle or control.Handle.

Also make sure that your device isn't lost. You aren't catching any exceptions which brings me to believe that the device has been lost. Mostly this is the exception that is thrown from the Present() method.

Take a look at Lost Devices from the DirectX Documentation.

I hope this helps a bit.
Take care.

Share this post


Link to post
Share on other sites
I tried passing this, this.Handle to the Device constructor, but to no avail. I will look into handling the DeviceLost event. Thanks for the info.

-AJ

Share this post


Link to post
Share on other sites
So it seems that if I move all my rendering code into my OnPaint override then it compiles and runs fine (an by that I mean, actually draw something). I'll have to play around with it I guess to get it to draw what I want it draw. Anyway, any particular reason it works when I put it in the OnPaint override rather than calling the render function seperately? Thanks.

-AJ

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this