Skip to content

Commit 0dddc9a

Browse files
Merge pull request #494 from GameTechDev/feature/new-inj
New features for flash injection
2 parents e83a22d + 8fce1e7 commit 0dddc9a

File tree

15 files changed

+399
-135
lines changed

15 files changed

+399
-135
lines changed

IntelPresentMon/AppCef/ipm-ui-vue/src/core/preferences.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ export interface Preferences {
6060
flashInjectionBackgroundEnable:boolean;
6161
flashInjectionBackgroundColor:RgbaColor;
6262
flashInjectionRightShift:number;
63+
flashInjectionFlashDuration:number;
64+
flashInjectionUseRainbow:boolean;
65+
flashInjectionBackgroundSize:number;
6366
};
6467

6568
export function makeDefaultPreferences(): Preferences {
@@ -129,6 +132,9 @@ export function makeDefaultPreferences(): Preferences {
129132
a: 255,
130133
},
131134
flashInjectionRightShift: 0.5,
135+
flashInjectionFlashDuration: 0.05,
136+
flashInjectionUseRainbow: false,
137+
flashInjectionBackgroundSize:0.25,
132138
};
133139
}
134140

IntelPresentMon/AppCef/ipm-ui-vue/src/views/FlashConfigView.vue

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,20 @@ watch(
9595
</v-col>
9696
</v-row>
9797

98+
<v-row class="mt-8">
99+
<v-col cols="3">
100+
Rainbow Flash
101+
<p class="text-medium-emphasis text-caption mb-0">Cycle through a rainbow of colors instead of using above flash color.</p>
102+
</v-col>
103+
<v-col cols="9">
104+
<v-switch v-model="prefs.preferences.flashInjectionUseRainbow" label="Enable"></v-switch>
105+
</v-col>
106+
</v-row>
107+
98108
<v-row class="mt-8">
99109
<v-col cols="3">
100110
Flash Width
101-
<p class="text-medium-emphasis text-caption mb-0">Width of the flash rectangle and background</p>
111+
<p class="text-medium-emphasis text-caption mb-0">Width of the flash rectangle</p>
102112
</v-col>
103113
<v-col cols="9">
104114
<v-slider
@@ -111,6 +121,22 @@ watch(
111121
</v-col>
112122
</v-row>
113123

124+
<v-row class="mt-8">
125+
<v-col cols="3">
126+
Background Width
127+
<p class="text-medium-emphasis text-caption mb-0">Width of the background rectangle (if active)</p>
128+
</v-col>
129+
<v-col cols="9">
130+
<v-slider
131+
v-model="prefs.preferences.flashInjectionBackgroundSize"
132+
:min="0.01"
133+
:max="1"
134+
:step="0.01"
135+
thumb-label="always"
136+
></v-slider>
137+
</v-col>
138+
</v-row>
139+
114140
<v-row class="mt-8">
115141
<v-col cols="3">
116142
Flash Offset
@@ -127,6 +153,22 @@ watch(
127153
</v-col>
128154
</v-row>
129155

156+
<v-row class="mt-8">
157+
<v-col cols="3">
158+
Flash Duration
159+
<p class="text-medium-emphasis text-caption mb-0">Duration of the flash in seconds.</p>
160+
</v-col>
161+
<v-col cols="9">
162+
<v-slider
163+
v-model="prefs.preferences.flashInjectionFlashDuration"
164+
:min="0"
165+
:max="1"
166+
:step="0.001"
167+
thumb-label="always"
168+
></v-slider>
169+
</v-col>
170+
</v-row>
171+
130172
<v-row class="mt-4">
131173
<v-col>
132174
<h3>Notes</h3>

IntelPresentMon/Core/source/kernel/InjectorComplex.cpp

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,16 @@ namespace p2c::kern
4545
{
4646
std::lock_guard lk{ mtx_ };
4747
if (IsActive(false) && targetModuleName_ != targetModuleName) {
48-
pmlog_dbg("Writting new target name to injectors").pmwatch(targetModuleName.value_or(""s));
48+
pmlog_dbg("Writing new target name to injectors").pmwatch(targetModuleName.value_or(""s));
4949
targetModuleName_ = targetModuleName;
5050
pInjector32_->ChangeTarget(targetModuleName);
5151
pInjector64_->ChangeTarget(targetModuleName);
5252
}
5353
}
5454
InjectorComplex::InjectorModule_::InjectorModule_(bool is32Bit)
55-
: pipeOut_(ioctx_), pipeIn_(ioctx_)
55+
:
56+
pipeOut_{ ioctx_ },
57+
pipeIn_{ ioctx_ }
5658
{
5759
// Determine the correct injector executable
5860
auto exe = is32Bit
@@ -66,7 +68,7 @@ namespace p2c::kern
6668
path.string(),
6769
/* no args = */ std::vector<std::string>{},
6870
bp2::windows::process_creation_flags<CREATE_NO_WINDOW>(),
69-
bp2::process_stdio{ pipeIn_, pipeOut_, {} }
71+
bp2::process_stdio{ pipeIn_, pipeOut_, nullptr }
7072
);
7173

7274
// Start the listener thread; on stop request we'll call ioctx_.stop()
@@ -86,21 +88,33 @@ namespace p2c::kern
8688
if (injectionPointClient_) {
8789
PushConfig_();
8890
}
89-
}
90-
void InjectorComplex::InjectorModule_::ChangeTarget(std::optional<std::string> targetModuleName)
91+
}void InjectorComplex::InjectorModule_::ChangeTarget(std::optional<std::string> targetModuleName)
9192
{
92-
// disconnect if connected to an injection point already (previous target)
93+
// Drop any prior action client (as you had)
9394
{
9495
std::lock_guard lk{ actionClientMutex_ };
9596
injectionPointClient_.reset();
9697
}
9798

98-
// Format the new line into writeBuffer_
99-
std::ostream{ &writeBuffer_ } << targetModuleName.value_or(""s) << std::endl;
100-
// Issue async write into the child’s stdin pipe
101-
as::async_write(pipeIn_, writeBuffer_, [this](boost::system::error_code ec, std::size_t bytes_transferred) {
99+
// Build one message per call; child expects a newline for getline()
100+
auto msg = targetModuleName.value_or(std::string{}) + "\n";
101+
102+
// Always hop to the io_context thread to ensure serialization and buffer (string) lifetime
103+
as::post(ioctx_, [this, m = std::move(msg)] {
104+
if (!pipeIn_.is_open()) {
105+
pmlog_warn("Injector stdin is closed; cannot send target");
106+
return;
107+
}
108+
109+
boost::system::error_code ec;
110+
const auto n = as::write(pipeIn_, as::buffer(m), ec);
102111
if (ec) {
103-
pmlog_error("Failed to write target name to injector");
112+
// Common Windows pipe errors:
113+
// 109 = ERROR_BROKEN_PIPE, 232 = ERROR_NO_DATA, 233 = ERROR_PIPE_NOT_CONNECTED
114+
pmlog_error("Sync write to injector failed").pmwatch(ec.value());
115+
}
116+
else if (n != m.size()) {
117+
pmlog_error("Short write to injector").pmwatch(n).pmwatch(m.size());
104118
}
105119
});
106120
}

IntelPresentMon/Core/source/kernel/InjectorComplex.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,14 @@ namespace p2c::kern
2727
void SpawnReadPidTask_();
2828
void PushConfig_();
2929
as::io_context ioctx_;
30-
as::readable_pipe pipeOut_; // child's stdout to us
3130
as::writable_pipe pipeIn_; // us to child's stdin
32-
std::optional<bp2::process> injectorProcess_;
31+
as::readable_pipe pipeOut_; // child's stdout to us
3332
as::streambuf readBuffer_;
34-
as::streambuf writeBuffer_;
3533
std::jthread listenerThread_;
3634
std::mutex actionClientMutex_;
3735
std::optional<iact::ActionClient> injectionPointClient_;
3836
GfxLayer::Extension::OverlayConfig config_;
37+
std::optional<bp2::process> injectorProcess_;
3938
};
4039
public:
4140
void SetActive(bool active);

IntelPresentMon/FlashInjectorLibrary/Extension/OverlayConfig.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,8 @@ namespace GfxLayer::Extension
1010
std::array<float, 4> BarColor = { 1.f, 1.f, 1.f, 1.f };
1111
bool RenderBackground = false;
1212
std::array<float, 4> BackgroundColor = { 0.f, 0.f, 0.f, 1.f };
13+
float FlashDuration = 0.05f;
14+
bool UseRainbow = false;
15+
float BackgroundSize = 0.2f;
1316
};
1417
}

