DS: Move graphics code into a separate file

This commit is contained in:
Cameron Cawley 2020-09-15 23:29:55 +01:00 committed by Eugene Sandulenko
parent 1c40d79732
commit 626b6ac4e9
7 changed files with 664 additions and 693 deletions

View File

@ -23,7 +23,7 @@
#include <nds.h>
#include "backends/events/ds/ds-events.h"
#include "osystem_ds.h"
#include "backends/platform/ds/osystem_ds.h"
bool DSEventSource::pollEvent(Common::Event &event) {
if (_eventQueue.empty()) {

View File

@ -0,0 +1,653 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <nds.h>
#include "backends/platform/ds/osystem_ds.h"
#include "backends/platform/ds/blitters.h"
#include "common/translation.h"
namespace DS {
// From console.c in NDSLib
// Defines
#define SCUMM_GAME_HEIGHT 142
#define SCUMM_GAME_WIDTH 227
// Scaled
static int scX;
static int scY;
static int subScX;
static int subScY;
static int subScTargetX;
static int subScTargetY;
static int subScreenWidth = SCUMM_GAME_WIDTH;
static int subScreenHeight = SCUMM_GAME_HEIGHT;
static int subScreenScale = 256;
static bool gameScreenSwap = false;
// Shake
static int s_shakeXOffset = 0;
static int s_shakeYOffset = 0;
// Touch
static int touchScX, touchScY, touchX, touchY;
// 8-bit surface size
static int gameWidth = 320;
static int gameHeight = 200;
void setGameScreenSwap(bool enable) {
gameScreenSwap = enable;
}
void setTopScreenZoom(int percentage) {
s32 scale = (percentage << 8) / 100;
subScreenScale = (256 * 256) / scale;
}
void setTopScreenTarget(int x, int y) {
subScTargetX = (x - (subScreenWidth >> 1));
subScTargetY = (y - (subScreenHeight >> 1));
if (subScTargetX < 0) subScTargetX = 0;
if (subScTargetX > gameWidth - subScreenWidth) subScTargetX = gameWidth - subScreenWidth;
if (subScTargetY < 0) subScTargetY = 0;
if (subScTargetY > gameHeight - subScreenHeight) subScTargetY = gameHeight - subScreenHeight;
subScTargetX <<=8;
subScTargetY <<=8;
}
void setGameSize(int width, int height) {
gameWidth = width;
gameHeight = height;
}
int getGameWidth() {
return gameWidth;
}
int getGameHeight() {
return gameHeight;
}
void displayMode8Bit() {
vramSetBankB(VRAM_B_MAIN_BG_0x06020000);
if (g_system->getGraphicsMode() == GFX_SWSCALE) {
REG_BG3CNT = BG_BMP16_256x256 | BG_BMP_BASE(8);
REG_BG3PA = 256;
REG_BG3PB = 0;
REG_BG3PC = 0;
REG_BG3PD = (int) ((200.0f / 192.0f) * 256);
} else {
REG_BG3CNT = BG_BMP8_512x256 | BG_BMP_BASE(8);
REG_BG3PA = (int) (((float) (gameWidth) / 256.0f) * 256);
REG_BG3PB = 0;
REG_BG3PC = 0;
REG_BG3PD = (int) ((200.0f / 192.0f) * 256);
}
#ifdef DISABLE_TEXT_CONSOLE
REG_BG3CNT_SUB = BG_BMP8_512x256;
REG_BG3PA_SUB = (int) (subScreenWidth / 256.0f * 256);
REG_BG3PB_SUB = 0;
REG_BG3PC_SUB = 0;
REG_BG3PD_SUB = (int) (subScreenHeight / 192.0f * 256);
#endif
if (gameScreenSwap) {
lcdMainOnTop();
} else {
lcdMainOnBottom();
}
}
void setShakePos(int shakeXOffset, int shakeYOffset) {
s_shakeXOffset = shakeXOffset;
s_shakeYOffset = shakeYOffset;
}
Common::Point warpMouse(int penX, int penY, bool isOverlayShown) {
int storedMouseX, storedMouseY;
if (!isOverlayShown) {
storedMouseX = ((penX - touchX) << 8) / touchScX;
storedMouseY = ((penY - touchY) << 8) / touchScY;
} else {
storedMouseX = penX;
storedMouseY = penY;
}
return Common::Point(storedMouseX, storedMouseY);
}
void setMainScreenScroll(int x, int y) {
REG_BG3X = x;
REG_BG3Y = y;
if (!gameScreenSwap) {
touchX = x >> 8;
touchY = y >> 8;
}
}
void setMainScreenScale(int x, int y) {
if ((g_system->getGraphicsMode() == GFX_SWSCALE) && (x==320)) {
REG_BG3PA = 256;
REG_BG3PB = 0;
REG_BG3PC = 0;
REG_BG3PD = y;
} else {
REG_BG3PA = x;
REG_BG3PB = 0;
REG_BG3PC = 0;
REG_BG3PD = y;
}
if (!gameScreenSwap) {
touchScX = x;
touchScY = y;
}
}
void setZoomedScreenScroll(int x, int y, bool shake) {
if (gameScreenSwap) {
touchX = x >> 8;
touchY = y >> 8;
}
#ifdef DISABLE_TEXT_CONSOLE
REG_BG3X_SUB = x;
REG_BG3Y_SUB = y;
#endif
}
void setZoomedScreenScale(int x, int y) {
if (gameScreenSwap) {
touchScX = x;
touchScY = y;
}
#ifdef DISABLE_TEXT_CONSOLE
REG_BG3PA_SUB = x;
REG_BG3PB_SUB = 0;
REG_BG3PC_SUB = 0;
REG_BG3PD_SUB = y;
#endif
}
Common::Point transformPoint(uint16 x, uint16 y, bool isOverlayShown) {
if (!isOverlayShown) {
x = ((x * touchScX) >> 8) + touchX;
x = CLIP<uint16>(x, 0, gameWidth - 1);
y = ((y * touchScY) >> 8) + touchY;
y = CLIP<uint16>(y, 0, gameHeight - 1);
}
return Common::Point(x, y);
}
void VBlankHandler(void) {
int xCenter = subScTargetX + ((subScreenWidth >> 1) << 8);
int yCenter = subScTargetY + ((subScreenHeight >> 1) << 8);
subScreenWidth = (256 * subScreenScale) >> 8;
subScreenHeight = (192 * subScreenScale) >> 8;
if ( ((subScreenWidth) > 256 - 8) && ((subScreenWidth) < 256 + 8) ) {
subScreenWidth = 256;
subScreenHeight = 192;
} else if ( ((subScreenWidth) > 128 - 8) && ((subScreenWidth) < 128 + 8) ) {
subScreenWidth = 128;
subScreenHeight = 96;
} else if (subScreenWidth > 256) {
subScreenWidth = 320;
subScreenHeight = 200;
}
subScTargetX = xCenter - ((subScreenWidth >> 1) << 8);
subScTargetY = yCenter - ((subScreenHeight >> 1) << 8);
subScTargetX = CLIP(subScTargetX, 0, (gameWidth - subScreenWidth) << 8);
subScTargetY = CLIP(subScTargetY, 0, (gameHeight - subScreenHeight) << 8);
subScX += (subScTargetX - subScX) >> 2;
subScY += (subScTargetY - subScY) >> 2;
if (g_system->getGraphicsMode() == GFX_NOSCALE) {
if (scX + 256 > gameWidth - 1) {
scX = gameWidth - 1 - 256;
}
if (scX < 0) {
scX = 0;
}
if (scY + 192 > gameHeight - 1) {
scY = gameHeight - 1 - 192;
}
if (scY < 0) {
scY = 0;
}
setZoomedScreenScroll(subScX, subScY, (subScreenWidth != 256) && (subScreenWidth != 128));
setZoomedScreenScale(subScreenWidth, ((subScreenHeight * (256 << 8)) / 192) >> 8);
setMainScreenScroll((scX << 8) + (s_shakeXOffset << 8), (scY << 8) + (s_shakeYOffset << 8));
setMainScreenScale(256, 256); // 1:1 scale
} else {
if (scY > gameHeight - 192 - 1) {
scY = gameHeight - 192 - 1;
}
if (scY < 0) {
scY = 0;
}
setZoomedScreenScroll(subScX, subScY, (subScreenWidth != 256) && (subScreenWidth != 128));
setZoomedScreenScale(subScreenWidth, ((subScreenHeight * (256 << 8)) / 192) >> 8);
setMainScreenScroll(64 + (s_shakeXOffset << 8), (scY << 8) + (s_shakeYOffset << 8));
setMainScreenScale(320, 256); // 1:1 scale
}
}
void setTalkPos(int x, int y) {
setTopScreenTarget(x, y);
}
void initHardware() {
powerOn(POWER_ALL);
for (int r = 0; r < 255; r++) {
BG_PALETTE[r] = 0;
}
videoSetMode(MODE_5_2D | DISPLAY_BG3_ACTIVE);
vramSetBankA(VRAM_A_MAIN_BG_0x06000000);
vramSetBankE(VRAM_E_MAIN_SPRITE);
REG_BG2CNT = BG_BMP16_256x256;
REG_BG2PA = 256;
REG_BG2PB = 0;
REG_BG2PC = 0;
REG_BG2PD = 256;
scX = 0;
scY = 0;
subScX = 0;
subScY = 0;
subScTargetX = 0;
subScTargetY = 0;
lcdMainOnBottom();
//irqs are nice
irqSet(IRQ_VBLANK, VBlankHandler);
irqEnable(IRQ_VBLANK);
#ifndef DISABLE_TEXT_CONSOLE
videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);
vramSetBankH(VRAM_H_SUB_BG);
consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true);
#else
videoSetModeSub(MODE_3_2D | DISPLAY_BG3_ACTIVE);
vramSetBankC(VRAM_C_SUB_BG_0x06200000);
#endif
}
}
void OSystem_DS::initGraphics() {
DS::initHardware();
oamInit(&oamMain, SpriteMapping_Bmp_1D_128, false);
_cursorSprite = oamAllocateGfx(&oamMain, SpriteSize_64x64, SpriteColorFormat_Bmp);
_overlay.create(256, 192, Graphics::PixelFormat(2, 5, 5, 5, 1, 0, 5, 10, 15));
}
bool OSystem_DS::hasFeature(Feature f) {
return (f == kFeatureCursorPalette) || (f == kFeatureStretchMode);
}
void OSystem_DS::setFeatureState(Feature f, bool enable) {
if (f == kFeatureCursorPalette) {
_disableCursorPalette = !enable;
refreshCursor(_cursorSprite, _cursor, !_disableCursorPalette ? _cursorPalette : _palette);
}
}
bool OSystem_DS::getFeatureState(Feature f) {
if (f == kFeatureCursorPalette)
return !_disableCursorPalette;
return false;
}
static const OSystem::GraphicsMode graphicsModes[] = {
{ "NONE", _s("Unscaled"), GFX_NOSCALE },
{ "HW", _s("Hardware scale (fast, but low quality)"), GFX_HWSCALE },
{ "SW", _s("Software scale (good quality, but slower)"), GFX_SWSCALE },
{ nullptr, nullptr, 0 }
};
const OSystem::GraphicsMode *OSystem_DS::getSupportedGraphicsModes() const {
return graphicsModes;
}
int OSystem_DS::getDefaultGraphicsMode() const {
return GFX_HWSCALE;
}
bool OSystem_DS::setGraphicsMode(int mode) {
switch (mode) {
case GFX_NOSCALE:
case GFX_HWSCALE:
case GFX_SWSCALE:
_graphicsMode = mode;
return true;
default:
return false;
}
}
int OSystem_DS::getGraphicsMode() const {
return _graphicsMode;
}
static const OSystem::GraphicsMode stretchModes[] = {
{ "100", "100%", 100 },
{ "150", "150%", 150 },
{ "200", "200%", 200 },
{ nullptr, nullptr, 0 }
};
const OSystem::GraphicsMode *OSystem_DS::getSupportedStretchModes() const {
return stretchModes;
}
int OSystem_DS::getDefaultStretchMode() const {
return 100;
}
bool OSystem_DS::setStretchMode(int mode) {
_stretchMode = mode;
DS::setTopScreenZoom(mode);
return true;
}
int OSystem_DS::getStretchMode() const {
return _stretchMode;
}
void OSystem_DS::initSize(uint width, uint height, const Graphics::PixelFormat *format) {
_framebuffer.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
// For Lost in Time, the title screen is displayed in 640x400.
// In order to support this game, the screen mode is set, but
// all draw calls are ignored until the game switches to 320x200.
if ((width == 640) && (height == 400)) {
_graphicsEnable = false;
} else {
_graphicsEnable = true;
DS::setGameSize(width, height);
}
}
int16 OSystem_DS::getHeight() {
return _framebuffer.h;
}
int16 OSystem_DS::getWidth() {
return _framebuffer.w;
}
void OSystem_DS::setPalette(const byte *colors, uint start, uint num) {
for (unsigned int r = start; r < start + num; r++) {
int red = *colors;
int green = *(colors + 1);
int blue = *(colors + 2);
red >>= 3;
green >>= 3;
blue >>= 3;
{
u16 paletteValue = red | (green << 5) | (blue << 10);
if (!_isOverlayShown) {
BG_PALETTE[r] = paletteValue;
#ifdef DISABLE_TEXT_CONSOLE
BG_PALETTE_SUB[r] = paletteValue;
#endif
}
_palette[r] = paletteValue;
}
colors += 3;
}
}
void OSystem_DS::setCursorPalette(const byte *colors, uint start, uint num) {
for (unsigned int r = start; r < start + num; r++) {
int red = *colors;
int green = *(colors + 1);
int blue = *(colors + 2);
red >>= 3;
green >>= 3;
blue >>= 3;
u16 paletteValue = red | (green << 5) | (blue << 10);
_cursorPalette[r] = paletteValue;
colors += 3;
}
_disableCursorPalette = false;
refreshCursor(_cursorSprite, _cursor, !_disableCursorPalette ? _cursorPalette : _palette);
}
void OSystem_DS::grabPalette(unsigned char *colors, uint start, uint num) const {
for (unsigned int r = start; r < start + num; r++) {
*colors++ = (BG_PALETTE[r] & 0x001F) << 3;
*colors++ = (BG_PALETTE[r] & 0x03E0) >> 5 << 3;
*colors++ = (BG_PALETTE[r] & 0x7C00) >> 10 << 3;
}
}
void OSystem_DS::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) {
_framebuffer.copyRectToSurface(buf, pitch, x, y, w, h);
}
void OSystem_DS::updateScreen() {
oamSet(&oamMain, 0, _cursorPos.x - _cursorHotX, _cursorPos.y - _cursorHotY, 0, 15, SpriteSize_64x64,
SpriteColorFormat_Bmp, _cursorSprite, 0, false, !_cursorVisible, false, false, false);
oamUpdate(&oamMain);
if (_isOverlayShown) {
u16 *back = (u16 *)_overlay.getPixels();
dmaCopyHalfWords(3, back, BG_GFX, 256 * 192 * 2);
} else if (!_graphicsEnable) {
return;
} else if (_graphicsMode == GFX_SWSCALE) {
u16 *base = BG_GFX + 0x10000;
Rescale_320x256xPAL8_To_256x256x1555(
base,
(const u8 *)_framebuffer.getPixels(),
256,
_framebuffer.pitch,
BG_PALETTE,
_framebuffer.h );
} else {
// The DS video RAM doesn't support 8-bit writes because Nintendo wanted
// to save a few pennies/euro cents on the hardware.
u16 *bg = BG_GFX + 0x10000;
s32 stride = 512;
u16 *src = (u16 *)_framebuffer.getPixels();
for (int dy = 0; dy < _framebuffer.h; dy++) {
DC_FlushRange(src, _framebuffer.w << 1);
u16 *dest1 = bg + (dy * (stride >> 1));
DC_FlushRange(dest1, _framebuffer.w << 1);
#ifdef DISABLE_TEXT_CONSOLE
u16 *dest2 = (u16 *)BG_GFX_SUB + (dy << 8);
DC_FlushRange(dest2, _framebuffer.w << 1);
dmaCopyHalfWordsAsynch(2, src, dest2, _framebuffer.w);
#endif
dmaCopyHalfWordsAsynch(3, src, dest1, _framebuffer.w);
while (dmaBusy(2) || dmaBusy(3));
src += _framebuffer.pitch >> 1;
}
}
}
void OSystem_DS::setShakePos(int shakeXOffset, int shakeYOffset) {
DS::setShakePos(shakeXOffset, shakeYOffset);
}
void OSystem_DS::showOverlay() {
dmaFillHalfWords(0, BG_GFX, 256 * 192 * 2);
videoBgEnable(2);
lcdMainOnBottom();
_isOverlayShown = true;
}
void OSystem_DS::hideOverlay() {
videoBgDisable(2);
DS::displayMode8Bit();
_isOverlayShown = false;
}
bool OSystem_DS::isOverlayVisible() const {
return _isOverlayShown;
}
void OSystem_DS::clearOverlay() {
memset(_overlay.getPixels(), 0, _overlay.pitch * _overlay.h);
}
void OSystem_DS::grabOverlay(void *buf, int pitch) {
byte *dst = (byte *)buf;
for (int y = 0; y < _overlay.h; ++y) {
memcpy(dst, _overlay.getBasePtr(0, y), _overlay.w * _overlay.format.bytesPerPixel);
dst += pitch;
}
}
void OSystem_DS::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) {
_overlay.copyRectToSurface(buf, pitch, x, y, w, h);
}
int16 OSystem_DS::getOverlayHeight() {
return _overlay.h;
}
int16 OSystem_DS::getOverlayWidth() {
return _overlay.w;
}
Graphics::PixelFormat OSystem_DS::getOverlayFormat() const {
return _overlay.format;
}
Common::Point OSystem_DS::transformPoint(uint16 x, uint16 y) {
return DS::transformPoint(x, y, _isOverlayShown);
}
bool OSystem_DS::showMouse(bool visible) {
const bool last = _cursorVisible;
_cursorVisible = visible;
return last;
}
void OSystem_DS::warpMouse(int x, int y) {
_cursorPos = DS::warpMouse(x, y, _isOverlayShown);
}
void OSystem_DS::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, u32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
if (!buf || w == 0 || h == 0 || (format && *format != Graphics::PixelFormat::createFormatCLUT8()))
return;
if (_cursor.w != w || _cursor.h != h)
_cursor.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
_cursor.copyRectToSurface(buf, w, 0, 0, w, h);
_cursorHotX = hotspotX;
_cursorHotY = hotspotY;
_cursorKey = keycolor;
refreshCursor(_cursorSprite, _cursor, !_disableCursorPalette ? _cursorPalette : _palette);
}
void OSystem_DS::refreshCursor(u16 *dst, const Graphics::Surface &src, const uint16 *palette) {
uint w = MIN<uint>(src.w, 64);
uint h = MIN<uint>(src.h, 64);
dmaFillHalfWords(0, dst, 64 * 64 * 2);
for (uint y = 0; y < h; y++) {
const uint8 *row = (const uint8 *)src.getBasePtr(0, y);
for (uint x = 0; x < w; x++) {
uint8 color = *row++;
if (color != _cursorKey)
dst[y * 64 + x] = palette[color] | 0x8000;
}
}
}
Graphics::Surface *OSystem_DS::lockScreen() {
return &_framebuffer;
}
void OSystem_DS::unlockScreen() {
// No need to do anything here. The screen will be updated in updateScreen().
}
void OSystem_DS::setFocusRectangle(const Common::Rect& rect) {
DS::setTalkPos(rect.left + rect.width() / 2, rect.top + rect.height() / 2);
}
void OSystem_DS::clearFocusRectangle() {
}

