Difference between revisions of "Game Window Cursor Clipping"

From Valve Developer Community
Jump to: navigation, search
(Summary)
m
 
(10 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 +
{{lang|Game Window Cursor Clipping}}
 
== Summary ==
 
== Summary ==
 
 
This implementation allows you to clip the cursor to the game window such as in [https://en.wikipedia.org/wiki/Doom_(2016_video_game) DOOM] and '''[https://en.wikipedia.org/wiki/Doom_Eternal DOOM Eternal]''' (id Tech [https://en.wikipedia.org/wiki/Id_Tech_6 6] - [https://en.wikipedia.org/wiki/Id_Tech_7 7]), also brings some fixes to various bugs on VGUI.
 
This implementation allows you to clip the cursor to the game window such as in [https://en.wikipedia.org/wiki/Doom_(2016_video_game) DOOM] and '''[https://en.wikipedia.org/wiki/Doom_Eternal DOOM Eternal]''' (id Tech [https://en.wikipedia.org/wiki/Id_Tech_6 6] - [https://en.wikipedia.org/wiki/Id_Tech_7 7]), also brings some fixes to various bugs on VGUI.
 +
Those games are only meant to be examples and might not do it in the way we'll do below.
 
{{Note|This works only when the window is active, otherwise, the cursor will be unlocked automatically just as in the games specified above.}}
 
{{Note|This works only when the window is active, otherwise, the cursor will be unlocked automatically just as in the games specified above.}}
{{Note|This is an incomplete sample. When the resolution gets changed, this will get broken. It will be updated as soon as possible.}}
+
{{Note|If you prefer to move all of the existing panels and dialogs to Client, you won't need the clipping for VGUI panels. This focuses on projects willing to use the existing dialogs coming from GameUI.}}
 
+
{{Note|<strike>This is an incomplete sample. When the resolution gets changed, this will get broken. It will be updated as soon as possible.</strike>}}
  
 
<gallery widths="420px" heights="370px" perrow="2" mode="packed">
 
<gallery widths="420px" heights="370px" perrow="2" mode="packed">
Line 17: Line 18:
  
 
== Getting the Implementation/Code==
 
== Getting the Implementation/Code==
 
 
First of all, you'll need the following files from the following GitHub repository:
 
First of all, you'll need the following files from the following GitHub repository:
  
 
* [https://github.com/LordOfXen/source-engine-examples/tree/main/cursor-clipping source-engine-examples-cursor-clipping]
 
* [https://github.com/LordOfXen/source-engine-examples/tree/main/cursor-clipping source-engine-examples-cursor-clipping]
 
  
 
Which you will copy to '''src/game/client/'''. You can also create a subfolder if you wish to, and copy these files there.
 
Which you will copy to '''src/game/client/'''. You can also create a subfolder if you wish to, and copy these files there.
 
  
 
== Implementation ==
 
== Implementation ==
 
+
Now head over to '''cdll_client_int.cpp''' and include
Now head over to ''cdll_client_int.cpp''' and include
 
 
<source lang="cpp">
 
<source lang="cpp">
 
#include "CCursorClipManagement.h"
 
#include "CCursorClipManagement.h"
Line 39: Line 36:
 
</source>
 
</source>
 
{{Note|Note that if you copy the header to a subfolder, you gotta specify that in your '''#include'''}}
 
{{Note|Note that if you copy the header to a subfolder, you gotta specify that in your '''#include'''}}
 
  
 
In the same cpp, find '''CHLClient::PostInit()''' and add this to the end:
 
In the same cpp, find '''CHLClient::PostInit()''' and add this to the end:
Line 46: Line 42:
 
</source>
 
</source>
  
Lastly, find '''void OnRenderEnd()''' and add this to the end:
+
Now find '''void OnRenderEnd()''' in the same cpp and add this to the end:
 
<source lang="cpp">
 
<source lang="cpp">
 
g_pCursorClipManager->Think();
 
g_pCursorClipManager->Think();
 
</source>
 
</source>
 +
 +
Once you're done with the steps above, head over to '''baseviewport.cpp''' and add the following:
 +
<source lang="cpp">
 +
#include "../CCursorClipManagement.h"
 +
</source>
 +
 +
After
 +
<source lang="cpp">
 +
// our definition
 +
#include "baseviewport.h"
 +
#include <filesystem.h>
 +
#include <convar.h>
 +
#include "ienginevgui.h"
 +
#include "iclientmode.h"
 +
</source>
 +
 +
Before
 +
<source lang="cpp">
 +
#include "tier0/etwprof.h"
 +
</source>
 +
 +
Lastly, find '''CBaseViewport::OnScreenSizeChanged(int iOldWide, int iOldTall)''' and add this to the end:
 +
<source lang="cpp">
 +
g_pCursorClipManager->SetLockAction(CURSOR_CLIPMANAGEMENT_RELOCKREQUIRED);
 +
</source>
 +
{{Note|This must be updated accordingly to your changes on how CCursorClipManagement::Think() is being used.}}
  
 
== Conclusion ==
 
== Conclusion ==
  
 
You're all set! Compile your client project and check if it works.
 
You're all set! Compile your client project and check if it works.
 
  
 
== Notes ==
 
== Notes ==
  
* If you start the game with '''-tools''', '''-dev''', '''-developer''', and '''-nocursorclipping''' the cursor clipping will be disabled and won't work by default.
+
* If you start the game with '''-tools''', '''-dev''', '''-developer''', or '''-nocursorclipping''', the cursor clipping will be disabled and won't work by default.
 
* If you're compiling into a different platform, else than WIN32, the cursor clipping will be disabled and won't work by default.
 
* If you're compiling into a different platform, else than WIN32, the cursor clipping will be disabled and won't work by default.
 
* You can also add a ConVar to enable or disable this dynamically in-game, all you'll need to do is adding one more check on '''CCursorClipManagement::Think()'''.
 
* You can also add a ConVar to enable or disable this dynamically in-game, all you'll need to do is adding one more check on '''CCursorClipManagement::Think()'''.
 
* If you do not want to check whether the window is active or not every time '''OnRenderEnd()''' gets called, you can also do this by hooking into window events/messages. Check [https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexa SetWindowsHookExA].
 
* If you do not want to check whether the window is active or not every time '''OnRenderEnd()''' gets called, you can also do this by hooking into window events/messages. Check [https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexa SetWindowsHookExA].
 
 
 
[[Category:Programming]]
 
[[Category:Programming]]
 
[[Category:Free source code]]
 
[[Category:Free source code]]
 +
[[Category:English]]

Latest revision as of 22:10, 1 May 2021

 English 

Summary

This implementation allows you to clip the cursor to the game window such as in DOOM and DOOM Eternal (id Tech 6 - 7), also brings some fixes to various bugs on VGUI. Those games are only meant to be examples and might not do it in the way we'll do below.

Note.png Note: This works only when the window is active, otherwise, the cursor will be unlocked automatically just as in the games specified above.
Note.png Note: If you prefer to move all of the existing panels and dialogs to Client, you won't need the clipping for VGUI panels. This focuses on projects willing to use the existing dialogs coming from GameUI.
Note.png Note: This is an incomplete sample. When the resolution gets changed, this will get broken. It will be updated as soon as possible.

Requirements

  • Knowledge of C++
  • Knowledge of Source Engine
  • Source SDK Base 2013 - Currently tested on Source SDK Base 2013 Multiplayer

Getting the Implementation/Code

First of all, you'll need the following files from the following GitHub repository:

Which you will copy to src/game/client/. You can also create a subfolder if you wish to, and copy these files there.

Implementation

Now head over to cdll_client_int.cpp and include

#include "CCursorClipManagement.h"

Anywhere before

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
Note.png Note: Note that if you copy the header to a subfolder, you gotta specify that in your #include

In the same cpp, find CHLClient::PostInit() and add this to the end:

CCursorClipManagement::Init();

Now find void OnRenderEnd() in the same cpp and add this to the end:

g_pCursorClipManager->Think();

Once you're done with the steps above, head over to baseviewport.cpp and add the following:

#include "../CCursorClipManagement.h"

After

// our definition
#include "baseviewport.h"
#include <filesystem.h>
#include <convar.h>
#include "ienginevgui.h"
#include "iclientmode.h"

Before

#include "tier0/etwprof.h"

Lastly, find CBaseViewport::OnScreenSizeChanged(int iOldWide, int iOldTall) and add this to the end:

g_pCursorClipManager->SetLockAction(CURSOR_CLIPMANAGEMENT_RELOCKREQUIRED);
Note.png Note: This must be updated accordingly to your changes on how CCursorClipManagement::Think() is being used.

Conclusion

You're all set! Compile your client project and check if it works.

Notes

  • If you start the game with -tools, -dev, -developer, or -nocursorclipping, the cursor clipping will be disabled and won't work by default.
  • If you're compiling into a different platform, else than WIN32, the cursor clipping will be disabled and won't work by default.
  • You can also add a ConVar to enable or disable this dynamically in-game, all you'll need to do is adding one more check on CCursorClipManagement::Think().
  • If you do not want to check whether the window is active or not every time OnRenderEnd() gets called, you can also do this by hooking into window events/messages. Check SetWindowsHookExA.