aboutsummaryrefslogtreecommitdiff
path: root/engines/sherlock/scalpel
diff options
context:
space:
mode:
authorPaul Gilbert2015-09-13 12:22:31 -0400
committerPaul Gilbert2015-09-13 12:22:31 -0400
commitbb01b27777bea9531cae117659d14d3d33f44c8a (patch)
tree3e04c6c399b623cd206c38f140ef955c62de7a60 /engines/sherlock/scalpel
parentdce5c96cc22ab406e371d7313a26d6d77e25187f (diff)
downloadscummvm-rg350-bb01b27777bea9531cae117659d14d3d33f44c8a.tar.gz
scummvm-rg350-bb01b27777bea9531cae117659d14d3d33f44c8a.tar.bz2
scummvm-rg350-bb01b27777bea9531cae117659d14d3d33f44c8a.zip
SHERLOCK: 3DO: Implementing high-resolution mode for 3DO version
This will allow us to play the portrait movies at full resolution, and better display the fonts, which dont look good at low resolution
Diffstat (limited to 'engines/sherlock/scalpel')
-rw-r--r--engines/sherlock/scalpel/scalpel.cpp76
-rw-r--r--engines/sherlock/scalpel/scalpel_screen.cpp204
-rw-r--r--engines/sherlock/scalpel/scalpel_screen.h40
3 files changed, 284 insertions, 36 deletions
diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp
index aef9dfd4f2..7b64ca379b 100644
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@ -28,6 +28,7 @@
#include "sherlock/scalpel/scalpel_map.h"
#include "sherlock/scalpel/scalpel_people.h"
#include "sherlock/scalpel/scalpel_scene.h"
+#include "sherlock/scalpel/scalpel_screen.h"
#include "sherlock/scalpel/tsage/logo.h"
#include "sherlock/sherlock.h"
#include "sherlock/music.h"
@@ -251,8 +252,8 @@ void ScalpelEngine::initialize() {
if (getPlatform() == Common::kPlatform3DO) {
const Graphics::PixelFormat pixelFormatRGB565 = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
- // 320x200 16-bit RGB565 for 3DO support
- initGraphics(320, 200, false, &pixelFormatRGB565);
+ // 16-bit RGB565 for 3DO support
+ initGraphics(640, 400, true, &pixelFormatRGB565);
} else {
// 320x200 palettized
initGraphics(320, 200, false);
@@ -668,9 +669,10 @@ bool ScalpelEngine::show3DOSplash() {
}
bool ScalpelEngine::showCityCutscene3DO() {
+ Scalpel3DOScreen &screen = *(Scalpel3DOScreen *)_screen;
_animation->_soundLibraryFilename = "TITLE.SND";
- _screen->clear();
+ screen.clear();
bool finished = _events->delay(2500, true);
// rain.aiff seems to be playing in an endless loop until
@@ -683,8 +685,8 @@ bool ScalpelEngine::showCityCutscene3DO() {
_music->loadSong("prolog");
// Fade screen to grey
- _screen->_backBuffer1.fill(0xCE59); // RGB565: 25, 50, 25 (grey)
- _screen->fadeIntoScreen3DO(2);
+ screen._backBuffer1.fill(0xCE59); // RGB565: 25, 50, 25 (grey)
+ screen.fadeIntoScreen3DO(2);
}
if (finished) {
@@ -692,27 +694,27 @@ bool ScalpelEngine::showCityCutscene3DO() {
}
if (finished) {
- _screen->_backBuffer1.fill(0); // fill backbuffer with black to avoid issues during fade from white
+ screen._backBuffer1.fill(0); // fill backbuffer with black to avoid issues during fade from white
finished = _animation->play3DO("26open1", true, 1, true, 2);
}
if (finished) {
- _screen->_backBuffer1.blitFrom(*_screen); // save into backbuffer 1, used for fade
- _screen->_backBuffer2.blitFrom(*_screen); // save into backbuffer 2, for restoring later
+ screen._backBuffer1.blitFrom(*_screen); // save into backbuffer 1, used for fade
+ screen._backBuffer2.blitFrom(*_screen); // save into backbuffer 2, for restoring later
// "London, England"
ImageFile3DO titleImage_London("title2a.cel", kImageFile3DOType_Cel);
- _screen->_backBuffer1.transBlitFrom(titleImage_London[0]._frame, Common::Point(30, 50));
+ screen._backBuffer1.transBlitFrom(titleImage_London[0]._frame, Common::Point(30, 50));
- _screen->fadeIntoScreen3DO(1);
+ screen.fadeIntoScreen3DO(1);
finished = _events->delay(1500, true);
if (finished) {
// "November, 1888"
ImageFile3DO titleImage_November("title2b.cel", kImageFile3DOType_Cel);
- _screen->_backBuffer1.transBlitFrom(titleImage_November[0]._frame, Common::Point(100, 100));
+ screen._backBuffer1.transBlitFrom(titleImage_November[0]._frame, Common::Point(100, 100));
- _screen->fadeIntoScreen3DO(1);
+ screen.fadeIntoScreen3DO(1);
finished = _music->waitUntilMSec(14700, 0, 0, 5000);
}
@@ -726,21 +728,21 @@ bool ScalpelEngine::showCityCutscene3DO() {
finished = _animation->play3DO("26open2", true, 1, false, 2);
if (finished) {
- _screen->_backBuffer1.blitFrom(*_screen); // save into backbuffer 1, used for fade
+ screen._backBuffer1.blitFrom(screen); // save into backbuffer 1, used for fade
// "Sherlock Holmes" (title)
ImageFile3DO titleImage_SherlockHolmesTitle("title1ab.cel", kImageFile3DOType_Cel);
- _screen->_backBuffer1.transBlitFrom(titleImage_SherlockHolmesTitle[0]._frame, Common::Point(34, 5));
+ screen._backBuffer1.transBlitFrom(titleImage_SherlockHolmesTitle[0]._frame, Common::Point(34, 5));
// Blend in
- _screen->fadeIntoScreen3DO(2);
+ screen.fadeIntoScreen3DO(2);
finished = _events->delay(500, true);
// Title should fade in, Copyright should be displayed a bit after that
if (finished) {
ImageFile3DO titleImage_Copyright("title1c.cel", kImageFile3DOType_Cel);
- _screen->transBlitFrom(titleImage_Copyright[0]._frame, Common::Point(20, 190));
+ screen.transBlitFrom(titleImage_Copyright[0]._frame, Common::Point(20, 190));
finished = _events->delay(3500, true);
}
}
@@ -750,27 +752,28 @@ bool ScalpelEngine::showCityCutscene3DO() {
if (finished) {
// Fade to black
- _screen->_backBuffer1.clear();
- _screen->fadeIntoScreen3DO(3);
+ screen._backBuffer1.clear();
+ screen.fadeIntoScreen3DO(3);
}
if (finished) {
// "In the alley behind the Regency Theatre..."
ImageFile3DO titleImage_InTheAlley("title1d.cel", kImageFile3DOType_Cel);
- _screen->_backBuffer1.transBlitFrom(titleImage_InTheAlley[0]._frame, Common::Point(72, 51));
+ screen._backBuffer1.transBlitFrom(titleImage_InTheAlley[0]._frame, Common::Point(72, 51));
// Fade in
- _screen->fadeIntoScreen3DO(4);
+ screen.fadeIntoScreen3DO(4);
finished = _music->waitUntilMSec(39900, 0, 0, 2500);
// Fade out
- _screen->_backBuffer1.clear();
- _screen->fadeIntoScreen3DO(4);
+ screen._backBuffer1.clear();
+ screen.fadeIntoScreen3DO(4);
}
return finished;
}
bool ScalpelEngine::showAlleyCutscene3DO() {
+ Scalpel3DOScreen &screen = *(Scalpel3DOScreen *)_screen;
bool finished = _music->waitUntilMSec(43500, 0, 0, 1000);
if (finished)
@@ -778,8 +781,8 @@ bool ScalpelEngine::showAlleyCutscene3DO() {
if (finished) {
// Fade out...
- _screen->_backBuffer1.clear();
- _screen->fadeIntoScreen3DO(3);
+ screen._backBuffer1.clear();
+ screen.fadeIntoScreen3DO(3);
finished = _music->waitUntilMSec(67100, 0, 0, 1000); // 66700
}
@@ -794,8 +797,8 @@ bool ScalpelEngine::showAlleyCutscene3DO() {
// Show screaming victim
ImageFile3DO titleImage_ScreamingVictim("scream.cel", kImageFile3DOType_Cel);
- _screen->clear();
- _screen->transBlitFrom(titleImage_ScreamingVictim[0]._frame, Common::Point(0, 0));
+ screen.clear();
+ screen.transBlitFrom(titleImage_ScreamingVictim[0]._frame, Common::Point(0, 0));
// Play "scream.aiff"
if (_sound->_voices)
@@ -806,8 +809,8 @@ bool ScalpelEngine::showAlleyCutscene3DO() {
if (finished) {
// Fade out
- _screen->_backBuffer1.clear();
- _screen->fadeIntoScreen3DO(5);
+ screen._backBuffer1.clear();
+ screen.fadeIntoScreen3DO(5);
finished = _music->waitUntilMSec(84400, 0, 0, 2000);
}
@@ -817,17 +820,17 @@ bool ScalpelEngine::showAlleyCutscene3DO() {
if (finished) {
// Fade out
- _screen->_backBuffer1.clear();
- _screen->fadeIntoScreen3DO(5);
+ screen._backBuffer1.clear();
+ screen.fadeIntoScreen3DO(5);
}
if (finished) {
// "Early the following morning on Baker Street..."
ImageFile3DO titleImage_EarlyTheFollowingMorning("title3.cel", kImageFile3DOType_Cel);
- _screen->_backBuffer1.transBlitFrom(titleImage_EarlyTheFollowingMorning[0]._frame, Common::Point(35, 51));
+ screen._backBuffer1.transBlitFrom(titleImage_EarlyTheFollowingMorning[0]._frame, Common::Point(35, 51));
// Fade in
- _screen->fadeIntoScreen3DO(4);
+ screen.fadeIntoScreen3DO(4);
finished = _music->waitUntilMSec(96700, 0, 0, 3000);
}
@@ -835,12 +838,13 @@ bool ScalpelEngine::showAlleyCutscene3DO() {
}
bool ScalpelEngine::showStreetCutscene3DO() {
+ Scalpel3DOScreen &screen = *(Scalpel3DOScreen *)_screen;
bool finished = true;
if (finished) {
// fade out "Early the following morning..."
- _screen->_backBuffer1.clear();
- _screen->fadeIntoScreen3DO(4);
+ screen._backBuffer1.clear();
+ screen.fadeIntoScreen3DO(4);
// wait for music a bit
finished = _music->waitUntilMSec(100300, 0, 0, 1000);
@@ -859,8 +863,8 @@ bool ScalpelEngine::showStreetCutscene3DO() {
if (finished) {
// Fade out
- _screen->_backBuffer1.clear();
- _screen->fadeIntoScreen3DO(4);
+ screen._backBuffer1.clear();
+ screen.fadeIntoScreen3DO(4);
}
return finished;
diff --git a/engines/sherlock/scalpel/scalpel_screen.cpp b/engines/sherlock/scalpel/scalpel_screen.cpp
index 44113b2a5d..df1a9d4306 100644
--- a/engines/sherlock/scalpel/scalpel_screen.cpp
+++ b/engines/sherlock/scalpel/scalpel_screen.cpp
@@ -88,6 +88,210 @@ void ScalpelScreen::makeField(const Common::Rect &r) {
_backBuffer->vLine(r.right - 1, r.top + 1, r.bottom - 2, BUTTON_TOP);
}
+/*----------------------------------------------------------------*/
+
+void Scalpel3DOScreen::blitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds) {
+ Common::Rect srcRect = srcBounds;
+ Common::Rect destRect(pt.x, pt.y, pt.x + srcRect.width(), pt.y + srcRect.height());
+
+ if (!srcRect.isValidRect() || !clip(srcRect, destRect))
+ return;
+
+ // Add dirty area remapped to the 640x200 surface
+ addDirtyRect(Common::Rect(destRect.left * 2, destRect.top * 2, destRect.right * 2, destRect.bottom * 2));
+
+ // Transfer the area, doubling each pixel
+ for (int yp = 0; yp < srcRect.height(); ++yp) {
+ const uint16 *srcP = (const uint16 *)src.getBasePtr(srcRect.left, srcRect.top + yp);
+ uint16 *destP = (uint16 *)getBasePtr(destRect.left * 2, (destRect.top + yp) * 2);
+
+ for (int xp = srcRect.left; xp < srcRect.right; ++xp, ++srcP, destP += 2) {
+ *destP = *srcP;
+ *(destP + 1) = *srcP;
+ *(destP + 640) = *srcP;
+ *(destP + 640 + 1) = *srcP;
+ }
+ }
+}
+
+void Scalpel3DOScreen::transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt,
+ bool flipped, int overrideColor) {
+ Common::Rect drawRect(0, 0, src.w, src.h);
+ Common::Rect destRect(pt.x, pt.y, pt.x + src.w, pt.y + src.h);
+
+ // Clip the display area to on-screen
+ if (!clip(drawRect, destRect))
+ // It's completely off-screen
+ return;
+
+ if (flipped)
+ drawRect = Common::Rect(src.w - drawRect.right, src.h - drawRect.bottom,
+ src.w - drawRect.left, src.h - drawRect.top);
+
+ Common::Point destPt(destRect.left, destRect.top);
+ addDirtyRect(Common::Rect(destPt.x * 2, destPt.y * 2, (destPt.x + drawRect.width()) * 2,
+ (destPt.y + drawRect.height()) * 2));
+
+ assert(src.format.bytesPerPixel == 2 && _surface.format.bytesPerPixel == 2);
+
+ for (int yp = 0; yp < drawRect.height(); ++yp) {
+ const uint16 *srcP = (const uint16 *)src.getBasePtr(
+ flipped ? drawRect.right - 1 : drawRect.left, drawRect.top + yp);
+ uint16 *destP = (uint16 *)getBasePtr(destPt.x * 2, (destPt.y + yp) * 2);
+
+ for (int xp = 0; xp < drawRect.width(); ++xp, destP += 2) {
+ // RGB 0, 0, 0 -> transparent on 3DO
+ if (*srcP) {
+ *destP = *srcP;
+ *(destP + 1) = *srcP;
+ *(destP + 640) = *srcP;
+ *(destP + 640 + 1) = *srcP;
+ }
+
+ srcP = flipped ? srcP - 1 : srcP + 1;
+ }
+ }
+}
+
+void Scalpel3DOScreen::fillRect(const Common::Rect &r, uint color) {
+ Screen::fillRect(Common::Rect(r.left * 2, r.top * 2, r.right * 2, r.bottom * 2), color);
+}
+
+void Scalpel3DOScreen::fadeIntoScreen3DO(int speed) {
+ Events &events = *_vm->_events;
+ uint16 *currentScreenBasePtr = (uint16 *)getPixels();
+ uint16 *targetScreenBasePtr = (uint16 *)_backBuffer->getPixels();
+ uint16 currentScreenPixel = 0;
+ uint16 targetScreenPixel = 0;
+
+ uint16 currentScreenPixelRed = 0;
+ uint16 currentScreenPixelGreen = 0;
+ uint16 currentScreenPixelBlue = 0;
+
+ uint16 targetScreenPixelRed = 0;
+ uint16 targetScreenPixelGreen = 0;
+ uint16 targetScreenPixelBlue = 0;
+
+ uint16 screenWidth = SHERLOCK_SCREEN_WIDTH;
+ uint16 screenHeight = SHERLOCK_SCREEN_HEIGHT;
+ uint16 screenX = 0;
+ uint16 screenY = 0;
+ uint16 pixelsChanged = 0;
+
+ clearDirtyRects();
+
+ do {
+ pixelsChanged = 0;
+ uint16 *currentScreenPtr = currentScreenBasePtr;
+ uint16 *targetScreenPtr = targetScreenBasePtr;
+
+ for (screenY = 0; screenY < screenHeight; screenY++, currentScreenPtr += 640) {
+ for (screenX = 0; screenX < screenWidth; screenX++) {
+ currentScreenPixel = *currentScreenPtr;
+ targetScreenPixel = *targetScreenPtr;
+
+ if (currentScreenPixel != targetScreenPixel) {
+ // pixel doesn't match, adjust accordingly
+ currentScreenPixelRed = currentScreenPixel & 0xF800;
+ currentScreenPixelGreen = currentScreenPixel & 0x07E0;
+ currentScreenPixelBlue = currentScreenPixel & 0x001F;
+ targetScreenPixelRed = targetScreenPixel & 0xF800;
+ targetScreenPixelGreen = targetScreenPixel & 0x07E0;
+ targetScreenPixelBlue = targetScreenPixel & 0x001F;
+
+ if (currentScreenPixelRed != targetScreenPixelRed) {
+ if (currentScreenPixelRed < targetScreenPixelRed) {
+ currentScreenPixelRed += 0x0800;
+ } else {
+ currentScreenPixelRed -= 0x0800;
+ }
+ }
+ if (currentScreenPixelGreen != targetScreenPixelGreen) {
+ // Adjust +2/-2 because we are running RGB555 at RGB565
+ if (currentScreenPixelGreen < targetScreenPixelGreen) {
+ currentScreenPixelGreen += 0x0040;
+ } else {
+ currentScreenPixelGreen -= 0x0040;
+ }
+ }
+ if (currentScreenPixelBlue != targetScreenPixelBlue) {
+ if (currentScreenPixelBlue < targetScreenPixelBlue) {
+ currentScreenPixelBlue += 0x0001;
+ } else {
+ currentScreenPixelBlue -= 0x0001;
+ }
+ }
+
+ uint16 v = currentScreenPixelRed | currentScreenPixelGreen | currentScreenPixelBlue;
+ *currentScreenPtr = v;
+ *(currentScreenPtr + 1) = v;
+ *(currentScreenPtr + 640) = v;
+ *(currentScreenPtr + 640 + 1) = v;
+
+ pixelsChanged++;
+ }
+
+ currentScreenPtr += 2;
+ targetScreenPtr++;
+ }
+ }
+
+ // Too much considered dirty at the moment
+ addDirtyRect(Common::Rect(0, 0, screenWidth * 2, screenHeight * 2));
+
+ events.pollEvents();
+ events.delay(10 * speed);
+ } while ((pixelsChanged) && (!_vm->shouldQuit()));
+}
+
+void Scalpel3DOScreen::blitFrom3DOcolorLimit(uint16 limitColor) {
+ uint16 *currentScreenPtr = (uint16 *)getPixels();
+ uint16 *targetScreenPtr = (uint16 *)_backBuffer->getPixels();
+ uint16 currentScreenPixel = 0;
+
+ uint16 screenWidth = SHERLOCK_SCREEN_WIDTH;
+ uint16 screenHeight = SHERLOCK_SCREEN_HEIGHT;
+ uint16 screenX = 0;
+ uint16 screenY = 0;
+
+ uint16 currentScreenPixelRed = 0;
+ uint16 currentScreenPixelGreen = 0;
+ uint16 currentScreenPixelBlue = 0;
+
+ uint16 limitPixelRed = limitColor & 0xF800;
+ uint16 limitPixelGreen = limitColor & 0x07E0;
+ uint16 limitPixelBlue = limitColor & 0x001F;
+
+ for (screenY = 0; screenY < screenHeight; screenY++, currentScreenPtr += 640) {
+ for (screenX = 0; screenX < screenWidth; screenX++) {
+ currentScreenPixel = *targetScreenPtr;
+
+ currentScreenPixelRed = currentScreenPixel & 0xF800;
+ currentScreenPixelGreen = currentScreenPixel & 0x07E0;
+ currentScreenPixelBlue = currentScreenPixel & 0x001F;
+
+ if (currentScreenPixelRed < limitPixelRed)
+ currentScreenPixelRed = limitPixelRed;
+ if (currentScreenPixelGreen < limitPixelGreen)
+ currentScreenPixelGreen = limitPixelGreen;
+ if (currentScreenPixelBlue < limitPixelBlue)
+ currentScreenPixelBlue = limitPixelBlue;
+
+ uint16 v = currentScreenPixelRed | currentScreenPixelGreen | currentScreenPixelBlue;
+ *currentScreenPtr = v;
+ *(currentScreenPtr + 1) = v;
+ *(currentScreenPtr + 640) = v;
+ *(currentScreenPtr + 640 + 1) = v;
+
+ currentScreenPtr += 2;
+ targetScreenPtr++;
+ }
+ }
+
+ // Too much considered dirty at the moment
+ addDirtyRect(Common::Rect(0, 0, screenWidth * 2, screenHeight * 2));
+}
+
} // End of namespace Scalpel
} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_screen.h b/engines/sherlock/scalpel/scalpel_screen.h
index 0277bcd16f..b1be1210e0 100644
--- a/engines/sherlock/scalpel/scalpel_screen.h
+++ b/engines/sherlock/scalpel/scalpel_screen.h
@@ -59,6 +59,46 @@ public:
void makeField(const Common::Rect &r);
};
+class Scalpel3DOScreen : public ScalpelScreen {
+protected:
+ /**
+ * Draws a sub-section of a surface at a given position within this surface
+ * Overriden for the 3DO to automatically double the size of everything to the underlying 640x400 surface
+ */
+ virtual void blitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds);
+
+ /**
+ * Draws a surface at a given position within this surface with transparency
+ */
+ virtual void transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt, bool flipped,
+ int overrideColor);
+public:
+ Scalpel3DOScreen(SherlockEngine *vm) : ScalpelScreen(vm) {}
+ virtual ~Scalpel3DOScreen() {}
+
+ /**
+ * Draws a sub-section of a surface at a given position within this surface
+ */
+ void rawBlitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds) {
+ ScalpelScreen::blitFrom(src, pt, srcBounds);
+ }
+
+ /**
+ * Fade backbuffer 1 into screen (3DO RGB!)
+ */
+ void fadeIntoScreen3DO(int speed);
+
+ void blitFrom3DOcolorLimit(uint16 color);
+
+ /**
+ * Fill a given area of the surface with a given color
+ */
+ virtual void fillRect(const Common::Rect &r, uint color);
+
+ inline virtual uint16 w() const { return _surface.w / 2; }
+ inline virtual uint16 h() const { return _surface.h / 2; }
+};
+
} // End of namespace Scalpel
} // End of namespace Sherlock