AGI: Hercules rendering for game screen

This commit is contained in:
Martin Kiewitz 2016-02-28 11:23:31 +01:00
parent 470cdabc58
commit 7a169c90f6
6 changed files with 177 additions and 13 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -59,6 +59,22 @@ static const uint8 PALETTE_CGA[4 * 3] = {
0xff, 0xff, 0xff
};
/**
* 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

View File

@ -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) {