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/TabVertices.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/CommonWindows.h"
19
#include <commctrl.h>
20
#include "Common/CommonTypes.h"
21
#include "Common/Data/Encoding/Utf8.h"
22
#include "Common/StringUtils.h"
23
#include "Core/System.h"
24
#include "Windows/resource.h"
25
#include "Windows/InputBox.h"
26
#include "Windows/GEDebugger/GEDebugger.h"
27
#include "Windows/GEDebugger/TabVertices.h"
28
#include "Windows/W32Util/ContextMenu.h"
29
#include "GPU/Common/VertexDecoderCommon.h"
30
#include "GPU/GPUState.h"
31
#include "GPU/GeDisasm.h"
32
#include "GPU/Common/GPUDebugInterface.h"
33
#include "GPU/Debugger/Breakpoints.h"
34
#include "GPU/Debugger/Stepping.h"
35
36
static const GenericListViewColumn vertexListCols[] = {
37
{ L"X", 0.1f },
38
{ L"Y", 0.1f },
39
{ L"Z", 0.1f },
40
{ L"U", 0.1f },
41
{ L"V", 0.1f },
42
{ L"Color", 0.1f },
43
{ L"NX", 0.1f },
44
{ L"NY", 0.1f },
45
{ L"NZ", 0.1f },
46
// TODO: weight, morph?
47
};
48
49
GenericListViewDef vertexListDef = {
50
vertexListCols, ARRAY_SIZE(vertexListCols), NULL, false
51
};
52
53
enum VertexListCols {
54
VERTEXLIST_COL_X,
55
VERTEXLIST_COL_Y,
56
VERTEXLIST_COL_Z,
57
VERTEXLIST_COL_U,
58
VERTEXLIST_COL_V,
59
VERTEXLIST_COL_COLOR,
60
VERTEXLIST_COL_NX,
61
VERTEXLIST_COL_NY,
62
VERTEXLIST_COL_NZ,
63
};
64
65
static const GenericListViewColumn matrixListCols[] = {
66
{ L"", 0.03f },
67
{ L"Name", 0.21f },
68
{ L"0", 0.19f },
69
{ L"1", 0.19f },
70
{ L"2", 0.19f },
71
{ L"3", 0.19f },
72
};
73
74
GenericListViewDef matrixListDef = {
75
matrixListCols, ARRAY_SIZE(matrixListCols), NULL, false
76
};
77
78
enum MatrixListCols {
79
MATRIXLIST_COL_BREAKPOINT,
80
MATRIXLIST_COL_NAME,
81
MATRIXLIST_COL_0,
82
MATRIXLIST_COL_1,
83
MATRIXLIST_COL_2,
84
MATRIXLIST_COL_3,
85
86
MATRIXLIST_COL_COUNT,
87
};
88
89
enum MatrixListRows {
90
MATRIXLIST_ROW_WORLD_0,
91
MATRIXLIST_ROW_WORLD_1,
92
MATRIXLIST_ROW_WORLD_2,
93
MATRIXLIST_ROW_VIEW_0,
94
MATRIXLIST_ROW_VIEW_1,
95
MATRIXLIST_ROW_VIEW_2,
96
MATRIXLIST_ROW_PROJ_0,
97
MATRIXLIST_ROW_PROJ_1,
98
MATRIXLIST_ROW_PROJ_2,
99
MATRIXLIST_ROW_PROJ_3,
100
MATRIXLIST_ROW_TGEN_0,
101
MATRIXLIST_ROW_TGEN_1,
102
MATRIXLIST_ROW_TGEN_2,
103
MATRIXLIST_ROW_BONE_0_0,
104
MATRIXLIST_ROW_BONE_0_1,
105
MATRIXLIST_ROW_BONE_0_2,
106
MATRIXLIST_ROW_BONE_1_0,
107
MATRIXLIST_ROW_BONE_1_1,
108
MATRIXLIST_ROW_BONE_1_2,
109
MATRIXLIST_ROW_BONE_2_0,
110
MATRIXLIST_ROW_BONE_2_1,
111
MATRIXLIST_ROW_BONE_2_2,
112
MATRIXLIST_ROW_BONE_3_0,
113
MATRIXLIST_ROW_BONE_3_1,
114
MATRIXLIST_ROW_BONE_3_2,
115
MATRIXLIST_ROW_BONE_4_0,
116
MATRIXLIST_ROW_BONE_4_1,
117
MATRIXLIST_ROW_BONE_4_2,
118
MATRIXLIST_ROW_BONE_5_0,
119
MATRIXLIST_ROW_BONE_5_1,
120
MATRIXLIST_ROW_BONE_5_2,
121
MATRIXLIST_ROW_BONE_6_0,
122
MATRIXLIST_ROW_BONE_6_1,
123
MATRIXLIST_ROW_BONE_6_2,
124
MATRIXLIST_ROW_BONE_7_0,
125
MATRIXLIST_ROW_BONE_7_1,
126
MATRIXLIST_ROW_BONE_7_2,
127
128
MATRIXLIST_ROW_COUNT,
129
};
130
131
CtrlVertexList::CtrlVertexList(HWND hwnd)
132
: GenericListControl(hwnd, vertexListDef), raw_(false) {
133
decoder = new VertexDecoder();
134
Update();
135
}
136
137
CtrlVertexList::~CtrlVertexList() {
138
delete decoder;
139
}
140
141
void CtrlVertexList::GetColumnText(wchar_t *dest, int row, int col) {
142
if (row < 0 || row >= rowCount_ ) {
143
wcscpy(dest, L"Invalid");
144
return;
145
}
146
147
if (!indices.empty()) {
148
if (row >= (int)indices.size()) {
149
swprintf(dest, 255, L"Invalid indice %d", row);
150
return;
151
}
152
row = indices[row];
153
}
154
155
if (raw_) {
156
FormatVertColRaw(dest, row, col);
157
} else {
158
if (row >= (int)vertices.size()) {
159
swprintf(dest, 255, L"Invalid vertex %d", row);
160
return;
161
}
162
163
FormatVertCol(dest, vertices[row], col);
164
}
165
}
166
167
void CtrlVertexList::FormatVertCol(wchar_t *dest, const GPUDebugVertex &vert, int col) {
168
switch (col) {
169
case VERTEXLIST_COL_X: swprintf(dest, 255, L"%f", vert.x); break;
170
case VERTEXLIST_COL_Y: swprintf(dest, 255, L"%f", vert.y); break;
171
case VERTEXLIST_COL_Z: swprintf(dest, 255, L"%f", vert.z); break;
172
case VERTEXLIST_COL_U: swprintf(dest, 255, L"%f", vert.u); break;
173
case VERTEXLIST_COL_V: swprintf(dest, 255, L"%f", vert.v); break;
174
case VERTEXLIST_COL_COLOR:
175
swprintf(dest, 255, L"%02x%02x%02x%02x", vert.c[0], vert.c[1], vert.c[2], vert.c[3]);
176
break;
177
case VERTEXLIST_COL_NX: swprintf(dest, 255, L"%f", vert.nx); break;
178
case VERTEXLIST_COL_NY: swprintf(dest, 255, L"%f", vert.ny); break;
179
case VERTEXLIST_COL_NZ: swprintf(dest, 255, L"%f", vert.nz); break;
180
181
default:
182
wcscpy(dest, L"Invalid");
183
break;
184
}
185
}
186
187
void CtrlVertexList::FormatVertColRaw(wchar_t *dest, int row, int col) {
188
auto memLock = Memory::Lock();
189
if (!PSP_IsInited()) {
190
wcscpy(dest, L"Invalid");
191
return;
192
}
193
194
// We could use the vertex decoder and reader, but those already do some minor adjustments.
195
// There's only a few values - let's just go after them directly.
196
const u8 *vert = Memory::GetPointer(gpuDebug->GetVertexAddress()) + row * decoder->size;
197
const u8 *pos = vert + decoder->posoff;
198
const u8 *tc = vert + decoder->tcoff;
199
const u8 *color = vert + decoder->coloff;
200
const u8 *norm = vert + decoder->nrmoff;
201
202
switch (col) {
203
case VERTEXLIST_COL_X:
204
FormatVertColRawType(dest, pos, decoder->pos, 0);
205
break;
206
case VERTEXLIST_COL_Y:
207
FormatVertColRawType(dest, pos, decoder->pos, 1);
208
break;
209
case VERTEXLIST_COL_Z:
210
FormatVertColRawType(dest, pos, decoder->pos, 2);
211
break;
212
case VERTEXLIST_COL_U:
213
FormatVertColRawType(dest, tc, decoder->tc, 0);
214
break;
215
case VERTEXLIST_COL_V:
216
FormatVertColRawType(dest, tc, decoder->tc, 1);
217
break;
218
case VERTEXLIST_COL_COLOR:
219
FormatVertColRawColor(dest, color, decoder->col);
220
break;
221
222
case VERTEXLIST_COL_NX: FormatVertColRawType(dest, norm, decoder->nrm, 0); break;
223
case VERTEXLIST_COL_NY: FormatVertColRawType(dest, norm, decoder->nrm, 1); break;
224
case VERTEXLIST_COL_NZ: FormatVertColRawType(dest, norm, decoder->nrm, 2); break;
225
226
default:
227
wcscpy(dest, L"Invalid");
228
break;
229
}
230
}
231
232
void CtrlVertexList::FormatVertColRawType(wchar_t *dest, const void *data, int type, int offset) {
233
switch (type) {
234
case 0:
235
wcscpy(dest, L"-");
236
break;
237
238
case 1: // 8-bit
239
swprintf(dest, 255, L"%02x", ((const u8 *)data)[offset]);
240
break;
241
242
case 2: // 16-bit
243
swprintf(dest, 255, L"%04x", ((const u16_le *)data)[offset]);
244
break;
245
246
case 3: // float
247
swprintf(dest, 255, L"%f", ((const float *)data)[offset]);
248
break;
249
250
default:
251
wcscpy(dest, L"Invalid");
252
break;
253
}
254
}
255
256
void CtrlVertexList::FormatVertColRawColor(wchar_t *dest, const void *data, int type) {
257
switch (type) {
258
case GE_VTYPE_COL_NONE >> GE_VTYPE_COL_SHIFT:
259
wcscpy(dest, L"-");
260
break;
261
262
case GE_VTYPE_COL_565 >> GE_VTYPE_COL_SHIFT:
263
case GE_VTYPE_COL_5551 >> GE_VTYPE_COL_SHIFT:
264
case GE_VTYPE_COL_4444 >> GE_VTYPE_COL_SHIFT:
265
swprintf(dest, 255, L"%04x", *(const u16_le *)data);
266
break;
267
268
case GE_VTYPE_COL_8888 >> GE_VTYPE_COL_SHIFT:
269
swprintf(dest, 255, L"%08x", *(const u32_le *)data);
270
break;
271
272
default:
273
wcscpy(dest, L"Invalid");
274
break;
275
}
276
}
277
278
int CtrlVertexList::GetRowCount() {
279
auto memLock = Memory::Lock();
280
if (!PSP_IsInited()) {
281
return 0;
282
}
283
284
if (!gpuDebug || !Memory::IsValidAddress(gpuDebug->GetVertexAddress())) {
285
rowCount_ = 0;
286
return rowCount_;
287
}
288
289
// TODO: Maybe there are smarter ways? Also, is this the best place to recalc?
290
auto state = gpuDebug->GetGState();
291
rowCount_ = state.prim & 0xFFFF;
292
293
// Override if we're on a prim command.
294
DisplayList list;
295
if (gpuDebug->GetCurrentDisplayList(list)) {
296
u32 cmd = Memory::Read_U32(list.pc);
297
if ((cmd >> 24) == GE_CMD_PRIM || (cmd >> 24) == GE_CMD_BOUNDINGBOX) {
298
rowCount_ = cmd & 0xFFFF;
299
} else if ((cmd >> 24) == GE_CMD_BEZIER || (cmd >> 24) == GE_CMD_SPLINE) {
300
u32 u = (cmd & 0x00FF) >> 0;
301
u32 v = (cmd & 0xFF00) >> 8;
302
rowCount_ = u * v;
303
}
304
}
305
306
if (!gpuDebug->GetCurrentSimpleVertices(rowCount_, vertices, indices)) {
307
rowCount_ = 0;
308
}
309
VertexDecoderOptions options{};
310
// TODO: Maybe an option?
311
options.applySkinInDecode = true;
312
decoder->SetVertexType(state.vertType, options);
313
return rowCount_;
314
}
315
316
TabVertices::TabVertices(HINSTANCE _hInstance, HWND _hParent)
317
: Dialog((LPCSTR)IDD_GEDBG_TAB_VERTICES, _hInstance, _hParent) {
318
values = new CtrlVertexList(GetDlgItem(m_hDlg, IDC_GEDBG_VERTICES));
319
}
320
321
TabVertices::~TabVertices() {
322
delete values;
323
}
324
325
void TabVertices::UpdateSize(WORD width, WORD height) {
326
struct Position {
327
int x,y;
328
int w,h;
329
};
330
331
Position position;
332
static const int borderMargin = 5;
333
static const int checkboxSpace = 22;
334
335
position.x = borderMargin;
336
position.y = borderMargin + checkboxSpace;
337
position.w = width - 2 * borderMargin;
338
position.h = height - 2 * borderMargin - checkboxSpace;
339
340
HWND handle = GetDlgItem(m_hDlg, IDC_GEDBG_VERTICES);
341
MoveWindow(handle, position.x, position.y, position.w, position.h, TRUE);
342
}
343
344
BOOL TabVertices::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
345
switch (message) {
346
case WM_INITDIALOG:
347
return TRUE;
348
349
case WM_SIZE:
350
UpdateSize(LOWORD(lParam), HIWORD(lParam));
351
return TRUE;
352
353
case WM_COMMAND:
354
if (LOWORD(wParam) == IDC_GEDBG_RAWVERTS) {
355
values->SetRaw(IsDlgButtonChecked(m_hDlg, IDC_GEDBG_RAWVERTS) == BST_CHECKED);
356
values->Update();
357
}
358
return TRUE;
359
360
case WM_NOTIFY:
361
switch (wParam)
362
{
363
case IDC_GEDBG_VERTICES:
364
SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, values->HandleNotify(lParam));
365
return TRUE;
366
}
367
break;
368
}
369
370
return FALSE;
371
}
372
373
CtrlMatrixList::CtrlMatrixList(HWND hwnd)
374
: GenericListControl(hwnd, matrixListDef) {
375
SetIconList(12, 12, { (HICON)LoadIcon(GetModuleHandle(nullptr), (LPCWSTR)IDI_BREAKPOINT_SMALL) });
376
Update();
377
}
378
379
bool CtrlMatrixList::OnColPrePaint(int row, int col, LPNMLVCUSTOMDRAW msg) {
380
const auto state = gpuDebug->GetGState();
381
const auto lastState = GPUStepping::LastState();
382
383
bool changed = false;
384
if (col < MATRIXLIST_COL_0) {
385
for (int c = MATRIXLIST_COL_0; c <= MATRIXLIST_COL_3; ++c) {
386
changed = changed || ColChanged(lastState, state, row, c);
387
}
388
} else {
389
changed = ColChanged(lastState, state, row, col);
390
}
391
392
// At the column level, we have to reset the color back.
393
static int lastRow = -1;
394
static COLORREF rowDefaultText;
395
if (lastRow != row) {
396
rowDefaultText = msg->clrText;
397
lastRow = row;
398
}
399
400
if (changed) {
401
msg->clrText = RGB(255, 0, 0);
402
return true;
403
} else if (msg->clrText != rowDefaultText) {
404
msg->clrText = rowDefaultText;
405
return true;
406
}
407
408
return false;
409
}
410
411
bool CtrlMatrixList::ColChanged(const GPUgstate &lastState, const GPUgstate &state, int row, int col) {
412
union {
413
float f;
414
uint32_t u;
415
} newVal, oldVal;
416
if (!GetValue(state, row, col, newVal.f) || !GetValue(lastState, row, col, oldVal.f))
417
return false;
418
419
// If there's any difference in bits, highlight.
420
return newVal.u != oldVal.u;
421
}
422
423
bool CtrlMatrixList::GetValue(const GPUgstate &state, int row, int col, float &val) {
424
if (!gpuDebug || row < 0 || row >= MATRIXLIST_ROW_COUNT || col < 0 || col >= MATRIXLIST_COL_COUNT)
425
return false;
426
427
if (col < MATRIXLIST_COL_0)
428
col = MATRIXLIST_COL_0;
429
430
if (row >= MATRIXLIST_ROW_BONE_0_0) {
431
int b = (row - MATRIXLIST_ROW_BONE_0_0) / 3;
432
int r = (row - MATRIXLIST_ROW_BONE_0_0) % 3;
433
int offset = b * 12 + r + (col - MATRIXLIST_COL_0) * 3;
434
435
val = state.boneMatrix[offset];
436
return true;
437
} else if (row >= MATRIXLIST_ROW_TGEN_0) {
438
int r = row - MATRIXLIST_ROW_TGEN_0;
439
int offset = r + (col - MATRIXLIST_COL_0) * 3;
440
441
val = state.tgenMatrix[offset];
442
return true;
443
} else if (row >= MATRIXLIST_ROW_PROJ_0) {
444
int r = row - MATRIXLIST_ROW_PROJ_0;
445
int offset = r + (col - MATRIXLIST_COL_0) * 4;
446
447
val = state.projMatrix[offset];
448
return true;
449
} else if (row >= MATRIXLIST_ROW_VIEW_0) {
450
int r = row - MATRIXLIST_ROW_VIEW_0;
451
int offset = r + (col - MATRIXLIST_COL_0) * 3;
452
453
val = state.viewMatrix[offset];
454
return true;
455
}
456
457
int r = row - MATRIXLIST_ROW_WORLD_0;
458
int offset = r + (col - MATRIXLIST_COL_0) * 3;
459
460
val = state.worldMatrix[offset];
461
return true;
462
}
463
464
void CtrlMatrixList::GetColumnText(wchar_t *dest, int row, int col) {
465
if (col == MATRIXLIST_COL_BREAKPOINT) {
466
wcscpy(dest, L" ");
467
return;
468
}
469
470
float val;
471
if (!GetValue(gpuDebug->GetGState(), row, col, val)) {
472
wcscpy(dest, L"Invalid");
473
return;
474
}
475
476
if (row >= MATRIXLIST_ROW_BONE_0_0) {
477
int b = (row - MATRIXLIST_ROW_BONE_0_0) / 3;
478
int r = (row - MATRIXLIST_ROW_BONE_0_0) % 3;
479
switch (col) {
480
case MATRIXLIST_COL_NAME:
481
swprintf(dest, 255, L"Bone #%d row %d", b, r);
482
break;
483
484
default:
485
swprintf(dest, 255, L"%f", val);
486
break;
487
}
488
} else if (row >= MATRIXLIST_ROW_TGEN_0) {
489
int r = row - MATRIXLIST_ROW_TGEN_0;
490
switch (col) {
491
case MATRIXLIST_COL_NAME:
492
swprintf(dest, 255, L"Texgen %d", r);
493
break;
494
495
default:
496
swprintf(dest, 255, L"%f", val);
497
break;
498
}
499
} else if (row >= MATRIXLIST_ROW_PROJ_0) {
500
int r = row - MATRIXLIST_ROW_PROJ_0;
501
switch (col) {
502
case MATRIXLIST_COL_NAME:
503
swprintf(dest, 255, L"Proj %d", r);
504
break;
505
506
default:
507
swprintf(dest, 255, L"%f", val);
508
break;
509
}
510
} else if (row >= MATRIXLIST_ROW_VIEW_0) {
511
int r = row - MATRIXLIST_ROW_VIEW_0;
512
switch (col) {
513
case MATRIXLIST_COL_NAME:
514
swprintf(dest, 255, L"View %d", r);
515
break;
516
517
default:
518
swprintf(dest, 255, L"%f", val);
519
break;
520
}
521
} else {
522
int r = row - MATRIXLIST_ROW_WORLD_0;
523
switch (col) {
524
case MATRIXLIST_COL_NAME:
525
swprintf(dest, 255, L"World %d", r);
526
break;
527
528
default:
529
swprintf(dest, 255, L"%f", val);
530
break;
531
}
532
}
533
}
534
535
int CtrlMatrixList::GetRowCount() {
536
if (!gpuDebug) {
537
return 0;
538
}
539
540
return MATRIXLIST_ROW_COUNT;
541
}
542
543
struct MatrixCmdPair {
544
MatrixListRows row;
545
GECommand numCmd;
546
GECommand cmd;
547
};
548
static constexpr MatrixCmdPair matrixCmds[] = {
549
{ MATRIXLIST_ROW_WORLD_0, GE_CMD_WORLDMATRIXNUMBER, GE_CMD_WORLDMATRIXDATA },
550
{ MATRIXLIST_ROW_VIEW_0, GE_CMD_VIEWMATRIXNUMBER, GE_CMD_VIEWMATRIXDATA },
551
{ MATRIXLIST_ROW_PROJ_0, GE_CMD_PROJMATRIXNUMBER, GE_CMD_PROJMATRIXDATA },
552
{ MATRIXLIST_ROW_TGEN_0, GE_CMD_TGENMATRIXNUMBER, GE_CMD_TGENMATRIXDATA },
553
{ MATRIXLIST_ROW_BONE_0_0, GE_CMD_BONEMATRIXNUMBER, GE_CMD_BONEMATRIXDATA },
554
{ MATRIXLIST_ROW_COUNT, GE_CMD_NOP },
555
};
556
557
static const MatrixCmdPair *FindCmdPair(int row) {
558
for (int i = 0; i < ARRAY_SIZE(matrixCmds) - 1; ++i) {
559
if (row < matrixCmds[i].row || row >= matrixCmds[i + 1].row)
560
continue;
561
562
return &matrixCmds[i];
563
}
564
return nullptr;
565
}
566
567
void CtrlMatrixList::ToggleBreakpoint(int row) {
568
const MatrixCmdPair *info = FindCmdPair(row);
569
if (!info)
570
return;
571
572
// Okay, this command is in range. Toggle the actual breakpoint.
573
bool state = !GPUBreakpoints::IsCmdBreakpoint(info->cmd);
574
if (state) {
575
GPUBreakpoints::AddCmdBreakpoint(info->cmd);
576
} else {
577
if (GPUBreakpoints::GetCmdBreakpointCond(info->cmd, nullptr)) {
578
int ret = MessageBox(GetHandle(), L"This breakpoint has a custom condition.\nDo you want to remove it?", L"Confirmation", MB_YESNO);
579
if (ret != IDYES)
580
return;
581
}
582
GPUBreakpoints::RemoveCmdBreakpoint(info->cmd);
583
}
584
585
for (int r = info->row; r < (info + 1)->row; ++r) {
586
SetItemState(r, state ? 1 : 0);
587
}
588
}
589
590
void CtrlMatrixList::PromptBreakpointCond(int row) {
591
const MatrixCmdPair *info = FindCmdPair(row);
592
if (!info)
593
return;
594
595
std::string expression;
596
GPUBreakpoints::GetCmdBreakpointCond(info->cmd, &expression);
597
if (!InputBox_GetString(GetModuleHandle(NULL), GetHandle(), L"Expression", expression, expression))
598
return;
599
600
std::string error;
601
if (!GPUBreakpoints::SetCmdBreakpointCond(info->cmd, expression, &error))
602
MessageBox(GetHandle(), ConvertUTF8ToWString(error).c_str(), L"Invalid expression", MB_OK | MB_ICONEXCLAMATION);
603
}
604
605
void CtrlMatrixList::OnDoubleClick(int row, int column) {
606
if (row >= GetRowCount())
607
return;
608
609
if (column == MATRIXLIST_COL_BREAKPOINT) {
610
ToggleBreakpoint(row);
611
return;
612
}
613
614
float val;
615
if (!GetValue(gpuDebug->GetGState(), row, column, val))
616
return;
617
618
std::string strvalue = StringFromFormat("%f", val);
619
bool res = InputBox_GetString(GetModuleHandle(NULL), GetHandle(), L"Column value", strvalue, strvalue);
620
if (!res)
621
return;
622
623
if (sscanf(strvalue.c_str(), "%f", &val) == 1) {
624
auto prevState = gpuDebug->GetGState();
625
auto setCmdValue = [&](u32 op) {
626
SendMessage(GetParent(GetParent(GetHandle())), WM_GEDBG_SETCMDWPARAM, op, NULL);
627
};
628
629
union {
630
float f;
631
u32 u;
632
} temp = { val };
633
634
for (int i = 0; i < ARRAY_SIZE(matrixCmds) - 1; ++i) {
635
if (row < matrixCmds[i].row || row >= matrixCmds[i + 1].row)
636
continue;
637
638
// Everything is 3 except the projection matrix, which is 4.
639
int sz = matrixCmds[i + 1].row - matrixCmds[i].row == 4 ? 4 : 3;
640
// Always zero except for bones.
641
int b = (row - matrixCmds[i].row) / sz;
642
int r = (row - matrixCmds[i].row) % sz;
643
int c = column >= MATRIXLIST_COL_0 ? column - MATRIXLIST_COL_0 : 0;
644
645
// Okay, now set the number, then data.
646
int n = b * 12 + r + c * sz;
647
setCmdValue((matrixCmds[i].numCmd << 24) | n);
648
setCmdValue((matrixCmds[i].cmd << 24) | (temp.u >> 8));
649
650
// Done, revert the number.
651
setCmdValue(prevState.cmdmem[matrixCmds[i].numCmd]);
652
Update();
653
}
654
}
655
}
656
657
void CtrlMatrixList::OnRightClick(int row, int column, const POINT &point) {
658
if (row >= GetRowCount())
659
return;
660
const MatrixCmdPair *info = FindCmdPair(row);
661
662
POINT screenPt(point);
663
ClientToScreen(GetHandle(), &screenPt);
664
665
HMENU subMenu = GetContextMenu(ContextMenuID::GEDBG_MATRIX);
666
SetMenuDefaultItem(subMenu, ID_REGLIST_CHANGE, FALSE);
667
EnableMenuItem(subMenu, ID_GEDBG_SETCOND, info && GPUBreakpoints::IsCmdBreakpoint(info->cmd) ? MF_ENABLED : MF_GRAYED);
668
669
switch (TriggerContextMenu(ContextMenuID::GEDBG_MATRIX, GetHandle(), ContextPoint::FromClient(point))) {
670
case ID_DISASM_TOGGLEBREAKPOINT:
671
ToggleBreakpoint(row);
672
break;
673
674
case ID_GEDBG_SETCOND:
675
PromptBreakpointCond(row);
676
break;
677
678
case ID_DISASM_COPYINSTRUCTIONDISASM:
679
{
680
float val;
681
if (GetValue(gpuDebug->GetGState(), row, column, val)) {
682
wchar_t dest[512];
683
swprintf(dest, 511, L"%f", val);
684
W32Util::CopyTextToClipboard(GetHandle(), dest);
685
}
686
break;
687
}
688
689
case ID_GEDBG_COPYALL:
690
CopyRows(0, GetRowCount());
691
break;
692
693
case ID_REGLIST_CHANGE:
694
OnDoubleClick(row, MATRIXLIST_COL_0);
695
break;
696
}
697
}
698
699
TabMatrices::TabMatrices(HINSTANCE _hInstance, HWND _hParent)
700
: Dialog((LPCSTR)IDD_GEDBG_TAB_MATRICES, _hInstance, _hParent) {
701
values = new CtrlMatrixList(GetDlgItem(m_hDlg, IDC_GEDBG_MATRICES));
702
}
703
704
TabMatrices::~TabMatrices() {
705
delete values;
706
}
707
708
void TabMatrices::UpdateSize(WORD width, WORD height) {
709
struct Position {
710
int x,y;
711
int w,h;
712
};
713
714
Position position;
715
static const int borderMargin = 5;
716
717
position.x = borderMargin;
718
position.y = borderMargin;
719
position.w = width - 2 * borderMargin;
720
position.h = height - 2 * borderMargin;
721
722
HWND handle = GetDlgItem(m_hDlg, IDC_GEDBG_MATRICES);
723
MoveWindow(handle, position.x, position.y, position.w, position.h, TRUE);
724
}
725
726
BOOL TabMatrices::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
727
switch (message) {
728
case WM_INITDIALOG:
729
return TRUE;
730
731
case WM_SIZE:
732
UpdateSize(LOWORD(lParam), HIWORD(lParam));
733
return TRUE;
734
735
case WM_NOTIFY:
736
switch (wParam)
737
{
738
case IDC_GEDBG_MATRICES:
739
SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, values->HandleNotify(lParam));
740
return TRUE;
741
}
742
break;
743
}
744
745
return FALSE;
746
}
747
748