justinstenning / Direct3DHook

DirectX Capture and Overlays by using Direct3D API hooks
http://spazzarama.com/2011/03/14/c-screen-capture-and-overlays-for-direct3d-9-10-and-11-using-api-hooks
MIT License
582 stars 176 forks source link

Overlaying 2D graphics #27

Closed KristjanLaane closed 9 years ago

KristjanLaane commented 9 years ago

How to overlay a plain red 2D rectangle with your library?

Specificially, with the SharpDX.Direct3D9.Device available from the library that sets up a Direct3D v9 device for me, so I'm hoping to be able to use that?

Found a tutorial on how to use Direct2D1 to draw a basic rectangle, but the code seems to be dependent on a Direct3D11 device, which I don't have - I need to be able to get the job done without Direct3D11 and without Direct3D10

unsafe int PresentHook(IntPtr devicePtr, SharpDX.Rectangle* pSourceRect, SharpDX.Rectangle* pDestRect, IntPtr hDestWindowOverride, IntPtr pDirtyRegion)
{
    _isUsingPresent = true;

    SharpDX.Direct3D9.Device device = (SharpDX.Direct3D9.Device)devicePtr;

    // How to draw rectangle here?

    if (pSourceRect == null || *pSourceRect == SharpDX.Rectangle.Empty)
        device.Present();
    else
    {
        if (hDestWindowOverride != IntPtr.Zero)
            device.Present(*pSourceRect, *pDestRect, hDestWindowOverride);
        else
            device.Present(*pSourceRect, *pDestRect);
    }
    return SharpDX.Result.Ok.Code;
}

I asked this question elsewhere, but noone knew how to use the managed code you have provided: http://stackoverflow.com/questions/31099504/drawing-a-2d-rectangle-with-sharpdx

justinstenning commented 9 years ago

If you want to use 3D geometry you could disable depth test, draw a screen-aligned rectangle and provide the coords in device coordinates.

If you want to do this using images, you can draw a sprite.

KristjanLaane commented 9 years ago

Thanks! Could you maybe provide some existing code in your library or perhaps a link on the web somewhere that unpacks what you said, as Im not versed in this world?

justinstenning commented 9 years ago

Yeah I'll try to dig some things up for you

justinstenning commented 9 years ago

For the sprite using something like (just make sure you don't instantiate the sprite and texture every frame or you will suffer some crap performance):

//use relative path
string dir = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string filename = dir + @"\image.bmp";

// Get image dimensions
using (var img = Image.FromFile(filename))
{
    imageSize = img.Size;
}
imageWidth = imageSize.Width;

var _mytext = SharpDX.Direct3D9.Texture.FromFile(device, filename);
var _sprite = new SharpDX.Direct3D9.Sprite(device);

float alertPosLeft = (device.Viewport.Width - imageSize.Width) / 2;
float alertPosTop = (device.Viewport.Height - imageSize.Height) / 2;
var pos = new SharpDX.Vector3(alertPosLeft, alertPosTop, 0);
var color = new SharpDX.ColorBGRA(0xffffffff);
_sprite.Begin(SharpDX.Direct3D9.SpriteFlags.AlphaBlend);
_sprite.Draw(_myText, color, null, null, pos);
_sprite.End();
KristjanLaane commented 9 years ago

Great stuff! It works mostly, except the image is not in the center vertically - see attached screenshot where the device resolution is 2160x1440 and the image resolution is 1024x768. There seems to be some stretching or squeezing involved because the non-square source image looks like a square to me on the screenshot? overlayingw1024h768

justinstenning commented 9 years ago

You can control the scale/rotation of the sprite by setting the sprite's transform.

// set scale of 0.5
sprite.Transform = SharpDX.Matrix.AffineTransformation2D(0.5f, 0f, SharpDX.Vector2.Zero);
KristjanLaane commented 9 years ago

the problem is not scaling as such but the observation that the image is stretched vertically. i have now attached the source image as well, which is width 1024 and height 768 i.e. it is not a square, it is not 1024x1024 and it is not 768x768. but if you look at the screenshot on my previous post here, you can see the image is a square i.e. it has been stretched downwards (and as a result is not in the centre of the screen as it should be)

i did some logging and i also used photoshop to measure the top and left positions, and they themselves are correct: DXHookD3D9: Left 568 top 336 image width 1024 height 768 device width 2160 height 1440

so indeed the image get stretched vertically for some reason with your code?

This is the (non-stretched) source image: gridw1024h768

justinstenning commented 9 years ago

The texture is likely loading as a Square / pow2 (or both):

You can transform the width/height to get the correct aspect ratio as follows:

var transform = SharpDX.Matrix.AffineTransformation2D(1f, 0f, Vector2.Zero);
// Calculate width scale
if (imageSize.Width <= 128)
{
    transform.M11 = (float)imageSize.Width / 128f; // scale x
}
else if (imageSize.Width <= 256)
{
    transform.M11 = (float)imageSize.Width / 256f; // scale x
}
else if (imageSize.Width <= 512)
{
    transform.M11 = (float)imageSize.Width / 512f; // scale x
}
else if (imageSize.Width <= 1024)
{
    transform.M11 = (float)imageSize.Width / 1024f; // scale x
}

// Calculate height scale
if (imageSize.Height <= 128)
{
    transform.M22 = (float)imageSize.Height / 128f; // scale y
}
else if (imageSize.Height <= 256)
{
    transform.M22 = (float)imageSize.Height / 256f; // scale y
}
else if (imageSize.Height <= 512)
{
    transform.M22 = (float)imageSize.Height / 512f; // scale y
}
else if (imageSize.Height <= 1024)
{
    transform.M22 = (float)imageSize.Height / 1024f; // scale y
}

_sprite.Transform = transform;

image

justinstenning commented 9 years ago

Another option, if the device capabilities support it, is to provide the size of the texture when you load it, e.g.

var _myText = SharpDX.Direct3D9.Texture.FromFile(device, filename, imageSize.Width, imageSize.Height, 0, Usage.None, Format.A8B8G8R8, Pool.Default, Filter.Default, Filter.Default, 0);
KristjanLaane commented 9 years ago

i tried the second option on one device and it worked perfekto. not sure what device capabilities are needed, but hoping this approach would work on most devices. thanks again!