veeenu / hudhook

A videogame overlay framework written in Rust, supporting DirectX and OpenGL
MIT License
165 stars 26 forks source link

Expose reference to original D3D Device of ImguiRenderer #80

Open Sunderous opened 1 year ago

Sunderous commented 1 year ago

Hey, this is more of an enhancement request.

There are some use cases for Imgui (drawing custom overlays in game world space), that are most easily achieved if we have access to the D3D Device that was used when we created the renderer. Not sure about OpenGL at the moment sorry.

The idea being, let's say you want to do an Imgui drawList to draw some lines in the game's world space. Some games already have the projection and view matrices necessary to do this in memory, but in order to call the D3D functions to do the math, you need to pass in the actual device's viewport (device ->GetViewport(*tempViewport)). Which I'm pretty sure wouldn't work with a dummy device, unless you knew the correct creation parameters ahead of time.

So you'd need to hold onto a reference to the D3D device when creating the ImguiRenderer, and expose that to the hooks class that the user actually interacts with in their code.

The alternative is to try and pull the games camera position/orientation + FOV out of memory, and do the math with those but it seems more involved and can't be re-used between games as easily.

The cleanest implementation of this would likely be to expose a function to the user that takes in a 3D vector, projection matrix, and view matrix, and returns the resulting screenspace vector. So that the API is essentially: WorldToScreen(pos, projectionMatrix, viewMatrix) -> screenPos, which could be re-used for any game since the user could handle any position conversions before the function, and handle finding the correct matrices.

If this sounds like something that you'd find useful, once I get to the point I need it I can take a stab at setting it up in a fresh fork. Thanks!

veeenu commented 1 year ago

Hey, this is a great idea! Feel free to submit a PR with this.

A few pointers: I think we may not want to jack up the abstractions and stick to the fundamentals instead; granted most games are going to have a screen-space perspective matrix somewhere but that's not a given, so I think it's going to be hard to find a unifying solution.

A design I'd like would be as follows. I'd have a per-engine trait, say,

pub trait DirectX11Internals {
  fn get_device(&mut self, dev: ID3D11Device);
  fn get_swap_chain(&mut self, dev: ID3D11SwapChain);
}

and the renderer's task would be to register those methods as callbacks and call them accordingly at some point (initialization/resize/whatever). The implementor would have to store that data internally and act on it as desired. I'd like to avoid dynamic dispatch and leverage the compile time type system instead.

Thank you!

Godnoken commented 1 year ago

pub trait DirectX11Internals {
  fn get_device(&mut self, dev: ID3D11Device);
  fn get_swap_chain(&mut self, dev: ID3D11SwapChain);
}

I've tried to implement something like the above, but I don't understand how to make it a part of the hook.

impl HookableBackend for ImguiDx11Hooks {
    fn from_struct<T: ImguiRenderLoop + Send + Sync + Sized + 'static>(t: T) -> Self {
        unsafe { ImguiDx11Hooks::new(t) }
    }
}

I assume I would have to modify this somehow, but I don't know how. Any help is appreciated! :)

veeenu commented 1 year ago

Might be harder than it looks considering that the type gets erased along the way. I will have to think about this as part of #97 which I wanted to address anyway.

veeenu commented 10 months ago

Is this still of interest? I had it planned for 0.5 but I haven't come up with a clean design idea for this, so I will probably postpone this.

Sunderous commented 10 months ago

Hey, sorry while I still think it's a good feature, the project I was planning to use it for I've been slacking on for a few months now. So I'm not near a point that I would personally use it, but I do think there's value in figuring it out at some point in the future. If the library gets wider adoption, I imagine more people will have use cases where they want to be able to draw arbitrary things in world space. But if nobody else is asking right now, can't hurt to let it percolate a bit until a clean design presents itself haha.