CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Windows/GEDebugger/SimpleGLWindow.cpp
Views: 1401
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include "Common/CommonTypes.h"
19
#include "Common/CommonWindows.h"
20
#include "Common/Log.h"
21
#include "Common/GPU/OpenGL/GLCommon.h"
22
#include "Common/GPU/OpenGL/GLFeatures.h"
23
#include "Common/GPU/OpenGL/GLSLProgram.h"
24
#include "Common/Math/lin/matrix4x4.h"
25
#include "GL/gl.h"
26
#include "GL/wglew.h"
27
#include "Windows/GEDebugger/SimpleGLWindow.h"
28
#include "Windows/W32Util/ContextMenu.h"
29
30
#include "Core/System.h"
31
32
const wchar_t *SimpleGLWindow::windowClass = L"SimpleGLWindow";
33
34
using namespace Lin;
35
36
void SimpleGLWindow::RegisterClass() {
37
WNDCLASSEX wndClass;
38
39
wndClass.cbSize = sizeof(wndClass);
40
wndClass.lpszClassName = windowClass;
41
wndClass.hInstance = GetModuleHandle(0);
42
wndClass.lpfnWndProc = WndProc;
43
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
44
wndClass.hIcon = 0;
45
wndClass.lpszMenuName = 0;
46
wndClass.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);
47
wndClass.style = CS_DBLCLKS;
48
wndClass.cbClsExtra = 0;
49
wndClass.cbWndExtra = sizeof(SimpleGLWindow *);
50
wndClass.hIconSm = 0;
51
52
RegisterClassEx(&wndClass);
53
}
54
55
static const char tex_fs[] =
56
"#ifdef GL_ES\n"
57
"precision mediump float;\n"
58
"#endif\n"
59
"uniform sampler2D sampler0;\n"
60
"varying vec2 v_texcoord0;\n"
61
"void main() {\n"
62
" gl_FragColor = texture2D(sampler0, v_texcoord0);\n"
63
" gl_FragColor.a = clamp(gl_FragColor.a, 0.2, 1.0);\n"
64
"}\n";
65
66
static const char basic_vs[] =
67
"#version 120\n"
68
"attribute vec4 a_position;\n"
69
"attribute vec2 a_texcoord0;\n"
70
"uniform mat4 u_viewproj;\n"
71
"varying vec2 v_texcoord0;\n"
72
"void main() {\n"
73
" v_texcoord0 = a_texcoord0;\n"
74
" gl_Position = u_viewproj * a_position;\n"
75
"}\n";
76
77
SimpleGLWindow::SimpleGLWindow(HWND wnd)
78
: hWnd_(wnd) {
79
SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR) this);
80
}
81
82
SimpleGLWindow::~SimpleGLWindow() {
83
if (vao_ != 0) {
84
glDeleteVertexArrays(1, &vao_);
85
}
86
if (drawProgram_ != nullptr) {
87
glsl_destroy(drawProgram_);
88
}
89
if (tex_) {
90
glDeleteTextures(1, &tex_);
91
glDeleteTextures(1, &checker_);
92
}
93
delete [] reformatBuf_;
94
};
95
96
void SimpleGLWindow::Initialize(u32 flags) {
97
RECT rect;
98
GetWindowRect(hWnd_, &rect);
99
100
SetFlags(flags);
101
SetupGL();
102
ResizeGL(rect.right-rect.left,rect.bottom-rect.top);
103
CreateProgram();
104
GenerateChecker();
105
}
106
107
void SimpleGLWindow::SetupGL() {
108
int pixelFormat;
109
110
static PIXELFORMATDESCRIPTOR pfd = {0};
111
pfd.nSize = sizeof(pfd);
112
pfd.nVersion = 1;
113
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
114
pfd.iPixelType = PFD_TYPE_RGBA;
115
pfd.cColorBits = 32;
116
pfd.cDepthBits = 16;
117
pfd.iLayerType = PFD_MAIN_PLANE;
118
119
#define ENFORCE(x, msg) { if (!(x)) { ERROR_LOG(Log::Common, "SimpleGLWindow: %s (%08x)", msg, (uint32_t)GetLastError()); return; } }
120
121
ENFORCE(hDC_ = GetDC(hWnd_), "Unable to create DC.");
122
ENFORCE(pixelFormat = ChoosePixelFormat(hDC_, &pfd), "Unable to match pixel format.");
123
ENFORCE(SetPixelFormat(hDC_, pixelFormat, &pfd), "Unable to set pixel format.");
124
ENFORCE(hGLRC_ = wglCreateContext(hDC_), "Unable to create GL context.");
125
ENFORCE(wglMakeCurrent(hDC_, hGLRC_), "Unable to activate GL context.");
126
127
valid_ = glewInit() == GLEW_OK;
128
129
// Switch to a modern context so RenderDoc doesn't get mad.
130
HGLRC oldGL = hGLRC_;
131
if (wglewIsSupported("WGL_ARB_create_context") == 1) {
132
static const int attribs33[] = {
133
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
134
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
135
WGL_CONTEXT_FLAGS_ARB, 0,
136
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
137
0,
138
};
139
hGLRC_ = wglCreateContextAttribsARB(hDC_, 0, attribs33);
140
141
if (!hGLRC_) {
142
hGLRC_ = oldGL;
143
} else {
144
// Switch to the new ARB context.
145
wglMakeCurrent(nullptr, nullptr);
146
wglDeleteContext(oldGL);
147
wglMakeCurrent(hDC_, hGLRC_);
148
149
valid_ = glewInit() == GLEW_OK;
150
}
151
}
152
}
153
154
void SimpleGLWindow::ResizeGL(int w, int h) {
155
if (!valid_) {
156
return;
157
}
158
159
w_ = w;
160
h_ = h;
161
}
162
163
void SimpleGLWindow::CreateProgram() {
164
if (!valid_) {
165
return;
166
}
167
168
wglMakeCurrent(hDC_, hGLRC_);
169
170
drawProgram_ = glsl_create_source(basic_vs, tex_fs);
171
glGenTextures(1, &tex_);
172
glGenTextures(1, &checker_);
173
174
glsl_bind(drawProgram_);
175
glUniform1i(drawProgram_->sampler0, 0);
176
glsl_unbind();
177
178
if (gl_extensions.ARB_vertex_array_object) {
179
glGenVertexArrays(1, &vao_);
180
glBindVertexArray(vao_);
181
182
glGenBuffers(1, &ibuf_);
183
glGenBuffers(1, &vbuf_);
184
185
const GLubyte indices[4] = {0, 1, 3, 2};
186
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf_);
187
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
188
189
glBindBuffer(GL_ARRAY_BUFFER, vbuf_);
190
} else {
191
vao_ = 0;
192
}
193
194
glEnableVertexAttribArray(drawProgram_->a_position);
195
glEnableVertexAttribArray(drawProgram_->a_texcoord0);
196
}
197
198
void SimpleGLWindow::GenerateChecker() {
199
if (!valid_) {
200
return;
201
}
202
203
// 2x2 RGBA bitmap
204
static const u8 checkerboard[] = {
205
192,192,192,255, 128,128,128,255,
206
128,128,128,255, 192,192,192,255,
207
};
208
209
wglMakeCurrent(hDC_, hGLRC_);
210
211
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
212
glBindTexture(GL_TEXTURE_2D, checker_);
213
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, checkerboard);
214
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
215
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
216
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
217
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
218
}
219
220
void SimpleGLWindow::DrawChecker() {
221
wglMakeCurrent(hDC_, hGLRC_);
222
223
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
224
glClear(GL_COLOR_BUFFER_BIT);
225
226
glBindTexture(GL_TEXTURE_2D, checker_);
227
228
glDisable(GL_BLEND);
229
glViewport(0, 0, w_, h_);
230
glScissor(0, 0, w_, h_);
231
232
glsl_bind(drawProgram_);
233
234
float fw = (float)w_, fh = (float)h_;
235
const float pos[12] = {0,0,0, fw,0,0, fw,fh,0, 0,fh,0};
236
const float texCoords[8] = {0,fh/22, fw/22,fh/22, fw/22,0, 0,0};
237
const GLubyte indices[4] = {0,1,3,2};
238
239
Matrix4x4 ortho;
240
ortho.setOrtho(0, (float)w_, (float)h_, 0, -1, 1);
241
glUniformMatrix4fv(drawProgram_->u_viewproj, 1, GL_FALSE, ortho.getReadPtr());
242
if (vao_) {
243
glBufferData(GL_ARRAY_BUFFER, sizeof(pos) + sizeof(texCoords), nullptr, GL_DYNAMIC_DRAW);
244
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(pos), pos);
245
glBufferSubData(GL_ARRAY_BUFFER, sizeof(pos), sizeof(texCoords), texCoords);
246
glVertexAttribPointer(drawProgram_->a_position, 3, GL_FLOAT, GL_FALSE, 12, 0);
247
glVertexAttribPointer(drawProgram_->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, (const void *)sizeof(pos));
248
} else {
249
glVertexAttribPointer(drawProgram_->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos);
250
glVertexAttribPointer(drawProgram_->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, texCoords);
251
}
252
glActiveTexture(GL_TEXTURE0);
253
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, vao_ ? 0 : indices);
254
}
255
256
void SimpleGLWindow::Draw(const u8 *data, int w, int h, bool flipped, Format fmt) {
257
wglMakeCurrent(hDC_, hGLRC_);
258
259
GLint components = GL_RGBA;
260
GLint memComponents = 0;
261
GLenum glfmt = GL_UNSIGNED_BYTE;
262
const u8 *finalData = data;
263
if (fmt == FORMAT_8888) {
264
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
265
glfmt = GL_UNSIGNED_BYTE;
266
} else if (fmt == FORMAT_8888_BGRA) {
267
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
268
glfmt = GL_UNSIGNED_BYTE;
269
memComponents = GL_BGRA;
270
} else if (fmt == FORMAT_FLOAT) {
271
glfmt = GL_FLOAT;
272
components = GL_RED;
273
} else if (fmt == FORMAT_FLOAT_DIV_256) {
274
glfmt = GL_UNSIGNED_INT;
275
components = GL_RED;
276
finalData = Reformat(data, fmt, w * h);
277
} else if (fmt == FORMAT_24BIT_8X) {
278
glfmt = GL_UNSIGNED_INT;
279
components = GL_RED;
280
finalData = Reformat(data, fmt, w * h);
281
} else if (fmt == FORMAT_24BIT_8X_DIV_256) {
282
glfmt = GL_UNSIGNED_INT;
283
components = GL_RED;
284
finalData = Reformat(data, fmt, w * h);
285
} else if (fmt == FORMAT_24X_8BIT) {
286
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
287
glfmt = GL_UNSIGNED_BYTE;
288
components = GL_RED;
289
finalData = Reformat(data, fmt, w * h);
290
} else {
291
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
292
if (fmt == FORMAT_4444) {
293
glfmt = GL_UNSIGNED_SHORT_4_4_4_4;
294
} else if (fmt == FORMAT_5551) {
295
glfmt = GL_UNSIGNED_SHORT_5_5_5_1;
296
} else if (fmt == FORMAT_565) {
297
glfmt = GL_UNSIGNED_SHORT_5_6_5;
298
components = GL_RGB;
299
} else if (fmt == FORMAT_4444_REV) {
300
glfmt = GL_UNSIGNED_SHORT_4_4_4_4_REV;
301
} else if (fmt == FORMAT_5551_REV) {
302
glfmt = GL_UNSIGNED_SHORT_1_5_5_5_REV;
303
} else if (fmt == FORMAT_565_REV) {
304
glfmt = GL_UNSIGNED_SHORT_5_6_5_REV;
305
components = GL_RGB;
306
} else if (fmt == FORMAT_5551_BGRA_REV) {
307
glfmt = GL_UNSIGNED_SHORT_1_5_5_5_REV;
308
memComponents = GL_BGRA;
309
} else if (fmt == FORMAT_4444_BGRA_REV) {
310
glfmt = GL_UNSIGNED_SHORT_4_4_4_4_REV;
311
memComponents = GL_BGRA;
312
} else if (fmt == FORMAT_16BIT) {
313
glfmt = GL_UNSIGNED_SHORT;
314
components = GL_RED;
315
} else if (fmt == FORMAT_8BIT) {
316
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
317
glfmt = GL_UNSIGNED_BYTE;
318
components = GL_RED;
319
} else {
320
_dbg_assert_msg_(false, "Invalid SimpleGLWindow format.");
321
}
322
}
323
324
if (memComponents == 0) {
325
memComponents = components;
326
}
327
328
glBindTexture(GL_TEXTURE_2D, tex_);
329
glTexImage2D(GL_TEXTURE_2D, 0, components, w, h, 0, memComponents, glfmt, finalData);
330
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
331
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
332
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
333
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
334
335
// Reset offset when the texture size changes.
336
if (tw_ != w || th_ != h) {
337
tw_ = w;
338
th_ = h;
339
offsetX_ = 0;
340
offsetY_ = 0;
341
}
342
tflipped_ = flipped;
343
344
Redraw();
345
}
346
347
void SimpleGLWindow::GetContentSize(float &x, float &y, float &fw, float &fh) {
348
fw = (float)tw_;
349
fh = (float)th_;
350
x = 0.0f;
351
y = 0.0f;
352
353
if ((flags_ & RESIZE_SHRINK_FIT) != 0 && !zoom_) {
354
float wscale = fw / w_, hscale = fh / h_;
355
356
// Too wide, and width is the biggest problem, so scale based on that.
357
if (wscale > 1.0f && wscale > hscale) {
358
fw = (float)w_;
359
fh /= wscale;
360
} else if (hscale > 1.0f) {
361
fw /= hscale;
362
fh = (float)h_;
363
}
364
}
365
if ((flags_ & RESIZE_GROW_FIT) != 0 && !zoom_) {
366
float wscale = fw / w_, hscale = fh / h_;
367
368
if (wscale > hscale && wscale < 1.0f) {
369
fw = (float)w_;
370
fh /= wscale;
371
} else if (hscale > wscale && hscale < 1.0f) {
372
fw /= hscale;
373
fh = (float)h_;
374
}
375
}
376
if (flags_ & RESIZE_CENTER) {
377
x = ((float)w_ - fw) / 2;
378
y = ((float)h_ - fh) / 2;
379
}
380
381
x += offsetX_;
382
y += offsetY_;
383
}
384
385
void SimpleGLWindow::Redraw(bool andSwap) {
386
DrawChecker();
387
388
auto swapWithCallback = [andSwap, this]() {
389
if (andSwap) {
390
swapped_ = false;
391
if (redrawCallback_ && !inRedrawCallback_) {
392
inRedrawCallback_ = true;
393
redrawCallback_();
394
inRedrawCallback_ = false;
395
}
396
// In case the callback swaps, don't do it twice.
397
if (!swapped_) {
398
Swap();
399
}
400
}
401
};
402
403
if (tw_ == 0 && th_ == 0) {
404
swapWithCallback();
405
return;
406
}
407
408
if (flags_ & ALPHA_BLEND) {
409
glEnable(GL_BLEND);
410
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
411
glBlendEquation(GL_FUNC_ADD);
412
} else {
413
glDisable(GL_BLEND);
414
}
415
glViewport(0, 0, w_, h_);
416
glScissor(0, 0, w_, h_);
417
418
glBindTexture(GL_TEXTURE_2D, tex_);
419
glsl_bind(drawProgram_);
420
421
float fw, fh;
422
float x, y;
423
GetContentSize(x, y, fw, fh);
424
425
const float pos[12] = {x,y,0, x+fw,y,0, x+fw,y+fh,0, x,y+fh,0};
426
static const float texCoordsNormal[8] = {0,0, 1,0, 1,1, 0,1};
427
static const float texCoordsFlipped[8] = {0,1, 1,1, 1,0, 0,0};
428
static const GLubyte indices[4] = {0,1,3,2};
429
const float *texCoords = tflipped_ ? texCoordsFlipped : texCoordsNormal;
430
431
Matrix4x4 ortho;
432
ortho.setOrtho(0, (float)w_, (float)h_, 0, -1, 1);
433
glUniformMatrix4fv(drawProgram_->u_viewproj, 1, GL_FALSE, ortho.getReadPtr());
434
if (vao_) {
435
glBufferData(GL_ARRAY_BUFFER, sizeof(pos) + sizeof(texCoordsNormal), nullptr, GL_DYNAMIC_DRAW);
436
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(pos), pos);
437
glBufferSubData(GL_ARRAY_BUFFER, sizeof(pos), sizeof(texCoordsNormal), texCoords);
438
glVertexAttribPointer(drawProgram_->a_position, 3, GL_FLOAT, GL_FALSE, 12, 0);
439
glVertexAttribPointer(drawProgram_->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, (const void *)sizeof(pos));
440
} else {
441
glVertexAttribPointer(drawProgram_->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos);
442
glVertexAttribPointer(drawProgram_->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, texCoords);
443
}
444
glActiveTexture(GL_TEXTURE0);
445
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, vao_ ? 0 : indices);
446
447
if (andSwap) {
448
swapWithCallback();
449
}
450
}
451
452
void SimpleGLWindow::Clear() {
453
tw_ = 0;
454
th_ = 0;
455
Redraw();
456
}
457
458
void SimpleGLWindow::Begin() {
459
if (!inRedrawCallback_) {
460
Redraw(false);
461
}
462
463
if (vao_) {
464
glBindVertexArray(0);
465
glBindBuffer(GL_ARRAY_BUFFER, 0);
466
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
467
} else {
468
glDisableVertexAttribArray(drawProgram_->a_position);
469
glDisableVertexAttribArray(drawProgram_->a_texcoord0);
470
}
471
}
472
473
void SimpleGLWindow::End() {
474
if (vao_) {
475
glBindVertexArray(vao_);
476
glBindBuffer(GL_ARRAY_BUFFER, vbuf_);
477
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf_);
478
} else {
479
glEnableVertexAttribArray(drawProgram_->a_position);
480
glEnableVertexAttribArray(drawProgram_->a_texcoord0);
481
}
482
483
Swap();
484
}
485
486
bool SimpleGLWindow::DragStart(int mouseX, int mouseY) {
487
// Only while zoomed in, otherwise it's shrink to fit mode or fixed.
488
if (!zoom_) {
489
return false;
490
}
491
492
dragging_ = true;
493
SetCapture(hWnd_);
494
dragStartX_ = mouseX - offsetX_;
495
dragStartY_ = mouseY - offsetY_;
496
dragLastUpdate_ = GetTickCount();
497
498
return true;
499
}
500
501
bool SimpleGLWindow::DragContinue(int mouseX, int mouseY) {
502
if (!dragging_) {
503
return false;
504
}
505
506
offsetX_ = mouseX - dragStartX_;
507
offsetY_ = mouseY - dragStartY_;
508
509
const u32 MS_BETWEEN_DRAG_REDRAWS = 5;
510
if (GetTickCount() - dragLastUpdate_ > MS_BETWEEN_DRAG_REDRAWS) {
511
Redraw();
512
}
513
514
return true;
515
}
516
517
bool SimpleGLWindow::DragEnd(int mouseX, int mouseY) {
518
if (!dragging_) {
519
return false;
520
}
521
522
dragging_ = false;
523
ReleaseCapture();
524
Redraw();
525
526
return true;
527
}
528
529
bool SimpleGLWindow::ToggleZoom() {
530
// Reset the offset when zooming out (or in, doesn't matter.)
531
offsetX_ = 0;
532
offsetY_ = 0;
533
534
zoom_ = !zoom_;
535
Redraw();
536
537
return true;
538
}
539
540
POINT SimpleGLWindow::PosFromMouse(int mouseX, int mouseY) {
541
float fw, fh;
542
float x, y;
543
GetContentSize(x, y, fw, fh);
544
545
if (mouseX < x || mouseX >= x + fw || mouseY < y || mouseY >= y + fh) {
546
// Outside of bounds.
547
return POINT{ -1, -1 };
548
}
549
550
float tx = (mouseX - x) * (tw_ / fw);
551
float ty = (mouseY - y) * (th_ / fh);
552
553
return POINT{ (int)tx, (int)ty };
554
}
555
556
bool SimpleGLWindow::Hover(int mouseX, int mouseY) {
557
if (hoverCallback_ == nullptr) {
558
return false;
559
}
560
561
POINT pos = PosFromMouse(mouseX, mouseY);
562
hoverCallback_(pos.x, pos.y);
563
564
if (pos.x == -1 || pos.y == -1) {
565
// Outside of bounds, don't track.
566
return true;
567
}
568
569
// Find out when they are done.
570
TRACKMOUSEEVENT tracking = {0};
571
tracking.cbSize = sizeof(tracking);
572
tracking.dwFlags = TME_LEAVE;
573
tracking.hwndTrack = hWnd_;
574
TrackMouseEvent(&tracking);
575
576
return true;
577
}
578
579
bool SimpleGLWindow::Leave() {
580
if (hoverCallback_ == nullptr) {
581
return false;
582
}
583
584
hoverCallback_(-1, -1);
585
return true;
586
}
587
588
bool SimpleGLWindow::RightClick(int mouseX, int mouseY) {
589
if (rightClickCallback_ == nullptr) {
590
return false;
591
}
592
593
POINT pt{mouseX, mouseY};
594
POINT pos = PosFromMouse(mouseX, mouseY);
595
596
rightClickCallback_(0, pos.x, pos.y);
597
598
// We don't want to let the users play with deallocated or uninitialized debugging objects
599
GlobalUIState state = GetUIState();
600
if (state != UISTATE_INGAME && state != UISTATE_PAUSEMENU) {
601
return true;
602
}
603
604
int result = TriggerContextMenu(rightClickMenu_, hWnd_, ContextPoint::FromClient(pt));
605
if (result > 0) {
606
rightClickCallback_(result, pos.x, pos.y);
607
}
608
609
return true;
610
}
611
612
const u8 *SimpleGLWindow::Reformat(const u8 *data, Format fmt, u32 numPixels) {
613
if (!reformatBuf_ || reformatBufSize_ < numPixels) {
614
delete [] reformatBuf_;
615
reformatBuf_ = new u32[numPixels];
616
reformatBufSize_ = numPixels;
617
}
618
619
const u32 *data32 = (const u32 *)data;
620
if (fmt == FORMAT_24BIT_8X) {
621
for (u32 i = 0; i < numPixels; ++i) {
622
reformatBuf_[i] = (data32[i] << 8) | ((data32[i] >> 16) & 0xFF);
623
}
624
} else if (fmt == FORMAT_24BIT_8X_DIV_256) {
625
for (u32 i = 0; i < numPixels; ++i) {
626
int z24 = data32[i] & 0x00FFFFFF;
627
int z16 = z24 - 0x800000 + 0x8000;
628
reformatBuf_[i] = (z16 << 16) | z16;
629
}
630
} else if (fmt == FORMAT_FLOAT_DIV_256) {
631
for (u32 i = 0; i < numPixels; ++i) {
632
double z = *(float *)&data32[i];
633
int z24 = (int)(z * 16777215.0);
634
int z16 = z24 - 0x800000 + 0x8000;
635
reformatBuf_[i] = (z16 << 16) | z16;
636
}
637
} else if (fmt == FORMAT_24X_8BIT) {
638
u8 *buf8 = (u8 *)reformatBuf_;
639
for (u32 i = 0; i < numPixels; ++i) {
640
u32 v = (data32[i] >> 24) & 0xFF;
641
buf8[i] = v;
642
}
643
}
644
return (const u8 *)reformatBuf_;
645
}
646
647
SimpleGLWindow *SimpleGLWindow::GetFrom(HWND hwnd) {
648
return (SimpleGLWindow*) GetWindowLongPtr(hwnd, GWLP_USERDATA);
649
}
650
651
LRESULT CALLBACK SimpleGLWindow::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
652
SimpleGLWindow *win = SimpleGLWindow::GetFrom(hwnd);
653
654
int mouseX = 0, mouseY = 0;
655
switch (msg) {
656
case WM_LBUTTONDOWN:
657
case WM_LBUTTONUP:
658
case WM_RBUTTONUP:
659
case WM_MOUSEMOVE:
660
mouseX = (int)(short)LOWORD(lParam);
661
mouseY = (int)(short)HIWORD(lParam);
662
break;
663
default:
664
break;
665
}
666
667
switch (msg) {
668
case WM_NCCREATE:
669
win = new SimpleGLWindow(hwnd);
670
671
// Continue with window creation.
672
return win != nullptr ? TRUE : FALSE;
673
674
case WM_NCDESTROY:
675
delete win;
676
return 0;
677
678
case WM_LBUTTONDBLCLK:
679
if (win->ToggleZoom()) {
680
return 0;
681
}
682
break;
683
684
case WM_LBUTTONDOWN:
685
if (win->DragStart(mouseX, mouseY)) {
686
return 0;
687
}
688
break;
689
690
case WM_LBUTTONUP:
691
if (win->DragEnd(mouseX, mouseY)) {
692
return 0;
693
}
694
break;
695
696
case WM_MOUSEMOVE:
697
if (win->DragContinue(mouseX, mouseY)) {
698
return 0;
699
}
700
if (win->Hover(mouseX, mouseY)) {
701
return 0;
702
}
703
break;
704
705
case WM_RBUTTONUP:
706
if (win->RightClick(mouseX, mouseY)) {
707
return 0;
708
}
709
break;
710
711
case WM_MOUSELEAVE:
712
if (win->Leave()) {
713
return 0;
714
}
715
break;
716
717
case WM_PAINT:
718
win->Redraw();
719
break;
720
}
721
722
return DefWindowProc(hwnd, msg, wParam, lParam);
723
}
724
725