34 if (!motherBoard)
return;
36 ImGui::SetNextWindowSize({528, 618}, ImGuiCond_FirstUseEver);
38 auto* vdp =
dynamic_cast<VDP*
>(motherBoard->
findDevice(
"VDP"));
39 if (!vdp || vdp->isMSX1VDP())
return;
42 auto base = mode.getBase();
57 int vdpMode = parseMode(vdp->getDisplayMode());
59 int vdpPages = vdpMode <= SCR6 ? 4 : 2;
60 int vdpPage = vdp->getDisplayPage();
61 if (vdpPage >= vdpPages) vdpPage &= 1;
63 int vdpLines = (vdp->getNumberOfLines() == 192) ? 0 : 1;
66 if (vdpMode ==
one_of(SCR8, SCR11, SCR12) || !vdp->getTransparency()) {
69 return vdp->getBackgroundColor() & 15;
72 auto modeToStr = [](
int mode) {
73 if (mode == SCR5 )
return "screen 5";
74 if (mode == SCR6 )
return "screen 6";
75 if (mode == SCR7 )
return "screen 7";
76 if (mode == SCR8 )
return "screen 8";
77 if (mode == SCR11)
return "screen 11";
78 if (mode == SCR12)
return "screen 12";
79 if (mode == OTHER)
return "non-bitmap";
80 assert(
false);
return "ERROR";
83 static const char*
const color0Str =
"0\0001\0002\0003\0004\0005\0006\0007\0008\0009\00010\00011\00012\00013\00014\00015\000none\000";
84 bool manualMode = overrideAll || overrideMode;
85 bool manualPage = overrideAll || overridePage;
86 bool manualLines = overrideAll || overrideLines;
87 bool manualColor0 = overrideAll || overrideColor0;
91 ImGui::AlignTextToFramePadding();
95 ImGui::AlignTextToFramePadding();
99 ImGui::AlignTextToFramePadding();
103 ImGui::AlignTextToFramePadding();
110 ImGui::Checkbox(
"Manual override", &overrideAll);
113 ImGui::Checkbox(
"##mode", overrideAll ? &overrideAll : &overrideMode);
114 ImGui::Checkbox(
"##page", overrideAll ? &overrideAll : &overridePage);
115 ImGui::Checkbox(
"##lines", overrideAll ? &overrideAll : &overrideLines);
116 ImGui::Checkbox(
"##color0", overrideAll ? &overrideAll : &overrideColor0);
123 ImGui::Combo(
"##Screen mode", &bitmapScrnMode,
"screen 5\000screen 6\000screen 7\000screen 8\000screen 11\000screen 12\000");
126 int numPages = bitmapScrnMode <= SCR6 ? 4 : 2;
127 if (bitmapPage >= numPages) bitmapPage = numPages - 1;
128 if (bitmapPage < 0) bitmapPage = numPages;
129 ImGui::Combo(
"##Display page", &bitmapPage, numPages == 2 ?
"0\0001\000All\000" :
"0\0001\0002\0003\000All\000");
130 if (bitmapPage == numPages) bitmapPage = -1;
133 ImGui::Combo(
"##Visible lines", &bitmapLines,
"192\000212\000256\000");
136 ImGui::Combo(
"##Color 0 replacement", &bitmapColor0, color0Str);
143 ImGui::Dummy(ImVec2(15, 1));
146 const auto& vram = vdp->getVRAM();
147 int mode = manualMode ? bitmapScrnMode : vdpMode;
148 int page = manualPage ? bitmapPage : vdpPage;
149 int lines = manualLines ? bitmapLines : vdpLines;
150 int color0 = manualColor0 ? bitmapColor0 : vdpColor0;
151 int divX = mode ==
one_of(SCR6, SCR7) ? 1 : 2;
152 int width = 512 / divX;
153 int height = (lines == 0) ? 192
157 int numPages = mode <= SCR6 ? 4 : 2;
158 height = 256 * numPages;
161 auto rasterBeamPos = vdp->getMSXPos(vdp->getCurrentTime());
162 rasterBeamPos.x /= divX;
165 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 10.0f);
166 ImGui::Combo(
"Palette", &
manager.
palette->whichPalette,
"VDP\000Custom\000Fixed\000");
167 if (ImGui::Button(
"Open palette editor")) {
171 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 3.0f);
172 ImGui::Combo(
"Zoom", &bitmapZoom,
"1x\0002x\0003x\0004x\0005x\0006x\0007x\0008x\000");
173 ImGui::Checkbox(
"grid", &bitmapGrid);
176 ImGui::ColorEdit4(
"Grid color", bitmapGridColor.data(),
177 ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaBar);
180 ImGui::Checkbox(
"beam", &rasterBeam);
183 ImGui::ColorEdit4(
"raster beam color", rasterBeamColor.data(),
184 ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaBar);
187 ImGui::StrCat(
'(', dec_string<4>(rasterBeamPos.x),
188 ',', dec_string<4>(rasterBeamPos.y),
')');
191 HelpMarker(
"Position of the raster beam, expressed in MSX coordinates.\n"
192 "Left/top border have negative x/y-coordinates.\n"
193 "Only practically useful when emulation is paused.");
198 std::array<uint32_t, 16> palette;
201 [](uint16_t msx) { return ImGuiPalette::toRGBA(msx); });
202 if (color0 < 16) palette[0] = palette[color0];
205 renderBitmap(vram.getData(), palette, mode, height, page,
208 bitmapTex.emplace(
false,
false);
211 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
212 GL_RGBA, GL_UNSIGNED_BYTE, pixels.
data());
213 int zx = (1 + bitmapZoom) * divX;
214 int zy = (1 + bitmapZoom) * 2;
218 auto msxSize =
gl::vec2(
float(width),
float(height));
219 auto size = msxSize * zm;
220 auto availSize =
gl::vec2(ImGui::GetContentRegionAvail()) -
gl::vec2(0.0f, ImGui::GetTextLineHeightWithSpacing());
221 auto reqSize = size +
gl::vec2(ImGui::GetStyle().ScrollbarSize);
222 im::Child(
"##bitmap", min(availSize, reqSize), 0, ImGuiWindowFlags_HorizontalScrollbar, [&]{
223 scrnPos = ImGui::GetCursorScreenPos();
224 auto pos = ImGui::GetCursorPos();
225 ImGui::Image(bitmapTex->getImGui(), size);
227 if (bitmapGrid && (zx > 1) && (zy > 1)) {
228 auto color = ImGui::ColorConvertFloat4ToU32(bitmapGridColor);
229 for (
auto y :
xrange(zy)) {
230 auto* line = &pixels[y * zx];
231 for (
auto x :
xrange(zx)) {
232 line[x] = (x == 0 || y == 0) ? color : 0;
235 if (!bitmapGridTex) {
236 bitmapGridTex.emplace(
false,
true);
238 bitmapGridTex->bind();
239 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, zx, zy, 0,
240 GL_RGBA, GL_UNSIGNED_BYTE, pixels.
data());
241 ImGui::SetCursorPos(pos);
242 ImGui::Image(bitmapGridTex->getImGui(), size,
gl::vec2{}, msxSize);
245 auto* drawList = ImGui::GetWindowDrawList();
247 auto color = ImGui::ColorConvertFloat4ToU32(rasterBeamColor);
248 auto thickness = zm.y * 0.5f;
249 auto zm1 = 1.5f * zm;
250 auto zm3 = 3.5f * zm;
251 drawList->AddRect(center - zm, center + zm, color, 0.0f, 0, thickness);
252 drawList->AddLine(center -
gl::vec2{zm1.x, 0.0f}, center -
gl::vec2{zm3.x, 0.0f}, color, thickness);
253 drawList->AddLine(center +
gl::vec2{zm1.x, 0.0f}, center +
gl::vec2{zm3.x, 0.0f}, color, thickness);
254 drawList->AddLine(center -
gl::vec2{0.0f, zm1.y}, center -
gl::vec2{0.0f, zm3.y}, color, thickness);
255 drawList->AddLine(center +
gl::vec2{0.0f, zm1.y}, center +
gl::vec2{0.0f, zm3.y}, color, thickness);
258 if (ImGui::IsItemHovered() && (mode != OTHER)) {
259 auto [x_, y_] = trunc((
gl::vec2(ImGui::GetIO().MousePos) - scrnPos) / zm);
260 auto x = x_;
auto y = y_;
261 if ((0 <= x) && (x < width) && (0 <= y) && (y < height)) {
262 auto dec3 = [&](
int d) {
264 ImGui::SameLine(0.0f, 0.0f);
265 ImGui::Text(
"%3d", d);
267 auto hex2 = [&](
unsigned h) {
269 ImGui::SameLine(0.0f, 0.0f);
272 auto hex5 = [&](
unsigned h) {
274 ImGui::SameLine(0.0f, 0.0f);
282 unsigned physAddr = 0x8000 * page + 128 * y;
284 case SCR5: physAddr += x / 2;
break;
285 case SCR6: physAddr += x / 4;
break;
286 case SCR7: physAddr += x / 4 + 0x08000 * (x & 2);
break;
287 case SCR8:
case SCR11:
case SCR12:
288 physAddr += x / 2 + 0x10000 * (x & 1);
break;
289 default: assert(
false);
292 auto value = vram.getData()[physAddr];
293 auto color = [&]() -> uint8_t {
295 case SCR5:
case SCR7:
296 return (value >> (4 * (1 - (x & 1)))) & 0x0f;
298 return (value >> (2 * (3 - (x & 3)))) & 0x03;
303 if (mode !=
one_of(SCR11, SCR12)) {
310 if (mode ==
one_of(SCR5, SCR6)) {
313 unsigned logAddr = (physAddr & 0x0ffff) << 1 | (physAddr >> 16);
315 ImGui::SameLine(0.0f, 0.0f);
317 ImGui::SameLine(0.0f, 0.0f);