View File

@ -65,327 +65,12 @@
// - Memory size for ite
// - Try discworld?
// Allow use of stuff in <nds.h>
#define FORBIDDEN_SYMBOL_EXCEPTION_printf
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
#include <nds.h>
#include <filesystem.h>
#include <stdlib.h>
#include <string.h>
#include "dsmain.h"
#include "osystem_ds.h"
#include "engines/engine.h"
#include "backends/platform/ds/osystem_ds.h"
#include "backends/plugins/ds/ds-provider.h"
#include "base/main.h"
#include "base/version.h"
#include "common/util.h"
namespace DS {
// From console.c in NDSLib
// Defines
#define SCUMM_GAME_HEIGHT 142
#define SCUMM_GAME_WIDTH 227
// Scaled
static int scX;
static int scY;
static int subScX;
static int subScY;
static int subScTargetX;
static int subScTargetY;
static int subScreenWidth = SCUMM_GAME_WIDTH;
static int subScreenHeight = SCUMM_GAME_HEIGHT;
static int subScreenScale = 256;
static bool gameScreenSwap = false;
// Shake
static int s_shakeXOffset = 0;
static int s_shakeYOffset = 0;
// Touch
static int touchScX, touchScY, touchX, touchY;
// 8-bit surface size
static int gameWidth = 320;
static int gameHeight = 200;
void setGameScreenSwap(bool enable) {
gameScreenSwap = enable;
}
void setTopScreenZoom(int percentage) {
s32 scale = (percentage << 8) / 100;
subScreenScale = (256 * 256) / scale;
}
void setGameSize(int width, int height) {
gameWidth = width;
gameHeight = height;
}
int getGameWidth() {
return gameWidth;
}
int getGameHeight() {
return gameHeight;
}
void displayMode8Bit() {
vramSetBankB(VRAM_B_MAIN_BG_0x06020000);
if (g_system->getGraphicsMode() == GFX_SWSCALE) {
REG_BG3CNT = BG_BMP16_256x256 | BG_BMP_BASE(8);
REG_BG3PA = 256;
REG_BG3PB = 0;
REG_BG3PC = 0;
REG_BG3PD = (int) ((200.0f / 192.0f) * 256);
} else {
REG_BG3CNT = BG_BMP8_512x256 | BG_BMP_BASE(8);
REG_BG3PA = (int) (((float) (gameWidth) / 256.0f) * 256);
REG_BG3PB = 0;
REG_BG3PC = 0;
REG_BG3PD = (int) ((200.0f / 192.0f) * 256);
}
#ifdef DISABLE_TEXT_CONSOLE
REG_BG3CNT_SUB = BG_BMP8_512x256;
REG_BG3PA_SUB = (int) (subScreenWidth / 256.0f * 256);
REG_BG3PB_SUB = 0;
REG_BG3PC_SUB = 0;
REG_BG3PD_SUB = (int) (subScreenHeight / 192.0f * 256);
#endif
if (gameScreenSwap) {
lcdMainOnTop();
} else {
lcdMainOnBottom();
}
}
void setShakePos(int shakeXOffset, int shakeYOffset) {
s_shakeXOffset = shakeXOffset;
s_shakeYOffset = shakeYOffset;
}
Common::Point warpMouse(int penX, int penY, bool isOverlayShown) {
int storedMouseX, storedMouseY;
if (!isOverlayShown) {
storedMouseX = ((penX - touchX) << 8) / touchScX;
storedMouseY = ((penY - touchY) << 8) / touchScY;
} else {
storedMouseX = penX;
storedMouseY = penY;
}
return Common::Point(storedMouseX, storedMouseY);
}
void setMainScreenScroll(int x, int y) {
REG_BG3X = x;
REG_BG3Y = y;
if (!gameScreenSwap) {
touchX = x >> 8;
touchY = y >> 8;
}
}
void setMainScreenScale(int x, int y) {
if ((g_system->getGraphicsMode() == GFX_SWSCALE) && (x==320)) {
REG_BG3PA = 256;
REG_BG3PB = 0;
REG_BG3PC = 0;
REG_BG3PD = y;
} else {
REG_BG3PA = x;
REG_BG3PB = 0;
REG_BG3PC = 0;
REG_BG3PD = y;
}
if (!gameScreenSwap) {
touchScX = x;
touchScY = y;
}
}
void setZoomedScreenScroll(int x, int y, bool shake) {
if (gameScreenSwap) {
touchX = x >> 8;
touchY = y >> 8;
}
#ifdef DISABLE_TEXT_CONSOLE
REG_BG3X_SUB = x;
REG_BG3Y_SUB = y;
#endif
}
void setZoomedScreenScale(int x, int y) {
if (gameScreenSwap) {
touchScX = x;
touchScY = y;
}
#ifdef DISABLE_TEXT_CONSOLE
REG_BG3PA_SUB = x;
REG_BG3PB_SUB = 0;
REG_BG3PC_SUB = 0;
REG_BG3PD_SUB = y;
#endif
}
Common::Point transformPoint(uint16 x, uint16 y, bool isOverlayShown) {
if (!isOverlayShown) {
x = ((x * touchScX) >> 8) + touchX;
x = CLIP<uint16>(x, 0, gameWidth - 1);
y = ((y * touchScY) >> 8) + touchY;
y = CLIP<uint16>(y, 0, gameHeight - 1);
}
return Common::Point(x, y);
}
void VBlankHandler(void) {
int xCenter = subScTargetX + ((subScreenWidth >> 1) << 8);
int yCenter = subScTargetY + ((subScreenHeight >> 1) << 8);
subScreenWidth = (256 * subScreenScale) >> 8;
subScreenHeight = (192 * subScreenScale) >> 8;
if ( ((subScreenWidth) > 256 - 8) && ((subScreenWidth) < 256 + 8) ) {
subScreenWidth = 256;
subScreenHeight = 192;
} else if ( ((subScreenWidth) > 128 - 8) && ((subScreenWidth) < 128 + 8) ) {
subScreenWidth = 128;
subScreenHeight = 96;
} else if (subScreenWidth > 256) {
subScreenWidth = 320;
subScreenHeight = 200;
}
subScTargetX = xCenter - ((subScreenWidth >> 1) << 8);
subScTargetY = yCenter - ((subScreenHeight >> 1) << 8);
subScTargetX = CLIP(subScTargetX, 0, (gameWidth - subScreenWidth) << 8);
subScTargetY = CLIP(subScTargetY, 0, (gameHeight - subScreenHeight) << 8);
subScX += (subScTargetX - subScX) >> 2;
subScY += (subScTargetY - subScY) >> 2;
if (g_system->getGraphicsMode() == GFX_NOSCALE) {
if (scX + 256 > gameWidth - 1) {
scX = gameWidth - 1 - 256;
}
if (scX < 0) {
scX = 0;
}
if (scY + 192 > gameHeight - 1) {
scY = gameHeight - 1 - 192;
}
if (scY < 0) {
scY = 0;
}
setZoomedScreenScroll(subScX, subScY, (subScreenWidth != 256) && (subScreenWidth != 128));
setZoomedScreenScale(subScreenWidth, ((subScreenHeight * (256 << 8)) / 192) >> 8);
setMainScreenScroll((scX << 8) + (s_shakeXOffset << 8), (scY << 8) + (s_shakeYOffset << 8));
setMainScreenScale(256, 256); // 1:1 scale
} else {
if (scY > gameHeight - 192 - 1) {
scY = gameHeight - 192 - 1;
}
if (scY < 0) {
scY = 0;
}
setZoomedScreenScroll(subScX, subScY, (subScreenWidth != 256) && (subScreenWidth != 128));
setZoomedScreenScale(subScreenWidth, ((subScreenHeight * (256 << 8)) / 192) >> 8);
setMainScreenScroll(64 + (s_shakeXOffset << 8), (scY << 8) + (s_shakeYOffset << 8));
setMainScreenScale(320, 256); // 1:1 scale
}
}
void setTalkPos(int x, int y) {
setTopScreenTarget(x, y);
}
void setTopScreenTarget(int x, int y) {
subScTargetX = (x - (subScreenWidth >> 1));
subScTargetY = (y - (subScreenHeight >> 1));
if (subScTargetX < 0) subScTargetX = 0;
if (subScTargetX > gameWidth - subScreenWidth) subScTargetX = gameWidth - subScreenWidth;
if (subScTargetY < 0) subScTargetY = 0;
if (subScTargetY > gameHeight - subScreenHeight) subScTargetY = gameHeight - subScreenHeight;
subScTargetX <<=8;
subScTargetY <<=8;
}
void initHardware() {
powerOn(POWER_ALL);
for (int r = 0; r < 255; r++) {
BG_PALETTE[r] = 0;
}
videoSetMode(MODE_5_2D | DISPLAY_BG3_ACTIVE);
vramSetBankA(VRAM_A_MAIN_BG_0x06000000);
vramSetBankE(VRAM_E_MAIN_SPRITE);
REG_BG2CNT = BG_BMP16_256x256;
REG_BG2PA = 256;
REG_BG2PB = 0;
REG_BG2PC = 0;
REG_BG2PD = 256;
scX = 0;
scY = 0;
subScX = 0;
subScY = 0;
subScTargetX = 0;
subScTargetY = 0;
lcdMainOnBottom();
//irqs are nice
irqSet(IRQ_VBLANK, VBlankHandler);
irqEnable(IRQ_VBLANK);
#ifndef DISABLE_TEXT_CONSOLE
videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);
vramSetBankH(VRAM_H_SUB_BG);
consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true);
#else
videoSetModeSub(MODE_3_2D | DISPLAY_BG3_ACTIVE);
vramSetBankC(VRAM_C_SUB_BG_0x06200000);
#endif
}
///////////////////
// Fast Ram
///////////////////