IntelPresentMon/FlashInjectorLibrary/Extension/OverlayRenderer.cpp

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
#include "../Logging.h"
44
#include "OverlayConfigPack.h"
55

6-
namespace GfxLayer::Extension
6+
namespace GfxLayer::Extension
77
{
8+
using namespace std::literals;
9+
810
void CheckResult(HRESULT result, const char* pMessage)
911
{
1012
if (FAILED(result))
@@ -19,15 +21,17 @@ namespace GfxLayer::Extension
1921
m_pSwapChain(pSwapChain)
2022
{}
2123

22-
RECT OverlayRenderer::GetScissorRect() const
24+
ScissorRects OverlayRenderer::GetScissorRects() const
2325
{
24-
const float rectWidth = m_width * m_currentConfig.BarSize;
25-
RECT scissor;
26-
scissor.left = LONG((m_width - rectWidth) * m_currentConfig.BarRightShift);
27-
scissor.top = 0;
28-
scissor.right = LONG(scissor.left + rectWidth);
29-
scissor.bottom = m_height;
30-
return scissor;
26+
const float wfg = m_width * m_currentConfig.BarSize;
27+
const float wbg = m_width * m_currentConfig.BackgroundSize;
28+
const float w = std::max(wfg, wbg);
29+
const float c = (m_width - w) * m_currentConfig.BarRightShift + 0.5f * w;
30+
31+
ScissorRects r{};
32+
r.fg = { LONG(c - 0.5f * wfg), 0, LONG(c - 0.5f * wfg + wfg), LONG(m_height) };
33+
r.bg = { LONG(c - 0.5f * wbg), 0, LONG(c - 0.5f * wbg + wbg), LONG(m_height) };
34+
return r;
3135
}
3236

3337
IDXGISwapChain3* OverlayRenderer::GetSwapChain() const
@@ -50,31 +54,48 @@ namespace GfxLayer::Extension
5054
UpdateConfig(m_currentConfig);
5155
}
5256

53-
static unsigned s_frameCounter = 0;
54-
static bool s_mouseClicked = false;
55-
56-
if (GetAsyncKeyState(VK_LBUTTON) & 0x8000)
57-
{
58-
if (!s_mouseClicked)
59-
{
60-
s_frameCounter = 16;
57+
bool flashStartedThisFrame = false;
58+
// we only check mouse state if we're not currently in a flash
59+
if (!m_flashStartTime) {
60+
if (GetAsyncKeyState(VK_LBUTTON) & 0x8000) {
61+
// if lmb is down, start a flash as long as we're not in holdoff
62+
if (!m_clickHoldoff) {
63+
m_flashStartTime = clock::now();
64+
flashStartedThisFrame = true;
65+
m_clickHoldoff = true;
66+
m_flashFrameIndex = 0;
67+
}
68+
}
69+
else {
70+
// if lmb up (and not in flash) remove the holdoff so another flash could begin
71+
m_clickHoldoff = false;
6172
}
62-
s_mouseClicked = true;
6373
}
64-
else
65-
{
66-
s_mouseClicked = false;
74+
else {
75+
// increment frame index for rainbow effect
76+
m_flashFrameIndex++;
6777
}
68-
69-
if (s_frameCounter > 0)
70-
{
71-
Render(true);
72-
--s_frameCounter;
78+
// if we have a flash start we might need to draw flash
79+
if (m_flashStartTime) {
80+
// draw flash if initiated this frame OR within flash duration
81+
const std::chrono::duration<float> flashDuration{ m_currentConfig.FlashDuration };
82+
if (flashStartedThisFrame || (clock::now() - *m_flashStartTime < flashDuration)) {
83+
Render(true, m_currentConfig.UseRainbow, m_currentConfig.RenderBackground);
84+
}
85+
else {
86+
// reset flash time if duration lapsed
87+
m_flashStartTime.reset();
88+
}
7389
}
74-
else if (m_currentConfig.RenderBackground)
75-
{
76-
Render(false);
90+
// if we're not in flash, we might need to draw background
91+
if (!m_flashStartTime && m_currentConfig.RenderBackground) {
92+
Render(false, m_currentConfig.UseRainbow, true);
7793
}
7894
}
95+
96+
size_t OverlayRenderer::GetRainbowIndex() const
97+
{
98+
return m_flashFrameIndex % m_rainbowColors.size();
99+
}
79100
}
80101

IntelPresentMon/FlashInjectorLibrary/Extension/OverlayRenderer.h

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,82 @@ using Microsoft::WRL::ComPtr;
66
#include "../Context.h"
77
#include "../NonCopyable.h"
88
#include "OverlayConfig.h"
9+
#include <chrono>
10+
#include <optional>
911

1012
namespace GfxLayer::Extension
1113
{
1214
void CheckResult(HRESULT result, const char* pMessage);
1315

16+
struct ScissorRects
17+
{
18+
RECT fg;
19+
RECT bg;
20+
};
21+
1422
class OverlayRenderer : public NonCopyable
1523
{
1624
public:
1725
OverlayRenderer(const OverlayConfig& cfg, IDXGISwapChain3* pSwapChain);
1826
virtual ~OverlayRenderer() = default;
1927

2028
// called from a hook whenever the host is resizing its render targets
21-
virtual void Resize(unsigned bufferCount, unsigned width, unsigned height) = 0;
29+
virtual void Resize(unsigned bufferCount, unsigned width, unsigned height) = 0;
2230

23-
void NewFrame();
24-
RECT GetScissorRect() const;
25-
IDXGISwapChain3* GetSwapChain() const;
31+
void NewFrame();
32+
ScissorRects GetScissorRects() const;
33+
IDXGISwapChain3* GetSwapChain() const;
2634

2735
protected:
28-
virtual void Render(bool renderBar) = 0;
36+
virtual void Render(bool renderBar, bool useRainbow, bool enableBackground) = 0;
2937
// this is triggered both by Resize and by UpdateConfig
30-
virtual void UpdateViewport(const OverlayConfig& cfg) = 0;
38+
virtual void UpdateViewport(const OverlayConfig& cfg) = 0;
3139
// called from Render when it is detected that config has changed (via IPC action)
32-
virtual void UpdateConfig(const OverlayConfig& cfg) = 0;
40+
virtual void UpdateConfig(const OverlayConfig& cfg) = 0;
41+
// get rainbow index for current flash frame
42+
size_t GetRainbowIndex() const;
43+
// get array of rainbow colors
44+
static constexpr const std::array<std::array<float, 4>, 16>& GetRainbowColors()
45+
{
46+
return m_rainbowColors;
47+
}
48+
template<class T>
49+
static T MakeViewport(const RECT& r)
50+
{
51+
return T{
52+
.TopLeftX = decltype(std::declval<T>().TopLeftX)(r.left),
53+
.TopLeftY = decltype(std::declval<T>().TopLeftY)(r.top),
54+
.Width = decltype(std::declval<T>().Width)(r.right - r.left),
55+
.Height = decltype(std::declval<T>().Height)(r.bottom - r.top),
56+
};
57+
}
3358

3459
private:
60+
static constexpr std::array<std::array<float, 4>, 16> m_rainbowColors = { {
61+
{{1.00f, 0.00f, 0.00f, 1.0f}}, // red
62+
{{1.00f, 0.50f, 0.00f, 1.0f}}, // orange
63+
{{1.00f, 1.00f, 0.00f, 1.0f}}, // yellow
64+
{{0.75f, 1.00f, 0.00f, 1.0f}}, // chartreuse
65+
{{0.00f, 1.00f, 0.00f, 1.0f}}, // green
66+
{{0.00f, 1.00f, 0.60f, 1.0f}}, // spring green
67+
{{0.00f, 1.00f, 1.00f, 1.0f}}, // cyan
68+
{{0.00f, 0.60f, 1.00f, 1.0f}}, // azure
69+
{{0.00f, 0.00f, 1.00f, 1.0f}}, // blue
70+
{{0.40f, 0.00f, 1.00f, 1.0f}}, // indigo
71+
{{0.60f, 0.00f, 1.00f, 1.0f}}, // violet
72+
{{0.80f, 0.00f, 0.80f, 1.0f}}, // purple
73+
{{1.00f, 0.00f, 1.00f, 1.0f}}, // magenta
74+
{{1.00f, 0.00f, 0.60f, 1.0f}}, // rose
75+
{{1.00f, 0.20f, 0.40f, 1.0f}}, // salmon
76+
{{1.00f, 0.40f, 0.60f, 1.0f}}, // pink
77+
} };
78+
using clock = std::chrono::high_resolution_clock;
3579
OverlayConfig m_currentConfig;
3680
ComPtr<IDXGISwapChain3> m_pSwapChain;
3781
unsigned m_width;
3882
unsigned m_height;
83+
std::optional<clock::time_point> m_flashStartTime;
84+
bool m_clickHoldoff = false;
85+
size_t m_flashFrameIndex = 0;
3986
};
4087
}

0 commit comments

Comments
 (0)