33 if (!motherBoard)
return;
35 ImGui::SetNextWindowSize({528, 618}, ImGuiCond_FirstUseEver);
37 auto* vdp =
dynamic_cast<VDP*
>(motherBoard->
findDevice(
"VDP"));
41 auto base = mode.getBase();
56 int vdpMode = parseMode(vdp->getDisplayMode());
58 int vdpPages = vdpMode <= SCR6 ? 4 : 2;
59 int vdpPage = vdp->getDisplayPage();
60 if (vdpPage >= vdpPages) vdpPage &= 1;
62 int vdpLines = (vdp->getNumberOfLines() == 192) ? 0 : 1;
65 if (vdpMode ==
one_of(SCR8, SCR11, SCR12) || !vdp->getTransparency()) {
68 return vdp->getBackgroundColor() & 15;
71 auto modeToStr = [](
int mode) {
72 if (mode == SCR5 )
return "screen 5";
73 if (mode == SCR6 )
return "screen 6";
74 if (mode == SCR7 )
return "screen 7";
75 if (mode == SCR8 )
return "screen 8";
76 if (mode == SCR11)
return "screen 11";
77 if (mode == SCR12)
return "screen 12";
78 if (mode == OTHER)
return "non-bitmap";
79 assert(
false);
return "ERROR";
82 static const char*
const color0Str =
"0\0001\0002\0003\0004\0005\0006\0007\0008\0009\00010\00011\00012\00013\00014\00015\000none\000";
84 ImGui::RadioButton(
"Use VDP settings", &bitmapManual, 0);
86 ImGui::AlignTextToFramePadding();
88 ImGui::AlignTextToFramePadding();
90 ImGui::AlignTextToFramePadding();
92 ImGui::AlignTextToFramePadding();
94 ImGui::AlignTextToFramePadding();
100 ImGui::RadioButton(
"Manual override", &bitmapManual, 1);
103 ImGui::Combo(
"##Screen mode", &bitmapScrnMode,
"screen 5\000screen 6\000screen 7\000screen 8\000screen 11\000screen 12\000");
104 int numPages = bitmapScrnMode <= SCR6 ? 4 : 2;
105 if (bitmapPage >= numPages) bitmapPage = numPages - 1;
106 ImGui::Combo(
"##Display page", &bitmapPage, numPages == 2 ?
"0\0001\000" :
"0\0001\0002\0003\000");
107 ImGui::Combo(
"##Visible lines", &bitmapLines,
"192\000212\000256\000");
108 ImGui::Combo(
"##Color 0 replacement", &bitmapColor0, color0Str);
114 ImGui::Dummy(ImVec2(25, 1));
117 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 10.0f);
118 ImGui::Combo(
"Palette", &
manager.
palette->whichPalette,
"VDP\000Custom\000Fixed\000");
119 if (ImGui::Button(
"Open palette editor")) {
123 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 3.0f);
124 ImGui::Combo(
"Zoom", &bitmapZoom,
"1x\0002x\0003x\0004x\0005x\0006x\0007x\0008x\000");
125 ImGui::Checkbox(
"grid", &bitmapGrid);
128 ImGui::ColorEdit4(
"Grid color", bitmapGridColor.data(),
129 ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaBar);
135 const auto& vram = vdp->getVRAM();
136 int mode = bitmapManual ? bitmapScrnMode : vdpMode;
137 int page = bitmapManual ? bitmapPage : vdpPage;
138 int lines = bitmapManual ? bitmapLines : vdpLines;
139 int color0 = bitmapManual ? bitmapColor0 : vdpColor0;
140 int width = mode ==
one_of(SCR6, SCR7) ? 512 : 256;
141 int height = (lines == 0) ? 192
145 std::array<uint32_t, 16> palette;
148 [](uint16_t msx) { return ImGuiPalette::toRGBA(msx); });
149 if (color0 < 16) palette[0] = palette[color0];
151 std::array<uint32_t, 512 * 256> pixels;
152 renderBitmap(vram.getData(), palette, mode, height, page,
155 bitmapTex.emplace(
false,
false);
158 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
159 GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
160 int zx = (1 + bitmapZoom) * (width == 256 ? 2 : 1);
161 int zy = (1 + bitmapZoom) * 2;
164 gl::vec2 size(
float(width * zx),
float(height * zy));
165 gl::vec2 availSize =
gl::vec2(ImGui::GetContentRegionAvail()) -
gl::vec2(0.0f, ImGui::GetTextLineHeightWithSpacing());
167 im::Child(
"##bitmap", min(availSize, reqSize), 0, ImGuiWindowFlags_HorizontalScrollbar, [&]{
168 scrnPos = ImGui::GetCursorScreenPos();
169 auto pos = ImGui::GetCursorPos();
170 ImGui::Image(bitmapTex->getImGui(), size);
172 if (bitmapGrid && (zx > 1) && (zy > 1)) {
173 auto color = ImGui::ColorConvertFloat4ToU32(bitmapGridColor);
174 for (
auto y :
xrange(zy)) {
175 auto* line = &pixels[y * zx];
176 for (
auto x :
xrange(zx)) {
177 line[x] = (x == 0 || y == 0) ? color : 0;
180 if (!bitmapGridTex) {
181 bitmapGridTex.emplace(
false,
true);
183 bitmapGridTex->bind();
184 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, zx, zy, 0,
185 GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
186 ImGui::SetCursorPos(pos);
187 ImGui::Image(bitmapGridTex->getImGui(), size,
188 ImVec2(0.0f, 0.0f), ImVec2(
float(width),
float(height)));
191 if (ImGui::IsItemHovered() && (mode != OTHER)) {
192 gl::vec2 zoom{float(zx), float(zy)};
193 auto [x_, y_] = trunc((
gl::vec2(ImGui::GetIO().MousePos) - scrnPos) / zoom);
194 auto x = x_;
auto y = y_;
195 if ((0 <= x) && (x < width) && (0 <= y) && (y < height)) {
196 auto dec3 = [&](
int d) {
198 ImGui::SameLine(0.0f, 0.0f);
199 ImGui::Text(
"%3d", d);
201 auto hex2 = [&](
unsigned h) {
203 ImGui::SameLine(0.0f, 0.0f);
206 auto hex5 = [&](
unsigned h) {
208 ImGui::SameLine(0.0f, 0.0f);
216 unsigned physAddr = 0x8000 * page + 128 * y;
218 case SCR5: physAddr += x / 2;
break;
219 case SCR6: physAddr += x / 4;
break;
220 case SCR7: physAddr += x / 4 + 0x08000 * (x & 2);
break;
221 case SCR8:
case SCR11:
case SCR12:
222 physAddr += x / 2 + 0x10000 * (x & 1);
break;
223 default: assert(
false);
226 auto value = vram.getData()[physAddr];
227 auto color = [&]() -> uint8_t {
229 case SCR5:
case SCR7:
230 return (value >> (4 * (1 - (x & 1)))) & 0x0f;
232 return (value >> (2 * (3 - (x & 3)))) & 0x03;
237 if (mode !=
one_of(SCR11, SCR12)) {
244 if (mode ==
one_of(SCR5, SCR6)) {
247 unsigned logAddr = (physAddr & 0x0ffff) << 1 | (physAddr >> 16);
249 ImGui::SameLine(0.0f, 0.0f);
251 ImGui::SameLine(0.0f, 0.0f);