View File

@ -23,51 +23,14 @@
#ifndef _DSMAIN_H
#define _DSMAIN_H
#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include <nds.h>
#include "osystem_ds.h"
#include "common/scummsys.h"
namespace DS {
// Video
void displayMode8Bit(); // Switch to 8-bit mode5
void displayMode16Bit(); // Switch to 16-bit mode5
// Get address of current back buffer
u16 * get16BitBackBuffer();
void setTalkPos(int x, int y);
void setTopScreenTarget(int x, int y);
void setTopScreenZoom(int percentage);
// Events
void VBlankHandler();
Common::Point transformPoint(uint16 x, uint16 y, bool isOverlayShown);
Common::Point warpMouse(int penX, int penY, bool isOverlayShown);
// Shake
void setShakePos(int shakeXOffset, int shakeYOffset);
// Options
void setGameScreenSwap(bool enable);
// Display
bool getIsDisplayMode8Bit();
void setGameSize(int width, int height);
int getGameWidth();
int getGameHeight();
void initHardware();
// Fast RAM allocation (ITCM)
void fastRamReset();
void* fastRamAlloc(int size);
} // End of namespace DS
int cygprofile_getHBlanks();
#endif

View File

@ -2,6 +2,7 @@ MODULE := backends/platform/ds
MODULE_OBJS := \
blitters_arm.o \
ds-graphics.o \
dsmain.o \
osystem_ds.o

