Lloyd.NET

Programing experiments

D2D Progress

For my DirectX WinRT wrapper (now on CodePlex http://directwinrt.codeplex.com/) I took a break of D3D as I had some problem with it (more on that later) and implemented most of D2D, it was easy! ^^

And I also made the initialization even easier and more flexible.

Screenshot of Sample_D2D

So today I will write a quick how to start (with D2D) and about my latest D3D breakthrough (which is just some  C++/CX – C# technicality)

 

Initializing DirectX Graphics

To start DirectX graphic (with my API) one just initialize a DXContext and set a target, like so

var ctxt = new DXContext();
ctxt.Target = (IRenderTarget) ...;

There are 3 types of target to choose from (so far):

DXTargetSwapPanelOrWindow;
DXTargetImageSource;
Texture2D;

Target can even be changed while drawing (for example draw first on a Texture2D, which then can be used in the final scene).

DXTargetSwapPanelOrWindow wrap a SwapChainBackgroundPanel in XAML application.
Of interest DXUtils.Scenes.ScenePanel initialize DirectX, create a Target and call render on every frame.

Then one can draw, for each frame, with pseudo code like that

void Draw(DXContext ctxt)
{
    ctxt.Render = true;
    ctxt.Clear(Colors.White);

    var g3 = new D3DGraphic(ctxt)
    g3.DrawSomething(...);

    var g2 = new D2DGraphic(ctxt);
    g2.DrawSomething(...);

    ctxt.Render = false;
}

 

D2D

Remark at this stage one can download the source (http://directwinrt.codeplex.com/) and have a look at the D2D sample: Sample2_D2D.

 

This weekend and week I wrapped most of D2D API. To be precise I wrapped the following:
- geometries, brushes, bitmap, stroke style, text format, text layout, transforms

(Missing, from the top of my head, would be 2d effects, glyph run and lots of DWrite)

 

Initialization

When drawing a scene (whether D2D or D3D), for performance reason, one should initialize all items first and just call the draw primitives while rendering.

For example lets create a few geometry and brushes

public MyD2DScene()
{
    bImage = new BitmapBrush { Bitmap = new Bitmap(), };
    bImage.Bitmap.CreateWic("Assets\\space-background.jpg");

    bYRB = new LinearGradientBrush
    {
        StartPoint = new Point(100, 100),
        EndPoint = new Point(800, 800),
        GradientStops = new []
        {
            new GradientStop { position = 0, color = Colors.Yellow },
            new GradientStop { position = 0.4f, color = Colors.Red },
            new GradientStop { position = 1, color = Colors.Blue},
        },
    };

    gPath = new PathGeometry();
    using (var sink = gPath.Open())
    {
        sink.BeginFigure(new Point(), FIGURE_BEGIN.FILLED);
        sink.AddLines(new[] {
            new Point(25, 200),
            new Point(275, 175),
            new Point(50, 30),
        });
        sink.EndFigure(FIGURE_END.OPEN);
    }

    //......
}

 

In that scene snippet I created an image brush from a resource image, a gradient brush and a simple path geometry.

 

Rendering

Now I can just render all my items with just few drawing command, like so (for the geometry):

public void Render(DXContext ctxt)
{
    var g = new D2DGraphics(ctxt);
    g.Clear(Colors.Beige);

    g.Transform = DXMath.translate2d(pSkewedRect);
    g.FillGeometry(gPath, bImage);
    g.DrawGeometry(gPath, bYRB, 12, null);
}

 

D3D

Now that was easy and I got back to try to solve my dissatisfaction with my current implementation of D3D. Mostly that the C# developer is (currently) limited to the vertex buffer that I hard coded in the API.

And then I had a breakthrough. Let’s create a native pointer wrapper and write some code on the C# side that make it strongly typed.

My first attempt looked like that:

public ref class NativePointer sealed
{
private:
    uint32 sizeoft, capacity;
    void* data;

internal:
    property void* Ptr { void* get(); }

public:
    NativePointer(uint32 sizeOfT);
    virtual ~NativePointer();

    property Platform::IntPtr Data { Platform::IntPtr get(); }
    property uint32 SizeOfT { uint32 get(); }
    property uint32 Capacity;
    void Insert(uint32 offset, uint32 count);
    void Remove(uint32 offset, uint32 count);
};

That look promising, it even compiled! But then… WTF!!! Platform::IntPtr doesn’t cross ABI!!
Damn you Microsoft!

Then I had a breakthrough, what about… size_t ?!

It’s a perfectly ordinary type, except for the little twist that it projects to int32 when compiling for x86 and int64 when compiling for x64! It worked just fine, sweet!

So this is the change:

property size_t Data { size_t get(); }

On the C# side I was originally hoping to have a generic Pointer<T> class and finally use some unsafe C#.

Well I did use the unsafe C#, but I couldn’t compile code like that

public unsafe static T Get<T>(IntPtr p, int pos)
{
    T* pp = (T*)p;
    return pp[pos];
}

The compiler returns the error

Cannot take the address of, get the size of, or declare a pointer to a managed type ('T')

But it did accepts

public unsafe static int GetInt(IntPtr p, int pos)
{
    int* pp = (int*)p;
    return pp[pos];
}

Sweet…

In the end I create an abstract BasePointer<T> and a .tt template that generate all the template that I need!

Now I just have to implement a class like XNA’s VertexDeclaration and I will get a (reasonably?) solid base to go on…

And also rewrite all my buffers to use this native pointer class.

That’s it for today!
And remember: http://directwinrt.codeplex.com/


Tags: , , ,
Categories: .NET | DirectX | WinRT | C#
Permalink | Comments (0) | Post RSSRSS comment feed
blog comments powered by Disqus