| e8555c89 Andy McCall |
1 |
#include "SDLRasterizer.hh" |
| 2 |
|
| 3 |
#include "Display.hh" |
| 4 |
#include "OutputSurface.hh" |
| 5 |
#include "PostProcessor.hh" |
| 6 |
#include "RawFrame.hh" |
| 7 |
#include "RenderSettings.hh" |
| 8 |
#include "Renderer.hh" |
| 9 |
#include "VDP.hh" |
| 10 |
#include "VDPVRAM.hh" |
| 11 |
|
| 12 |
#include "MemoryOps.hh" |
| 13 |
#include "enumerate.hh" |
| 14 |
#include "one_of.hh" |
| 15 |
#include "xrange.hh" |
| 16 |
|
| 17 |
#include <algorithm> |
| 18 |
#include <array> |
| 19 |
#include <cassert> |
| 20 |
#include <cstdint> |
| 21 |
#include <memory> |
| 22 |
|
| 23 |
using namespace gl; |
| 24 |
|
| 25 |
namespace openmsx { |
| 26 |
|
| 27 |
using Pixel = SDLRasterizer::Pixel; |
| 28 |
|
| 29 |
|
| 30 |
|
| 31 |
static constexpr int TICKS_LEFT_BORDER = 100 + 102; |
| 32 |
static constexpr int TICKS_RIGHT_BORDER = 100 + 102 + 56 + 1024 + 59; |
| 33 |
|
| 34 |
|
| 35 |
|
| 36 |
|
| 37 |
|
| 38 |
static constexpr int TICKS_VISIBLE_MIDDLE = |
| 39 |
TICKS_LEFT_BORDER + (VDP::TICKS_PER_LINE - TICKS_LEFT_BORDER - 27) / 2; |
| 40 |
|
| 41 |
|
| 42 |
|
| 43 |
|
| 44 |
|
| 45 |
|
| 46 |
|
| 47 |
static constexpr int translateX(int absoluteX, bool narrow) |
| 48 |
{ |
| 49 |
int maxX = narrow ? 640 : 320; |
| 50 |
|
| 51 |
|
| 52 |
|
| 53 |
|
| 54 |
|
| 55 |
|
| 56 |
|
| 57 |
|
| 58 |
|
| 59 |
|
| 60 |
|
| 61 |
|
| 62 |
|
| 63 |
|
| 64 |
|
| 65 |
|
| 66 |
|
| 67 |
|
| 68 |
|
| 69 |
|
| 70 |
if (absoluteX < TICKS_LEFT_BORDER) return 0; |
| 71 |
if (absoluteX > TICKS_RIGHT_BORDER) return maxX; |
| 72 |
|
| 73 |
|
| 74 |
|
| 75 |
|
| 76 |
|
| 77 |
static_assert((TICKS_VISIBLE_MIDDLE % 4) == 3); |
| 78 |
const int origin = TICKS_VISIBLE_MIDDLE - 1; |
| 79 |
return ((absoluteX - origin) |
| 80 |
>> (narrow ? 1 : 2)) |
| 81 |
+ maxX / 2; |
| 82 |
} |
| 83 |
|
| 84 |
inline void SDLRasterizer::renderBitmapLine(std::span<Pixel> buf, unsigned vramLine) |
| 85 |
{ |
| 86 |
if (vdp.getDisplayMode().isPlanar()) { |
| 87 |
auto [vramPtr0, vramPtr1] = |
| 88 |
vram.bitmapCacheWindow.getReadAreaPlanar<256>(vramLine * 256); |
| 89 |
bitmapConverter.convertLinePlanar(buf, vramPtr0, vramPtr1); |
| 90 |
} else { |
| 91 |
auto vramPtr = |
| 92 |
vram.bitmapCacheWindow.getReadArea<128>(vramLine * 128); |
| 93 |
bitmapConverter.convertLine(buf, vramPtr); |
| 94 |
} |
| 95 |
} |
| 96 |
|
| 97 |
SDLRasterizer::SDLRasterizer( |
| 98 |
VDP& vdp_, Display& display, OutputSurface& screen_, |
| 99 |
std::unique_ptr<PostProcessor> postProcessor_) |
| 100 |
: vdp(vdp_), vram(vdp.getVRAM()) |
| 101 |
, screen(screen_) |
| 102 |
, postProcessor(std::move(postProcessor_)) |
| 103 |
, workFrame(std::make_unique<RawFrame>(640, 240)) |
| 104 |
, renderSettings(display.getRenderSettings()) |
| 105 |
, characterConverter(vdp, subspan<16>(palFg), palBg) |
| 106 |
, bitmapConverter(palFg, PALETTE256, V9958_COLORS) |
| 107 |
, spriteConverter(vdp.getSpriteChecker(), palBg) |
| 108 |
{ |
| 109 |
|
| 110 |
precalcPalette(); |
| 111 |
|
| 112 |
|
| 113 |
if (!vdp.isMSX1VDP()) { |
| 114 |
for (auto i : xrange(16)) { |
| 115 |
palFg[i] = palFg[i + 16] = palBg[i] = |
| 116 |
V9938_COLORS[0][0][0]; |
| 117 |
} |
| 118 |
} |
| 119 |
|
| 120 |
renderSettings.getGammaSetting() .attach(*this); |
| 121 |
renderSettings.getBrightnessSetting() .attach(*this); |
| 122 |
renderSettings.getContrastSetting() .attach(*this); |
| 123 |
renderSettings.getColorMatrixSetting().attach(*this); |
| 124 |
} |
| 125 |
|
| 126 |
SDLRasterizer::~SDLRasterizer() |
| 127 |
{ |
| 128 |
renderSettings.getColorMatrixSetting().detach(*this); |
| 129 |
renderSettings.getGammaSetting() .detach(*this); |
| 130 |
renderSettings.getBrightnessSetting() .detach(*this); |
| 131 |
renderSettings.getContrastSetting() .detach(*this); |
| 132 |
} |
| 133 |
|
| 134 |
PostProcessor* SDLRasterizer::getPostProcessor() const |
| 135 |
{ |
| 136 |
return postProcessor.get(); |
| 137 |
} |
| 138 |
|
| 139 |
const RawFrame* SDLRasterizer::getWorkingFrame() const |
| 140 |
{ |
| 141 |
return workFrame.get(); |
| 142 |
} |
| 143 |
|
| 144 |
const RawFrame* SDLRasterizer::getLastFrame() const |
| 145 |
{ |
| 146 |
return postProcessor->getLastRawFrame(); |
| 147 |
} |
| 148 |
|
| 149 |
bool SDLRasterizer::isActive() |
| 150 |
{ |
| 151 |
return postProcessor->needRender() && |
| 152 |
vdp.getMotherBoard().isActive() && |
| 153 |
!vdp.getMotherBoard().isFastForwarding(); |
| 154 |
} |
| 155 |
|
| 156 |
void SDLRasterizer::reset() |
| 157 |
{ |
| 158 |
|
| 159 |
setDisplayMode(vdp.getDisplayMode()); |
| 160 |
spriteConverter.setTransparency(vdp.getTransparency()); |
| 161 |
|
| 162 |
resetPalette(); |
| 163 |
} |
| 164 |
|
| 165 |
void SDLRasterizer::resetPalette() |
| 166 |
{ |
| 167 |
if (!vdp.isMSX1VDP()) { |
| 168 |
|
| 169 |
for (auto i : xrange(16)) { |
| 170 |
setPalette(i, vdp.getPalette(i)); |
| 171 |
} |
| 172 |
} |
| 173 |
} |
| 174 |
|
| 175 |
void SDLRasterizer::setSuperimposeVideoFrame(const RawFrame* videoSource) |
| 176 |
{ |
| 177 |
postProcessor->setSuperimposeVideoFrame(videoSource); |
| 178 |
precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(), |
| 179 |
videoSource, vdp.getBackgroundColor()); |
| 180 |
} |
| 181 |
|
| 182 |
void SDLRasterizer::frameStart(EmuTime time) |
| 183 |
{ |
| 184 |
workFrame = postProcessor->rotateFrames(std::move(workFrame), time); |
| 185 |
workFrame->init( |
| 186 |
vdp.isInterlaced() ? (vdp.getEvenOdd() ? FrameSource::FieldType::ODD |
| 187 |
: FrameSource::FieldType::EVEN) |
| 188 |
: FrameSource::FieldType::NONINTERLACED); |
| 189 |
|
| 190 |
|
| 191 |
|
| 192 |
|
| 193 |
|
| 194 |
|
| 195 |
lineRenderTop = vdp.isPalTiming() ? 59 - 14 : 32 - 14; |
| 196 |
} |
| 197 |
|
| 198 |
void SDLRasterizer::frameEnd() |
| 199 |
{ |
| 200 |
} |
| 201 |
|
| 202 |
void SDLRasterizer::setDisplayMode(DisplayMode mode) |
| 203 |
{ |
| 204 |
if (mode.isBitmapMode()) { |
| 205 |
bitmapConverter.setDisplayMode(mode); |
| 206 |
} else { |
| 207 |
characterConverter.setDisplayMode(mode); |
| 208 |
} |
| 209 |
precalcColorIndex0(mode, vdp.getTransparency(), |
| 210 |
vdp.isSuperimposing(), vdp.getRawBackgroundColor()); |
| 211 |
spriteConverter.setDisplayMode(mode); |
| 212 |
spriteConverter.setPalette(mode.getByte() == DisplayMode::GRAPHIC7 |
| 213 |
? palGraphic7Sprites : palBg); |
| 214 |
|
| 215 |
} |
| 216 |
|
| 217 |
void SDLRasterizer::setPalette(unsigned index, int grb) |
| 218 |
{ |
| 219 |
|
| 220 |
Pixel newColor = V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7]; |
| 221 |
palFg[index ] = newColor; |
| 222 |
palFg[index + 16] = newColor; |
| 223 |
palBg[index ] = newColor; |
| 224 |
bitmapConverter.palette16Changed(); |
| 225 |
|
| 226 |
precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(), |
| 227 |
vdp.isSuperimposing(), vdp.getBackgroundColor()); |
| 228 |
} |
| 229 |
|
| 230 |
void SDLRasterizer::setBackgroundColor(uint8_t index) |
| 231 |
{ |
| 232 |
if (vdp.getDisplayMode().getByte() != DisplayMode::GRAPHIC7) { |
| 233 |
precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(), |
| 234 |
vdp.isSuperimposing(), index); |
| 235 |
} |
| 236 |
} |
| 237 |
|
| 238 |
void SDLRasterizer::setHorizontalAdjust(int ) |
| 239 |
{ |
| 240 |
} |
| 241 |
|
| 242 |
void SDLRasterizer::setHorizontalScrollLow(uint8_t ) |
| 243 |
{ |
| 244 |
} |
| 245 |
|
| 246 |
void SDLRasterizer::setBorderMask(bool ) |
| 247 |
{ |
| 248 |
} |
| 249 |
|
| 250 |
void SDLRasterizer::setTransparency(bool enabled) |
| 251 |
{ |
| 252 |
spriteConverter.setTransparency(enabled); |
| 253 |
precalcColorIndex0(vdp.getDisplayMode(), enabled, |
| 254 |
vdp.isSuperimposing(), vdp.getBackgroundColor()); |
| 255 |
} |
| 256 |
|
| 257 |
void SDLRasterizer::precalcPalette() |
| 258 |
{ |
| 259 |
if (vdp.isMSX1VDP()) { |
| 260 |
|
| 261 |
const auto palette = vdp.getMSX1Palette(); |
| 262 |
for (auto i : xrange(16)) { |
| 263 |
const auto rgb = palette[i]; |
| 264 |
palFg[i] = palFg[i + 16] = palBg[i] = |
| 265 |
screen.mapRGB( |
| 266 |
renderSettings.transformRGB( |
| 267 |
vec3(rgb[0], rgb[1], rgb[2]) * (1.0f / 255.0f))); |
| 268 |
} |
| 269 |
} else { |
| 270 |
if (vdp.hasYJK()) { |
| 271 |
|
| 272 |
if (renderSettings.isColorMatrixIdentity()) { |
| 273 |
|
| 274 |
|
| 275 |
std::array<int, 32> intensity; |
| 276 |
for (auto [i, r] : enumerate(intensity)) { |
| 277 |
r = narrow_cast<int>(255.0f * renderSettings.transformComponent(narrow<float>(i) * (1.0f / 31.0f))); |
| 278 |
} |
| 279 |
for (auto [rgb, col] : enumerate(V9958_COLORS)) { |
| 280 |
col = screen.mapRGB255(ivec3( |
| 281 |
intensity[(rgb >> 10) & 31], |
| 282 |
intensity[(rgb >> 5) & 31], |
| 283 |
intensity[(rgb >> 0) & 31])); |
| 284 |
} |
| 285 |
} else { |
| 286 |
for (auto r : xrange(32)) { |
| 287 |
for (auto g : xrange(32)) { |
| 288 |
for (auto b : xrange(32)) { |
| 289 |
vec3 rgb{narrow<float>(r), |
| 290 |
narrow<float>(g), |
| 291 |
narrow<float>(b)}; |
| 292 |
V9958_COLORS[(r << 10) + (g << 5) + b] = |
| 293 |
screen.mapRGB( |
| 294 |
renderSettings.transformRGB(rgb * (1.0f / 31.0f))); |
| 295 |
} |
| 296 |
} |
| 297 |
} |
| 298 |
} |
| 299 |
|
| 300 |
|
| 301 |
|
| 302 |
for (auto r3 : xrange(8)) { |
| 303 |
int r5 = (r3 << 2) | (r3 >> 1); |
| 304 |
for (auto g3 : xrange(8)) { |
| 305 |
int g5 = (g3 << 2) | (g3 >> 1); |
| 306 |
for (auto b3 : xrange(8)) { |
| 307 |
int b5 = (b3 << 2) | (b3 >> 1); |
| 308 |
V9938_COLORS[r3][g3][b3] = |
| 309 |
V9958_COLORS[(r5 << 10) + (g5 << 5) + b5]; |
| 310 |
} |
| 311 |
} |
| 312 |
} |
| 313 |
} else { |
| 314 |
|
| 315 |
if (renderSettings.isColorMatrixIdentity()) { |
| 316 |
std::array<int, 8> intensity; |
| 317 |
for (auto [i, r] : enumerate(intensity)) { |
| 318 |
r = narrow_cast<int>(255.0f * renderSettings.transformComponent(narrow<float>(i) * (1.0f / 7.0f))); |
| 319 |
} |
| 320 |
for (auto r : xrange(8)) { |
| 321 |
for (auto g : xrange(8)) { |
| 322 |
for (auto b : xrange(8)) { |
| 323 |
V9938_COLORS[r][g][b] = |
| 324 |
screen.mapRGB255(ivec3( |
| 325 |
intensity[r], |
| 326 |
intensity[g], |
| 327 |
intensity[b])); |
| 328 |
} |
| 329 |
} |
| 330 |
} |
| 331 |
} else { |
| 332 |
for (auto r : xrange(8)) { |
| 333 |
for (auto g : xrange(8)) { |
| 334 |
for (auto b : xrange(8)) { |
| 335 |
vec3 rgb{narrow<float>(r), |
| 336 |
narrow<float>(g), |
| 337 |
narrow<float>(b)}; |
| 338 |
V9938_COLORS[r][g][b] = |
| 339 |
screen.mapRGB( |
| 340 |
renderSettings.transformRGB(rgb * (1.0f / 7.0f))); |
| 341 |
} |
| 342 |
} |
| 343 |
} |
| 344 |
} |
| 345 |
} |
| 346 |
|
| 347 |
for (auto i : xrange(256)) { |
| 348 |
PALETTE256[i] = V9938_COLORS |
| 349 |
[(i & 0x1C) >> 2] |
| 350 |
[(i & 0xE0) >> 5] |
| 351 |
[(i & 0x03) == 3 ? 7 : (i & 0x03) * 2]; |
| 352 |
} |
| 353 |
|
| 354 |
for (auto i : xrange(16)) { |
| 355 |
uint16_t grb = Renderer::GRAPHIC7_SPRITE_PALETTE[i]; |
| 356 |
palGraphic7Sprites[i] = |
| 357 |
V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7]; |
| 358 |
} |
| 359 |
} |
| 360 |
} |
| 361 |
|
| 362 |
void SDLRasterizer::precalcColorIndex0(DisplayMode mode, |
| 363 |
bool transparency, const RawFrame* superimposing, uint8_t bgColorIndex) |
| 364 |
{ |
| 365 |
|
| 366 |
if (mode.getByte() == DisplayMode::GRAPHIC7) { |
| 367 |
transparency = false; |
| 368 |
} else { |
| 369 |
bgColorIndex &= 0x0f; |
| 370 |
} |
| 371 |
|
| 372 |
int tpIndex = transparency ? bgColorIndex : 0; |
| 373 |
if (mode.getBase() != DisplayMode::GRAPHIC5) { |
| 374 |
Pixel c = (superimposing && (bgColorIndex == 0)) |
| 375 |
? screen.getKeyColor() |
| 376 |
: palBg[tpIndex]; |
| 377 |
|
| 378 |
if (palFg[0] != c) { |
| 379 |
palFg[0] = c; |
| 380 |
bitmapConverter.palette16Changed(); |
| 381 |
} |
| 382 |
} else { |
| 383 |
|
| 384 |
if ((palFg[ 0] != palBg[tpIndex >> 2]) || |
| 385 |
(palFg[16] != palBg[tpIndex & 3])) { |
| 386 |
palFg[ 0] = palBg[tpIndex >> 2]; |
| 387 |
palFg[16] = palBg[tpIndex & 3]; |
| 388 |
bitmapConverter.palette16Changed(); |
| 389 |
} |
| 390 |
} |
| 391 |
} |
| 392 |
|
| 393 |
std::pair<Pixel, Pixel> SDLRasterizer::getBorderColors() |
| 394 |
{ |
| 395 |
DisplayMode mode = vdp.getDisplayMode(); |
| 396 |
int bgColor = vdp.getBackgroundColor(); |
| 397 |
if (mode.getBase() == DisplayMode::GRAPHIC5) { |
| 398 |
|
| 399 |
|
| 400 |
return {palBg[(bgColor & 0x0C) >> 2], |
| 401 |
palBg[(bgColor & 0x03) >> 0]}; |
| 402 |
} |
| 403 |
Pixel col = [&] { |
| 404 |
if (mode.getByte() == DisplayMode::GRAPHIC7) { |
| 405 |
return PALETTE256[bgColor]; |
| 406 |
} else { |
| 407 |
if (!bgColor && vdp.isSuperimposing()) { |
| 408 |
return screen.getKeyColor(); |
| 409 |
} else { |
| 410 |
return palBg[bgColor]; |
| 411 |
} |
| 412 |
} |
| 413 |
}(); |
| 414 |
return {col, col}; |
| 415 |
} |
| 416 |
|
| 417 |
void SDLRasterizer::drawBorder( |
| 418 |
int fromX, int fromY, int limitX, int limitY) |
| 419 |
{ |
| 420 |
auto [border0, border1] = getBorderColors(); |
| 421 |
|
| 422 |
int startY = std::max(fromY - lineRenderTop, 0); |
| 423 |
int endY = std::min(limitY - lineRenderTop, 240); |
| 424 |
if ((fromX == 0) && (limitX == VDP::TICKS_PER_LINE) && |
| 425 |
(border0 == border1)) { |
| 426 |
|
| 427 |
for (auto y : xrange(startY, endY)) { |
| 428 |
workFrame->setBlank(y, border0); |
| 429 |
|
| 430 |
|
| 431 |
|
| 432 |
} |
| 433 |
} else { |
| 434 |
unsigned lineWidth = vdp.getDisplayMode().getLineWidth(); |
| 435 |
unsigned x = translateX(fromX, (lineWidth == 512)); |
| 436 |
unsigned num = translateX(limitX, (lineWidth == 512)) - x; |
| 437 |
unsigned width = (lineWidth == 512) ? 640 : 320; |
| 438 |
for (auto y : xrange(startY, endY)) { |
| 439 |
MemoryOps::fill_2(workFrame->getLineDirect(y).subspan(x, num), |
| 440 |
border0, border1); |
| 441 |
if (limitX == VDP::TICKS_PER_LINE) { |
| 442 |
|
| 443 |
|
| 444 |
|
| 445 |
|
| 446 |
|
| 447 |
workFrame->setLineWidth(y, width); |
| 448 |
} |
| 449 |
} |
| 450 |
} |
| 451 |
} |
| 452 |
|
| 453 |
void SDLRasterizer::drawDisplay( |
| 454 |
int , int fromY, |
| 455 |
int displayX, int displayY, |
| 456 |
int displayWidth, int displayHeight) |
| 457 |
{ |
| 458 |
|
| 459 |
|
| 460 |
|
| 461 |
DisplayMode mode = vdp.getDisplayMode(); |
| 462 |
unsigned lineWidth = mode.getLineWidth(); |
| 463 |
if (lineWidth == 256) { |
| 464 |
int endX = displayX + displayWidth; |
| 465 |
displayX /= 2; |
| 466 |
displayWidth = endX / 2 - displayX; |
| 467 |
} |
| 468 |
|
| 469 |
|
| 470 |
int screenLimitY = std::min( |
| 471 |
fromY + displayHeight - lineRenderTop, |
| 472 |
240); |
| 473 |
int screenY = fromY - lineRenderTop; |
| 474 |
if (screenY < 0) { |
| 475 |
displayY -= screenY; |
| 476 |
|
| 477 |
screenY = 0; |
| 478 |
} |
| 479 |
displayHeight = screenLimitY - screenY; |
| 480 |
if (displayHeight <= 0) return; |
| 481 |
|
| 482 |
int leftBackground = |
| 483 |
translateX(vdp.getLeftBackground(), lineWidth == 512); |
| 484 |
|
| 485 |
|
| 486 |
unsigned hScroll = |
| 487 |
mode.isTextMode() |
| 488 |
? 0 |
| 489 |
: 8 * (lineWidth / 256) * (vdp.getHorizontalScrollHigh() & 0x1F); |
| 490 |
|
| 491 |
|
| 492 |
|
| 493 |
|
| 494 |
|
| 495 |
|
| 496 |
int pageBorder = displayX + displayWidth; |
| 497 |
auto [scrollPage1, scrollPage2] = [&] -> std::pair<int, int> { |
| 498 |
if (vdp.isMultiPageScrolling()) { |
| 499 |
int p1 = vdp.getHorizontalScrollHigh() >> 5; |
| 500 |
int p2 = p1 ^ 1; |
| 501 |
return {p1, p2}; |
| 502 |
} else { |
| 503 |
return {0, 0}; |
| 504 |
} |
| 505 |
}(); |
| 506 |
|
| 507 |
|
| 508 |
int pageSplit = narrow<int>(lineWidth - hScroll); |
| 509 |
pageBorder = std::min(pageBorder, pageSplit); |
| 510 |
|
| 511 |
if (mode.isBitmapMode()) { |
| 512 |
for (auto y : xrange(screenY, screenLimitY)) { |
| 513 |
|
| 514 |
|
| 515 |
|
| 516 |
|
| 517 |
|
| 518 |
|
| 519 |
|
| 520 |
unsigned pageMaskOdd = (mode.isPlanar() ? 0x000 : 0x200) | |
| 521 |
vdp.getEvenOddMask(y); |
| 522 |
unsigned pageMaskEven = vdp.isMultiPageScrolling() |
| 523 |
? (pageMaskOdd & ~0x100) |
| 524 |
: pageMaskOdd; |
| 525 |
const std::array<unsigned, 2> vramLine = { |
| 526 |
(vram.nameTable.getMask() >> 7) & (pageMaskEven | displayY), |
| 527 |
(vram.nameTable.getMask() >> 7) & (pageMaskOdd | displayY) |
| 528 |
}; |
| 529 |
|
| 530 |
std::array<Pixel, 512> buf; |
| 531 |
auto lineInBuf = unsigned(-1); |
| 532 |
auto dst = workFrame->getLineDirect(y).subspan(leftBackground + displayX); |
| 533 |
int firstPageWidth = pageBorder - displayX; |
| 534 |
if (firstPageWidth > 0) { |
| 535 |
if (((displayX + hScroll) == 0) && |
| 536 |
(firstPageWidth == narrow<int>(lineWidth))) { |
| 537 |
|
| 538 |
renderBitmapLine(dst, vramLine[scrollPage1]); |
| 539 |
} else { |
| 540 |
lineInBuf = vramLine[scrollPage1]; |
| 541 |
renderBitmapLine(buf, vramLine[scrollPage1]); |
| 542 |
auto src = subspan(buf, displayX + hScroll, firstPageWidth); |
| 543 |
copy_to_range(src, dst); |
| 544 |
} |
| 545 |
} else { |
| 546 |
firstPageWidth = 0; |
| 547 |
} |
| 548 |
if (firstPageWidth < displayWidth) { |
| 549 |
if (lineInBuf != vramLine[scrollPage2]) { |
| 550 |
renderBitmapLine(buf, vramLine[scrollPage2]); |
| 551 |
} |
| 552 |
unsigned x = displayX < pageBorder |
| 553 |
? 0 : displayX + hScroll - lineWidth; |
| 554 |
copy_to_range(subspan(buf, x, displayWidth - firstPageWidth), |
| 555 |
subspan(dst, firstPageWidth)); |
| 556 |
} |
| 557 |
|
| 558 |
displayY = (displayY + 1) & 255; |
| 559 |
} |
| 560 |
} else { |
| 561 |
|
| 562 |
for (auto y : xrange(screenY, screenLimitY)) { |
| 563 |
assert(!vdp.isMSX1VDP() || displayY < 192); |
| 564 |
|
| 565 |
auto dst = workFrame->getLineDirect(y).subspan(leftBackground + displayX); |
| 566 |
if ((displayX == 0) && (displayWidth == narrow<int>(lineWidth))){ |
| 567 |
characterConverter.convertLine(dst, displayY); |
| 568 |
} else { |
| 569 |
std::array<Pixel, 512> buf; |
| 570 |
characterConverter.convertLine(buf, displayY); |
| 571 |
auto src = subspan(buf, displayX, displayWidth); |
| 572 |
copy_to_range(src, dst); |
| 573 |
} |
| 574 |
|
| 575 |
displayY = (displayY + 1) & 255; |
| 576 |
} |
| 577 |
} |
| 578 |
} |
| 579 |
|
| 580 |
void SDLRasterizer::drawSprites( |
| 581 |
int , int fromY, |
| 582 |
int displayX, int , |
| 583 |
int displayWidth, int displayHeight) |
| 584 |
{ |
| 585 |
|
| 586 |
|
| 587 |
int screenLimitY = std::min( |
| 588 |
fromY + displayHeight - lineRenderTop, |
| 589 |
240); |
| 590 |
int screenY = fromY - lineRenderTop; |
| 591 |
if (screenY < 0) { |
| 592 |
fromY = lineRenderTop; |
| 593 |
screenY = 0; |
| 594 |
} |
| 595 |
displayHeight = screenLimitY - screenY; |
| 596 |
if (displayHeight <= 0) return; |
| 597 |
|
| 598 |
|
| 599 |
|
| 600 |
|
| 601 |
int spriteMode = vdp.getDisplayMode().getSpriteMode(vdp.isMSX1VDP()); |
| 602 |
int displayLimitX = displayX + displayWidth; |
| 603 |
int limitY = fromY + displayHeight; |
| 604 |
int screenX = translateX( |
| 605 |
vdp.getLeftSprites(), |
| 606 |
vdp.getDisplayMode().getLineWidth() == 512); |
| 607 |
if (spriteMode == 1) { |
| 608 |
for (int y = fromY; y < limitY; y++, screenY++) { |
| 609 |
auto dst = workFrame->getLineDirect(screenY).subspan(screenX); |
| 610 |
spriteConverter.drawMode1(y, displayX, displayLimitX, dst); |
| 611 |
} |
| 612 |
} else { |
| 613 |
uint8_t mode = vdp.getDisplayMode().getByte(); |
| 614 |
if (mode == DisplayMode::GRAPHIC5) { |
| 615 |
for (int y = fromY; y < limitY; y++, screenY++) { |
| 616 |
auto dst = workFrame->getLineDirect(screenY).subspan(screenX); |
| 617 |
spriteConverter.template drawMode2<DisplayMode::GRAPHIC5>( |
| 618 |
y, displayX, displayLimitX, dst); |
| 619 |
} |
| 620 |
} else if (mode == DisplayMode::GRAPHIC6) { |
| 621 |
for (int y = fromY; y < limitY; y++, screenY++) { |
| 622 |
auto dst = workFrame->getLineDirect(screenY).subspan(screenX); |
| 623 |
spriteConverter.template drawMode2<DisplayMode::GRAPHIC6>( |
| 624 |
y, displayX, displayLimitX, dst); |
| 625 |
} |
| 626 |
} else { |
| 627 |
for (int y = fromY; y < limitY; y++, screenY++) { |
| 628 |
auto dst = workFrame->getLineDirect(screenY).subspan(screenX); |
| 629 |
spriteConverter.template drawMode2<DisplayMode::GRAPHIC4>( |
| 630 |
y, displayX, displayLimitX, dst); |
| 631 |
} |
| 632 |
} |
| 633 |
} |
| 634 |
} |
| 635 |
|
| 636 |
bool SDLRasterizer::isRecording() const |
| 637 |
{ |
| 638 |
return postProcessor->isRecording(); |
| 639 |
} |
| 640 |
|
| 641 |
void SDLRasterizer::update(const Setting& setting) noexcept |
| 642 |
{ |
| 643 |
if (&setting == one_of(&renderSettings.getGammaSetting(), |
| 644 |
&renderSettings.getBrightnessSetting(), |
| 645 |
&renderSettings.getContrastSetting(), |
| 646 |
&renderSettings.getColorMatrixSetting())) { |
| 647 |
precalcPalette(); |
| 648 |
resetPalette(); |
| 649 |
} |
| 650 |
} |
| 651 |
|
| 652 |
} |