View File

@ -20,35 +20,21 @@
*
*/
// Allow use of stuff in <time.h>
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
// Allow use of stuff in <nds.h>
#define FORBIDDEN_SYMBOL_EXCEPTION_printf
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
#include <nds.h>
#include <filesystem.h>
#include "common/scummsys.h"
#include "common/system.h"
#include "backends/platform/ds/osystem_ds.h"
#include "common/util.h"
#include "common/rect.h"
#include "common/savefile.h"
#include "common/translation.h"
#include "osystem_ds.h"
#include "dsmain.h"
#include "blitters.h"
#include "common/config-manager.h"
#include "common/str.h"
#include "graphics/surface.h"
#include "backends/fs/devoptab/devoptab-fs-factory.h"
#include "backends/keymapper/hardware-input.h"
#include "common/translation.h"
#include "backends/audiocd/default/default-audiocd.h"
#include "backends/events/default/default-events.h"
#include "backends/fs/devoptab/devoptab-fs-factory.h"
#include "backends/keymapper/hardware-input.h"
#include "backends/mixer/maxmod/maxmod-mixer.h"
#include "backends/mutex/null/null-mutex.h"
#include "backends/saves/default/default-saves.h"
@ -83,7 +69,7 @@ void timerTickHandler() {
}
void OSystem_DS::initBackend() {
DS::initHardware();
initGraphics();
defaultExceptionHandler();
@ -100,312 +86,9 @@ void OSystem_DS::initBackend() {
_mixerManager = new MaxModMixerManager(11025, 4096);
_mixerManager->init();
oamInit(&oamMain, SpriteMapping_Bmp_1D_128, false);
_cursorSprite = oamAllocateGfx(&oamMain, SpriteSize_64x64, SpriteColorFormat_Bmp);
_overlay.create(256, 192, Graphics::PixelFormat(2, 5, 5, 5, 1, 0, 5, 10, 15));
BaseBackend::initBackend();
}
bool OSystem_DS::hasFeature(Feature f) {
return (f == kFeatureCursorPalette) || (f == kFeatureStretchMode);
}
void OSystem_DS::setFeatureState(Feature f, bool enable) {
if (f == kFeatureCursorPalette) {
_disableCursorPalette = !enable;
refreshCursor(_cursorSprite, _cursor, !_disableCursorPalette ? _cursorPalette : _palette);
}
}
bool OSystem_DS::getFeatureState(Feature f) {
if (f == kFeatureCursorPalette)
return !_disableCursorPalette;
return false;
}
static const OSystem::GraphicsMode graphicsModes[] = {
{ "NONE", _s("Unscaled"), GFX_NOSCALE },
{ "HW", _s("Hardware scale (fast, but low quality)"), GFX_HWSCALE },
{ "SW", _s("Software scale (good quality, but slower)"), GFX_SWSCALE },
{ nullptr, nullptr, 0 }
};
const OSystem::GraphicsMode *OSystem_DS::getSupportedGraphicsModes() const {
return graphicsModes;
}
int OSystem_DS::getDefaultGraphicsMode() const {
return GFX_HWSCALE;
}
bool OSystem_DS::setGraphicsMode(int mode) {
switch (mode) {
case GFX_NOSCALE:
case GFX_HWSCALE:
case GFX_SWSCALE:
_graphicsMode = mode;
return true;
default:
return false;
}
}
int OSystem_DS::getGraphicsMode() const {
return _graphicsMode;
}
static const OSystem::GraphicsMode stretchModes[] = {
{ "100", "100%", 100 },
{ "150", "150%", 150 },
{ "200", "200%", 200 },
{ nullptr, nullptr, 0 }
};
const OSystem::GraphicsMode *OSystem_DS::getSupportedStretchModes() const {
return stretchModes;
}
int OSystem_DS::getDefaultStretchMode() const {
return 100;
}
bool OSystem_DS::setStretchMode(int mode) {
_stretchMode = mode;
DS::setTopScreenZoom(mode);
return true;
}
int OSystem_DS::getStretchMode() const {
return _stretchMode;
}
void OSystem_DS::initSize(uint width, uint height, const Graphics::PixelFormat *format) {
_framebuffer.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
// For Lost in Time, the title screen is displayed in 640x400.
// In order to support this game, the screen mode is set, but
// all draw calls are ignored until the game switches to 320x200.
if ((width == 640) && (height == 400)) {
_graphicsEnable = false;
} else {
_graphicsEnable = true;
DS::setGameSize(width, height);
}
}
int16 OSystem_DS::getHeight() {
return _framebuffer.h;
}
int16 OSystem_DS::getWidth() {
return _framebuffer.w;
}
void OSystem_DS::setPalette(const byte *colors, uint start, uint num) {
for (unsigned int r = start; r < start + num; r++) {
int red = *colors;
int green = *(colors + 1);
int blue = *(colors + 2);
red >>= 3;
green >>= 3;
blue >>= 3;
{
u16 paletteValue = red | (green << 5) | (blue << 10);
if (!_isOverlayShown) {
BG_PALETTE[r] = paletteValue;
#ifdef DISABLE_TEXT_CONSOLE
BG_PALETTE_SUB[r] = paletteValue;
#endif
}
_palette[r] = paletteValue;
}
colors += 3;
}
}
void OSystem_DS::setCursorPalette(const byte *colors, uint start, uint num) {
for (unsigned int r = start; r < start + num; r++) {
int red = *colors;
int green = *(colors + 1);
int blue = *(colors + 2);
red >>= 3;
green >>= 3;
blue >>= 3;
u16 paletteValue = red | (green << 5) | (blue << 10);
_cursorPalette[r] = paletteValue;
colors += 3;
}
_disableCursorPalette = false;
refreshCursor(_cursorSprite, _cursor, !_disableCursorPalette ? _cursorPalette : _palette);
}
void OSystem_DS::grabPalette(unsigned char *colors, uint start, uint num) const {
for (unsigned int r = start; r < start + num; r++) {
*colors++ = (BG_PALETTE[r] & 0x001F) << 3;
*colors++ = (BG_PALETTE[r] & 0x03E0) >> 5 << 3;
*colors++ = (BG_PALETTE[r] & 0x7C00) >> 10 << 3;
}
}
void OSystem_DS::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) {
_framebuffer.copyRectToSurface(buf, pitch, x, y, w, h);
}
void OSystem_DS::updateScreen() {
oamSet(&oamMain, 0, _cursorPos.x - _cursorHotX, _cursorPos.y - _cursorHotY, 0, 15, SpriteSize_64x64,
SpriteColorFormat_Bmp, _cursorSprite, 0, false, !_cursorVisible, false, false, false);
oamUpdate(&oamMain);
if (_isOverlayShown) {
u16 *back = (u16 *)_overlay.getPixels();
dmaCopyHalfWords(3, back, BG_GFX, 256 * 192 * 2);
} else if (!_graphicsEnable) {
return;
} else if (_graphicsMode == GFX_SWSCALE) {
u16 *base = BG_GFX + 0x10000;
Rescale_320x256xPAL8_To_256x256x1555(
base,
(const u8 *)_framebuffer.getPixels(),
256,
_framebuffer.pitch,
BG_PALETTE,
_framebuffer.h );
} else {
// The DS video RAM doesn't support 8-bit writes because Nintendo wanted
// to save a few pennies/euro cents on the hardware.
u16 *bg = BG_GFX + 0x10000;
s32 stride = 512;
u16 *src = (u16 *)_framebuffer.getPixels();
for (int dy = 0; dy < _framebuffer.h; dy++) {
DC_FlushRange(src, _framebuffer.w << 1);
u16 *dest1 = bg + (dy * (stride >> 1));
DC_FlushRange(dest1, _framebuffer.w << 1);
#ifdef DISABLE_TEXT_CONSOLE
u16 *dest2 = (u16 *)BG_GFX_SUB + (dy << 8);
DC_FlushRange(dest2, _framebuffer.w << 1);
dmaCopyHalfWordsAsynch(2, src, dest2, _framebuffer.w);
#endif
dmaCopyHalfWordsAsynch(3, src, dest1, _framebuffer.w);
while (dmaBusy(2) || dmaBusy(3));
src += _framebuffer.pitch >> 1;
}
}
}
void OSystem_DS::setShakePos(int shakeXOffset, int shakeYOffset) {
DS::setShakePos(shakeXOffset, shakeYOffset);
}
void OSystem_DS::showOverlay() {
dmaFillHalfWords(0, BG_GFX, 256 * 192 * 2);
videoBgEnable(2);
lcdMainOnBottom();
_isOverlayShown = true;
}
void OSystem_DS::hideOverlay() {
videoBgDisable(2);
DS::displayMode8Bit();
_isOverlayShown = false;
}
bool OSystem_DS::isOverlayVisible() const {
return _isOverlayShown;
}
void OSystem_DS::clearOverlay() {
memset(_overlay.getPixels(), 0, _overlay.pitch * _overlay.h);
}
void OSystem_DS::grabOverlay(void *buf, int pitch) {
byte *dst = (byte *)buf;
for (int y = 0; y < _overlay.h; ++y) {
memcpy(dst, _overlay.getBasePtr(0, y), _overlay.w * _overlay.format.bytesPerPixel);
dst += pitch;
}
}
void OSystem_DS::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) {
_overlay.copyRectToSurface(buf, pitch, x, y, w, h);
}
int16 OSystem_DS::getOverlayHeight() {
return _overlay.h;
}
int16 OSystem_DS::getOverlayWidth() {
return _overlay.w;
}
Graphics::PixelFormat OSystem_DS::getOverlayFormat() const {
return _overlay.format;
}
Common::Point OSystem_DS::transformPoint(uint16 x, uint16 y) {
return DS::transformPoint(x, y, _isOverlayShown);
}
bool OSystem_DS::showMouse(bool visible) {
const bool last = _cursorVisible;
_cursorVisible = visible;
return last;
}
void OSystem_DS::warpMouse(int x, int y) {
_cursorPos = DS::warpMouse(x, y, _isOverlayShown);
}
void OSystem_DS::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, u32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
if (!buf || w == 0 || h == 0 || (format && *format != Graphics::PixelFormat::createFormatCLUT8()))
return;
if (_cursor.w != w || _cursor.h != h)
_cursor.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
_cursor.copyRectToSurface(buf, w, 0, 0, w, h);
_cursorHotX = hotspotX;
_cursorHotY = hotspotY;
_cursorKey = keycolor;
refreshCursor(_cursorSprite, _cursor, !_disableCursorPalette ? _cursorPalette : _palette);
}
void OSystem_DS::refreshCursor(u16 *dst, const Graphics::Surface &src, const uint16 *palette) {
uint w = MIN<uint>(src.w, 64);
uint h = MIN<uint>(src.h, 64);
dmaFillHalfWords(0, dst, 64 * 64 * 2);
for (uint y = 0; y < h; y++) {
const uint8 *row = (const uint8 *)src.getBasePtr(0, y);
for (uint x = 0; x < w; x++) {
uint8 color = *row++;
if (color != _cursorKey)
dst[y * 64 + x] = palette[color] | 0x8000;
}
}
}
void OSystem_DS::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
s.add("nitro:/", new Common::FSDirectory("nitro:/"), priority);
}
@ -445,22 +128,6 @@ void OSystem_DS::getTimeAndDate(TimeDate &td) const {
void OSystem_DS::quit() {
}
Graphics::Surface *OSystem_DS::lockScreen() {
return &_framebuffer;
}
void OSystem_DS::unlockScreen() {
// No need to do anything here. The screen will be updated in updateScreen().
}
void OSystem_DS::setFocusRectangle(const Common::Rect& rect) {
DS::setTalkPos(rect.left + rect.width() / 2, rect.top + rect.height() / 2);
}
void OSystem_DS::clearFocusRectangle() {
}
void OSystem_DS::engineInit() {
#ifdef DISABLE_TEXT_CONSOLE
videoBgEnableSub(3);

View File

@ -56,6 +56,8 @@ protected:
DSEventSource *_eventSource;
void initGraphics();
Graphics::Surface *createTempFrameBuffer();
bool _disableCursorPalette;