aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Kiewitz2016-02-28 11:23:31 +0100
committerMartin Kiewitz2016-02-28 11:23:31 +0100
commit7a169c90f676ead7de6aa2624ac257ff5e85c10e (patch)
tree901c4a71a7183b75eb75ca22f63e91dce5fe8f48
parent470cdabc586956be53f768cb19e2c73b8405b502 (diff)
downloadscummvm-rg350-7a169c90f676ead7de6aa2624ac257ff5e85c10e.tar.gz
scummvm-rg350-7a169c90f676ead7de6aa2624ac257ff5e85c10e.tar.bz2
scummvm-rg350-7a169c90f676ead7de6aa2624ac257ff5e85c10e.zip
AGI: Hercules rendering for game screen
-rw-r--r--engines/agi/agi.cpp19
-rw-r--r--engines/agi/font.cpp17
-rw-r--r--engines/agi/graphics.cpp127
-rw-r--r--engines/agi/graphics.h1
-rw-r--r--engines/agi/palette.h16
-rw-r--r--engines/agi/text.cpp10
6 files changed, 177 insertions, 13 deletions
diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index 6773398271..6e63cd3e71 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -283,18 +283,7 @@ void AgiBase::initRenderMode() {
switch (platform) {
case Common::kPlatformDOS:
- switch (configRenderMode) {
- case Common::kRenderCGA:
- _renderMode = Common::kRenderCGA;
- break;
- // Hercules is not supported atm
- //case Common::kRenderHercA:
- //case Common::kRenderHercG:
- // _renderMode = Common::kRenderHercG;
- // break;
- default:
- break;
- }
+ // Keep EGA
break;
case Common::kPlatformAmiga:
_renderMode = Common::kRenderAmiga;
@@ -323,6 +312,12 @@ void AgiBase::initRenderMode() {
case Common::kRenderVGA:
_renderMode = Common::kRenderVGA;
break;
+ case Common::kRenderHercG:
+ _renderMode = Common::kRenderHercG;
+ break;
+ case Common::kRenderHercA:
+ _renderMode = Common::kRenderHercA;
+ break;
case Common::kRenderAmiga:
_renderMode = Common::kRenderAmiga;
break;
diff --git a/engines/agi/font.cpp b/engines/agi/font.cpp
index c453ee5aa1..5e6ba1e8ce 100644
--- a/engines/agi/font.cpp
+++ b/engines/agi/font.cpp
@@ -624,6 +624,16 @@ void GfxFont::init() {
if (ConfMan.getBool("herculesfont")) {
// User wants, that we use Hercules hires font, try to load it
loadFontHercules();
+ } else {
+ switch (_vm->_renderMode) {
+ case Common::kRenderHercA:
+ case Common::kRenderHercG:
+ // Render mode is Hercules, we try to load Hercules hires font
+ loadFontHercules();
+ break;
+ default:
+ break;
+ }
}
if (!_fontData) {
@@ -650,6 +660,8 @@ void GfxFont::init() {
}
}
break;
+ case Common::kRenderHercA:
+ case Common::kRenderHercG:
case Common::kRenderCGA:
case Common::kRenderEGA:
case Common::kRenderVGA:
@@ -699,6 +711,11 @@ void GfxFont::overwriteSaveRestoreDialogCharacter() {
// Overwrite extended character set (0x80-0xFF) with Russian characters
void GfxFont::overwriteExtendedWithRussianSet() {
+ if (_fontIsHires) {
+ // TODO: Implement overwriting hires font characters too
+ return;
+ }
+
if (!_fontDataAllocated) {
// nothing allocated, we need to allocate space ourselves to be able to modify an internal font
_fontDataAllocated = (uint8 *)calloc(256, 8);
diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp
index 5fa652c5ff..6d3563a451 100644
--- a/engines/agi/graphics.cpp
+++ b/engines/agi/graphics.cpp
@@ -69,6 +69,8 @@ GfxMgr::GfxMgr(AgiBase *vm, GfxFont *font) : _vm(vm), _font(font) {
* @see deinit_video()
*/
int GfxMgr::initVideo() {
+ bool forceHires = false;
+
// Set up palettes
initPalette(_paletteTextMode, PALETTE_EGA);
@@ -82,6 +84,14 @@ int GfxMgr::initVideo() {
case Common::kRenderVGA:
initPalette(_paletteGfxMode, PALETTE_VGA, 256, 8);
break;
+ case Common::kRenderHercG:
+ initPalette(_paletteGfxMode, PALETTE_HERCULES_GREEN, 2, 8);
+ forceHires = true;
+ break;
+ case Common::kRenderHercA:
+ initPalette(_paletteGfxMode, PALETTE_HERCULES_AMBER, 2, 8);
+ forceHires = true;
+ break;
case Common::kRenderAmiga:
if (!ConfMan.getBool("altamigapalette")) {
// Set the correct Amiga palette depending on AGI interpreter version
@@ -137,7 +147,7 @@ int GfxMgr::initVideo() {
//bool forcedUpscale = true;
- if (_font->isFontHires()) {
+ if (_font->isFontHires() || forceHires) {
// Upscaling enable
_upscaledHires = DISPLAY_UPSCALED_640x400;
_displayScreenWidth = 640;
@@ -154,6 +164,8 @@ int GfxMgr::initVideo() {
case Common::kRenderEGA:
case Common::kRenderCGA:
case Common::kRenderVGA:
+ case Common::kRenderHercG:
+ case Common::kRenderHercA:
initMouseCursor(&_mouseCursor, MOUSECURSOR_SCI, 11, 16, 0, 0);
initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_SCI_BUSY, 15, 16, 7, 8);
break;
@@ -500,6 +512,10 @@ void GfxMgr::render_Block(int16 x, int16 y, int16 width, int16 height, bool copy
return;
switch (_vm->_renderMode) {
+ case Common::kRenderHercG:
+ case Common::kRenderHercA:
+ render_BlockHercules(x, y, width, height, copyToScreen);
+ break;
case Common::kRenderCGA:
render_BlockCGA(x, y, width, height, copyToScreen);
break;
@@ -654,6 +670,106 @@ void GfxMgr::render_BlockCGA(int16 x, int16 y, int16 width, int16 height, bool c
}
}
+static const uint8 herculesColorMapping[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x88, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
+ 0x80, 0x10, 0x02, 0x20, 0x01, 0x08, 0x40, 0x04,
+ 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
+ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+ 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00,
+ 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
+ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+ 0x22, 0x00, 0x88, 0x00, 0x22, 0x00, 0x88, 0x00,
+ 0xD7, 0xFF, 0x7D, 0xFF, 0xD7, 0xFF, 0x7D, 0xFF,
+ 0xDD, 0x55, 0x77, 0xAA, 0xDD, 0x55, 0x77, 0xAA,
+ 0x7F, 0xEF, 0xFD, 0xDF, 0xFE, 0xF7, 0xBF, 0xFB,
+ 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF,
+ 0x77, 0xBB, 0xDD, 0xEE, 0x77, 0xBB, 0xDD, 0xEE,
+ 0x77, 0xFF, 0xFF, 0xFF, 0xDD, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+// Sierra actually seems to have rendered the whole screen all the time
+void GfxMgr::render_BlockHercules(int16 x, int16 y, int16 width, int16 height, bool copyToScreen) {
+ uint32 offsetVisual = SCRIPT_WIDTH * y + x;
+ uint32 offsetDisplay = getDisplayOffsetToGameScreenPos(x, y);
+ int16 remainingWidth = width;
+ int16 remainingHeight = height;
+ byte curColor = 0;
+ int16 displayWidth = width * (2 + _displayWidthMulAdjust);
+
+ assert(_upscaledHires == DISPLAY_UPSCALED_640x400);
+
+ uint16 lookupOffset1 = (y * 2 & 0x07);
+ uint16 lookupOffset2 = 0;
+ bool getUpperNibble = false;
+ byte herculesColors1 = 0;
+ byte herculesColors2 = 0;
+
+ while (remainingHeight) {
+ remainingWidth = width;
+
+ lookupOffset1 = (lookupOffset1 + 0) & 0x07;
+ lookupOffset2 = (lookupOffset1 + 1) & 0x07;
+
+ getUpperNibble = (x & 1) ? false : true;
+ while (remainingWidth) {
+ curColor = _activeScreen[offsetVisual++] & 0x0F;
+
+ if (getUpperNibble) {
+ herculesColors1 = herculesColorMapping[curColor * 8 + lookupOffset1] & 0x0F;
+ herculesColors2 = herculesColorMapping[curColor * 8 + lookupOffset2] & 0x0F;
+ } else {
+ herculesColors1 = herculesColorMapping[curColor * 8 + lookupOffset1] >> 4;
+ herculesColors2 = herculesColorMapping[curColor * 8 + lookupOffset2] >> 4;
+ }
+ getUpperNibble ^= true;
+
+ _displayScreen[offsetDisplay + 0] = (herculesColors1 & 0x08) ? 1 : 0;
+ _displayScreen[offsetDisplay + 1] = (herculesColors1 & 0x04) ? 1 : 0;
+ _displayScreen[offsetDisplay + 2] = (herculesColors1 & 0x02) ? 1 : 0;
+ _displayScreen[offsetDisplay + 3] = (herculesColors1 & 0x01) ? 1 : 0;
+
+ _displayScreen[offsetDisplay + _displayScreenWidth + 0] = (herculesColors2 & 0x08) ? 1 : 0;
+ _displayScreen[offsetDisplay + _displayScreenWidth + 1] = (herculesColors2 & 0x04) ? 1 : 0;
+ _displayScreen[offsetDisplay + _displayScreenWidth + 2] = (herculesColors2 & 0x02) ? 1 : 0;
+ _displayScreen[offsetDisplay + _displayScreenWidth + 3] = (herculesColors2 & 0x01) ? 1 : 0;
+
+ offsetDisplay += 4;
+ remainingWidth--;
+ }
+
+ lookupOffset1 += 2;
+
+ offsetVisual += SCRIPT_WIDTH - width;
+ offsetDisplay += _displayScreenWidth - displayWidth;
+ offsetDisplay += _displayScreenWidth;;
+
+ remainingHeight--;
+ }
+}
+
+// Table used for at least Manhunter 2, it renders 2 lines -> 3 lines instead of 4
+// Manhunter 1 is shipped with a broken Hercules font
+// King's Quest 4 aborts right at the start, when Hercules rendering is active
+#if 0
+static const uint8 herculesCoordinateOffset[] = {
+ 0x00, 0x01, 0x03, 0x04, 0x06, 0x07, 0x01, 0x02,
+ 0x04, 0x05, 0x07, 0x00, 0x02, 0x03, 0x05, 0x06
+};
+
+static const uint8 herculesColorMapping[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x02, 0x00, 0x40, 0x00, 0x08, 0x00,
+ 0x80, 0x10, 0x02, 0x20, 0x01, 0x08, 0x40, 0x04, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
+ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00,
+ 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+ 0x22, 0x00, 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0xD7, 0xFF, 0x7D, 0xFF, 0xD7, 0xFF, 0x7D, 0xFF,
+ 0xDD, 0x55, 0x77, 0xAA, 0xDD, 0x55, 0x77, 0xAA, 0x7F, 0xEF, 0xFD, 0xDF, 0xFE, 0xF7, 0xBF, 0xFB,
+ 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0x77, 0xBB, 0xDD, 0xEE, 0x77, 0xBB, 0xDD, 0xEE,
+ 0x7F, 0xEF, 0xFB, 0xBF, 0xEF, 0xFE, 0xBF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+#endif
+
void GfxMgr::transition_Amiga() {
uint16 screenPos = 1;
uint32 screenStepPos = 1;
@@ -876,6 +992,10 @@ void GfxMgr::drawBox(int16 x, int16 y, int16 width, int16 height, byte backgroun
drawDisplayRect(x, +1, y + height, -2, width, -2, 0, 1, 0);
drawDisplayRect(x, +1, y, +1, 0, 1, height, -2, 0);
break;
+ case Common::kRenderHercA:
+ case Common::kRenderHercG:
+ lineColor = 0; // change linecolor to black
+ // supposed to fall through
case Common::kRenderCGA:
case Common::kRenderEGA:
case Common::kRenderVGA:
@@ -895,6 +1015,11 @@ void GfxMgr::drawDisplayRect(int16 x, int16 y, int16 width, int16 height, byte c
case Common::kRenderCGA:
drawDisplayRectCGA(x, y, width, height, color);
break;
+ case Common::kRenderHercG:
+ case Common::kRenderHercA:
+ if (color)
+ color = 1; // change any color except black to green/amber
+ // supposed to fall through
case Common::kRenderEGA:
default:
drawDisplayRectEGA(x, y, width, height, color);
diff --git a/engines/agi/graphics.h b/engines/agi/graphics.h
index c523b61a8f..1cb595cdfa 100644
--- a/engines/agi/graphics.h
+++ b/engines/agi/graphics.h
@@ -180,6 +180,7 @@ public:
private:
void render_BlockEGA(int16 x, int16 y, int16 width, int16 height, bool copyToScreen);
void render_BlockCGA(int16 x, int16 y, int16 width, int16 height, bool copyToScreen);
+ void render_BlockHercules(int16 x, int16 y, int16 width, int16 height, bool copyToScreen);
public:
void transition_Amiga();
diff --git a/engines/agi/palette.h b/engines/agi/palette.h
index e0db81ed7b..40c31da425 100644
--- a/engines/agi/palette.h
+++ b/engines/agi/palette.h
@@ -60,6 +60,22 @@ static const uint8 PALETTE_CGA[4 * 3] = {
};
/**
+ * 2 color Hercules (green) palette. Using 8-bit RGB values.
+ */
+static const uint8 PALETTE_HERCULES_GREEN[2 * 3] = {
+ 0x00, 0x00, 0x00, // black
+ 0x00, 0xdc, 0x28 // green
+};
+
+/**
+ * 2 color Hercules (amber) palette. Using 8-bit RGB values.
+ */
+static const uint8 PALETTE_HERCULES_AMBER[2 * 3] = {
+ 0x00, 0x00, 0x00, // black
+ 0xdc, 0xb4, 0x00 // amber
+};
+
+/**
* Atari ST AGI palette.
* Used by all of the tested Atari ST AGI games
* from Donald Duck's Playground (1986) to Manhunter II (1989).
diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp
index 31f364d856..18254d88f8 100644
--- a/engines/agi/text.cpp
+++ b/engines/agi/text.cpp
@@ -179,6 +179,16 @@ void TextMgr::charAttrib_Set(byte foreground, byte background) {
_textAttrib.combinedBackground = 0;
}
break;
+ case Common::kRenderHercA:
+ case Common::kRenderHercG:
+ if (background) {
+ _textAttrib.combinedForeground = 0;
+ _textAttrib.combinedBackground = 1;
+ } else {
+ _textAttrib.combinedForeground = 1;
+ _textAttrib.combinedBackground = 0;
+ }
+ break;
default:
// EGA-handling:
if (background) {