/
Overlay.cpp
263 lines (210 loc) · 7.12 KB
/
Overlay.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
#include "Overlay.h"
#include "imainframe.h"
#include "registry/registry.h"
#include "math/Vector3.h"
#include "math/Matrix4.h"
#include "texturelib.h"
#include "OverlayRegistryKeys.h"
namespace ui {
/* CONSTANTS */
namespace {
const float MIN_SCALE = 0.001f;
const float MAX_SCALE = 20.0f;
const float TRANSLATION_MIN = -20.0f;
const float TRANSLATION_MAX = 20.0f;
}
// Main constructor
Overlay::Overlay()
: _imageName(GlobalRegistry().get(RKEY_OVERLAY_IMAGE)),
_visible(registry::getValue<bool>(RKEY_OVERLAY_VISIBLE)),
_transparency(registry::getValue<float>(RKEY_OVERLAY_TRANSPARENCY)),
_scale(registry::getValue<float>(RKEY_OVERLAY_SCALE)),
_scaleWithXYView(registry::getValue<bool>(RKEY_OVERLAY_SCALE_WITH_XY)),
_panWithXYView(registry::getValue<bool>(RKEY_OVERLAY_PAN_WITH_XY)),
_keepProportions(registry::getValue<bool>(RKEY_OVERLAY_PROPORTIONAL)),
_translationX(registry::getValue<float>(RKEY_OVERLAY_TRANSLATIONX)),
_translationY(registry::getValue<float>(RKEY_OVERLAY_TRANSLATIONY))
{
// Watch the relevant registry keys
observeKey(RKEY_OVERLAY_VISIBLE);
observeKey(RKEY_OVERLAY_TRANSPARENCY);
observeKey(RKEY_OVERLAY_IMAGE);
observeKey(RKEY_OVERLAY_SCALE);
observeKey(RKEY_OVERLAY_TRANSLATIONX);
observeKey(RKEY_OVERLAY_TRANSLATIONY);
observeKey(RKEY_OVERLAY_PROPORTIONAL);
observeKey(RKEY_OVERLAY_SCALE_WITH_XY);
observeKey(RKEY_OVERLAY_PAN_WITH_XY);
}
void Overlay::observeKey(const std::string& key)
{
GlobalRegistry().signalForKey(key).connect(
sigc::mem_fun(this, &Overlay::keyChanged)
);
}
void Overlay::onMainFrameShuttingDown()
{
_texture.reset();
destroyInstance();
}
void Overlay::destroyInstance() {
InstancePtr() = OverlayPtr();
}
OverlayPtr& Overlay::InstancePtr()
{
static OverlayPtr _instancePtr;
if (_instancePtr == NULL) {
// Not yet instantiated, do it now
_instancePtr = OverlayPtr(new Overlay);
// Pre-destruction cleanup
GlobalMainFrame().signal_MainFrameShuttingDown().connect(
sigc::mem_fun(*_instancePtr, &Overlay::onMainFrameShuttingDown)
);
}
return _instancePtr;
}
// Static instance owner
Overlay& Overlay::Instance() {
return *InstancePtr();
}
void Overlay::show(bool shown) {
_visible = shown;
}
void Overlay::setTransparency(const float& transparency) {
_transparency = transparency;
// Check for valid bounds (0.0f ... 1.0f)
if (_transparency > 1.0f) {
_transparency = 1.0f;
}
else if (_transparency < 0.0f) {
_transparency = 0.0f;
}
}
void Overlay::setImage(const std::string& imageName) {
// Do nothing, if the current image is the same
if (imageName == _imageName) {
return;
}
_imageName = imageName;
// Set the visibility flag to zero, if no imageName is specified
if (_imageName == "") {
_visible = false;
}
captureTexture();
}
void Overlay::captureTexture() {
if (_imageName != "") {
// Load the image using the GDK image module
_texture = GlobalMaterialManager().loadTextureFromFile(_imageName);
}
}
// Main draw function
void Overlay::draw(float xbegin, float xend, float ybegin, float yend,
float xyviewscale)
{
if (!_visible) {
return;
}
// Check if the texture is realised
if (_texture == NULL) {
// Try to realise it
captureTexture();
}
// Return without drawing anything if the texture pointer is invalid
if (!_texture)
return;
// The two corners of the window (default: stretches to window borders)
Vector3 windowUpperLeft(xbegin, ybegin, 0);
Vector3 windowLowerRight(xend, yend, 0);
if (_keepProportions) {
float aspectRatio = static_cast<float>(_texture->getWidth())/_texture->getHeight();
// Calculate the proportionally stretched yEnd coordinate
float newYend = ybegin + (xend - xbegin) / aspectRatio;
windowLowerRight = Vector3(xend, newYend, 0);
// Now calculate how far the center went off due to this stretch
float deltaCenter = (newYend - yend)/2;
// Correct the y coordinates with the delta, so that the image gets centered again
windowLowerRight.y() -= deltaCenter;
windowUpperLeft.y() -= deltaCenter;
}
// Calculate the (virtual) window center
Vector3 windowOrigin((xend + xbegin)/2, (yend + ybegin)/2, 0);
windowUpperLeft -= windowOrigin;
windowLowerRight -= windowOrigin;
// The translation vector
Vector3 translation(_translationX * (xend - xbegin) * xyviewscale, _translationY * (yend - ybegin) * xyviewscale, 0);
// Create a translation matrix
Matrix4 scaleTranslation = Matrix4::getTranslation(translation);
// Store the scale into the matrix
scaleTranslation.xx() = _scale;
scaleTranslation.yy() = _scale;
if (_scaleWithXYView) {
// Scale once again with the xyviewscale, if enabled
scaleTranslation.xx() *= xyviewscale;
scaleTranslation.yy() *= xyviewscale;
}
// Apply the transformations onto the window corners
windowUpperLeft = scaleTranslation.transformPoint(windowUpperLeft);
windowLowerRight = scaleTranslation.transformPoint(windowLowerRight);
if (!_panWithXYView) {
windowUpperLeft += windowOrigin;
windowLowerRight += windowOrigin;
}
// Enable the blend functions and textures
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// Define the blend function for transparency
glBlendColor(0,0,0, _transparency);
glBlendFunc(GL_CONSTANT_ALPHA_EXT, GL_ONE_MINUS_CONSTANT_ALPHA_EXT);
// Define the texture (get the ID from the texture object)
glBindTexture (GL_TEXTURE_2D, _texture->getGLTexNum());
glColor3f (1,1,1);
// Draw the rectangle with the texture on it
glBegin(GL_QUADS);
glTexCoord2i(0,1);
glVertex3d(windowUpperLeft.x(), windowUpperLeft.y(), 0.0f);
glTexCoord2i(1,1);
glVertex3d(windowLowerRight.x(), windowUpperLeft.y(), 0.0f);
glTexCoord2i(1,0);
glVertex3d(windowLowerRight.x(), windowLowerRight.y(), 0.0f);
glTexCoord2i(0,0);
glVertex3d(windowUpperLeft.x(), windowLowerRight.y(), 0.0f);
glEnd();
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}
// Sets the image scale to the given float (1.0f is no scaling)
void Overlay::setImageScale(float scale) {
_scale = constrainFloat(scale, MIN_SCALE, MAX_SCALE);
}
void Overlay::keyChanged()
{
show(registry::getValue<bool>(RKEY_OVERLAY_VISIBLE));
_keepProportions = registry::getValue<bool>(RKEY_OVERLAY_PROPORTIONAL);
_scaleWithXYView = registry::getValue<bool>(RKEY_OVERLAY_SCALE_WITH_XY),
_panWithXYView = registry::getValue<bool>(RKEY_OVERLAY_PAN_WITH_XY),
setImage(GlobalRegistry().get(RKEY_OVERLAY_IMAGE));
setTransparency(registry::getValue<float>(RKEY_OVERLAY_TRANSPARENCY));
setImageScale(registry::getValue<float>(RKEY_OVERLAY_SCALE));
setImagePosition( registry::getValue<float>(RKEY_OVERLAY_TRANSLATIONX),
registry::getValue<float>(RKEY_OVERLAY_TRANSLATIONY) );
}
// Helper method, constrains the <input> float to the given min/max values
float Overlay::constrainFloat(const float& input, const float& min, const float& max) {
if (input < min) {
return min;
}
else if (input > max) {
return max;
}
else {
return input;
}
}
// Sets the image position in quasi texture coordinates (-0.5f .. 0.5f)
void Overlay::setImagePosition(const float& x, const float& y) {
_translationX = constrainFloat(x, TRANSLATION_MIN, TRANSLATION_MAX);
_translationY = constrainFloat(y, TRANSLATION_MIN, TRANSLATION_MAX);
}
} // namespace ui