diff options
81 files changed, 2842 insertions, 775 deletions
diff --git a/Makefile.common b/Makefile.common index 51261d65d9..cea30a5f9f 100644 --- a/Makefile.common +++ b/Makefile.common @@ -37,6 +37,10 @@ ifdef DISABLE_SCALERS DEFINES += -DDISABLE_SCALERS endif +ifdef ENABLE_RGB_COLOR +DEFINES += -DENABLE_RGB_COLOR +endif + ifdef DISABLE_HQ_SCALERS DEFINES += -DDISABLE_HQ_SCALERS endif diff --git a/backends/platform/sdl/graphics.cpp b/backends/platform/sdl/graphics.cpp index 78b8bd8c63..27f32ee8d2 100644 --- a/backends/platform/sdl/graphics.cpp +++ b/backends/platform/sdl/graphics.cpp @@ -97,6 +97,9 @@ void OSystem_SDL::beginGFXTransaction(void) { _transactionDetails.needUpdatescreen = false; _transactionDetails.normal1xScaler = false; +#ifdef ENABLE_RGB_COLOR + _transactionDetails.formatChanged = false; +#endif _oldVideoMode = _videoMode; } @@ -120,6 +123,13 @@ OSystem::TransactionError OSystem_SDL::endGFXTransaction(void) { _videoMode.mode = _oldVideoMode.mode; _videoMode.scaleFactor = _oldVideoMode.scaleFactor; +#ifdef ENABLE_RGB_COLOR + } else if (_videoMode.format != _oldVideoMode.format) { + errors |= kTransactionFormatNotSupported; + + _videoMode.format = _oldVideoMode.format; + _screenFormat = _videoMode.format; +#endif } else if (_videoMode.screenWidth != _oldVideoMode.screenWidth || _videoMode.screenHeight != _oldVideoMode.screenHeight) { errors |= kTransactionSizeChangeFailed; @@ -143,7 +153,11 @@ OSystem::TransactionError OSystem_SDL::endGFXTransaction(void) { } } +#ifdef ENABLE_RGB_COLOR + if (_transactionDetails.sizeChanged || _transactionDetails.formatChanged) { +#else if (_transactionDetails.sizeChanged) { +#endif unloadGFXMode(); if (!loadGFXMode()) { if (_oldVideoMode.setup) { @@ -186,7 +200,7 @@ OSystem::TransactionError OSystem_SDL::endGFXTransaction(void) { } else if (_transactionDetails.needUpdatescreen) { setGraphicsModeIntern(); internUpdateScreen(); - } + } _transactionMode = kTransactionNone; return (TransactionError)errors; @@ -340,9 +354,27 @@ int OSystem_SDL::getGraphicsMode() const { return _videoMode.mode; } -void OSystem_SDL::initSize(uint w, uint h) { +void OSystem_SDL::initSize(uint w, uint h, const Graphics::PixelFormat *format) { assert(_transactionMode == kTransactionActive); +#ifdef ENABLE_RGB_COLOR + //avoid redundant format changes + Graphics::PixelFormat newFormat; + if (!format) + newFormat = Graphics::PixelFormat::createFormatCLUT8(); + else + newFormat = *format; + + assert(newFormat.bytesPerPixel > 0); + + if (newFormat != _videoMode.format) + { + _videoMode.format = newFormat; + _transactionDetails.formatChanged = true; + _screenFormat = newFormat; + } +#endif + // Avoid redundant res changes if ((int)w == _videoMode.screenWidth && (int)h == _videoMode.screenHeight) return; @@ -384,9 +416,21 @@ bool OSystem_SDL::loadGFXMode() { // // Create the surface that contains the 8 bit game data // +#ifdef ENABLE_RGB_COLOR + _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth, _videoMode.screenHeight, + _screenFormat.bytesPerPixel << 3, + ((1 << _screenFormat.rBits()) - 1) << _screenFormat.rShift , + ((1 << _screenFormat.gBits()) - 1) << _screenFormat.gShift , + ((1 << _screenFormat.bBits()) - 1) << _screenFormat.bShift , + ((1 << _screenFormat.aBits()) - 1) << _screenFormat.aShift ); + if (_screen == NULL) + error("allocating _screen failed"); + +#else _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth, _videoMode.screenHeight, 8, 0, 0, 0, 0); if (_screen == NULL) error("allocating _screen failed"); +#endif // // Create the surface that contains the scaled graphics in 16 bit mode @@ -525,8 +569,8 @@ bool OSystem_SDL::hotswapGFXMode() { // Keep around the old _screen & _overlayscreen so we can restore the screen data // after the mode switch. SDL_Surface *old_screen = _screen; - SDL_Surface *old_overlayscreen = _overlayscreen; _screen = NULL; + SDL_Surface *old_overlayscreen = _overlayscreen; _overlayscreen = NULL; // Release the HW screen surface @@ -832,8 +876,19 @@ void OSystem_SDL::copyRectToScreen(const byte *src, int pitch, int x, int y, int if (SDL_LockSurface(_screen) == -1) error("SDL_LockSurface failed: %s", SDL_GetError()); +#ifdef ENABLE_RGB_COLOR + byte *dst = (byte *)_screen->pixels + y * _videoMode.screenWidth * _screenFormat.bytesPerPixel + x * _screenFormat.bytesPerPixel; + if (_videoMode.screenWidth == w && pitch == w * _screenFormat.bytesPerPixel) { + memcpy(dst, src, h*w*_screenFormat.bytesPerPixel); + } else { + do { + memcpy(dst, src, w * _screenFormat.bytesPerPixel); + src += pitch; + dst += _videoMode.screenWidth * _screenFormat.bytesPerPixel; + } while (--h); + } +#else byte *dst = (byte *)_screen->pixels + y * _videoMode.screenWidth + x; - if (_videoMode.screenWidth == pitch && pitch == w) { memcpy(dst, src, h*w); } else { @@ -843,6 +898,7 @@ void OSystem_SDL::copyRectToScreen(const byte *src, int pitch, int x, int y, int dst += _videoMode.screenWidth; } while (--h); } +#endif // Unlock the screen surface SDL_UnlockSurface(_screen); @@ -866,7 +922,11 @@ Graphics::Surface *OSystem_SDL::lockScreen() { _framebuffer.w = _screen->w; _framebuffer.h = _screen->h; _framebuffer.pitch = _screen->pitch; +#ifdef ENABLE_RGB_COLOR + _framebuffer.bytesPerPixel = _screenFormat.bytesPerPixel; +#else _framebuffer.bytesPerPixel = 1; +#endif return &_framebuffer; } @@ -1050,6 +1110,11 @@ int16 OSystem_SDL::getWidth() { void OSystem_SDL::setPalette(const byte *colors, uint start, uint num) { assert(colors); +#ifdef ENABLE_RGB_COLOR + if (_screenFormat.bytesPerPixel > 1) + return; //not using a paletted pixel format +#endif + // Setting the palette before _screen is created is allowed - for now - // since we don't actually set the palette until the screen is updated. // But it could indicate a programming error, so let's warn about it. @@ -1103,10 +1168,10 @@ void OSystem_SDL::setCursorPalette(const byte *colors, uint start, uint num) { } _cursorPaletteDisabled = false; - blitCursor(); } + void OSystem_SDL::setShakePos(int shake_pos) { assert (_transactionMode == kTransactionNone); @@ -1311,7 +1376,17 @@ void OSystem_SDL::warpMouse(int x, int y) { } } -void OSystem_SDL::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale) { +void OSystem_SDL::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) { +#ifdef ENABLE_RGB_COLOR + if (!format) + _cursorFormat = Graphics::PixelFormat(1,8,8,8,8,0,0,0,0); + else if (format->bytesPerPixel <= _screenFormat.bytesPerPixel) + _cursorFormat = *format; + keycolor &= (1 << (_cursorFormat.bytesPerPixel << 3)) - 1; +#else + keycolor &= 0xFF; +#endif + if (w == 0 || h == 0) return; @@ -1345,16 +1420,26 @@ void OSystem_SDL::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, } free(_mouseData); - +#ifdef ENABLE_RGB_COLOR + _mouseData = (byte *)malloc(w * h * _cursorFormat.bytesPerPixel); + memcpy(_mouseData, buf, w * h * _cursorFormat.bytesPerPixel); +#else _mouseData = (byte *)malloc(w * h); memcpy(_mouseData, buf, w * h); +#endif + blitCursor(); } void OSystem_SDL::blitCursor() { byte *dstPtr; const byte *srcPtr = _mouseData; +#ifdef ENABLE_RGB_COLOR + uint32 color; + uint32 colormask = (1 << (_cursorFormat.bytesPerPixel << 3)) - 1; +#else byte color; +#endif int w, h, i, j; if (!_mouseOrigSurface || !_mouseData) @@ -1388,13 +1473,29 @@ void OSystem_SDL::blitCursor() { for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { - color = *srcPtr; - if (color != _mouseKeyColor) { // transparent, don't draw - *(uint16 *)dstPtr = SDL_MapRGB(_mouseOrigSurface->format, - palette[color].r, palette[color].g, palette[color].b); +#ifdef ENABLE_RGB_COLOR + if (_cursorFormat.bytesPerPixel > 1) { + color = (*(uint32 *) srcPtr) & colormask; + if (color != _mouseKeyColor) { // transparent, don't draw + uint8 r,g,b; + _cursorFormat.colorToRGB(color,r,g,b); + *(uint16 *)dstPtr = SDL_MapRGB(_mouseOrigSurface->format, + r, g, b); + } + dstPtr += 2; + srcPtr += _cursorFormat.bytesPerPixel; + } else { +#endif + color = *srcPtr; + if (color != _mouseKeyColor) { // transparent, don't draw + *(uint16 *)dstPtr = SDL_MapRGB(_mouseOrigSurface->format, + palette[color].r, palette[color].g, palette[color].b); + } + dstPtr += 2; + srcPtr++; +#ifdef ENABLE_RGB_COLOR } - dstPtr += 2; - srcPtr++; +#endif } dstPtr += _mouseOrigSurface->pitch - w * 2; } diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index b353c79495..105206ec07 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -196,6 +196,10 @@ OSystem_SDL::OSystem_SDL() _osdSurface(0), _osdAlpha(SDL_ALPHA_TRANSPARENT), _osdFadeStartTime(0), #endif _hwscreen(0), _screen(0), _tmpscreen(0), +#ifdef ENABLE_RGB_COLOR + _screenFormat(Graphics::PixelFormat::createFormatCLUT8()), + _cursorFormat(Graphics::PixelFormat::createFormatCLUT8()), +#endif _overlayVisible(false), _overlayscreen(0), _tmpscreen2(0), _samplesPerSec(0), diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index 7498f48b08..68dfe64d53 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -81,9 +81,49 @@ public: void beginGFXTransaction(void); TransactionError endGFXTransaction(void); - // Set the size of the video bitmap. - // Typically, 320x200 - virtual void initSize(uint w, uint h); // overloaded by CE backend +#ifdef ENABLE_RGB_COLOR + // Game screen + virtual Graphics::PixelFormat getScreenFormat() const { return _screenFormat; } + + // Highest supported + virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const { + //TODO determine hardware color component order + Common::List<Graphics::PixelFormat> list; + SDL_PixelFormat *HWFormat = SDL_GetVideoInfo()->vfmt; +#ifdef ENABLE_32BIT + if (HWFormat->BitsPerPixel >= 32) + { + list.push_back(Graphics::PixelFormat::createFormatRGBA8888()); + list.push_back(Graphics::PixelFormat::createFormatARGB8888()); + list.push_back(Graphics::PixelFormat::createFormatABGR8888()); + list.push_back(Graphics::PixelFormat::createFormatBGRA8888()); } + if (HWFormat->BitsPerPixel >= 24) + { + list.push_back(Graphics::PixelFormat::createFormatRGB888()); + list.push_back(Graphics::PixelFormat::createFormatBGR888()); + } +#endif //ENABLE_32BIT + if (HWFormat->BitsPerPixel >= 16) + { + list.push_back(Graphics::PixelFormat::createFormatRGB565()); + list.push_back(Graphics::PixelFormat::createFormatXRGB1555()); + list.push_back(Graphics::PixelFormat::createFormatRGB555()); + list.push_back(Graphics::PixelFormat::createFormatRGBA4444()); + list.push_back(Graphics::PixelFormat::createFormatARGB4444()); + list.push_back(Graphics::PixelFormat::createFormatBGR565()); + list.push_back(Graphics::PixelFormat::createFormatXBGR1555()); + list.push_back(Graphics::PixelFormat::createFormatBGR555()); + list.push_back(Graphics::PixelFormat::createFormatABGR4444()); + list.push_back(Graphics::PixelFormat::createFormatBGRA4444()); + } + list.push_back(Graphics::PixelFormat::createFormatCLUT8()); + return list; + } +#endif + + // Set the size and format of the video bitmap. + // Typically, 320x200 CLUT8 + virtual void initSize(uint w, uint h, const Graphics::PixelFormat *format); // overloaded by CE backend virtual int getScreenChangeID() const { return _screenChangeCount; } @@ -112,7 +152,7 @@ public: virtual void warpMouse(int x, int y); // overloaded by CE backend (FIXME) // Set the bitmap that's used when drawing the cursor. - virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale); // overloaded by CE backend (FIXME) + virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format); // overloaded by CE backend (FIXME) // Set colors of cursor palette void setCursorPalette(const byte *colors, uint start, uint num); @@ -174,6 +214,7 @@ public: // Overlay virtual Graphics::PixelFormat getOverlayFormat() const { return _overlayFormat; } + virtual void showOverlay(); virtual void hideOverlay(); virtual void clearOverlay(); @@ -227,6 +268,10 @@ protected: // unseen game screen SDL_Surface *_screen; +#ifdef ENABLE_RGB_COLOR + Graphics::PixelFormat _screenFormat; + Graphics::PixelFormat _cursorFormat; +#endif // temporary screen (for scalers) SDL_Surface *_tmpscreen; @@ -260,6 +305,9 @@ protected: bool needHotswap; bool needUpdatescreen; bool normal1xScaler; +#ifdef ENABLE_RGB_COLOR + bool formatChanged; +#endif }; TransactionDetails _transactionDetails; @@ -274,6 +322,9 @@ protected: int screenWidth, screenHeight; int overlayWidth, overlayHeight; +#ifdef ENABLE_RGB_COLOR + Graphics::PixelFormat format; +#endif }; VideoState _videoMode, _oldVideoMode; diff --git a/common/error.h b/common/error.h index 23305a5c2e..6522fbf4af 100644 --- a/common/error.h +++ b/common/error.h @@ -48,6 +48,9 @@ enum Error { kInvalidPathError, //!< Engine initialization: Invalid game path was passed kNoGameDataFoundError, //!< Engine initialization: No game data was found in the specified location kUnsupportedGameidError, //!< Engine initialization: Gameid not supported by this (Meta)Engine +#ifdef ENABLE_RGB_COLOR + kUnsupportedColorMode, //!< Engine initialization: Engine does not support backend's color mode +#endif kReadPermissionDenied, //!< Unable to read data due to missing read permission diff --git a/common/system.h b/common/system.h index 5b3c208661..6f3dc6b6c8 100644 --- a/common/system.h +++ b/common/system.h @@ -31,6 +31,9 @@ #include "common/rect.h" #include "graphics/pixelformat.h" +#ifdef ENABLE_RGB_COLOR +#include "graphics/conversion.h" +#endif namespace Audio { class Mixer; @@ -347,8 +350,50 @@ public: */ virtual int getGraphicsMode() const = 0; +#ifdef ENABLE_RGB_COLOR + /** + * Determine the pixel format currently in use for screen rendering. + * @return the active screen pixel format. + * @see Graphics::PixelFormat + */ + virtual Graphics::PixelFormat getScreenFormat() const = 0; + + /** + * Returns a list of all pixel formats supported by the backend. + * The first item in the list must be directly supported by hardware, + * and provide the largest color space of those formats with direct + * hardware support. It is also strongly recommended that remaining + * formats should be placed in order of descending preference for the + * backend to use. + * + * EG: a backend that supports 32-bit ABGR and 16-bit 555 BGR in hardware + * and provides conversion from equivalent RGB(A) modes should order its list + * 1) Graphics::PixelFormat::createFormatABGR8888() + * 2) Graphics::PixelFormat::createFormatBGR555() + * 3) Graphics::PixelFormat::createFormatRGBA8888() + * 4) Graphics::PixelFormat::createFormatRGB555() + * 5) Graphics::PixelFormat::createFormatCLUT8() + * + * @see Graphics::PixelFormat + * + * @note All backends supporting RGB color must be able to accept game data + * in RGB color order, even if hardware uses BGR or some other color order. + */ + virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const = 0; +#else + inline Graphics::PixelFormat getScreenFormat() const { + return Graphics::PixelFormat::createFormatCLUT8(); + }; + + inline Common::List<Graphics::PixelFormat> getSupportedFormats() const { + Common::List<Graphics::PixelFormat> list; + list.push_back(Graphics::PixelFormat::createFormatCLUT8()); + return list; + }; +#endif + /** - * Set the size of the virtual screen. Typical sizes include: + * Set the size and color format of the virtual screen. Typical sizes include: * - 320x200 (e.g. for most SCUMM games, and Simon) * - 320x240 (e.g. for FM-TOWN SCUMM games) * - 640x480 (e.g. for Curse of Monkey Island) @@ -359,10 +404,21 @@ public: * GraphicsMode); stretch the data to perform aspect ratio correction; * or shrink it to fit on small screens (in cell phones). * + * Typical formats include: + * CLUT8 (e.g. 256 color, for most games) + * RGB555 (e.g. 16-bit color, for later SCUMM HE games) + * RGB565 (e.g. 16-bit color, for Urban Runner) + * + * This is the pixel format for which the client code generates data; + * this is not necessarily equal to the hardware pixel format. For example, + * a backend may perform color lookup of 8-bit graphics before pushing + * a screen to hardware, or correct the ARGB color order. + * * @param width the new virtual screen width * @param height the new virtual screen height + * @param format the new virtual screen pixel format */ - virtual void initSize(uint width, uint height) = 0; + virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format = NULL) = 0; /** * Return an int value which is changed whenever any screen @@ -411,6 +467,9 @@ public: kTransactionAspectRatioFailed = (1 << 0), /**< Failed switchting aspect ratio correction mode */ kTransactionFullscreenFailed = (1 << 1), /**< Failed switchting fullscreen mode */ kTransactionModeSwitchFailed = (1 << 2), /**< Failed switchting the GFX graphics mode (setGraphicsMode) */ +#ifdef ENABLE_RGB_COLOR + kTransactionFormatNotSupported = (1 << 4), /**< Failed setting the color format (function not yet implemented) */ +#endif kTransactionSizeChangeFailed = (1 << 3) /**< Failed switchting the screen dimensions (initSize) */ }; @@ -705,8 +764,9 @@ public: * @param hotspotY vertical offset from the top side to the hotspot * @param keycolor transparency color index * @param cursorTargetScale scale factor which cursor is designed for + * @param format pointer to the pixel format which cursor graphic uses */ - virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255, int cursorTargetScale = 1) = 0; + virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 0xFFFFFFFF, int cursorTargetScale = 1, const Graphics::PixelFormat *format = NULL) = 0; /** * Replace the specified range of cursor the palette with new colors. @@ -962,6 +1022,31 @@ public: */ virtual Common::WriteStream *createConfigWriteStream() = 0; +#ifdef ENABLE_RGB_COLOR +private: + /** + * Convert a rectangle from the screen format to the hardware format. + * + * @param dstbuf the buffer which will recieve the converted graphics data + * @param srcbuf the buffer containing the original graphics data + * @param dstpitch width in bytes of one full line of the dest buffer + * @param srcpitch width in bytes of one full line of the source buffer + * @param w the width of the graphics data + * @param h the height of the graphics data + * @param hwFmt the pixel format currently set in hardware + * @return true if conversion completes successfully, + * false if there is an error. + * + * @note This implementation is slow. Please override this if + * your backend hardware has a better way to deal with this. + * @note This implementation requires the screen pixel format and + * the hardware pixel format to have a matching bytedepth + */ + virtual bool convertScreenRect(byte *dstbuf, const byte *srcbuf, int dstpitch, int srcpitch, + int w, int h, Graphics::PixelFormat hwFmt) { + return Graphics::crossBlit(dstbuf,srcbuf,dstpitch,srcpitch,w,h,hwFmt,getScreenFormat()); + }; +#endif // ENABLE_RGB_COLOR //@} }; @@ -110,6 +110,7 @@ _alsa=auto _zlib=auto _mpeg2=no _fluidsynth=auto +_16bit=yes _mt32emu=yes # Default option behaviour yes/no _build_hq_scalers=yes @@ -629,6 +630,8 @@ DEBFLAGS="-g" for ac_option in $@; do case "$ac_option" in + --enable-16bit) _16bit=yes ;; + --disable-16bit) _16bit=no ;; --disable-hq-scalers) _build_hq_scalers=no ;; --disable-scalers) _build_scalers=no ;; --enable-alsa) _alsa=yes ;; @@ -1566,6 +1569,11 @@ fi add_to_config_mk_if_yes "$_mt32emu" 'USE_MT32EMU = 1' # +# Check whether 16bit color support is requested +# +add_to_config_mk_if_yes "$_16bit" 'ENABLE_RGB_COLOR = 1' + +# # Check whether to enable the (hq) scalers # add_to_config_mk_if_no $_build_hq_scalers 'DISABLE_HQ_SCALERS = 1' @@ -1876,6 +1884,10 @@ if test "$_nasm" = yes ; then echo_n ", assembly routines" fi +if test "$_16bit" = yes ; then + echo_n ", 16bit color" +fi + if test "$_build_hq_scalers" = yes ; then echo_n ", HQ scalers" fi diff --git a/dists/msvc7/scummvm.vcproj b/dists/msvc7/scummvm.vcproj index aee0ca2032..def73f7e59 100644 --- a/dists/msvc7/scummvm.vcproj +++ b/dists/msvc7/scummvm.vcproj @@ -1046,6 +1046,12 @@ RelativePath="..\..\graphics\colormasks.h"> </File> <File + RelativePath="..\..\graphics\conversion.cpp"> + </File> + <File + RelativePath="..\..\graphics\conversion.h"> + </File> + <File RelativePath="..\..\graphics\cursorman.cpp"> </File> <File @@ -1082,6 +1088,12 @@ RelativePath="..\..\graphics\imagedec.h"> </File> <File + RelativePath="..\..\graphics\jpeg.cpp"> + </File> + <File + RelativePath="..\..\graphics\jpeg.h"> + </File> + <File RelativePath="..\..\graphics\pixelformat.h"> </File> <File diff --git a/dists/msvc71/scummvm.vcproj b/dists/msvc71/scummvm.vcproj index aa9e3b9066..24f486f7e3 100644 --- a/dists/msvc71/scummvm.vcproj +++ b/dists/msvc71/scummvm.vcproj @@ -1060,6 +1060,12 @@ RelativePath="..\..\graphics\colormasks.h"> </File> <File + RelativePath="..\..\graphics\conversion.cpp"> + </File> + <File + RelativePath="..\..\graphics\conversion.h"> + </File> + <File RelativePath="..\..\graphics\cursorman.cpp"> </File> <File @@ -1096,6 +1102,12 @@ RelativePath="..\..\graphics\imagedec.h"> </File> <File + RelativePath="..\..\graphics\jpeg.cpp"> + </File> + <File + RelativePath="..\..\graphics\jpeg.h"> + </File> + <File RelativePath="..\..\graphics\pixelformat.h"> </File> <File diff --git a/dists/msvc8/gob.vcproj b/dists/msvc8/gob.vcproj index 315cabc7d3..14259ac2fd 100644 --- a/dists/msvc8/gob.vcproj +++ b/dists/msvc8/gob.vcproj @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="windows-1252"?> <VisualStudioProject ProjectType="Visual C++" - Version="8,00" + Version="8.00" Name="gob" ProjectGUID="{976D947A-A45F-4437-991E-412F695C64C7}" RootNamespace="gob" @@ -43,7 +43,7 @@ Optimization="0" InlineFunctionExpansion="0" AdditionalIncludeDirectories="../../;../../engines" - PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS" + PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;ENABLE_RGB_COLOR" MinimalRebuild="true" ExceptionHandling="1" BasicRuntimeChecks="3" diff --git a/dists/msvc8/groovie.vcproj b/dists/msvc8/groovie.vcproj index 14ab5726fc..e6e7e792ba 100644 --- a/dists/msvc8/groovie.vcproj +++ b/dists/msvc8/groovie.vcproj @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="windows-1252"?> <VisualStudioProject ProjectType="Visual C++" - Version="8,00" + Version="8.00" Name="groovie" ProjectGUID="{2C1EA540-0B09-11DD-BD00-000000000000}" RootNamespace="groovie" @@ -42,7 +42,7 @@ AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996" Optimization="0" AdditionalIncludeDirectories="../..;../../engines" - PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS" + PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS; ENABLE_RGB_COLOR; GROOVIE_EXPERIMENTAL" MinimalRebuild="true" ExceptionHandling="1" BasicRuntimeChecks="3" @@ -259,7 +259,7 @@ <File RelativePath="..\..\engines\groovie\saveload.h" > - </File> + </File> <File RelativePath="..\..\engines\groovie\script.cpp" > diff --git a/dists/msvc8/sci.vcproj b/dists/msvc8/sci.vcproj index b85419c515..8575096239 100644 --- a/dists/msvc8/sci.vcproj +++ b/dists/msvc8/sci.vcproj @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="windows-1252"?> <VisualStudioProject ProjectType="Visual C++" - Version="8,00" + Version="8.00" Name="sci" ProjectGUID="{53F17B2B-0412-4EC3-A999-ED0537BB5223}" RootNamespace="sci" @@ -43,7 +43,7 @@ Optimization="0" InlineFunctionExpansion="0" AdditionalIncludeDirectories="../../;../../engines" - PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS" + PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;ENABLE_RGB_COLOR" MinimalRebuild="true" ExceptionHandling="1" BasicRuntimeChecks="3" diff --git a/dists/msvc8/scumm.vcproj b/dists/msvc8/scumm.vcproj index 6e9e70da97..8cc0ab9719 100644 --- a/dists/msvc8/scumm.vcproj +++ b/dists/msvc8/scumm.vcproj @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="windows-1252"?> <VisualStudioProject ProjectType="Visual C++" - Version="8,00" + Version="8.00" Name="scumm" ProjectGUID="{B6AFD548-63D2-40CD-A652-E87095AFCBAF}" RootNamespace="scumm" @@ -43,7 +43,7 @@ Optimization="0" InlineFunctionExpansion="0" AdditionalIncludeDirectories="../../;../../engines" - PreprocessorDefinitions="WIN32;_DEBUG;ENABLE_SCUMM_7_8;ENABLE_HE;USE_ZLIB;USE_MAD;USE_VORBIS" + PreprocessorDefinitions="WIN32;_DEBUG;ENABLE_SCUMM_7_8;ENABLE_HE;USE_ZLIB;USE_MAD;USE_VORBIS;ENABLE_RGB_COLOR" MinimalRebuild="true" ExceptionHandling="1" BasicRuntimeChecks="3" diff --git a/dists/msvc8/scummvm.vcproj b/dists/msvc8/scummvm.vcproj index a88167c0b0..d60a904dd6 100644 --- a/dists/msvc8/scummvm.vcproj +++ b/dists/msvc8/scummvm.vcproj @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="windows-1252"?> <VisualStudioProject ProjectType="Visual C++" - Version="8,00" + Version="8.00" Name="scummvm" ProjectGUID="{8434CB15-D08F-427D-9E6D-581AE5B28440}" RootNamespace="scummvm" @@ -43,7 +43,7 @@ Optimization="0" InlineFunctionExpansion="0" AdditionalIncludeDirectories="../../;../../engines" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2;USE_NASM;USE_MT32EMU;ENABLE_AGI;ENABLE_AGOS;ENABLE_CINE;ENABLE_CRUISE;ENABLE_DRASCULA;ENABLE_GOB;ENABLE_IGOR;ENABLE_KYRA;ENABLE_LURE;ENABLE_M4;ENABLE_MADE;ENABLE_PARALLACTION;ENABLE_QUEEN;ENABLE_SAGA;ENABLE_SCI;ENABLE_SCUMM;ENABLE_SKY;ENABLE_SWORD1;ENABLE_SWORD2;ENABLE_TOUCHE;ENABLE_SCUMM_7_8;ENABLE_HE;ENABLE_TINSEL;ENABLE_TUCKER;ENABLE_GROOVIE" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2;USE_NASM;USE_MT32EMU;ENABLE_AGI;ENABLE_AGOS;ENABLE_CINE;ENABLE_CRUISE;ENABLE_DRASCULA;ENABLE_GOB;ENABLE_IGOR;ENABLE_KYRA;ENABLE_LURE;ENABLE_M4;ENABLE_MADE;ENABLE_PARALLACTION;ENABLE_QUEEN;ENABLE_SAGA;ENABLE_SCI;ENABLE_SCUMM;ENABLE_SKY;ENABLE_SWORD1;ENABLE_SWORD2;ENABLE_TOUCHE;ENABLE_SCUMM_7_8;ENABLE_HE;ENABLE_TINSEL;ENABLE_TUCKER;ENABLE_GROOVIE;ENABLE_RGB_COLOR" MinimalRebuild="true" ExceptionHandling="1" BasicRuntimeChecks="3" @@ -100,6 +100,9 @@ Name="VCAppVerifierTool" /> <Tool + Name="VCWebDeploymentTool" + /> + <Tool Name="VCPostBuildEventTool" /> </Configuration> @@ -192,6 +195,9 @@ Name="VCAppVerifierTool" /> <Tool + Name="VCWebDeploymentTool" + /> + <Tool Name="VCPostBuildEventTool" /> </Configuration> @@ -1425,6 +1431,14 @@ > </File> <File + RelativePath="..\..\graphics\conversion.cpp" + > + </File> + <File + RelativePath="..\..\graphics\conversion.h" + > + </File> + <File RelativePath="..\..\graphics\cursorman.cpp" > </File> @@ -1473,6 +1487,14 @@ > </File> <File + RelativePath="..\..\graphics\jpeg.cpp" + > + </File> + <File + RelativePath="..\..\graphics\jpeg.h" + > + </File> + <File RelativePath="..\..\graphics\pixelformat.h" > </File> diff --git a/dists/msvc9/scummvm.vcproj b/dists/msvc9/scummvm.vcproj index 6bbc21f9e4..bec6f97ce4 100644 --- a/dists/msvc9/scummvm.vcproj +++ b/dists/msvc9/scummvm.vcproj @@ -1430,6 +1430,14 @@ > </File> <File + RelativePath="..\..\graphics\conversion.cpp" + > + </File> + <File + RelativePath="..\..\graphics\conversion.h" + > + </File> + <File RelativePath="..\..\graphics\cursorman.cpp" > </File> @@ -1478,6 +1486,14 @@ > </File> <File + RelativePath="..\..\graphics\jpeg.cpp" + > + </File> + <File + RelativePath="..\..\graphics\jpeg.h" + > + </File> + <File RelativePath="..\..\graphics\pixelformat.h" > </File> diff --git a/dists/wii/meta.xml.in b/dists/wii/meta.xml.in deleted file mode 100644 index 7df9f6d350..0000000000 --- a/dists/wii/meta.xml.in +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<app version="1"> - <name>ScummVM</name> - <coder>The ScummVM Team</coder> - <version>@VERSION@@REVISION@</version> - <release_date>@TIMESTAMP@</release_date> - <short_description>Point & Click Adventures</short_description> - <long_description>ScummVM is a program which allows you to run certain classic graphical point-and-click adventure games, provided you already have their data files. The clever part about this: ScummVM just replaces the executables shipped with the games, allowing you to play them on systems for which they were never designed! - -Some of the adventures ScummVM supports include Adventure Soft's Simon the Sorcerer 1 and 2; Revolution's Beneath A Steel Sky, Broken Sword 1 and Broken Sword 2; Flight of the Amazon Queen; Wyrmkeep's Inherit the Earth; Coktel Vision's Gobliiins; Westwood Studios' The Legend of Kyrandia and games based on LucasArts' SCUMM (Script Creation Utility for Maniac Mansion) system such as Monkey Island, Day of the Tentacle, Sam and Max and more.</long_description> -</app> - diff --git a/engines/cine/pal.h b/engines/cine/pal.h index 4764d5a474..26513eb5a1 100644 --- a/engines/cine/pal.h +++ b/engines/cine/pal.h @@ -36,7 +36,8 @@ namespace Cine { #define kLowPalNumBytes ((kLowPalNumColors) * (kLowPalBytesPerColor)) /*! \brief Low resolution (9-bit) color format used in Cine's 16-color modes. */ -static const Graphics::PixelFormat kLowPalFormat = {kLowPalBytesPerColor, 5, 5, 5, 8, 8, 4, 0, 0}; + static const Graphics::PixelFormat kLowPalFormat(kLowPalBytesPerColor, 5, 5, 5, 8, 8, 4, 0, 0); + // Constants related to kHighPalFormat #define kHighPalBytesPerColor 3 @@ -44,10 +45,10 @@ static const Graphics::PixelFormat kLowPalFormat = {kLowPalBytesPerColor, 5, 5, #define kHighPalNumBytes ((kHighPalNumColors) * (kHighPalBytesPerColor)) /*! \brief High resolution (24-bit) color format used in Cine's 256-color modes. */ -static const Graphics::PixelFormat kHighPalFormat = {kHighPalBytesPerColor, 0, 0, 0, 8, 0, 8, 16, 0}; +static const Graphics::PixelFormat kHighPalFormat(kHighPalBytesPerColor, 0, 0, 0, 8, 0, 8, 16, 0); /*! \brief The color format used by OSystem's setPalette-function. */ -static const Graphics::PixelFormat kSystemPalFormat = {4, 0, 0, 0, 8, 0, 8, 16, 0}; +static const Graphics::PixelFormat kSystemPalFormat(4, 0, 0, 0, 8, 0, 8, 16, 0); /*! \brief Endian types. Used at least by Palette class's load and save functions. * TODO: Move somewhere more general as this is definitely not Cine-engine specific diff --git a/engines/engine.cpp b/engines/engine.cpp index 0847e27246..1fd77eb310 100644 --- a/engines/engine.cpp +++ b/engines/engine.cpp @@ -125,11 +125,16 @@ void initCommonGFX(bool defaultTo1XScaler) { g_system->setFeatureState(OSystem::kFeatureFullscreenMode, ConfMan.getBool("fullscreen")); } -void initGraphics(int width, int height, bool defaultTo1xScaler) { +void initGraphics(int width, int height, bool defaultTo1xScaler, const Graphics::PixelFormat *format) { + g_system->beginGFXTransaction(); initCommonGFX(defaultTo1xScaler); +#ifdef ENABLE_RGB_COLOR + g_system->initSize(width, height, format); +#else g_system->initSize(width, height); +#endif OSystem::TransactionError gfxError = g_system->endGFXTransaction(); @@ -150,6 +155,15 @@ void initGraphics(int width, int height, bool defaultTo1xScaler) { } // Just show warnings then these occur: +#ifdef ENABLE_RGB_COLOR + if (gfxError & OSystem::kTransactionFormatNotSupported) { + Common::String message = "Could not initialize color format."; + + GUI::MessageDialog dialog(message); + dialog.runModal(); + } +#endif + if (gfxError & OSystem::kTransactionModeSwitchFailed) { Common::String message = "Could not switch to video mode: '"; message += ConfMan.get("gfx_mode"); diff --git a/engines/engine.h b/engines/engine.h index ff3ce6c326..c643d5895f 100644 --- a/engines/engine.h +++ b/engines/engine.h @@ -29,6 +29,7 @@ #include "common/error.h" #include "common/fs.h" #include "common/str.h" +#include "graphics/pixelformat.h" class OSystem; @@ -59,7 +60,7 @@ void initCommonGFX(bool defaultTo1XScaler); * Errors out when backend is not able to switch to the specified * mode. */ -void initGraphics(int width, int height, bool defaultTo1xScaler); +void initGraphics(int width, int height, bool defaultTo1xScaler, const Graphics::PixelFormat *format = NULL); /** * Initializes graphics and shows error message. diff --git a/engines/gob/video_v6.cpp b/engines/gob/video_v6.cpp index 74447f1a84..983eeea8cf 100644 --- a/engines/gob/video_v6.cpp +++ b/engines/gob/video_v6.cpp @@ -25,6 +25,7 @@ #include "common/endian.h" #include "common/savefile.h" +#include "graphics/conversion.h" #include "graphics/dither.h" #include "gob/gob.h" @@ -45,8 +46,8 @@ void Video_v6::setPrePalette() { for (int i = 0; i < 256; i++) { byte r, g, b; - Graphics::PaletteLUT::YUV2RGB(fpal[i * 3 + 0], fpal[i * 3 + 1], fpal[i * 3 + 2], - r, g, b); + Graphics::YUV2RGB(fpal[i * 3 + 0], fpal[i * 3 + 1], fpal[i * 3 + 2], + r, g, b); tpal[i * 3 + 0] = r >> 2; tpal[i * 3 + 1] = g >> 2; diff --git a/engines/groovie/graphics.cpp b/engines/groovie/graphics.cpp index 647eaa913b..1e54f0e79b 100644 --- a/engines/groovie/graphics.cpp +++ b/engines/groovie/graphics.cpp @@ -31,8 +31,8 @@ namespace Groovie { GraphicsMan::GraphicsMan(GroovieEngine *vm) : _vm(vm), _changed(false), _fading(0) { // Create the game surfaces - _foreground.create(640, 320, 1); - _background.create(640, 320, 1); + _foreground.create(640, 320, _vm->_pixelFormat.bytesPerPixel); + _background.create(640, 320, _vm->_pixelFormat.bytesPerPixel); } GraphicsMan::~GraphicsMan() { diff --git a/engines/groovie/groovie.cpp b/engines/groovie/groovie.cpp index 9381b5b47c..cdf05e803b 100644 --- a/engines/groovie/groovie.cpp +++ b/engines/groovie/groovie.cpp @@ -70,7 +70,21 @@ GroovieEngine::~GroovieEngine() { Common::Error GroovieEngine::run() { // Initialize the graphics - initGraphics(640, 480, true); + switch (_gameDescription->version) { + case kGroovieV2: + // Request the mode with the highest precision available + _pixelFormat = _system->getSupportedFormats().front(); + initGraphics(640, 480, true, &_pixelFormat); + + // Save the enabled mode as it can be both an RGB mode or CLUT8 + _pixelFormat = _system->getScreenFormat(); + _mode8bit = (_pixelFormat == Graphics::PixelFormat::createFormatCLUT8()); + break; + case kGroovieT7G: + initGraphics(640, 480, true); + _pixelFormat = Graphics::PixelFormat::createFormatCLUT8(); + break; + } // Create debugger. It requires GFX to be initialized _debugger = new Debugger(this); diff --git a/engines/groovie/groovie.h b/engines/groovie/groovie.h index a137193adf..bf57ae77de 100644 --- a/engines/groovie/groovie.h +++ b/engines/groovie/groovie.h @@ -85,6 +85,8 @@ protected: public: void waitForInput(); + Graphics::PixelFormat _pixelFormat; + bool _mode8bit; Script _script; ResMan *_resMan; GrvCursorMan *_grvCursorMan; diff --git a/engines/groovie/roq.cpp b/engines/groovie/roq.cpp index 28d0d23fc1..4c8bbe55ac 100644 --- a/engines/groovie/roq.cpp +++ b/engines/groovie/roq.cpp @@ -29,6 +29,12 @@ #include "groovie/groovie.h" #include "groovie/roq.h" +#include "graphics/jpeg.h" + +#ifdef ENABLE_RGB_COLOR +// Required for the YUV to RGB conversion +#include "graphics/conversion.h" +#endif #include "sound/mixer.h" namespace Groovie { @@ -43,50 +49,52 @@ ROQPlayer::ROQPlayer(GroovieEngine *vm) : _currBuf = new Graphics::Surface(); _prevBuf = new Graphics::Surface(); - byte pal[256 * 4]; + if (_vm->_mode8bit) { + byte pal[256 * 4]; #ifdef DITHER - byte pal3[256 * 3]; - // Initialize to a black palette - for (int i = 0; i < 256 * 3; i++) { - pal3[i] = 0; - } - - // Build a basic color palette - for (int r = 0; r < 4; r++) { - for (int g = 0; g < 4; g++) { - for (int b = 0; b < 4; b++) { - byte col = (r << 4) | (g << 2) | (b << 0); - pal3[3 * col + 0] = r << 6; - pal3[3 * col + 1] = g << 6; - pal3[3 * col + 2] = b << 6; + byte pal3[256 * 3]; + // Initialize to a black palette + for (int i = 0; i < 256 * 3; i++) { + pal3[i] = 0; + } + + // Build a basic color palette + for (int r = 0; r < 4; r++) { + for (int g = 0; g < 4; g++) { + for (int b = 0; b < 4; b++) { + byte col = (r << 4) | (g << 2) | (b << 0); + pal3[3 * col + 0] = r << 6; + pal3[3 * col + 1] = g << 6; + pal3[3 * col + 2] = b << 6; + } } } - } - // Initialize the dithering algorithm - _paletteLookup = new Graphics::PaletteLUT(8, Graphics::PaletteLUT::kPaletteYUV); - _paletteLookup->setPalette(pal3, Graphics::PaletteLUT::kPaletteRGB, 8); - for (int i = 0; (i < 64) && !_vm->shouldQuit(); i++) { - debug("Groovie::ROQ: Building palette table: %02d/63", i); - _paletteLookup->buildNext(); - } + // Initialize the dithering algorithm + _paletteLookup = new Graphics::PaletteLUT(8, Graphics::PaletteLUT::kPaletteYUV); + _paletteLookup->setPalette(pal3, Graphics::PaletteLUT::kPaletteRGB, 8); + for (int i = 0; (i < 64) && !_vm->shouldQuit(); i++) { + debug("Groovie::ROQ: Building palette table: %02d/63", i); + _paletteLookup->buildNext(); + } - // Prepare the palette to show - for (int i = 0; i < 256; i++) { - pal[(i * 4) + 0] = pal3[(i * 3) + 0]; - pal[(i * 4) + 1] = pal3[(i * 3) + 1]; - pal[(i * 4) + 2] = pal3[(i * 3) + 2]; - } -#else - // Set a grayscale palette - for (int i = 0; i < 256; i++) { - pal[(i * 4) + 0] = i; - pal[(i * 4) + 1] = i; - pal[(i * 4) + 2] = i; - } -#endif + // Prepare the palette to show + for (int i = 0; i < 256; i++) { + pal[(i * 4) + 0] = pal3[(i * 3) + 0]; + pal[(i * 4) + 1] = pal3[(i * 3) + 1]; + pal[(i * 4) + 2] = pal3[(i * 3) + 2]; + } +#else // !DITHER + // Set a grayscale palette + for (int i = 0; i < 256; i++) { + pal[(i * 4) + 0] = i; + pal[(i * 4) + 1] = i; + pal[(i * 4) + 2] = i; + } +#endif // DITHER - _syst->setPalette(pal, 0, 256); + _syst->setPalette(pal, 0, 256); + } } ROQPlayer::~ROQPlayer() { @@ -154,13 +162,25 @@ void ROQPlayer::buildShowBuf() { byte *out = (byte *)_showBuf.getBasePtr(0, line); byte *in = (byte *)_prevBuf->getBasePtr(0, line / _scaleY); for (int x = 0; x < _showBuf.w; x++) { + if (_vm->_mode8bit) { #ifdef DITHER - *out = _dither->dither(*in, *(in + 1), *(in + 2), x); + *out = _dither->dither(*in, *(in + 1), *(in + 2), x); #else - // Just use the luminancy component - *out = *in; -#endif - out++; + // Just use the luminancy component + *out = *in; +#endif // DITHER +#ifdef ENABLE_RGB_COLOR + } else { + // Do the format conversion (YUV -> RGB -> Screen format) + byte r, g, b; + Graphics::YUV2RGB(*in, *(in + 1), *(in + 2), r, g, b); + // FIXME: this is fixed to 16bit + *(uint16 *)out = (uint16)_vm->_pixelFormat.RGBToColor(r, g, b); +#endif // ENABLE_RGB_COLOR + } + + // Skip to the next pixel + out += _vm->_pixelFormat.bytesPerPixel; if (!(x % _scaleX)) in += _prevBuf->bytesPerPixel; } @@ -189,7 +209,7 @@ bool ROQPlayer::playFrameInternal() { if (_dirty) { // Update the screen - _syst->copyRectToScreen((byte *)_showBuf.getBasePtr(0, 0), _showBuf.w, 0, (_syst->getHeight() - _showBuf.h) / 2, _showBuf.pitch, _showBuf.h); + _syst->copyRectToScreen((byte *)_showBuf.getBasePtr(0, 0), _showBuf.pitch, 0, (_syst->getHeight() - _showBuf.h) / 2, _showBuf.w, _showBuf.h); _syst->updateScreen(); // Clear the dirty flag @@ -316,7 +336,19 @@ bool ROQPlayer::processBlockInfo(ROQBlockHeader &blockHeader) { // Allocate new buffers _currBuf->create(width, height, 3); _prevBuf->create(width, height, 3); - _showBuf.create(width * _scaleX, height * _scaleY, 1); + _showBuf.create(width * _scaleX, height * _scaleY, _vm->_pixelFormat.bytesPerPixel); + + // Clear the buffers with black YUV values + byte *ptr1 = (byte *)_currBuf->getBasePtr(0, 0); + byte *ptr2 = (byte *)_prevBuf->getBasePtr(0, 0); + for (int i = 0; i < width * height; i++) { + *ptr1++ = 0; + *ptr1++ = 128; + *ptr1++ = 128; + *ptr2++ = 0; + *ptr2++ = 128; + *ptr2++ = 128; + } #ifdef DITHER // Reset the dithering algorithm with the new width @@ -455,10 +487,21 @@ void ROQPlayer::processBlockQuadVectorBlockSub(int baseX, int baseY, int8 Mx, in bool ROQPlayer::processBlockStill(ROQBlockHeader &blockHeader) { debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing still (JPEG) block"); - warning("Groovie::ROQ: JPEG frame (unimplemented)"); - memset(_prevBuf->getBasePtr(0, 0), 0, _prevBuf->w * _prevBuf->h * _prevBuf->bytesPerPixel); + warning("Groovie::ROQ: JPEG frame (unfinshed)"); + + Graphics::JPEG *jpg = new Graphics::JPEG(); + jpg->read(_file); + byte *y = (byte *)jpg->getComponent(1)->getBasePtr(0, 0); + byte *u = (byte *)jpg->getComponent(2)->getBasePtr(0, 0); + byte *v = (byte *)jpg->getComponent(3)->getBasePtr(0, 0); + + byte *ptr = (byte *)_prevBuf->getBasePtr(0, 0); + for (int i = 0; i < _prevBuf->w * _prevBuf->h; i++) { + *ptr++ = *y++; + *ptr++ = *u++; + *ptr++ = *v++; + } - _file->skip(blockHeader.size); return true; } diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp index eb53842b91..934400fb15 100644 --- a/engines/groovie/script.cpp +++ b/engines/groovie/script.cpp @@ -354,7 +354,7 @@ bool Script::hotspot(Common::Rect rect, uint16 address, uint8 cursor) { Common::isDebugChannelEnabled(kGroovieDebugAll)) { rect.translate(0, -80); _vm->_graphicsMan->_foreground.frameRect(rect, 250); - _vm->_system->copyRectToScreen((byte*)_vm->_graphicsMan->_foreground.getBasePtr(0, 0), 640, 0, 80, 640, 320); + _vm->_system->copyRectToScreen((byte*)_vm->_graphicsMan->_foreground.getBasePtr(0, 0), _vm->_graphicsMan->_foreground.pitch, 0, 80, 640, 320); _vm->_system->updateScreen(); } diff --git a/engines/sci/gfx/gfx_driver.cpp b/engines/sci/gfx/gfx_driver.cpp index c665eef3b8..9457727b33 100644 --- a/engines/sci/gfx/gfx_driver.cpp +++ b/engines/sci/gfx/gfx_driver.cpp @@ -27,18 +27,19 @@ #include "common/system.h" #include "graphics/cursorman.h" #include "graphics/primitives.h" +#include "graphics/surface.h" #include "sci/sci.h" #include "sci/gfx/gfx_driver.h" #include "sci/gfx/gfx_tools.h" + namespace Sci { -GfxDriver::GfxDriver(int xfact, int yfact, int bytespp) { +GfxDriver::GfxDriver(int xfact, int yfact, Graphics::PixelFormat format) { int i; - Graphics::PixelFormat format = { bytespp, 0, 0, 0, 0, 0, 0, 0, 0 }; - _mode = gfx_new_mode(xfact, yfact, format, new Palette(256), 0); + _mode = gfx_new_mode(xfact, yfact, format, format.bytesPerPixel == 1 ? new Palette(256) : 0, 0); _mode->xsize = xfact * 320; _mode->ysize = yfact * 200; @@ -51,14 +52,15 @@ GfxDriver::GfxDriver(int xfact, int yfact, int bytespp) { // create the visual buffers for (i = 0; i < 2; i++) { _visual[i] = NULL; - _visual[i] = new byte[_mode->xsize * _mode->ysize]; + _visual[i] = new byte[_mode->xsize * _mode->ysize * _mode->bytespp]; if (!_visual[i]) { error("Out of memory: Could not allocate visual buffers! (%dx%d)\n", _mode->xsize, _mode->ysize); } - memset(_visual[i], 0, _mode->xsize * _mode->ysize); + memset(_visual[i], 0, _mode->xsize * _mode->ysize * _mode->bytespp); } - _mode->palette->name = "global"; + if (_mode->palette) + _mode->palette->name = "global"; } GfxDriver::~GfxDriver() { @@ -77,10 +79,12 @@ GfxDriver::~GfxDriver() { // Drawing operations +template<int COPY_BYTES, typename SIZETYPE, int EXTRA_BYTE_OFFSET> static void drawProc(int x, int y, int c, void *data) { GfxDriver *drv = (GfxDriver *)data; byte *p = drv->getVisual0(); - p[y * 320* drv->getMode()->xfact + x] = c; + SIZETYPE col = c << (EXTRA_BYTE_OFFSET * 8); + memcpy(p + (y * 320* drv->getMode()->xfact + x) * COPY_BYTES, &col, COPY_BYTES); } int GfxDriver::drawLine(Common::Point start, Common::Point end, gfx_color_t color, @@ -91,6 +95,28 @@ int GfxDriver::drawLine(Common::Point start, Common::Point end, gfx_color_t colo int xsize = _mode->xsize; int ysize = _mode->ysize; + void (*modeDrawProc)(int,int,int,void*); + switch (_mode->bytespp) { + case 1: + modeDrawProc = drawProc<1, uint8, 0>; + break; + case 2: + modeDrawProc = drawProc<2, uint16, 0>; + break; + case 3: +#ifdef SCUMM_BIG_ENDIAN + modeDrawProc = drawProc<3, uint32, 1>; +#else + modeDrawProc = drawProc<3, uint32, 0>; +#endif + break; + case 4: + modeDrawProc = drawProc<4, uint32, 0>; + break; + default: + GFXERROR("Invalid mode->bytespp=%d\n", _mode->bytespp); + } + if (color.mask & GFX_MASK_VISUAL) { Common::Point nstart, nend; @@ -102,7 +128,7 @@ int GfxDriver::drawLine(Common::Point start, Common::Point end, gfx_color_t colo nend.x = CLIP<int16>(end.x + xc, 0, xsize - 1); nend.y = CLIP<int16>(end.y + yc, 0, ysize - 1); - Graphics::drawLine(nstart.x, nstart.y, nend.x, nend.y, scolor, drawProc, this); + Graphics::drawLine(nstart.x, nstart.y, nend.x, nend.y, scolor, modeDrawProc, this); if (color.mask & GFX_MASK_PRIORITY) { gfx_draw_line_pixmap_i(_priority[0], nstart, nend, color.priority); @@ -118,7 +144,8 @@ int GfxDriver::drawFilledRect(rect_t rect, gfx_color_t color1, gfx_color_t color gfx_rectangle_fill_t shade_mode) { if (color1.mask & GFX_MASK_VISUAL) { for (int i = rect.y; i < rect.y + rect.height; i++) { - memset(_visual[0] + i * _mode->xsize + rect.x, color1.visual.parent_index, rect.width); + memset(_visual[0] + (i * _mode->xsize + rect.x) * _mode->bytespp, + color1.visual.parent_index, rect.width * _mode->bytespp); } } @@ -138,8 +165,10 @@ int GfxDriver::drawPixmap(gfx_pixmap_t *pxm, int priority, rect_t src, rect_t de return GFX_ERROR; } - gfx_crossblit_pixmap(_mode, pxm, priority, src, dest, _visual[bufnr], _mode->xsize, - _priority[bufnr]->index_data, _priority[bufnr]->index_width, 1, 0); + gfx_crossblit_pixmap(_mode, pxm, priority, src, dest, _visual[bufnr], + _mode->xsize * _mode->bytespp, + _priority[bufnr]->index_data, + _priority[bufnr]->index_width, 1, 0); return GFX_OK; } @@ -161,7 +190,9 @@ int GfxDriver::grabPixmap(rect_t src, gfx_pixmap_t *pxm, gfx_map_mask_t map) { pxm->width = src.width; pxm->height = src.height; for (int i = 0; i < src.height; i++) { - memcpy(pxm->data + i * src.width, _visual[0] + (i + src.y) * _mode->xsize + src.x, src.width); + memcpy(pxm->data + i * src.width * _mode->bytespp, + _visual[0] + _mode->bytespp * ((i + src.y) * _mode->xsize + src.x), + src.width * _mode->bytespp); } break; @@ -193,17 +224,18 @@ int GfxDriver::update(rect_t src, Common::Point dest, gfx_buffer_t buffer) { switch (buffer) { case GFX_BUFFER_BACK: for (int i = 0; i < src.height; i++) { - memcpy(_visual[0] + (dest.y + i) * _mode->xsize + dest.x, - _visual[1] + (src.y + i) * _mode->xsize + src.x, src.width); + memcpy(_visual[0] + _mode->bytespp * ( (dest.y + i) * _mode->xsize + dest.x), + _visual[1] + _mode->bytespp * ( (src.y + i) * _mode->xsize + src.x), src.width * _mode->bytespp ); } if ((src.x == dest.x) && (src.y == dest.y)) gfx_copy_pixmap_box_i(_priority[0], _priority[1], src); break; - case GFX_BUFFER_FRONT: - g_system->copyRectToScreen(_visual[0] + src.x + src.y * _mode->xsize, _mode->xsize, dest.x, dest.y, src.width, src.height); + case GFX_BUFFER_FRONT: { + g_system->copyRectToScreen(_visual[0] + _mode->bytespp * (src.x + src.y * _mode->xsize), _mode->xsize * _mode->bytespp, dest.x, dest.y, src.width, src.height); g_system->updateScreen(); break; + } default: GFXERROR("Invalid buffer %d in update!\n", buffer); return GFX_ERROR; @@ -213,7 +245,7 @@ int GfxDriver::update(rect_t src, Common::Point dest, gfx_buffer_t buffer) { } int GfxDriver::setStaticBuffer(gfx_pixmap_t *pic, gfx_pixmap_t *priority) { - memcpy(_visual[1], pic->data, _mode->xsize * _mode->ysize); + memcpy(_visual[1], pic->data, _mode->xsize * _mode->ysize * _mode->bytespp); gfx_copy_pixmap_box_i(_priority[1], priority, gfx_rect(0, 0, _mode->xsize, _mode->ysize)); return GFX_OK; diff --git a/engines/sci/gfx/gfx_driver.h b/engines/sci/gfx/gfx_driver.h index f7cbd0b6c2..cc8a5208d4 100644 --- a/engines/sci/gfx/gfx_driver.h +++ b/engines/sci/gfx/gfx_driver.h @@ -29,6 +29,8 @@ #include "sci/gfx/gfx_system.h" #include "sci/uinput.h" +#include "graphics/pixelformat.h" + namespace Sci { enum gfx_buffer_t { @@ -85,7 +87,7 @@ public: * not be set, or GFX_FATAL if the graphics target * is unuseable. */ - GfxDriver(int xfact, int yfact, int bytespp); + GfxDriver(int xfact, int yfact, Graphics::PixelFormat mode); /** * Uninitializes the current graphics mode. diff --git a/engines/sci/gfx/gfx_pixmap_scale.cpp b/engines/sci/gfx/gfx_pixmap_scale.cpp index 52c7b12396..37843743b9 100644 --- a/engines/sci/gfx/gfx_pixmap_scale.cpp +++ b/engines/sci/gfx/gfx_pixmap_scale.cpp @@ -70,14 +70,11 @@ void _gfx_xlate_pixmap_unfiltered(gfx_mode_t *mode, gfx_pixmap_t *pxm, int scale // Calculate all colors for (i = 0; i < pxm->colors_nr(); i++) { int col; - const PaletteEntry& color = pxm->palette->getColor(i); if (mode->palette) col = color.parent_index; else { - col = mode->red_mask & ((EXTEND_COLOR(color.r)) >> mode->red_shift); - col |= mode->green_mask & ((EXTEND_COLOR(color.g)) >> mode->green_shift); - col |= mode->blue_mask & ((EXTEND_COLOR(color.b)) >> mode->blue_shift); + col = mode->format.ARGBToColor(0, color.r, color.g, color.b); col |= alpha_ormask; } result_colors[i] = col; diff --git a/engines/sci/gfx/gfx_resmgr.cpp b/engines/sci/gfx/gfx_resmgr.cpp index 1289997721..282931d004 100644 --- a/engines/sci/gfx/gfx_resmgr.cpp +++ b/engines/sci/gfx/gfx_resmgr.cpp @@ -268,7 +268,8 @@ void GfxResManager::setStaticPalette(Palette *newPalette) _staticPalette = newPalette; _staticPalette->name = "static palette"; - _staticPalette->mergeInto(_driver->getMode()->palette); + if (_driver->getMode()->palette) + _staticPalette->mergeInto(_driver->getMode()->palette); } #if 0 diff --git a/engines/sci/gfx/gfx_system.h b/engines/sci/gfx/gfx_system.h index 6b7724a6bd..4d9a39934d 100644 --- a/engines/sci/gfx/gfx_system.h +++ b/engines/sci/gfx/gfx_system.h @@ -30,6 +30,7 @@ #include "common/rect.h" #include "sci/tools.h" #include "sci/gfx/palette.h" +#include "graphics/pixelformat.h" namespace Sci { @@ -77,8 +78,10 @@ struct gfx_mode_t { */ Palette *palette; + // TODO: remove those uint32 red_mask, green_mask, blue_mask, alpha_mask; short red_shift, green_shift, blue_shift, alpha_shift; + Graphics::PixelFormat format; }; diff --git a/engines/sci/gfx/gfx_tools.cpp b/engines/sci/gfx/gfx_tools.cpp index e89fb1572a..b835084b0c 100644 --- a/engines/sci/gfx/gfx_tools.cpp +++ b/engines/sci/gfx/gfx_tools.cpp @@ -49,6 +49,7 @@ gfx_mode_t *gfx_new_mode(int xfact, int yfact, const Graphics::PixelFormat &form mode->xfact = xfact; mode->yfact = yfact; mode->bytespp = format.bytesPerPixel; + mode->format = format; // FIXME: I am not sure whether the following assignments are quite right. // The only code using these are the built-in scalers of the SCI engine. @@ -60,10 +61,10 @@ gfx_mode_t *gfx_new_mode(int xfact, int yfact, const Graphics::PixelFormat &form mode->green_mask = format.ARGBToColor(0, 0, 0xFF, 0); mode->blue_mask = format.ARGBToColor(0, 0, 0, 0xFF); mode->alpha_mask = format.ARGBToColor(0xFF, 0, 0, 0); - mode->red_shift = format.rLoss; - mode->green_shift = format.gLoss; - mode->blue_shift = format.bLoss; - mode->alpha_shift = format.aLoss; + mode->red_shift = format.rShift; + mode->green_shift = format.gShift; + mode->blue_shift = format.bShift; + mode->alpha_shift = format.aShift; } else { mode->red_mask = mode->green_mask = mode->blue_mask = 0; mode->alpha_mask = 0; diff --git a/engines/sci/gfx/operations.cpp b/engines/sci/gfx/operations.cpp index 82b5e78117..1f7c4ed479 100644 --- a/engines/sci/gfx/operations.cpp +++ b/engines/sci/gfx/operations.cpp @@ -411,8 +411,9 @@ static void init_aux_pixmap(gfx_pixmap_t **pixmap) { (*pixmap)->palette = new Palette(default_colors, DEFAULT_COLORS_NR); } -int gfxop_init(int version, bool isVGA, GfxState *state, gfx_options_t *options, ResourceManager *resManager, - int xfact, int yfact, gfx_color_mode_t bpp) { +int gfxop_init(int version, bool isVGA, GfxState *state, + gfx_options_t *options, ResourceManager *resManager, + Graphics::PixelFormat mode, int xfact, int yfact) { //int color_depth = bpp ? bpp : 1; //int initialized = 0; @@ -430,7 +431,7 @@ int gfxop_init(int version, bool isVGA, GfxState *state, gfx_options_t *options, state->pic_port_bounds = gfx_rect(0, 10, 320, 190); state->_dirtyRects.clear(); - state->driver = new GfxDriver(xfact, yfact, bpp); + state->driver = new GfxDriver(xfact, yfact, mode); state->gfxResMan = new GfxResManager(version, isVGA, state->options, state->driver, resManager); @@ -1165,8 +1166,10 @@ static int _gfxop_set_pointer(GfxState *state, gfx_pixmap_t *pxm, Common::Point // may change when a new PIC is loaded. The cursor has to be regenerated // from this pxm at that point. (An alternative might be to ensure the // cursor only uses colours in the static part of the palette?) - if (pxm && pxm->palette) + if (pxm && state->driver->getMode()->palette) { + assert(pxm->palette); pxm->palette->mergeInto(state->driver->getMode()->palette); + } state->driver->setPointer(pxm, hotspot); return GFX_OK; @@ -1762,7 +1765,8 @@ static int _gfxop_set_pic(GfxState *state) { // FIXME: The _gfxop_install_pixmap call below updates the OSystem palette. // This is too soon, since it causes brief palette corruption until the // screen is updated too. (Possibly related: EngineState::pic_not_valid .) - state->pic->visual_map->palette->forceInto(state->driver->getMode()->palette); + if (state->driver->getMode()->palette) + state->pic->visual_map->palette->forceInto(state->driver->getMode()->palette); _gfxop_install_pixmap(state->driver, state->pic->visual_map); #ifdef CUSTOM_GRAPHICS_OPTIONS @@ -1787,7 +1791,7 @@ int gfxop_new_pic(GfxState *state, int nr, int flags, int default_palette) { if (state->driver->getMode()->xfact == 1 && state->driver->getMode()->yfact == 1) { state->pic_unscaled = state->pic; } else { - state->pic = state->gfxResMan->getPic(nr, GFX_MASK_VISUAL, flags, default_palette, false); + state->pic_unscaled = state->gfxResMan->getPic(nr, GFX_MASK_VISUAL, flags, default_palette, false); } if (!state->pic || !state->pic_unscaled) { diff --git a/engines/sci/gfx/operations.h b/engines/sci/gfx/operations.h index 491b485da0..d567934ceb 100644 --- a/engines/sci/gfx/operations.h +++ b/engines/sci/gfx/operations.h @@ -139,17 +139,16 @@ struct GfxState { * @param[in] state The state to initialize * @param[in] xfact Horizontal scale factor * @param[in] yfact Vertical scale factors - * @param[in] bpp Bytes per pixel to initialize with, or 0 - * (GFX_COLOR_MODE_AUTO) to auto-detect + * @param[in] mode Graphics mode to use * @param[in] options Rendering options * @param[in] resManager Resource manager to use * @return GFX_OK on success, GFX_ERROR if that particular mode * is unavailable, or GFX_FATAL if the graphics driver * is unable to provide any useful graphics support */ -int gfxop_init(int version, bool isVGA, GfxState *state, gfx_options_t *options, - ResourceManager *resManager, int xfact = 1, int yfact = 1, - gfx_color_mode_t bpp = GFX_COLOR_MODE_INDEX); +int gfxop_init(int version, bool isVGA, GfxState *state, + gfx_options_t *options, ResourceManager *resManager, + Graphics::PixelFormat mode, int xfact = 1, int yfact = 1); /** * Deinitializes a currently active driver. diff --git a/engines/sci/gfx/res_pic.cpp b/engines/sci/gfx/res_pic.cpp index 5ee2665b50..2c91cb579f 100644 --- a/engines/sci/gfx/res_pic.cpp +++ b/engines/sci/gfx/res_pic.cpp @@ -1548,7 +1548,7 @@ void gfxr_draw_pic01(gfxr_pic_t *pic, int flags, int default_palette, int size, view->index_height = CLIP<int>(view->index_height, 0, portBounds.height()); // Set up mode structure for resizing the view - Graphics::PixelFormat format = { 1, 0, 0, 0, 0, 0, 0, 0, 0 }; // 1byte/p, which handles masks and the rest for us + Graphics::PixelFormat format(1, 0, 0, 0, 0, 0, 0, 0, 0); // 1byte/p, which handles masks and the rest for us gfx_mode_t *mode = gfx_new_mode(pic->visual_map->index_width / 320, pic->visual_map->index_height / 200, format, view->palette, 0); @@ -1654,7 +1654,7 @@ void gfxr_draw_pic11(gfxr_pic_t *pic, int flags, int default_palette, int size, view->palette = pic->visual_map->palette->getref(); // Set up mode structure for resizing the view - Graphics::PixelFormat format = { 1, 0, 0, 0, 0, 0, 0, 0, 0 }; // 1 byte/p, which handles masks and the rest for us + Graphics::PixelFormat format(1, 0, 0, 0, 0, 0, 0, 0, 0); // 1 byte/p, which handles masks and the rest for us gfx_mode_t *mode = gfx_new_mode(pic->visual_map->index_width / 320, pic->visual_map->index_height / 200, format, view->palette, 0); gfx_xlate_pixmap(view, mode, GFX_XLATE_FILTER_NONE); diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 250460c5de..822542839b 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -102,7 +102,14 @@ SciEngine::~SciEngine() { } Common::Error SciEngine::run() { + Graphics::PixelFormat gfxmode; +#ifdef ENABLE_RGB_COLOR + gfxmode = _system->getSupportedFormats().front(); + initGraphics(320, 200, false, &gfxmode); +#else initGraphics(320, 200, false); +#endif + gfxmode = _system->getScreenFormat(); // Create debugger console. It requires GFX to be initialized _console = new Console(this); @@ -216,7 +223,7 @@ Common::Error SciEngine::run() { #endif bool isVGA = _resmgr->_sciVersion >= SCI_VERSION_01_VGA && !(getFlags() & GF_SCI1_EGA); - if (gfxop_init(_resmgr->_sciVersion, isVGA, &gfx_state, &gfx_options, _resmgr)) { + if (gfxop_init(_resmgr->_sciVersion, isVGA, &gfx_state, &gfx_options, _resmgr, gfxmode, 1, 1)) { warning("Graphics initialization failed. Aborting..."); return Common::kUnknownError; } diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index 88c258a2e6..52866279b8 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -2400,7 +2400,7 @@ void ScummEngine_v71he::postProcessAuxQueue() { uint8 *dst2 = pvs->getBackPixels(0, pvs->topline); switch (comp) { case 1: - Wiz::copyAuxImage(dst1, dst2, axfd + 10, pvs->w, pvs->h, x, y, w, h); + Wiz::copyAuxImage(dst1, dst2, axfd + 10, pvs->pitch, pvs->h, x, y, w, h, _bitDepth); break; default: error("unimplemented compression type %d", comp); @@ -2500,9 +2500,10 @@ void Actor::saveLoadWithSerializer(Serializer *ser) { MKLINE(Actor, _flip, sleByte, VER(32)), MKLINE(Actor, _heSkipLimbs, sleByte, VER(32)), - // Actor palette grew from 64 to 256 bytes + // Actor palette grew from 64 to 256 bytes and switched to uint16 in HE games MKARRAY_OLD(Actor, _palette[0], sleByte, 64, VER(8), VER(9)), - MKARRAY(Actor, _palette[0], sleByte, 256, VER(10)), + MKARRAY_OLD(Actor, _palette[0], sleByte, 256, VER(10), VER(77)), + MKARRAY(Actor, _palette[0], sleUint16, 256, VER(78)), MK_OBSOLETE(Actor, _mask, sleByte, VER(8), VER(9)), MKLINE(Actor, _shadowMode, sleByte, VER(8)), diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h index 3e8fe6626b..d32f268b11 100644 --- a/engines/scumm/actor.h +++ b/engines/scumm/actor.h @@ -157,7 +157,7 @@ protected: }; - byte _palette[256]; + uint16 _palette[256]; int _elevation; uint16 _facing; uint16 _targetFacing; diff --git a/engines/scumm/akos.cpp b/engines/scumm/akos.cpp index ab7db2c4a7..f4bb8a2c8b 100644 --- a/engines/scumm/akos.cpp +++ b/engines/scumm/akos.cpp @@ -289,7 +289,7 @@ void AkosCostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) { } while ((uint16)mask); } -void AkosRenderer::setPalette(byte *new_palette) { +void AkosRenderer::setPalette(uint16 *new_palette) { uint size, i; size = _vm->getResourceDataSize(akpl); @@ -299,22 +299,23 @@ void AkosRenderer::setPalette(byte *new_palette) { if (size > 256) error("akos_setPalette: %d is too many colors", size); - if (_vm->_game.heversion >= 99 && _paletteNum) { - for (i = 0; i < size; i++) - _palette[i] = (byte)_vm->_hePalettes[_paletteNum * 1024 + 768 + akpl[i]]; - } else if ((_vm->_game.features & GF_16BIT_COLOR) && rgbs) { - for (i = 0; i < size; i++) { - if (new_palette[i] == 0xFF) { - uint8 col = akpl[i]; - uint8 r = rgbs[col * 3 + 0]; - uint8 g = rgbs[col * 3 + 1]; - uint8 b = rgbs[col * 3 + 2]; - - _palette[i] = _vm->remapPaletteColor(r, g, b, -1); - } else { - _palette[i] = new_palette[i]; + if (_vm->_game.features & GF_16BIT_COLOR) { + if (_paletteNum) { + for (i = 0; i < size; i++) + _palette[i] = READ_LE_UINT16(_vm->_hePalettes + _paletteNum * _vm->_hePaletteSlot + 768 + akpl[i] * 2); + } else if (rgbs) { + for (i = 0; i < size; i++) { + if (new_palette[i] == 0xFF) { + uint8 col = akpl[i]; + _palette[i] = _vm->get16BitColor(rgbs[col * 3 + 0], rgbs[col * 3 + 1], rgbs[col * 3 + 2]); + } else { + _palette[i] = new_palette[i]; + } } } + } else if (_vm->_game.heversion >= 99 && _paletteNum) { + for (i = 0; i < size; i++) + _palette[i] = (byte)_vm->_hePalettes[_paletteNum * _vm->_hePaletteSlot + 768 + akpl[i]]; } else { for (i = 0; i < size; i++) { _palette[i] = new_palette[i] != 0xFF ? new_palette[i] : akpl[i]; @@ -545,7 +546,7 @@ void AkosRenderer::codec1_genericDecode(Codec1 &v1) { byte *dst; byte len, maskbit; int y; - uint color, height, pcolor; + uint16 color, height, pcolor; const byte *scaleytab; bool masked; bool skip_column = false; @@ -589,7 +590,11 @@ void AkosRenderer::codec1_genericDecode(Codec1 &v1) { } else if (_shadow_mode == 2) { error("codec1_spec2"); // TODO } else if (_shadow_mode == 3) { - if (_vm->_game.heversion >= 90) { + if (_vm->_game.features & GF_16BIT_COLOR) { + uint16 srcColor = (pcolor >> 1) & 0x7DEF; + uint16 dstColor = (READ_UINT16(dst) >> 1) & 0x7DEF; + pcolor = srcColor + dstColor; + } else if (_vm->_game.heversion >= 90) { pcolor = (pcolor << 8) + *dst; pcolor = xmap[pcolor]; } else if (pcolor < 8) { @@ -597,7 +602,11 @@ void AkosRenderer::codec1_genericDecode(Codec1 &v1) { pcolor = _shadow_table[pcolor]; } } - *dst = pcolor; + if (_vm->_bitDepth == 2) { + WRITE_UINT16(dst, pcolor); + } else { + *dst = pcolor; + } } } dst += _out.pitch; @@ -617,7 +626,7 @@ void AkosRenderer::codec1_genericDecode(Codec1 &v1) { if (v1.x < 0 || v1.x >= v1.boundsRect.right) return; maskbit = revBitMask(v1.x & 7); - v1.destptr += v1.scaleXstep; + v1.destptr += v1.scaleXstep * _vm->_bitDepth; skip_column = false; } else skip_column = true; @@ -987,7 +996,7 @@ byte AkosRenderer::codec1(int xmoveCur, int ymoveCur) { if (_draw_bottom < rect.bottom) _draw_bottom = rect.bottom; - v1.destptr = (byte *)_out.pixels + v1.y * _out.pitch + v1.x; + v1.destptr = (byte *)_out.pixels + v1.y * _out.pitch + v1.x * _vm->_bitDepth; codec1_genericDecode(v1); @@ -1056,7 +1065,12 @@ byte AkosRenderer::codec5(int xmoveCur, int ymoveCur) { bdd.shadowMode = _shadow_mode; bdd.shadowPalette = _vm->_shadowPalette; - bdd.actorPalette = _useBompPalette ? _palette : 0; + bdd.actorPalette = 0; + if (_useBompPalette) { + for (uint i = 0; i < 256; i++) + bdd.actorPalette[i] = _palette[i]; + } + bdd.mirror = !_mirror; drawBomp(bdd); @@ -1176,6 +1190,8 @@ void AkosRenderer::akos16Decompress(byte *dest, int32 pitch, const byte *src, in } byte AkosRenderer::codec16(int xmoveCur, int ymoveCur) { + assert(_vm->_bitDepth == 1); + Common::Rect clip; int32 minx, miny, maxw, maxh; int32 skip_x, skip_y, cur_x, cur_y; @@ -1278,7 +1294,7 @@ byte AkosRenderer::codec16(int xmoveCur, int ymoveCur) { int32 numskip_before = skip_x + (skip_y * _width); int32 numskip_after = _width - cur_x; - byte *dst = (byte *)_out.pixels + width_unk + height_unk * _out.pitch; + byte *dst = (byte *)_out.pixels + height_unk * _out.pitch + width_unk * _vm->_bitDepth; akos16Decompress(dst, _out.pitch, _srcptr, cur_x, out_height, dir, numskip_before, numskip_after, transparency, clip.left, clip.top, _zbuf); return 0; @@ -1335,18 +1351,27 @@ byte AkosRenderer::codec32(int xmoveCur, int ymoveCur) { _draw_bottom = dst.bottom; const uint8 *palPtr = NULL; - if (_vm->_game.heversion >= 99) { - palPtr = _vm->_hePalettes + 1792; + if (_vm->_game.features & GF_16BIT_COLOR) { + palPtr = _vm->_hePalettes + _vm->_hePaletteSlot + 768; + if (_paletteNum) { + palPtr = _vm->_hePalettes + _paletteNum * _vm->_hePaletteSlot + 768; + } else if (rgbs) { + for (uint i = 0; i < 256; i++) + WRITE_LE_UINT16(_palette + i, _vm->get16BitColor(rgbs[i * 3 + 0], rgbs[i * 3 + 1], rgbs[i * 3 + 2])); + palPtr = (uint8 *)_palette; + } + } else if (_vm->_game.heversion >= 99) { + palPtr = _vm->_hePalettes + _vm->_hePaletteSlot + 768; } - byte *dstPtr = (byte *)_out.pixels + dst.left + dst.top * _out.pitch; + byte *dstPtr = (byte *)_out.pixels + dst.top * _out.pitch + dst.left * _vm->_bitDepth; if (_shadow_mode == 3) { - Wiz::decompressWizImage<kWizXMap>(dstPtr, _out.pitch, _srcptr, src, 0, palPtr, xmap); + Wiz::decompressWizImage<kWizXMap>(dstPtr, _out.pitch, kDstScreen, _srcptr, src, 0, palPtr, xmap, _vm->_bitDepth); } else { if (palPtr != NULL) { - Wiz::decompressWizImage<kWizRMap>(dstPtr, _out.pitch, _srcptr, src, 0, palPtr); + Wiz::decompressWizImage<kWizRMap>(dstPtr, _out.pitch, kDstScreen, _srcptr, src, 0, palPtr, NULL, _vm->_bitDepth); } else { - Wiz::decompressWizImage<kWizCopy>(dstPtr, _out.pitch, _srcptr, src, 0); + Wiz::decompressWizImage<kWizCopy>(dstPtr, _out.pitch, kDstScreen, _srcptr, src, 0, NULL, NULL, _vm->_bitDepth); } } #endif diff --git a/engines/scumm/akos.h b/engines/scumm/akos.h index be532b804d..9f4f09d4dc 100644 --- a/engines/scumm/akos.h +++ b/engines/scumm/akos.h @@ -60,7 +60,7 @@ protected: uint16 _codec; // actor _palette - byte _palette[256]; + uint16 _palette[256]; bool _useBompPalette; // pointer to various parts of the costume resource @@ -107,7 +107,7 @@ public: int16 _actorHitX, _actorHitY; bool _actorHitResult; - void setPalette(byte *_palette); + void setPalette(uint16 *_palette); void setFacing(const Actor *a); void setCostume(int costume, int shadow); diff --git a/engines/scumm/base-costume.cpp b/engines/scumm/base-costume.cpp index 795abb8685..ef706afaac 100644 --- a/engines/scumm/base-costume.cpp +++ b/engines/scumm/base-costume.cpp @@ -40,7 +40,7 @@ byte BaseCostumeRenderer::drawCostume(const VirtScreen &vs, int numStrips, const _out.pixels = vs.getPixels(0, 0); _actorX += _vm->_virtscr[kMainVirtScreen].xstart & 7; - _out.w = _out.pitch; + _out.w = _out.pitch / _vm->_bitDepth; _out.pixels = (byte *)_out.pixels - (_vm->_virtscr[kMainVirtScreen].xstart & 7); _numStrips = numStrips; diff --git a/engines/scumm/base-costume.h b/engines/scumm/base-costume.h index 59ca3ded1f..d41d795e34 100644 --- a/engines/scumm/base-costume.h +++ b/engines/scumm/base-costume.h @@ -145,7 +145,7 @@ public: } virtual ~BaseCostumeRenderer() {} - virtual void setPalette(byte *palette) = 0; + virtual void setPalette(uint16 *palette) = 0; virtual void setFacing(const Actor *a) = 0; virtual void setCostume(int costume, int shadow) = 0; diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp index 193fc434e4..d6dfa4c5bb 100644 --- a/engines/scumm/charset.cpp +++ b/engines/scumm/charset.cpp @@ -819,9 +819,9 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr, byte imagePalette[256]; memset(imagePalette, 0, sizeof(imagePalette)); memcpy(imagePalette, _vm->_charsetColorMap, 4); - Wiz::copyWizImage(dstPtr, charPtr, vs->w, vs->h, _left, _top, origWidth, origHeight, &rScreen, 0, imagePalette); + Wiz::copyWizImage(dstPtr, charPtr, vs->pitch, kDstScreen, vs->w, vs->h, _left, _top, origWidth, origHeight, &rScreen, 0, imagePalette, NULL, _vm->_bitDepth); } else { - Wiz::copyWizImage(dstPtr, charPtr, vs->w, vs->h, _left, _top, origWidth, origHeight, &rScreen); + Wiz::copyWizImage(dstPtr, charPtr, vs->pitch, kDstScreen, vs->w, vs->h, _left, _top, origWidth, origHeight, &rScreen, 0, NULL, NULL, _vm->_bitDepth); } if (_blitAlso && vs->hasTwoBuffers) { diff --git a/engines/scumm/costume.cpp b/engines/scumm/costume.cpp index 82497de87a..39c2f73e88 100644 --- a/engines/scumm/costume.cpp +++ b/engines/scumm/costume.cpp @@ -791,7 +791,7 @@ byte ClassicCostumeRenderer::drawLimb(const Actor *a, int limb) { } -void NESCostumeRenderer::setPalette(byte *palette) { +void NESCostumeRenderer::setPalette(uint16 *palette) { // TODO } @@ -874,17 +874,20 @@ void ClassicCostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) } while (mask&0xFFFF); } -void ClassicCostumeRenderer::setPalette(byte *palette) { +void ClassicCostumeRenderer::setPalette(uint16 *palette) { int i; byte color; if (_loaded._format == 0x57) { - memcpy(_palette, palette, 13); + for (i = 0; i < 13; i++) + _palette[i] = palette[i]; } else if (_vm->_game.features & GF_OLD_BUNDLE) { if (_vm->getCurrentLights() & LIGHTMODE_actor_use_colors) { - memcpy(_palette, palette, 16); + for (i = 0; i < 16; i++) + _palette[i] = palette[i]; } else { - memset(_palette, 8, 16); + for (i = 0; i < 16; i++) + _palette[i] = 8; _palette[12] = 0; } _palette[_loaded._palette[0]] = _palette[0]; diff --git a/engines/scumm/costume.h b/engines/scumm/costume.h index 003bd6ce2b..ecb12986cf 100644 --- a/engines/scumm/costume.h +++ b/engines/scumm/costume.h @@ -94,7 +94,7 @@ protected: public: ClassicCostumeRenderer(ScummEngine *vm) : BaseCostumeRenderer(vm), _loaded(vm) {} - void setPalette(byte *palette); + void setPalette(uint16 *palette); void setFacing(const Actor *a); void setCostume(int costume, int shadow); @@ -116,7 +116,7 @@ protected: public: NESCostumeRenderer(ScummEngine *vm) : BaseCostumeRenderer(vm), _loaded(vm) {} - void setPalette(byte *palette); + void setPalette(uint16 *palette); void setFacing(const Actor *a); void setCostume(int costume, int shadow); @@ -131,7 +131,7 @@ protected: public: C64CostumeRenderer(ScummEngine *vm) : BaseCostumeRenderer(vm), _loaded(vm) {} - void setPalette(byte *palette) {} + void setPalette(uint16 *palette) {} void setFacing(const Actor *a) {} void setCostume(int costume, int shadow); diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp index 64829114ca..66ac68bd95 100644 --- a/engines/scumm/cursor.cpp +++ b/engines/scumm/cursor.cpp @@ -111,11 +111,20 @@ void ScummEngine_v6::setCursorTransparency(int a) { } void ScummEngine::updateCursor() { - const int transColor = (_game.heversion >= 80) ? 5 : 255; + int transColor = (_game.heversion >= 80) ? 5 : 255; +#ifdef ENABLE_RGB_COLOR + Graphics::PixelFormat format = _system->getScreenFormat(); + CursorMan.replaceCursor(_grabbedCursor, _cursor.width, _cursor.height, + _cursor.hotspotX, _cursor.hotspotY, + (_game.platform == Common::kPlatformNES ? _grabbedCursor[63] : transColor), + (_game.heversion == 70 ? 2 : 1), + &format); +#else CursorMan.replaceCursor(_grabbedCursor, _cursor.width, _cursor.height, _cursor.hotspotX, _cursor.hotspotY, (_game.platform == Common::kPlatformNES ? _grabbedCursor[63] : transColor), (_game.heversion == 70 ? 2 : 1)); +#endif } void ScummEngine_v6::grabCursor(int x, int y, int w, int h) { @@ -138,7 +147,7 @@ void ScummEngine::setCursorFromBuffer(const byte *ptr, int width, int height, in uint size; byte *dst; - size = width * height; + size = width * height * _bitDepth; if (size > sizeof(_grabbedCursor)) error("grabCursor: grabbed cursor too big"); @@ -148,8 +157,8 @@ void ScummEngine::setCursorFromBuffer(const byte *ptr, int width, int height, in dst = _grabbedCursor; for (; height; height--) { - memcpy(dst, ptr, width); - dst += width; + memcpy(dst, ptr, width * _bitDepth); + dst += width * _bitDepth; ptr += pitch; } @@ -166,8 +175,13 @@ void ScummEngine_v70he::setDefaultCursor() { static const byte palette[] = {0, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0}; - - memset(_grabbedCursor, 5, sizeof(_grabbedCursor)); + + if (_bitDepth == 2) { + for (i = 0; i < 1024; i++) + WRITE_UINT16(_grabbedCursor + i * 2, 5); + } else { + memset(_grabbedCursor, 5, sizeof(_grabbedCursor)); + } _cursor.hotspotX = _cursor.hotspotY = 2; src = default_he_cursor; @@ -180,10 +194,16 @@ void ScummEngine_v70he::setDefaultCursor() { for (j = 0; j < 32; j++) { switch ((p & (0x3 << 14)) >> 14) { case 1: - _grabbedCursor[32 * i + j] = 0xfe; + if (_bitDepth == 2) + WRITE_UINT16(_grabbedCursor + 64 * i + j * 2, get16BitColor(palette[4], palette[5], palette[6])); + else + _grabbedCursor[32 * i + j] = 0xfe; break; case 2: - _grabbedCursor[32 * i + j] = 0xfd; + if (_bitDepth == 2) + WRITE_UINT16(_grabbedCursor + 64 * i + j * 2, get16BitColor(palette[0], palette[1], palette[2])); + else + _grabbedCursor[32 * i + j] = 0xfd; break; default: break; @@ -195,9 +215,11 @@ void ScummEngine_v70he::setDefaultCursor() { } } - // Since white color position is not guaranteed - // we setup our own palette if supported by backend - CursorMan.replaceCursorPalette(palette, 0xfd, 3); + if (_bitDepth == 1) { + // Since white color position is not guaranteed + // we setup our own palette if supported by backend + CursorMan.replaceCursorPalette(palette, 0xfd, 3); + } updateCursor(); } diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index 07640ca551..4574ece6d0 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -43,12 +43,12 @@ extern "C" void asmCopy8Col(byte* dst, int dstPitch, const byte* src, int height namespace Scumm { -static void blit(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h); -static void fill(byte *dst, int dstPitch, byte color, int w, int h); +static void blit(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h, uint8 bitDepth); +static void fill(byte *dst, int dstPitch, uint16 color, int w, int h, uint8 bitDepth); #ifndef USE_ARM_GFX_ASM -static void copy8Col(byte *dst, int dstPitch, const byte *src, int height); +static void copy8Col(byte *dst, int dstPitch, const byte *src, int height, uint8 bitDepth); #endif -static void clear8Col(byte *dst, int dstPitch, int height); +static void clear8Col(byte *dst, int dstPitch, int height, uint8 bitDepth); static void ditherHerc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *width, int *height); static void scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h); @@ -231,6 +231,9 @@ GdiV2::~GdiV2() { free(_roomStrips); } +Gdi16Bit::Gdi16Bit(ScummEngine *vm) : Gdi(vm) { +} + void Gdi::init() { _numStrips = _vm->_screenWidth / 8; @@ -341,8 +344,8 @@ void ScummEngine::initVirtScreen(VirtScreenNumber slot, int top, int width, int vs->hasTwoBuffers = twobufs; vs->xstart = 0; vs->backBuf = NULL; - vs->bytesPerPixel = 1; - vs->pitch = width; + vs->bytesPerPixel = (_game.features & GF_16BIT_COLOR) ? 2 : 1; + vs->pitch = width * vs->bytesPerPixel; if (_game.version >= 7) { // Increase the pitch by one; needed to accomodate the extra screen @@ -586,7 +589,7 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i vsPitch = _screenWidth * m - width * m; } else { - vsPitch = vs->pitch - width; + vsPitch = vs->pitch - width * vs->bytesPerPixel; } @@ -612,36 +615,49 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i #else // We blit four pixels at a time, for improved performance. const uint32 *src32 = (const uint32 *)src; - const uint32 *text32 = (const uint32 *)text; uint32 *dst32 = (uint32 *)_compositeBuf; vsPitch >>= 2; - const int textPitch = (_textSurface.pitch - width * m) >> 2; - for (int h = height * m; h > 0; --h) { - for (int w = width*m; w > 0; w-=4) { - uint32 temp = *text32++; - - // Generate a byte mask for those text pixels (bytes) with - // value CHARSET_MASK_TRANSPARENCY. In the end, each byte - // in mask will be either equal to 0x00 or 0xFF. - // Doing it this way avoids branches and bytewise operations, - // at the cost of readability ;). - uint32 mask = temp ^ CHARSET_MASK_TRANSPARENCY_32; - mask = (((mask & 0x7f7f7f7f) + 0x7f7f7f7f) | mask) & 0x80808080; - mask = ((mask >> 7) + 0x7f7f7f7f) ^ 0x80808080; - - // The following line is equivalent to this code: - // *dst32++ = (*src32++ & mask) | (temp & ~mask); - // However, some compilers can generate somewhat better - // machine code for this equivalent statement: - *dst32++ = ((temp ^ *src32++) & mask) ^ temp; + + if (_bitDepth == 2) { + // Sprites always seem to be used for subtitles in 16Bit color HE games, and not + // the charset renderer, so charset masking isn't required. + for (int h = height * m; h > 0; --h) { + for (int w = width * m; w > 0; w -= 4) { + *dst32++ = *src32++; + *dst32++ = *src32++; + } + src32 += vsPitch; + } + } else { + const uint32 *text32 = (const uint32 *)text; + const int textPitch = (_textSurface.pitch - width * m) >> 2; + for (int h = height * m; h > 0; --h) { + for (int w = width * m; w > 0; w -= 4) { + uint32 temp = *text32++; + + // Generate a byte mask for those text pixels (bytes) with + // value CHARSET_MASK_TRANSPARENCY. In the end, each byte + // in mask will be either equal to 0x00 or 0xFF. + // Doing it this way avoids branches and bytewise operations, + // at the cost of readability ;). + uint32 mask = temp ^ CHARSET_MASK_TRANSPARENCY_32; + mask = (((mask & 0x7f7f7f7f) + 0x7f7f7f7f) | mask) & 0x80808080; + mask = ((mask >> 7) + 0x7f7f7f7f) ^ 0x80808080; + + // The following line is equivalent to this code: + // *dst32++ = (*src32++ & mask) | (temp & ~mask); + // However, some compilers can generate somewhat better + // machine code for this equivalent statement: + *dst32++ = ((temp ^ *src32++) & mask) ^ temp; + } + src32 += vsPitch; + text32 += textPitch; } - src32 += vsPitch; - text32 += textPitch; } #endif src = _compositeBuf; - pitch = width; + pitch = width * vs->bytesPerPixel; if (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG) { ditherHerc(_compositeBuf, _herculesBuf, width, &x, &y, &width, &height); @@ -976,13 +992,13 @@ void ScummEngine::restoreBackground(Common::Rect rect, byte backColor) { return; if (vs->hasTwoBuffers && _currentRoom != 0 && isLightOn()) { - blit(screenBuf, vs->pitch, vs->getBackPixels(rect.left, rect.top), vs->pitch, width, height); + blit(screenBuf, vs->pitch, vs->getBackPixels(rect.left, rect.top), vs->pitch, width, height, vs->bytesPerPixel); if (vs->number == kMainVirtScreen && _charset->_hasMask) { byte *mask = (byte *)_textSurface.getBasePtr(rect.left, rect.top - _screenTop); - fill(mask, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, width, height); + fill(mask, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, width, height, _textSurface.bytesPerPixel); } } else { - fill(screenBuf, vs->pitch, backColor, width, height); + fill(screenBuf, vs->pitch, backColor, width, height, vs->bytesPerPixel); } } @@ -1011,7 +1027,7 @@ void ScummEngine::restoreCharsetBg() { if (vs->number != kMainVirtScreen) { // Restore from back buffer const byte *backBuf = vs->getBackPixels(0, 0); - blit(screenBuf, vs->pitch, backBuf, vs->pitch, vs->w, vs->h); + blit(screenBuf, vs->pitch, backBuf, vs->pitch, vs->w, vs->h, vs->bytesPerPixel); } } else { // Clear area @@ -1047,34 +1063,42 @@ byte *Gdi::getMaskBuffer(int x, int y, int z) { #pragma mark --- Misc --- #pragma mark - -static void blit(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h) { +static void blit(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h, uint8 bitDepth) { assert(w > 0); assert(h > 0); assert(src != NULL); assert(dst != NULL); - if (w == srcPitch && w == dstPitch) { - memcpy(dst, src, w*h); + if ((w * bitDepth == srcPitch) && (w * bitDepth == dstPitch)) { + memcpy(dst, src, w * h * bitDepth); } else { do { - memcpy(dst, src, w); + memcpy(dst, src, w * bitDepth); dst += dstPitch; src += srcPitch; } while (--h); } } -static void fill(byte *dst, int dstPitch, byte color, int w, int h) { +static void fill(byte *dst, int dstPitch, uint16 color, int w, int h, uint8 bitDepth) { assert(h > 0); assert(dst != NULL); - if (w == dstPitch) { - memset(dst, color, w*h); - } else { + if (bitDepth == 2) { do { - memset(dst, color, w); + for (int i = 0; i < w; i++) + WRITE_UINT16(dst + i * 2, color); dst += dstPitch; } while (--h); + } else { + if (w == dstPitch) { + memset(dst, color, w * h); + } else { + do { + memset(dst, color, w); + dst += dstPitch; + } while (--h); + } } } @@ -1084,14 +1108,18 @@ static void fill(byte *dst, int dstPitch, byte color, int w, int h) { #else -static void copy8Col(byte *dst, int dstPitch, const byte *src, int height) { +static void copy8Col(byte *dst, int dstPitch, const byte *src, int height, uint8 bitDepth) { do { #if defined(SCUMM_NEED_ALIGNMENT) - memcpy(dst, src, 8); + memcpy(dst, src, 8 * bitDepth); #else ((uint32 *)dst)[0] = ((const uint32 *)src)[0]; ((uint32 *)dst)[1] = ((const uint32 *)src)[1]; + if (bitDepth == 2) { + ((uint32 *)dst)[2] = ((const uint32 *)src)[2]; + ((uint32 *)dst)[3] = ((const uint32 *)src)[3]; + } #endif dst += dstPitch; src += dstPitch; @@ -1100,13 +1128,17 @@ static void copy8Col(byte *dst, int dstPitch, const byte *src, int height) { #endif /* USE_ARM_GFX_ASM */ -static void clear8Col(byte *dst, int dstPitch, int height) { +static void clear8Col(byte *dst, int dstPitch, int height, uint8 bitDepth) { do { #if defined(SCUMM_NEED_ALIGNMENT) - memset(dst, 0, 8); + memset(dst, 0, 8 * bitDepth); #else ((uint32 *)dst)[0] = 0; ((uint32 *)dst)[1] = 0; + if (bitDepth == 2) { + ((uint32 *)dst)[2] = 0; + ((uint32 *)dst)[3] = 0; + } #endif dst += dstPitch; } while (--height); @@ -1171,41 +1203,41 @@ void ScummEngine::drawBox(int x, int y, int x2, int y2, int color) { if (color == -1) { if (vs->number != kMainVirtScreen) error("can only copy bg to main window"); - blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height); + blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height, vs->bytesPerPixel); if (_charset->_hasMask) { byte *mask = (byte *)_textSurface.getBasePtr(x * _textSurfaceMultiplier, (y - _screenTop) * _textSurfaceMultiplier); - fill(mask, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier); + fill(mask, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier, _textSurface.bytesPerPixel); } } else if (_game.heversion >= 72) { // Flags are used for different methods in HE games uint32 flags = color; if ((flags & 0x2000) || (flags & 0x4000000)) { - blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height); + blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height, vs->bytesPerPixel); } else if ((flags & 0x4000) || (flags & 0x2000000)) { - blit(bgbuff, vs->pitch, backbuff, vs->pitch, width, height); + blit(bgbuff, vs->pitch, backbuff, vs->pitch, width, height, vs->bytesPerPixel); } else if ((flags & 0x8000) || (flags & 0x1000000)) { flags &= (flags & 0x1000000) ? 0xFFFFFF : 0x7FFF; - fill(backbuff, vs->pitch, flags, width, height); - fill(bgbuff, vs->pitch, flags, width, height); + fill(backbuff, vs->pitch, flags, width, height, vs->bytesPerPixel); + fill(bgbuff, vs->pitch, flags, width, height, vs->bytesPerPixel); } else { - fill(backbuff, vs->pitch, flags, width, height); + fill(backbuff, vs->pitch, flags, width, height, vs->bytesPerPixel); } } else if (_game.heversion >= 60) { // Flags are used for different methods in HE games uint16 flags = color; if (flags & 0x2000) { - blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height); + blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height, vs->bytesPerPixel); } else if (flags & 0x4000) { - blit(bgbuff, vs->pitch, backbuff, vs->pitch, width, height); + blit(bgbuff, vs->pitch, backbuff, vs->pitch, width, height, vs->bytesPerPixel); } else if (flags & 0x8000) { flags &= 0x7FFF; - fill(backbuff, vs->pitch, flags, width, height); - fill(bgbuff, vs->pitch, flags, width, height); + fill(backbuff, vs->pitch, flags, width, height, vs->bytesPerPixel); + fill(bgbuff, vs->pitch, flags, width, height, vs->bytesPerPixel); } else { - fill(backbuff, vs->pitch, flags, width, height); + fill(backbuff, vs->pitch, flags, width, height, vs->bytesPerPixel); } } else { - fill(backbuff, vs->pitch, color, width, height); + fill(backbuff, vs->pitch, color, width, height, vs->bytesPerPixel); } } @@ -1243,7 +1275,7 @@ void ScummEngine_v5::drawFlashlight() { _flashlight.y, _flashlight.y + _flashlight.h, USAGE_BIT_DIRTY); if (_flashlight.buffer) { - fill(_flashlight.buffer, vs->pitch, 0, _flashlight.w, _flashlight.h); + fill(_flashlight.buffer, vs->pitch, 0, _flashlight.w, _flashlight.h, vs->bytesPerPixel); } _flashlight.isDrawn = false; } @@ -1290,7 +1322,7 @@ void ScummEngine_v5::drawFlashlight() { _flashlight.buffer = vs->getPixels(_flashlight.x, _flashlight.y); bgbak = vs->getBackPixels(_flashlight.x, _flashlight.y); - blit(_flashlight.buffer, vs->pitch, bgbak, vs->pitch, _flashlight.w, _flashlight.h); + blit(_flashlight.buffer, vs->pitch, bgbak, vs->pitch, _flashlight.w, _flashlight.h, vs->bytesPerPixel); // Round the corners. To do so, we simply hard-code a set of nicely // rounded corners. @@ -1599,7 +1631,7 @@ void Gdi::drawBitmap(const byte *ptr, VirtScreen *vs, int x, const int y, const warning("Gdi::drawBitmap, strip drawn to %d below window bottom %d", y + height, vs->h); } - _vertStripNextInc = height * vs->pitch - 1; + _vertStripNextInc = height * vs->pitch - 1 * vs->bytesPerPixel; _objectMode = (flag & dbObjectMode) == dbObjectMode; prepareDrawBitmap(ptr, vs, x, y, width, height, stripnr, numstrip); @@ -1632,9 +1664,9 @@ void Gdi::drawBitmap(const byte *ptr, VirtScreen *vs, int x, const int y, const // In the case of a double buffered virtual screen, we draw to // the backbuffer, otherwise to the primary surface memory. if (vs->hasTwoBuffers) - dstPtr = vs->backBuf + y * vs->pitch + x * 8; + dstPtr = vs->backBuf + y * vs->pitch + (x * 8 * vs->bytesPerPixel); else - dstPtr = (byte *)vs->pixels + y * vs->pitch + x * 8; + dstPtr = (byte *)vs->pixels + y * vs->pitch + (x * 8 * vs->bytesPerPixel); transpStrip = drawStrip(dstPtr, vs, x, y, width, height, stripnr, smap_ptr); @@ -1643,11 +1675,11 @@ void Gdi::drawBitmap(const byte *ptr, VirtScreen *vs, int x, const int y, const transpStrip = true; if (vs->hasTwoBuffers) { - byte *frontBuf = (byte *)vs->pixels + y * vs->pitch + x * 8; + byte *frontBuf = (byte *)vs->pixels + y * vs->pitch + (x * 8 * vs->bytesPerPixel); if (lightsOn) - copy8Col(frontBuf, vs->pitch, dstPtr, height); + copy8Col(frontBuf, vs->pitch, dstPtr, height, vs->bytesPerPixel); else - clear8Col(frontBuf, vs->pitch, height); + clear8Col(frontBuf, vs->pitch, height, vs->bytesPerPixel); } decodeMask(x, y, width, height, stripnr, numzbuf, zplane_list, transpStrip, flag, tmsk_ptr); @@ -1875,7 +1907,7 @@ void Gdi::drawBMAPBg(const byte *ptr, VirtScreen *vs) { drawStripHE(dst, vs->pitch, bmap_ptr, vs->w, vs->h, true); break; case 150: - fill(dst, vs->pitch, *bmap_ptr, vs->w, vs->h); + fill(dst, vs->pitch, *bmap_ptr, vs->w, vs->h, vs->bytesPerPixel); break; default: // Alternative russian freddi3 uses badly formatted bitmaps @@ -1931,12 +1963,12 @@ void Gdi::drawBMAPObject(const byte *ptr, VirtScreen *vs, int obj, int x, int y, assert(bmap_ptr); byte code = *bmap_ptr++; - int scrX = _vm->_screenStartStrip * 8; + int scrX = _vm->_screenStartStrip * 8 * _vm->_bitDepth; if (code == 8 || code == 9) { Common::Rect rScreen(0, 0, vs->w, vs->h); byte *dst = (byte *)_vm->_virtscr[kMainVirtScreen].backBuf + scrX; - Wiz::copyWizImage(dst, bmap_ptr, vs->w, vs->h, x - scrX, y, w, h, &rScreen); + Wiz::copyWizImage(dst, bmap_ptr, vs->pitch, kDstScreen, vs->w, vs->h, x - scrX, y, w, h, &rScreen, 0, 0, 0, _vm->_bitDepth); } Common::Rect rect1(x, y, x + w, y + h); @@ -1986,7 +2018,7 @@ void ScummEngine_v70he::restoreBackgroundHE(Common::Rect rect, int dirtybit) { assert(rw <= _screenWidth && rw > 0); assert(rh <= _screenHeight && rh > 0); - blit(dst, _virtscr[kMainVirtScreen].pitch, src, _virtscr[kMainVirtScreen].pitch, rw, rh); + blit(dst, _virtscr[kMainVirtScreen].pitch, src, _virtscr[kMainVirtScreen].pitch, rw, rh, vs->bytesPerPixel); markRectAsDirty(kMainVirtScreen, rect, dirtybit); } #endif @@ -2016,15 +2048,15 @@ void Gdi::resetBackground(int top, int bottom, int strip) { if (bottom > vs->bdirty[strip]) vs->bdirty[strip] = bottom; - bgbak_ptr = (byte *)vs->backBuf + top * vs->pitch + (strip + vs->xstart/8) * 8; - backbuff_ptr = (byte *)vs->pixels + top * vs->pitch + (strip + vs->xstart/8) * 8; + bgbak_ptr = (byte *)vs->backBuf + top * vs->pitch + (strip + vs->xstart/8) * 8 * vs->bytesPerPixel; + backbuff_ptr = (byte *)vs->pixels + top * vs->pitch + (strip + vs->xstart/8) * 8 * vs->bytesPerPixel; numLinesToProcess = bottom - top; if (numLinesToProcess) { if (_vm->isLightOn()) { - copy8Col(backbuff_ptr, vs->pitch, bgbak_ptr, numLinesToProcess); + copy8Col(backbuff_ptr, vs->pitch, bgbak_ptr, numLinesToProcess, vs->bytesPerPixel); } else { - clear8Col(backbuff_ptr, vs->pitch, numLinesToProcess); + clear8Col(backbuff_ptr, vs->pitch, numLinesToProcess, vs->bytesPerPixel); } } } @@ -2775,12 +2807,12 @@ void Gdi::drawStripHE(byte *dst, int dstPitch, const byte *src, int width, int h int x = width; while (1) { if (!transpCheck || color != _transparentColor) - *dst = _roomPalette[color]; - dst++; + writeRoomColor(dst, color); + dst += _vm->_bitDepth; --x; if (x == 0) { x = width; - dst += dstPitch - width; + dst += dstPitch - width * _vm->_bitDepth; --height; if (height == 0) return; @@ -2864,8 +2896,8 @@ void Gdi::drawStripComplex(byte *dst, int dstPitch, const byte *src, int height, do { FILL_BITS; if (!transpCheck || color != _transparentColor) - *dst = _roomPalette[color] + _paletteMod; - dst++; + writeRoomColor(dst, color); + dst += _vm->_bitDepth; againPos: if (!READ_BIT) { @@ -2886,13 +2918,13 @@ void Gdi::drawStripComplex(byte *dst, int dstPitch, const byte *src, int height, do { if (!--x) { x = 8; - dst += dstPitch - 8; + dst += dstPitch - 8 * _vm->_bitDepth; if (!--height) return; } if (!transpCheck || color != _transparentColor) - *dst = _roomPalette[color] + _paletteMod; - dst++; + writeRoomColor(dst, color); + dst += _vm->_bitDepth; } while (--reps); bits >>= 8; bits |= (*src++) << (cl - 8); @@ -2900,7 +2932,7 @@ void Gdi::drawStripComplex(byte *dst, int dstPitch, const byte *src, int height, } } } while (--x); - dst += dstPitch - 8; + dst += dstPitch - 8 * _vm->_bitDepth; } while (--height); } @@ -2916,8 +2948,8 @@ void Gdi::drawStripBasicH(byte *dst, int dstPitch, const byte *src, int height, do { FILL_BITS; if (!transpCheck || color != _transparentColor) - *dst = _roomPalette[color] + _paletteMod; - dst++; + writeRoomColor(dst, color); + dst += _vm->_bitDepth; if (!READ_BIT) { } else if (!READ_BIT) { FILL_BITS; @@ -2932,7 +2964,7 @@ void Gdi::drawStripBasicH(byte *dst, int dstPitch, const byte *src, int height, color += inc; } } while (--x); - dst += dstPitch - 8; + dst += dstPitch - 8 * _vm->_bitDepth; } while (--height); } @@ -2949,7 +2981,7 @@ void Gdi::drawStripBasicV(byte *dst, int dstPitch, const byte *src, int height, do { FILL_BITS; if (!transpCheck || color != _transparentColor) - *dst = _roomPalette[color] + _paletteMod; + writeRoomColor(dst, color); dst += dstPitch; if (!READ_BIT) { } else if (!READ_BIT) { @@ -3017,7 +3049,7 @@ void Gdi::drawStripRaw(byte *dst, int dstPitch, const byte *src, int height, con for (x = 0; x < 8; x ++) { byte color = *src++; if (!transpCheck || color != _transparentColor) - dst[x] = _roomPalette[color] + _paletteMod; + writeRoomColor(dst + x * _vm->_bitDepth, color); } dst += dstPitch; } while (--height); @@ -3140,6 +3172,14 @@ void Gdi::unkDecode11(byte *dst, int dstPitch, const byte *src, int height) cons #undef NEXT_ROW #undef READ_BIT_256 +void Gdi16Bit::writeRoomColor(byte *dst, byte color) const { + WRITE_UINT16(dst, READ_LE_UINT16(_vm->_hePalettes + 2048 + color * 2)); +} + +void Gdi::writeRoomColor(byte *dst, byte color) const { + *dst = _roomPalette[color] + _paletteMod; +} + #pragma mark - #pragma mark --- Transition effects --- diff --git a/engines/scumm/gfx.h b/engines/scumm/gfx.h index e4c1054450..0910d9bc59 100644 --- a/engines/scumm/gfx.h +++ b/engines/scumm/gfx.h @@ -155,11 +155,11 @@ struct VirtScreen : Graphics::Surface { } byte *getPixels(int x, int y) const { - return (byte *)pixels + xstart + y * pitch + x; + return (byte *)pixels + y * pitch + (xstart + x) * bytesPerPixel; } byte *getBackPixels(int x, int y) const { - return (byte *)backBuf + xstart + y * pitch + x; + return (byte *)backBuf + y * pitch + (xstart + x) * bytesPerPixel; } }; @@ -215,6 +215,7 @@ protected: void drawStrip3DO(byte *dst, int dstPitch, const byte *src, int height, const bool transpCheck) const; void drawStripHE(byte *dst, int dstPitch, const byte *src, int width, int height, const bool transpCheck) const; + virtual void writeRoomColor(byte *dst, byte color) const; /* Mask decompressors */ void decompressTMSK(byte *dst, const byte *tmsk, const byte *src, int height) const; @@ -361,6 +362,13 @@ public: virtual void roomChanged(byte *roomptr); }; +class Gdi16Bit : public Gdi { +protected: + virtual void writeRoomColor(byte *dst, byte color) const; +public: + Gdi16Bit(ScummEngine *vm); +}; + } // End of namespace Scumm #endif diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp index 0cc4419778..92b72bd9be 100644 --- a/engines/scumm/he/animation_he.cpp +++ b/engines/scumm/he/animation_he.cpp @@ -66,6 +66,32 @@ int MoviePlayer::load(const char *filename, int flags, int image) { return 0; } +void MoviePlayer::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { + uint h = getHeight(); + uint w = getWidth(); + + byte *src = _videoFrameBuffer; + + if (_vm->_game.features & GF_16BIT_COLOR) { + dst += y * pitch + x * 2; + do { + for (uint i = 0; i < w; i++) { + uint16 col = READ_LE_UINT16(_vm->_hePalettes + _vm->_hePaletteSlot + 768 + src[i] * 2); + WRITE_UINT16(dst + i * 2, col); + } + dst += pitch; + src += w; + } while (--h); + } else { + dst += y * pitch + x; + do { + memcpy(dst, src, w); + dst += pitch; + src += w; + } while (--h); + } +} + void MoviePlayer::handleNextFrame() { if (!isVideoLoaded()) { return; @@ -80,14 +106,14 @@ void MoviePlayer::handleNextFrame() { assert(dstPtr); uint8 *dst = _vm->findWrappedBlock(MKID_BE('WIZD'), dstPtr, 0, 0); assert(dst); - copyFrameToBuffer(dst, 0, 0, _vm->_screenWidth); + copyFrameToBuffer(dst, 0, 0, _vm->_screenWidth * _vm->_bitDepth); } else if (_flags & 1) { - copyFrameToBuffer(pvs->getBackPixels(0, 0), 0, 0, _vm->_screenWidth); + copyFrameToBuffer(pvs->getBackPixels(0, 0), 0, 0, pvs->pitch); Common::Rect imageRect(getWidth(), getHeight()); _vm->restoreBackgroundHE(imageRect); } else { - copyFrameToBuffer(pvs->getPixels(0, 0), 0, 0, _vm->_screenWidth); + copyFrameToBuffer(pvs->getPixels(0, 0), 0, 0, pvs->pitch); Common::Rect imageRect(getWidth(), getHeight()); _vm->markRectAsDirty(kMainVirtScreen, imageRect); diff --git a/engines/scumm/he/animation_he.h b/engines/scumm/he/animation_he.h index 39f03960c4..e2fc1d04b7 100644 --- a/engines/scumm/he/animation_he.h +++ b/engines/scumm/he/animation_he.h @@ -54,6 +54,7 @@ public: int getImageNum(); int load(const char *filename, int flags, int image = 0); + void copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch); void handleNextFrame(); protected: diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h index c2079fa5fe..949113aeeb 100644 --- a/engines/scumm/he/intern_he.h +++ b/engines/scumm/he/intern_he.h @@ -455,6 +455,7 @@ protected: uint8 *getHEPaletteIndex(int palSlot); int getHEPaletteColor(int palSlot, int color); int getHEPaletteSimilarColor(int palSlot, int red, int green, int start, int end); + int getHEPalette16BitColorComponent(int component, int type); int getHEPaletteColorComponent(int palSlot, int color, int component); void setHEPaletteColor(int palSlot, uint8 color, uint8 r, uint8 g, uint8 b); void setHEPaletteFromPtr(int palSlot, const uint8 *palData); @@ -463,7 +464,7 @@ protected: void setHEPaletteFromRoom(int palSlot, int resId, int state); void restoreHEPalette(int palSlot); void copyHEPalette(int dstPalSlot, int srcPalSlot); - void copyHEPaletteColor(int palSlot, uint8 dstColor, uint8 srcColor); + void copyHEPaletteColor(int palSlot, uint8 dstColor, uint16 srcColor); protected: /* HE version 90 script opcodes */ diff --git a/engines/scumm/he/palette_he.cpp b/engines/scumm/he/palette_he.cpp index d055b77ee2..812c39d173 100644 --- a/engines/scumm/he/palette_he.cpp +++ b/engines/scumm/he/palette_he.cpp @@ -31,6 +31,27 @@ namespace Scumm { +uint8 *ScummEngine::getHEPaletteSlot(uint16 palSlot) { + assertRange(0, palSlot, _numPalettes, "palette"); + + if (_game.heversion >= 99) { + if (palSlot) + return _hePalettes + palSlot * _hePaletteSlot + 768; + else + return _hePalettes + _hePaletteSlot + 768; + } + + return NULL; +} + +uint16 ScummEngine::get16BitColor(uint8 r, uint8 g, uint8 b) { + uint16 ar = (r >> 3) << 10; + uint16 ag = (g >> 3) << 5; + uint16 ab = (b >> 3) << 0; + uint16 col = ar | ag | ab; + return col; +} + void ScummEngine_v71he::remapHEPalette(const uint8 *src, uint8 *dst) { int r, g, b, sum, bestitem, bestsum; int ar, ag, ab; @@ -38,7 +59,7 @@ void ScummEngine_v71he::remapHEPalette(const uint8 *src, uint8 *dst) { src += 30; if (_game.heversion >= 99) { - palPtr = _hePalettes + 1024 + 30; + palPtr = _hePalettes + _hePaletteSlot + 30; } else { palPtr = _currentPalette + 30; } @@ -73,9 +94,9 @@ void ScummEngine_v71he::remapHEPalette(const uint8 *src, uint8 *dst) { uint8 *ScummEngine_v90he::getHEPaletteIndex(int palSlot) { if (palSlot) { assert(palSlot >= 1 && palSlot <= _numPalettes); - return _hePalettes + palSlot * 1024; + return _hePalettes + palSlot * _hePaletteSlot; } else { - return _hePalettes + 1024; + return _hePalettes + _hePaletteSlot; } } @@ -84,7 +105,7 @@ int ScummEngine_v90he::getHEPaletteSimilarColor(int palSlot, int red, int green, assertRange(0, start, 255, "start palette slot"); assertRange(0, end, 255, "pend alette slot"); - uint8 *pal = _hePalettes + palSlot * 1024 + start * 3; + uint8 *pal = _hePalettes + palSlot * _hePaletteSlot + start * 3; int bestsum = 0x7FFFFFFF; int bestitem = start; @@ -105,39 +126,83 @@ int ScummEngine_v90he::getHEPaletteSimilarColor(int palSlot, int red, int green, return bestitem; } +int ScummEngine_v90he::getHEPalette16BitColorComponent(int component, int type) { + uint16 col; + if (type == 2) { + col = (((component & 0xFFFF) >> 0) & 0x1F) << 3;; + } else if (type == 1) { + col = (((component & 0xFFFF) >> 5) & 0x1F) << 3; + } else { + col = (((component & 0xFFFF) >> 10) & 0x1F) << 3; + } + return col; +} + int ScummEngine_v90he::getHEPaletteColorComponent(int palSlot, int color, int component) { assertRange(1, palSlot, _numPalettes, "palette"); assertRange(0, color, 255, "palette slot"); - return _hePalettes[palSlot * 1024 + color * 3 + component % 3]; + return _hePalettes[palSlot * _hePaletteSlot + color * 3 + component % 3]; } int ScummEngine_v90he::getHEPaletteColor(int palSlot, int color) { assertRange(1, palSlot, _numPalettes, "palette"); assertRange(0, color, 255, "palette slot"); - return _hePalettes[palSlot * 1024 + 768 + color]; + if (_game.features & GF_16BIT_COLOR) + return READ_LE_UINT16(_hePalettes + palSlot * _hePaletteSlot + 768 + color * 2); + else + return _hePalettes[palSlot * _hePaletteSlot + 768 + color]; } void ScummEngine_v90he::setHEPaletteColor(int palSlot, uint8 color, uint8 r, uint8 g, uint8 b) { debug(7, "setHEPaletteColor(%d, %d, %d, %d, %d)", palSlot, color, r, g, b); assertRange(1, palSlot, _numPalettes, "palette"); - uint8 *p = _hePalettes + palSlot * 1024 + color * 3; + + uint8 *p = _hePalettes + palSlot * _hePaletteSlot + color * 3; *(p + 0) = r; *(p + 1) = g; *(p + 2) = b; - _hePalettes[palSlot * 1024 + 768 + color] = color; + if (_game.features & GF_16BIT_COLOR) { + WRITE_LE_UINT16(_hePalettes + palSlot * _hePaletteSlot + 768 + color * 2, get16BitColor(r, g, b)); + } else { + _hePalettes[palSlot * _hePaletteSlot + 768 + color] = color; + } } void ScummEngine_v90he::setHEPaletteFromPtr(int palSlot, const uint8 *palData) { assertRange(1, palSlot, _numPalettes, "palette"); - uint8 *pc = _hePalettes + palSlot * 1024; + + uint8 *pc = _hePalettes + palSlot * _hePaletteSlot; uint8 *pi = pc + 768; - for (int i = 0; i < 256; ++i) { - *pc++ = *palData++; - *pc++ = *palData++; - *pc++ = *palData++; - *pi++ = i; + if (_game.features & GF_16BIT_COLOR) { + for (int i = 0; i < 256; ++i) { + uint8 r = *pc++ = *palData++; + uint8 g = *pc++ = *palData++; + uint8 b = *pc++ = *palData++; + WRITE_LE_UINT16(pi, get16BitColor(r, g, b)); pi += 2; + } + } else { + for (int i = 0; i < 256; ++i) { + *pc++ = *palData++; + *pc++ = *palData++; + *pc++ = *palData++; + *pi++ = i; + } + } + + int i; + uint8 *palPtr = _hePalettes + palSlot * _hePaletteSlot + 768; + if (_game.features & GF_16BIT_COLOR) { + for (i = 0; i < 10; ++i) + WRITE_LE_UINT16(palPtr + i * 2, i); + for (i = 246; i < 256; ++i) + WRITE_LE_UINT16(palPtr + i * 2, i); + } else { + for (i = 0; i < 10; ++i) + *(palPtr + i) = i; + for (i = 246; i < 256; ++i) + *(palPtr + i) = i; } } @@ -176,8 +241,9 @@ void ScummEngine_v90he::setHEPaletteFromRoom(int palSlot, int resId, int state) void ScummEngine_v90he::restoreHEPalette(int palSlot) { debug(7, "restoreHEPalette(%d)", palSlot); assertRange(1, palSlot, _numPalettes, "palette"); + if (palSlot != 1) { - memcpy(_hePalettes + palSlot * 1024, _hePalettes + 1024, 1024); + memcpy(_hePalettes + palSlot * _hePaletteSlot, _hePalettes + _hePaletteSlot, _hePaletteSlot); } } @@ -185,18 +251,27 @@ void ScummEngine_v90he::copyHEPalette(int dstPalSlot, int srcPalSlot) { debug(7, "copyHEPalette(%d, %d)", dstPalSlot, srcPalSlot); assert(dstPalSlot >= 1 && dstPalSlot <= _numPalettes); assert(srcPalSlot >= 1 && srcPalSlot <= _numPalettes); + if (dstPalSlot != srcPalSlot) { - memcpy(_hePalettes + dstPalSlot * 1024, _hePalettes + srcPalSlot * 1024, 1024); + memcpy(_hePalettes + dstPalSlot * _hePaletteSlot, _hePalettes + srcPalSlot * _hePaletteSlot, _hePaletteSlot); } } -void ScummEngine_v90he::copyHEPaletteColor(int palSlot, uint8 dstColor, uint8 srcColor) { +void ScummEngine_v90he::copyHEPaletteColor(int palSlot, uint8 dstColor, uint16 srcColor) { debug(7, "copyHEPaletteColor(%d, %d, %d)", palSlot, dstColor, srcColor); assertRange(1, palSlot, _numPalettes, "palette"); - uint8 *dstPal = _hePalettes + palSlot * 1024 + dstColor * 3; - uint8 *srcPal = _hePalettes + 1024 + srcColor * 3; - memcpy(dstPal, srcPal, 3); - _hePalettes[palSlot * 1024 + 768 + dstColor] = srcColor; + + uint8 *dstPal = _hePalettes + palSlot * _hePaletteSlot + dstColor * 3; + uint8 *srcPal = _hePalettes + _hePaletteSlot + srcColor * 3; + if (_game.features & GF_16BIT_COLOR) { + dstPal[0] = (srcColor >> 10) << 3; + dstPal[1] = (srcColor >> 5) << 3; + dstPal[2] = (srcColor >> 0) << 3; + WRITE_LE_UINT16(_hePalettes + palSlot * _hePaletteSlot + 768 + dstColor * 2, srcColor); + } else { + memcpy(dstPal, srcPal, 3); + _hePalettes[palSlot * _hePaletteSlot + 768 + dstColor] = srcColor; + } } void ScummEngine_v99he::setPaletteFromPtr(const byte *ptr, int numcolor) { @@ -209,7 +284,7 @@ void ScummEngine_v99he::setPaletteFromPtr(const byte *ptr, int numcolor) { assertRange(0, numcolor, 256, "setPaletteFromPtr: numcolor"); - dest = _hePalettes + 1024; + dest = _hePalettes + _hePaletteSlot; for (i = 0; i < numcolor; i++) { r = *ptr++; @@ -220,48 +295,63 @@ void ScummEngine_v99he::setPaletteFromPtr(const byte *ptr, int numcolor) { *dest++ = r; *dest++ = g; *dest++ = b; - _hePalettes[1792 + i] = i; + + if (_game.features & GF_16BIT_COLOR) { + WRITE_LE_UINT16(_hePalettes + 2048 + i * 2, get16BitColor(r, g, b)); + } else { + _hePalettes[1792 + i] = i; + } } else { dest += 3; } } - memcpy(_hePalettes, _hePalettes + 1024, 768); - - for (i = 0; i < 10; ++i) - _hePalettes[1792 + i] = i; - for (i = 246; i < 256; ++i) - _hePalettes[1792 + i] = i; + memcpy(_hePalettes, _hePalettes + _hePaletteSlot, 768); + if (_game.features & GF_16BIT_COLOR) { + for (i = 0; i < 10; ++i) + WRITE_LE_UINT16(_hePalettes + 2048 + i * 2, i); + for (i = 246; i < 256; ++i) + WRITE_LE_UINT16(_hePalettes + 2048 + i * 2, i); + } else { + for (i = 0; i < 10; ++i) + _hePalettes[1792 + i] = i; + for (i = 246; i < 256; ++i) + _hePalettes[1792 + i] = i; + } setDirtyColors(0, numcolor - 1); } void ScummEngine_v99he::darkenPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor) { uint8 *src, *dst; - int color, j; + int j, r, g, b; src = _hePalettes + startColor * 3; - dst = _hePalettes + 1024 + startColor * 3; + dst = _hePalettes + _hePaletteSlot + startColor * 3; for (j = startColor; j <= endColor; j++) { - color = *src++; - color = color * redScale / 0xFF; - if (color > 255) - color = 255; - *dst++ = color; - - color = *src++; - color = color * greenScale / 0xFF; - if (color > 255) - color = 255; - *dst++ = color; - - color = *src++; - color = color * blueScale / 0xFF; - if (color > 255) - color = 255; - *dst++ = color; - - _hePalettes[1792 + j] = j; + r = *src++; + r = r * redScale / 0xFF; + if (r > 255) + r = 255; + *dst++ = r; + + g = *src++; + g = g * greenScale / 0xFF; + if (g > 255) + g = 255; + *dst++ = g; + + b = *src++; + b = b * blueScale / 0xFF; + if (b > 255) + b = 255; + *dst++ = b; + + if (_game.features & GF_16BIT_COLOR) { + WRITE_LE_UINT16(_hePalettes + 2048 + j * 2, get16BitColor(r, g, b)); + } else { + _hePalettes[1792 + j] = j; + } setDirtyColors(j, endColor); } } @@ -272,26 +362,39 @@ void ScummEngine_v99he::copyPalColor(int dst, int src) { if ((uint) dst >= 256 || (uint) src >= 256) error("copyPalColor: invalid values, %d, %d", dst, src); - dp = &_hePalettes[1024 + dst * 3]; - sp = &_hePalettes[1024 + src * 3]; + dp = &_hePalettes[_hePaletteSlot + dst * 3]; + sp = &_hePalettes[_hePaletteSlot + src * 3]; dp[0] = sp[0]; dp[1] = sp[1]; dp[2] = sp[2]; - _hePalettes[1792 + dst] = dst; + + if (_game.features & GF_16BIT_COLOR) { + WRITE_LE_UINT16(_hePalettes + 2048 + dst * 2, get16BitColor(sp[0], sp[1], sp[2])); + } else { + _hePalettes[1792 + dst] = dst; + } setDirtyColors(dst, dst); } void ScummEngine_v99he::setPalColor(int idx, int r, int g, int b) { - _hePalettes[1024 + idx * 3 + 0] = r; - _hePalettes[1024 + idx * 3 + 1] = g; - _hePalettes[1024 + idx * 3 + 2] = b; - _hePalettes[1792 + idx] = idx; + _hePalettes[_hePaletteSlot + idx * 3 + 0] = r; + _hePalettes[_hePaletteSlot + idx * 3 + 1] = g; + _hePalettes[_hePaletteSlot + idx * 3 + 2] = b; + + if (_game.features & GF_16BIT_COLOR) { + WRITE_LE_UINT16(_hePalettes + 2048 + idx * 2, get16BitColor(r, g, b)); + } else { + _hePalettes[1792 + idx] = idx; + } setDirtyColors(idx, idx); } void ScummEngine_v99he::updatePalette() { + if (_game.features & GF_16BIT_COLOR) + return; + if (_palDirtyMax == -1) return; diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp index fe0904d632..58a858ede4 100644 --- a/engines/scumm/he/script_v100he.cpp +++ b/engines/scumm/he/script_v100he.cpp @@ -1574,7 +1574,10 @@ void ScummEngine_v100he::o100_roomOps() { case 130: a = pop(); b = pop(); - copyPalColor(a, b); + if (_game.features & GF_16BIT_COLOR) + copyHEPaletteColor(1, a, b); + else + copyPalColor(a, b); break; case 131: // SO_ROOM_FADE @@ -2151,8 +2154,9 @@ void ScummEngine_v100he::o100_systemOps() { } void ScummEngine_v100he::o100_cursorCommand() { - int a, i; + int a, b, i; int args[16]; + byte subOp = fetchScriptByte(); switch (subOp) { @@ -2167,12 +2171,12 @@ void ScummEngine_v100he::o100_cursorCommand() { case 0x80: case 0x81: a = pop(); - _wiz->loadWizCursor(a); + _wiz->loadWizCursor(a, 0); break; case 0x82: - pop(); + b = pop(); a = pop(); - _wiz->loadWizCursor(a); + _wiz->loadWizCursor(a, b); break; case 0x86: // SO_CURSOR_ON Turn cursor on _cursor.state = 1; @@ -2575,7 +2579,8 @@ void ScummEngine_v100he::o100_getWizData() { } void ScummEngine_v100he::o100_getPaletteData() { - int b, c, d, e; + int c, d, e; + int r, g, b; int palSlot, color; byte subOp = fetchScriptByte(); @@ -2584,7 +2589,10 @@ void ScummEngine_v100he::o100_getPaletteData() { case 13: c = pop(); b = pop(); - push(getHEPaletteColorComponent(1, b, c)); + if (_game.features & GF_16BIT_COLOR) + push(getHEPalette16BitColorComponent(b, c)); + else + push(getHEPaletteColorComponent(1, b, c)); break; case 20: color = pop(); @@ -2595,20 +2603,26 @@ void ScummEngine_v100he::o100_getPaletteData() { e = pop(); d = pop(); palSlot = pop(); - pop(); - c = pop(); b = pop(); - push(getHEPaletteSimilarColor(palSlot, b, c, d, e)); + g = pop(); + r = pop(); + push(getHEPaletteSimilarColor(palSlot, r, g, d, e)); break; case 53: - pop(); - c = pop(); - c = MAX(0, c); - c = MIN(c, 255); b = pop(); b = MAX(0, b); b = MIN(b, 255); - push(getHEPaletteSimilarColor(1, b, c, 10, 245)); + g = pop(); + g = MAX(0, g); + g = MIN(g, 255); + r = pop(); + r = MAX(0, r); + r = MIN(r, 255); + if (_game.features & GF_16BIT_COLOR) { + push(get16BitColor(r, g, b)); + } else { + push(getHEPaletteSimilarColor(1, r, g, 10, 245)); + } break; case 73: c = pop(); diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp index 5ad447b1c7..b416a0e75d 100644 --- a/engines/scumm/he/script_v60he.cpp +++ b/engines/scumm/he/script_v60he.cpp @@ -115,6 +115,8 @@ int ScummEngine_v60he::convertFilePath(byte *dst) { int r = 0; if (dst[0] == '.' && dst[1] == '/') { // Game Data Path r = 2; + } else if (dst[2] == 'b' && dst[5] == 'k') { // Backyard Basketball INI + r = 13; } else if (dst[0] == '*' && dst[1] == '/') { // Save Game Path (HE72 - HE100) r = 2; } else if (dst[0] == 'c' && dst[1] == ':') { // Save Game Path (HE60 - HE71) diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp index 64c63baa9d..9d5bd0b23d 100644 --- a/engines/scumm/he/script_v72he.cpp +++ b/engines/scumm/he/script_v72he.cpp @@ -1482,6 +1482,7 @@ void ScummEngine_v72he::o72_readFile() { fetchScriptByte(); size = pop(); slot = pop(); + assert(_hInFileTable[slot]); val = readFileToArray(slot, size); push(val); break; @@ -1571,7 +1572,7 @@ void ScummEngine_v72he::o72_rename() { } void ScummEngine_v72he::o72_getPixel() { - byte area; + uint16 area; int y = pop(); int x = pop(); @@ -1586,11 +1587,17 @@ void ScummEngine_v72he::o72_getPixel() { switch (subOp) { case 9: // HE 100 case 218: - area = *vs->getBackPixels(x, y - vs->topline); + if (_game.features & GF_16BIT_COLOR) + area = READ_UINT16(vs->getBackPixels(x, y - vs->topline)); + else + area = *vs->getBackPixels(x, y - vs->topline); break; case 8: // HE 100 case 219: - area = *vs->getPixels(x, y - vs->topline); + if (_game.features & GF_16BIT_COLOR) + area = READ_UINT16(vs->getPixels(x, y - vs->topline)); + else + area = *vs->getPixels(x, y - vs->topline); break; default: error("o72_getPixel: default case %d", subOp); @@ -1803,9 +1810,7 @@ void ScummEngine_v72he::o72_readINI() { switch (subOp) { case 43: // HE 100 case 6: // number - if (!strcmp((char *)option, "NoFontsInstalled")) { - push(1); - } else if (!strcmp((char *)option, "NoPrinting")) { + if (!strcmp((char *)option, "NoPrinting")) { push(1); } else if (!strcmp((char *)option, "TextOn")) { push(ConfMan.getBool("subtitles")); diff --git a/engines/scumm/he/script_v80he.cpp b/engines/scumm/he/script_v80he.cpp index b71a0f9e10..4b759dec53 100644 --- a/engines/scumm/he/script_v80he.cpp +++ b/engines/scumm/he/script_v80he.cpp @@ -241,7 +241,7 @@ void ScummEngine_v80he::o80_writeConfigFile() { } void ScummEngine_v80he::o80_cursorCommand() { - int a, i; + int a, b, i; int args[16]; byte subOp = fetchScriptByte(); @@ -250,12 +250,12 @@ void ScummEngine_v80he::o80_cursorCommand() { case 0x13: case 0x14: a = pop(); - _wiz->loadWizCursor(a); + _wiz->loadWizCursor(a, 0); break; case 0x3C: - pop(); + b = pop(); a = pop(); - _wiz->loadWizCursor(a); + _wiz->loadWizCursor(a, b); break; case 0x90: // SO_CURSOR_ON Turn cursor on _cursor.state = 1; diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp index f97771a4f8..7a7a1ff58b 100644 --- a/engines/scumm/he/script_v90he.cpp +++ b/engines/scumm/he/script_v90he.cpp @@ -1253,7 +1253,7 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() { void ScummEngine_v90he::o90_getWizData() { byte filename[4096]; - int state, resId; + int resId, state, type; int32 w, h; int32 x, y; @@ -1317,9 +1317,10 @@ void ScummEngine_v90he::o90_getWizData() { push(computeWizHistogram(resId, state, x, y, w, h)); break; case 139: - pop(); - pop(); - push(0); + type = pop(); + state = pop(); + resId = pop(); + push(_wiz->getWizImageData(resId, state, type)); break; case 141: pop(); @@ -2099,7 +2100,8 @@ void ScummEngine_v90he::o90_getObjectData() { } void ScummEngine_v90he::o90_getPaletteData() { - int b, c, d, e; + int c, d, e; + int r, g, b; int palSlot, color; byte subOp = fetchScriptByte(); @@ -2109,10 +2111,10 @@ void ScummEngine_v90he::o90_getPaletteData() { e = pop(); d = pop(); palSlot = pop(); - pop(); - c = pop(); b = pop(); - push(getHEPaletteSimilarColor(palSlot, b, c, d, e)); + g = pop(); + r = pop(); + push(getHEPaletteSimilarColor(palSlot, r, g, d, e)); break; case 52: c = pop(); @@ -2128,17 +2130,27 @@ void ScummEngine_v90he::o90_getPaletteData() { case 132: c = pop(); b = pop(); - push(getHEPaletteColorComponent(1, b, c)); + if (_game.features & GF_16BIT_COLOR) + push(getHEPalette16BitColorComponent(b, c)); + else + push(getHEPaletteColorComponent(1, b, c)); break; case 217: - pop(); - c = pop(); - c = MAX(0, c); - c = MIN(c, 255); b = pop(); b = MAX(0, b); b = MIN(b, 255); - push(getHEPaletteSimilarColor(1, b, c, 10, 245)); + g = pop(); + g = MAX(0, g); + g = MIN(g, 255); + r = pop(); + r = MAX(0, r); + r = MIN(r, 255); + + if (_game.features & GF_16BIT_COLOR) { + push(get16BitColor(r, g, b)); + } else { + push(getHEPaletteSimilarColor(1, r, g, 10, 245)); + } break; default: error("o90_getPaletteData: Unknown case %d", subOp); diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp index b23b7ac869..2e414f2a1e 100644 --- a/engines/scumm/he/wiz_he.cpp +++ b/engines/scumm/he/wiz_he.cpp @@ -254,7 +254,9 @@ bool Wiz::polygonContains(const WizPolygon &pol, int x, int y) { return r; } -void Wiz::copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch) { +void Wiz::copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, uint8 bitDepth) { + assert(bitDepth == 1); + Common::Rect dstRect(srcx, srcy, srcx + srcw, srcy + srch); dstRect.clip(dstw, dsth); @@ -263,8 +265,8 @@ void Wiz::copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int if (rh <= 0 || rw <= 0) return; - uint8 *dst1Ptr = dst1 + dstRect.left + dstRect.top * dstw; - uint8 *dst2Ptr = dst2 + dstRect.left + dstRect.top * dstw; + uint8 *dst1Ptr = dst1 + dstRect.top * dstw + dstRect.left; + uint8 *dst2Ptr = dst2 + dstRect.top * dstw + dstRect.left; const uint8 *dataPtr = src; while (rh--) { @@ -353,12 +355,24 @@ static bool calcClipRects(int dst_w, int dst_h, int src_x, int src_y, int src_w, return srcRect.isValidRect() && dstRect.isValidRect(); } -void Wiz::copy16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, const uint8 *xmapPtr) { - // TODO: Compressed 16 bits in 555 format +void Wiz::writeColor(uint8 *dstPtr, int dstType, uint16 color) { + switch (dstType) { + case kDstScreen: + WRITE_UINT16(dstPtr, color); + break; + case kDstMemory: + case kDstResource: + WRITE_LE_UINT16(dstPtr, color); + break; + default: + error("writeColor: Unknown dstType %d", dstType); + } +} +void Wiz::copy16BitWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *xmapPtr) { Common::Rect r1, r2; if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { - dst += r2.top * dstw + r2.left; + dst += r2.top * dstPitch + r2.left * 2; if (flags & kWIFFlipY) { const int dy = (srcy < 0) ? srcy : (srch - r1.height()); r1.translate(0, dy); @@ -368,17 +382,17 @@ void Wiz::copy16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, in r1.translate(dx, 0); } if (xmapPtr) { - decompress16BitWizImage<kWizXMap>(dst, dstw, src, r1, flags, palPtr, xmapPtr); + decompress16BitWizImage<kWizXMap>(dst, dstPitch, dstType, src, r1, flags, xmapPtr); } else { - decompress16BitWizImage<kWizCopy>(dst, dstw, src, r1, flags); + decompress16BitWizImage<kWizCopy>(dst, dstPitch, dstType, src, r1, flags); } } } -void Wiz::copyWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, const uint8 *xmapPtr) { +void Wiz::copyWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, const uint8 *xmapPtr, uint8 bitDepth) { Common::Rect r1, r2; if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { - dst += r2.left + r2.top * dstw; + dst += r2.top * dstPitch + r2.left * bitDepth; if (flags & kWIFFlipY) { const int dy = (srcy < 0) ? srcy : (srch - r1.height()); r1.translate(0, dy); @@ -388,11 +402,11 @@ void Wiz::copyWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int src r1.translate(dx, 0); } if (xmapPtr) { - decompressWizImage<kWizXMap>(dst, dstw, src, r1, flags, palPtr, xmapPtr); + decompressWizImage<kWizXMap>(dst, dstPitch, dstType, src, r1, flags, palPtr, xmapPtr, bitDepth); } else if (palPtr) { - decompressWizImage<kWizRMap>(dst, dstw, src, r1, flags, palPtr); + decompressWizImage<kWizRMap>(dst, dstPitch, dstType, src, r1, flags, palPtr, NULL, bitDepth); } else { - decompressWizImage<kWizCopy>(dst, dstw, src, r1, flags); + decompressWizImage<kWizCopy>(dst, dstPitch, dstType, src, r1, flags, NULL, NULL, bitDepth); } } } @@ -431,13 +445,100 @@ static void decodeWizMask(uint8 *&dst, uint8 &mask, int w, int maskType) { } } -void Wiz::copyWizImageWithMask(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int maskT, int maskP) { +void Wiz::copyMaskWizImage(uint8 *dst, const uint8 *src, const uint8 *mask, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr) { Common::Rect srcRect, dstRect; if (!calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, srcRect, dstRect)) { return; } - dstw = dstw / 8; - dst += dstRect.top * dstw + dstRect.left / 8; + dst += dstRect.top * dstPitch + dstRect.left * 2; + if (flags & kWIFFlipY) { + const int dy = (srcy < 0) ? srcy : (srch - srcRect.height()); + srcRect.translate(0, dy); + } + if (flags & kWIFFlipX) { + const int dx = (srcx < 0) ? srcx : (srcw - srcRect.width()); + srcRect.translate(dx, 0); + } + + const uint8 *dataPtr, *dataPtrNext; + const uint8 *maskPtr, *maskPtrNext; + uint8 code, *dstPtr, *dstPtrNext; + int h, w, dstInc; + + dataPtr = src; + dstPtr = dst; + maskPtr = mask; + + // Skip over the first 'srcRect->top' lines in the data + dataPtr += dstRect.top * dstPitch + dstRect.left * 2; + + h = dstRect.height(); + w = dstRect.width(); + if (h <= 0 || w <= 0) + return; + + dstInc = 2; + if (flags & kWIFFlipX) { + dstPtr += (w - 1) * 2; + dstInc = -2; + } + + while (h--) { + w = dstRect.width(); + uint16 lineSize = READ_LE_UINT16(maskPtr); maskPtr += 2; + dataPtrNext = dataPtr + dstPitch; + dstPtrNext = dstPtr + dstPitch; + maskPtrNext = maskPtr + lineSize; + if (lineSize != 0) { + while (w > 0) { + code = *maskPtr++; + if (code & 1) { + code >>= 1; + dataPtr += dstInc * code; + dstPtr += dstInc * code; + w -= code; + } else if (code & 2) { + code = (code >> 2) + 1; + w -= code; + if (w < 0) { + code += w; + } + while (code--) { + if (*maskPtr != 5) + write16BitColor<kWizCopy>(dstPtr, dataPtr, dstType, palPtr); + dataPtr += 2; + dstPtr += dstInc; + } + maskPtr++; + } else { + code = (code >> 2) + 1; + w -= code; + if (w < 0) { + code += w; + } + while (code--) { + if (*maskPtr != 5) + write16BitColor<kWizCopy>(dstPtr, dataPtr, dstType, palPtr); + dataPtr += 2; + dstPtr += dstInc; + maskPtr++; + } + } + } + } + dataPtr = dataPtrNext; + dstPtr = dstPtrNext; + maskPtr = maskPtrNext; + } +} + +void Wiz::copyWizImageWithMask(uint8 *dst, const uint8 *src, int dstPitch, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int maskT, int maskP) { + Common::Rect srcRect, dstRect; + if (!calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, srcRect, dstRect)) { + return; + } + dstPitch /= 8; + dst += dstRect.top * dstPitch + dstRect.left / 8; const uint8 *dataPtr, *dataPtrNext; uint8 code, mask, *dstPtr, *dstPtrNext; @@ -462,7 +563,7 @@ void Wiz::copyWizImageWithMask(uint8 *dst, const uint8 *src, int dstw, int dsth, w = srcRect.width(); mask = revBitMask(dstRect.left & 7); off = READ_LE_UINT16(dataPtr); dataPtr += 2; - dstPtrNext = dstPtr + dstw; + dstPtrNext = dstPtr + dstPitch; dataPtrNext = dataPtr + off; if (off != 0) { while (w > 0) { @@ -520,7 +621,7 @@ void Wiz::copyWizImageWithMask(uint8 *dst, const uint8 *src, int dstw, int dsth, } } -void Wiz::copyRawWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor) { +void Wiz::copyRawWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor, uint8 bitDepth) { Common::Rect r1, r2; if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { if (flags & kWIFFlipX) { @@ -537,19 +638,17 @@ void Wiz::copyRawWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int } int h = r1.height(); int w = r1.width(); - src += r1.left + r1.top * srcw; - dst += r2.left + r2.top * dstw; + src += r1.top * srcw + r1.left; + dst += r2.top * dstPitch + r2.left * bitDepth; if (palPtr) { - decompressRawWizImage<kWizRMap>(dst, dstw, src, srcw, w, h, transColor, palPtr); + decompressRawWizImage<kWizRMap>(dst, dstPitch, dstType, src, srcw, w, h, transColor, palPtr, bitDepth); } else { - decompressRawWizImage<kWizCopy>(dst, dstw, src, srcw, w, h, transColor); + decompressRawWizImage<kWizCopy>(dst, dstPitch, dstType, src, srcw, w, h, transColor, NULL, bitDepth); } } } -void Wiz::copyRaw16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor) { - // TODO: RAW 16 bits in 555 format - +void Wiz::copyRaw16BitWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, int transColor) { Common::Rect r1, r2; if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { if (flags & kWIFFlipX) { @@ -567,37 +666,44 @@ void Wiz::copyRaw16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int h = r1.height(); int w = r1.width(); src += (r1.top * srcw + r1.left) * 2; - dst += r2.top * dstw + r2.left; + dst += r2.top * dstPitch + r2.left * 2; while (h--) { - for (int i = 0; i < w; ++i) { + for (int i = 0; i < w; ++ i) { uint16 col = READ_LE_UINT16(src + 2 * i); - uint8 r = ((col >> 10) & 0x1F) << 3; - uint8 g = ((col >> 5) & 0x1F) << 3; - uint8 b = ((col >> 0) & 0x1F) << 3; - uint8 color = _vm->convert16BitColor(col, r, g, b); - if (transColor == -1 || transColor != col) { - dst[i] = color; + writeColor(dst + i * 2, dstType, col); } } src += srcw * 2; - dst += dstw; + dst += dstPitch; } } } template <int type> -void Wiz::decompress16BitWizImage(uint8 *dst, int dstPitch, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr, const uint8 *xmapPtr) { +void Wiz::write16BitColor(uint8 *dstPtr, const uint8 *dataPtr, int dstType, const uint8 *xmapPtr) { + uint16 col = READ_LE_UINT16(dataPtr); + if (type == kWizXMap) { + uint16 srcColor = (col >> 1) & 0x7DEF; + uint16 dstColor = (READ_UINT16(dstPtr) >> 1) & 0x7DEF; + uint16 newColor = srcColor + dstColor; + writeColor(dstPtr, dstType, newColor); + } + if (type == kWizCopy) { + writeColor(dstPtr, dstType, col); + } +} + +template <int type> +void Wiz::decompress16BitWizImage(uint8 *dst, int dstPitch, int dstType, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *xmapPtr) { const uint8 *dataPtr, *dataPtrNext; - uint8 code, *dstPtr, *dstPtrNext; + uint8 code; + uint8 *dstPtr, *dstPtrNext; int h, w, xoff, dstInc; if (type == kWizXMap) { assert(xmapPtr != 0); } - if (type == kWizRMap) { - assert(palPtr != 0); - } dstPtr = dst; dataPtr = src; @@ -616,10 +722,10 @@ void Wiz::decompress16BitWizImage(uint8 *dst, int dstPitch, const uint8 *src, co dstPtr += (h - 1) * dstPitch; dstPitch = -dstPitch; } - dstInc = 1; + dstInc = 2; if (flags & kWIFFlipX) { - dstPtr += w - 1; - dstInc = -1; + dstPtr += (w - 1) * 2; + dstInc = -2; } while (h--) { @@ -658,21 +764,10 @@ void Wiz::decompress16BitWizImage(uint8 *dst, int dstPitch, const uint8 *src, co code += w; } while (code--) { - uint16 col = READ_LE_UINT16(dataPtr); - uint8 r = ((col >> 10) & 0x1F) << 3; - uint8 g = ((col >> 5) & 0x1F) << 3; - uint8 b = ((col >> 0) & 0x1F) << 3; - col = _vm->convert16BitColor(col, r, g, b); - - if (type == kWizXMap) { - *dstPtr = xmapPtr[col * 256 + *dstPtr]; - } - if (type == kWizCopy) { - *dstPtr = col; - } + write16BitColor<type>(dstPtr, dataPtr, dstType, xmapPtr); dstPtr += dstInc; } - dataPtr+= 2; + dataPtr += 2; } else { code = (code >> 2) + 1; if (xoff > 0) { @@ -689,18 +784,7 @@ void Wiz::decompress16BitWizImage(uint8 *dst, int dstPitch, const uint8 *src, co code += w; } while (code--) { - uint16 col = READ_LE_UINT16(dataPtr); - uint8 r = ((col >> 10) & 0x1F) << 3; - uint8 g = ((col >> 5) & 0x1F) << 3; - uint8 b = ((col >> 0) & 0x1F) << 3; - col = _vm->convert16BitColor(col, r, g, b); - - if (type == kWizXMap) { - *dstPtr = xmapPtr[col * 256 + *dstPtr]; - } - if (type == kWizCopy) { - *dstPtr = col; - } + write16BitColor<type>(dstPtr, dataPtr, dstType, xmapPtr); dataPtr += 2; dstPtr += dstInc; } @@ -713,7 +797,36 @@ void Wiz::decompress16BitWizImage(uint8 *dst, int dstPitch, const uint8 *src, co } template <int type> -void Wiz::decompressWizImage(uint8 *dst, int dstPitch, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr, const uint8 *xmapPtr) { +void Wiz::write8BitColor(uint8 *dstPtr, const uint8 *dataPtr, int dstType, const uint8 *palPtr, const uint8 *xmapPtr, uint8 bitDepth) { + if (bitDepth == 2) { + if (type == kWizXMap) { + uint16 color = READ_LE_UINT16(palPtr + *dataPtr * 2); + uint16 srcColor = (color >> 1) & 0x7DEF; + uint16 dstColor = (READ_UINT16(dstPtr) >> 1) & 0x7DEF; + uint16 newColor = srcColor + dstColor; + writeColor(dstPtr, dstType, newColor); + } + if (type == kWizRMap) { + writeColor(dstPtr, dstType, READ_LE_UINT16(palPtr + *dataPtr * 2)); + } + if (type == kWizCopy) { + writeColor(dstPtr, dstType, *dataPtr); + } + } else { + if (type == kWizXMap) { + *dstPtr = xmapPtr[*dataPtr * 256 + *dstPtr]; + } + if (type == kWizRMap) { + *dstPtr = palPtr[*dataPtr]; + } + if (type == kWizCopy) { + *dstPtr = *dataPtr; + } + } +} + +template <int type> +void Wiz::decompressWizImage(uint8 *dst, int dstPitch, int dstType, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr, const uint8 *xmapPtr, uint8 bitDepth) { const uint8 *dataPtr, *dataPtrNext; uint8 code, *dstPtr, *dstPtrNext; int h, w, xoff, dstInc; @@ -742,10 +855,10 @@ void Wiz::decompressWizImage(uint8 *dst, int dstPitch, const uint8 *src, const C dstPtr += (h - 1) * dstPitch; dstPitch = -dstPitch; } - dstInc = 1; + dstInc = bitDepth; if (flags & kWIFFlipX) { - dstPtr += w - 1; - dstInc = -1; + dstPtr += (w - 1) * bitDepth; + dstInc = -bitDepth; } while (h--) { @@ -784,15 +897,7 @@ void Wiz::decompressWizImage(uint8 *dst, int dstPitch, const uint8 *src, const C code += w; } while (code--) { - if (type == kWizXMap) { - *dstPtr = xmapPtr[*dataPtr * 256 + *dstPtr]; - } - if (type == kWizRMap) { - *dstPtr = palPtr[*dataPtr]; - } - if (type == kWizCopy) { - *dstPtr = *dataPtr; - } + write8BitColor<type>(dstPtr, dataPtr, dstType, palPtr, xmapPtr, bitDepth); dstPtr += dstInc; } dataPtr++; @@ -812,15 +917,8 @@ void Wiz::decompressWizImage(uint8 *dst, int dstPitch, const uint8 *src, const C code += w; } while (code--) { - if (type == kWizXMap) { - *dstPtr = xmapPtr[*dataPtr++ * 256 + *dstPtr]; - } - if (type == kWizRMap) { - *dstPtr = palPtr[*dataPtr++]; - } - if (type == kWizCopy) { - *dstPtr = *dataPtr++; - } + write8BitColor<type>(dstPtr, dataPtr, dstType, palPtr, xmapPtr, bitDepth); + dataPtr++; dstPtr += dstInc; } } @@ -832,7 +930,7 @@ void Wiz::decompressWizImage(uint8 *dst, int dstPitch, const uint8 *src, const C } template <int type> -void Wiz::decompressRawWizImage(uint8 *dst, int dstPitch, const uint8 *src, int srcPitch, int w, int h, int transColor, const uint8 *palPtr) { +void Wiz::decompressRawWizImage(uint8 *dst, int dstPitch, int dstType, const uint8 *src, int srcPitch, int w, int h, int transColor, const uint8 *palPtr, uint8 bitDepth) { if (type == kWizRMap) { assert(palPtr != 0); } @@ -845,10 +943,18 @@ void Wiz::decompressRawWizImage(uint8 *dst, int dstPitch, const uint8 *src, int uint8 col = src[i]; if (transColor == -1 || transColor != col) { if (type == kWizRMap) { - dst[i] = palPtr[col]; + if (bitDepth == 2) { + writeColor(dst + i * 2, dstType, READ_LE_UINT16(palPtr + col * 2)); + } else { + dst[i] = palPtr[col]; + } } if (type == kWizCopy) { - dst[i] = col; + if (bitDepth == 2) { + writeColor(dst + i * 2, dstType, col); + } else { + dst[i] = col; + } } } } @@ -938,7 +1044,7 @@ uint16 Wiz::getWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint } if (bitDepth == 2) - return (READ_LE_UINT16(data) & 1) ? color : READ_LE_UINT16(data + 1); + return (READ_LE_UINT16(data) & 1) ? color : READ_LE_UINT16(data + 2); else return (data[0] & 1) ? color : data[1]; @@ -949,7 +1055,7 @@ uint16 Wiz::getRawWizPixelColor(const uint8 *data, int x, int y, int w, int h, u return color; } if (bitDepth == 2) - return READ_LE_UINT16(data + y * w + x * 2); + return READ_LE_UINT16(data + (y * w + x) * 2); else return data[y * w + x]; } @@ -1038,6 +1144,23 @@ void Wiz::computeRawWizHistogram(uint32 *histogram, const uint8 *data, int srcPi } } +static int wizPackType2(uint8 *dst, const uint8 *src, int srcPitch, const Common::Rect& rCapt) { + debug(9, "wizPackType2([%d,%d,%d,%d])", rCapt.left, rCapt.top, rCapt.right, rCapt.bottom); + int w = rCapt.width(); + int h = rCapt.height(); + int size = w * h * 2; + if (dst) { + src += rCapt.top * srcPitch + rCapt.left * 2; + while (h--) { + for (int i = 0; i < w; i++) + WRITE_LE_UINT16(dst + i * 2, READ_UINT16(src + i * 2)); + dst += w * 2; + src += srcPitch; + } + } + return size; +} + static int wizPackType1(uint8 *dst, const uint8 *src, int srcPitch, const Common::Rect& rCapt, uint8 transColor) { debug(9, "wizPackType1(%d, [%d,%d,%d,%d])", transColor, rCapt.left, rCapt.top, rCapt.right, rCapt.bottom); src += rCapt.top * srcPitch + rCapt.left; @@ -1174,7 +1297,6 @@ static int wizPackType0(uint8 *dst, const uint8 *src, int srcPitch, const Common } void Wiz::captureWizImage(int resNum, const Common::Rect& r, bool backBuffer, int compType) { - debug(5, "ScummEngine_v72he::captureWizImage(%d, %d, [%d,%d,%d,%d])", resNum, compType, r.left, r.top, r.right, r.bottom); uint8 *src = NULL; VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen]; if (backBuffer) { @@ -1182,12 +1304,17 @@ void Wiz::captureWizImage(int resNum, const Common::Rect& r, bool backBuffer, in } else { src = pvs->getPixels(0, 0); } - Common::Rect rCapt(pvs->w, pvs->h); + captureImage(src, pvs->pitch, pvs->w, pvs->h, resNum, r, compType); +} + +void Wiz::captureImage(uint8 *src, int srcPitch, int srcw, int srch, int resNum, const Common::Rect& r, int compType) { + debug(0, "captureImage(%d, %d, [%d,%d,%d,%d])", resNum, compType, r.left, r.top, r.right, r.bottom); + Common::Rect rCapt(srcw, srch); if (rCapt.intersects(r)) { rCapt.clip(r); const uint8 *palPtr; if (_vm->_game.heversion >= 99) { - palPtr = _vm->_hePalettes + 1024; + palPtr = _vm->_hePalettes + _vm->_hePaletteSlot; } else { palPtr = _vm->_currentPalette; } @@ -1196,15 +1323,21 @@ void Wiz::captureWizImage(int resNum, const Common::Rect& r, bool backBuffer, in int h = rCapt.height(); int transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : 5; + if (_vm->_game.features & GF_16BIT_COLOR) + compType = 2; + // compute compressed size int dataSize = 0; int headerSize = palPtr ? 1080 : 36; switch (compType) { case 0: - dataSize = wizPackType0(0, src, pvs->pitch, rCapt); + dataSize = wizPackType0(0, src, srcPitch, rCapt); break; case 1: - dataSize = wizPackType1(0, src, pvs->pitch, rCapt, transColor); + dataSize = wizPackType1(0, src, srcPitch, rCapt, transColor); + break; + case 2: + dataSize = wizPackType2(0, src, srcPitch, rCapt); break; default: error("unhandled compression type %d", compType); @@ -1244,10 +1377,13 @@ void Wiz::captureWizImage(int resNum, const Common::Rect& r, bool backBuffer, in // write compressed data switch (compType) { case 0: - wizPackType0(wizImg + headerSize, src, pvs->pitch, rCapt); + wizPackType0(wizImg + headerSize, src, srcPitch, rCapt); break; case 1: - wizPackType1(wizImg + headerSize, src, pvs->pitch, rCapt, transColor); + wizPackType1(wizImg + headerSize, src, srcPitch, rCapt, transColor); + break; + case 2: + wizPackType2(wizImg + headerSize, src, srcPitch, rCapt); break; default: break; @@ -1274,24 +1410,15 @@ void Wiz::displayWizImage(WizImage *pwi) { drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags, 0, 0, 0); } else { const Common::Rect *r = NULL; - drawWizImage(pwi->resNum, pwi->state, pwi->x1, pwi->y1, 0, 0, 0, r, pwi->flags, 0, 0); + drawWizImage(pwi->resNum, pwi->state, 0, 0, pwi->x1, pwi->y1, 0, 0, 0, r, pwi->flags, 0, _vm->getHEPaletteSlot(0)); } } -uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, int palette) { - debug(3, "drawWizImage(resNum %d, x1 %d y1 %d flags 0x%X zorder %d shadow %d field_390 %d dstResNum %d palette %d)", resNum, x1, y1, flags, zorder, shadow, field_390, dstResNum, palette); +uint8 *Wiz::drawWizImage(int resNum, int state, int maskNum, int maskState, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, const uint8 *palPtr) { + debug(3, "drawWizImage(resNum %d, state %d maskNum %d maskState %d x1 %d y1 %d flags 0x%X zorder %d shadow %d field_390 %d dstResNum %d)", resNum, state, maskNum, maskState, x1, y1, flags, zorder, shadow, field_390, dstResNum); uint8 *dataPtr; uint8 *dst = NULL; - const uint8 *palPtr = NULL; - if (_vm->_game.heversion >= 99) { - if (palette) { - palPtr = _vm->_hePalettes + palette * 1024 + 768; - } else { - palPtr = _vm->_hePalettes + 1792; - } - } - const uint8 *xmapPtr = NULL; if (shadow) { dataPtr = _vm->getResourceAddress(rtImage, shadow); @@ -1313,6 +1440,21 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int uint8 *wizd = _vm->findWrappedBlock(MKID_BE('WIZD'), dataPtr, state, 0); assert(wizd); + uint8 *mask = NULL; + if (maskNum) { + uint8 *maskPtr = _vm->getResourceAddress(rtImage, maskNum); + assert(maskPtr); + + wizh = _vm->findWrappedBlock(MKID_BE('WIZH'), maskPtr, maskState, 0); + assert(wizh); + assert(comp == 2 && READ_LE_UINT32(wizh + 0x0) == 1); + width = READ_LE_UINT32(wizh + 0x4); + height = READ_LE_UINT32(wizh + 0x8); + + mask = _vm->findWrappedBlock(MKID_BE('WIZD'), maskPtr, maskState, 0); + assert(mask); + } + if (flags & kWIFHasPalette) { uint8 *pal = _vm->findWrappedBlock(MKID_BE('RGBS'), dataPtr, state, 0); assert(pal); @@ -1334,13 +1476,25 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int error("WizImage printing is unimplemented"); } - int32 cw, ch; + int32 dstPitch, dstType, cw, ch; if (flags & kWIFBlitToMemBuffer) { - dst = (uint8 *)malloc(width * height); + dst = (uint8 *)malloc(width * height * _vm->_bitDepth); int transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? (_vm->VAR(_vm->VAR_WIZ_TCOLOR)) : 5; - memset(dst, transColor, width * height); + + if (_vm->_bitDepth == 2) { + uint8 *tmpPtr = dst; + for (uint i = 0; i < height; i++) { + for (uint j = 0; j < width; j++) + WRITE_LE_UINT16(tmpPtr + j * 2, transColor); + tmpPtr += width * 2; + } + } else { + memset(dst, transColor, width * height); + } cw = width; ch = height; + dstPitch = cw * _vm->_bitDepth; + dstType = kDstMemory; } else { if (dstResNum) { uint8 *dstPtr = _vm->getResourceAddress(rtImage, dstResNum); @@ -1348,6 +1502,8 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int dst = _vm->findWrappedBlock(MKID_BE('WIZD'), dstPtr, 0, 0); assert(dst); getWizImageDim(dstResNum, 0, cw, ch); + dstPitch = cw * _vm->_bitDepth; + dstType = kDstResource; } else { VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen]; if (flags & kWIFMarkBufferDirty) { @@ -1357,6 +1513,8 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int } cw = pvs->w; ch = pvs->h; + dstPitch = pvs->pitch; + dstType = kDstScreen; } } @@ -1376,7 +1534,7 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int } } - if (flags & kWIFRemapPalette) { + if (flags & kWIFRemapPalette && _vm->_bitDepth == 1) { palPtr = rmap + 4; } @@ -1388,28 +1546,33 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int switch (comp) { case 0: - copyRawWizImage(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, transColor); + copyRawWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, transColor, _vm->_bitDepth); break; case 1: if (flags & 0x80) { dst = _vm->getMaskBuffer(0, 0, 1); - copyWizImageWithMask(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, 0, 2); + dstPitch /= _vm->_bitDepth; + copyWizImageWithMask(dst, wizd, dstPitch, cw, ch, x1, y1, width, height, &rScreen, 0, 2); } else if (flags & 0x100) { dst = _vm->getMaskBuffer(0, 0, 1); - copyWizImageWithMask(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, 0, 1); + dstPitch /= _vm->_bitDepth; + copyWizImageWithMask(dst, wizd, dstPitch, cw, ch, x1, y1, width, height, &rScreen, 0, 1); } else { - copyWizImage(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, xmapPtr); + copyWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, xmapPtr, _vm->_bitDepth); } break; case 2: - copyRaw16BitWizImage(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, transColor); + if (maskNum) { + copyMaskWizImage(dst, wizd, mask, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr); + } else { + copyRaw16BitWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, transColor); + } break; case 4: // TODO: Unknown image type break; case 5: - // TODO: 16bit color compressed image - copy16BitWizImage(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, xmapPtr); + copy16BitWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, xmapPtr); break; default: error("drawWizImage: Unhandled wiz compression type %d", comp); @@ -1512,6 +1675,74 @@ struct PolygonDrawData { } }; +void Wiz::captureWizPolygon(int resNum, int maskNum, int maskState, int id1, int id2, int compType) { + debug(0, "captureWizPolygon: resNum %d, maskNum %d maskState %d, id1 %d id2 %d compType %d", resNum, maskNum, maskState, id1, id2, compType); + + int i, j; + WizPolygon *wp; + + wp = NULL; + for (i = 0; i < ARRAYSIZE(_polygons); ++i) { + if (_polygons[i].id == id1) { + wp = &_polygons[i]; + break; + } + } + if (!wp) { + error("Polygon1 %d is not defined", id1); + } + if (wp->numVerts != 5) { + error("Invalid point count %d for Polygon1 %d", wp->numVerts, id1); + } + + wp = NULL; + for (i = 0; i < ARRAYSIZE(_polygons); ++i) { + if (_polygons[i].id == id2) { + wp = &_polygons[i]; + break; + } + } + if (!wp) { + error("Polygon2 %d is not defined", id2); + } + if (wp->numVerts != 5) { + error("Invalid point count %d for Polygon2 %d", wp->numVerts, id2); + } + + int32 dstw, dsth, dstpitch; + int32 srcw, srch; + uint8 *imageBuffer; + + assert(maskNum); + const Common::Rect *r = NULL; + const uint8 *src = drawWizImage(maskNum, maskState, 0, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, 0); + getWizImageDim(maskNum, maskState, srcw, srch); + + dstw = wp->bound.width(); + dsth = wp->bound.height(); + dstpitch = dstw * _vm->_bitDepth; + imageBuffer = (uint8 *)malloc(dstw * dsth * _vm->_bitDepth); + assert(imageBuffer); + + const uint16 transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : 5; + if (_vm->_bitDepth == 2) { + uint8 *tmpPtr = imageBuffer; + for (i = 0; i < dsth; i++) { + for (j = 0; j < dstw; j++) + WRITE_LE_UINT16(tmpPtr + j * 2, transColor); + tmpPtr += dstpitch; + } + } else { + memset(imageBuffer, transColor, dstw * dsth); + } + + Common::Rect bound; + drawWizPolygonImage(imageBuffer, src, NULL, dstpitch, kDstMemory, dstw, dsth, srcw, srch, bound, wp->vert, _vm->_bitDepth); + + captureImage(imageBuffer, dstpitch, dstw, dsth, resNum, wp->bound, compType); + free(imageBuffer); +} + void Wiz::drawWizComplexPolygon(int resNum, int state, int po_x, int po_y, int shadow, int angle, int scale, const Common::Rect *r, int flags, int dstResNum, int palette) { Common::Point pts[4]; @@ -1539,11 +1770,10 @@ void Wiz::drawWizPolygon(int resNum, int state, int id, int flags, int shadow, i } void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int flags, int shadow, int dstResNum, int palette) { - debug(3, "drawWizPolygonTransform(resNum %d, flags 0x%X, shadow %d dstResNum %d palette %d)", resNum, flags, shadow, dstResNum, palette); + debug(0, "drawWizPolygonTransform(resNum %d, flags 0x%X, shadow %d dstResNum %d palette %d)", resNum, flags, shadow, dstResNum, palette); const Common::Rect *r = NULL; uint8 *srcWizBuf = NULL; bool freeBuffer = true; - int i; if (_vm->_game.heversion >= 99) { if (getWizImageData(resNum, state, 0) != 0 || (flags & (kWIFRemapPalette | kWIFFlipX | kWIFFlipY)) || palette != 0) { @@ -1552,8 +1782,10 @@ void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int if (flags & 0x800000) { debug(0, "drawWizPolygonTransform() unhandled flag 0x800000"); } - srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, shadow, 0, r, flags, 0, palette); + + srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, 0, 0, shadow, 0, r, flags, 0, _vm->getHEPaletteSlot(palette)); } else { + assert(_vm->_bitDepth == 1); uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum); assert(dataPtr); srcWizBuf = _vm->findWrappedBlock(MKID_BE('WIZD'), dataPtr, state, 0); @@ -1562,7 +1794,7 @@ void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int } } else { if (getWizImageData(resNum, state, 0) != 0) { - srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, shadow, 0, r, kWIFBlitToMemBuffer, 0, palette); + srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, 0, 0, shadow, 0, r, kWIFBlitToMemBuffer, 0, _vm->getHEPaletteSlot(palette)); } else { uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum); assert(dataPtr); @@ -1572,146 +1804,163 @@ void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int } } - if (srcWizBuf) { - uint8 *dst; - int32 dstw, dsth, dstpitch, wizW, wizH; - VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen]; - int transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : 5; + assert(srcWizBuf); - if (dstResNum) { - uint8 *dstPtr = _vm->getResourceAddress(rtImage, dstResNum); - assert(dstPtr); - dst = _vm->findWrappedBlock(MKID_BE('WIZD'), dstPtr, 0, 0); - assert(dst); - getWizImageDim(dstResNum, 0, dstw, dsth); - dstpitch = dstw; + uint8 *dst; + int32 dstw, dsth, dstpitch, dstType, wizW, wizH; + VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen]; + + if (dstResNum) { + uint8 *dstPtr = _vm->getResourceAddress(rtImage, dstResNum); + assert(dstPtr); + dst = _vm->findWrappedBlock(MKID_BE('WIZD'), dstPtr, 0, 0); + assert(dst); + getWizImageDim(dstResNum, 0, dstw, dsth); + dstpitch = dstw * _vm->_bitDepth; + dstType = kDstResource; + } else { + if (flags & kWIFMarkBufferDirty) { + dst = pvs->getPixels(0, 0); } else { - if (flags & kWIFMarkBufferDirty) { - dst = pvs->getPixels(0, 0); - } else { - dst = pvs->getBackPixels(0, 0); + dst = pvs->getBackPixels(0, 0); + } + dstw = pvs->w; + dsth = pvs->h; + dstpitch = pvs->pitch; + dstType = kDstScreen; + } + + Common::Rect bound; + getWizImageDim(resNum, state, wizW, wizH); + drawWizPolygonImage(dst, srcWizBuf, 0, dstpitch, dstType, dstw, dsth, wizW, wizH, bound, wp, _vm->_bitDepth); + + if (flags & kWIFMarkBufferDirty) { + _vm->markRectAsDirty(kMainVirtScreen, bound); + } else { + _vm->restoreBackgroundHE(bound); + } + + if (freeBuffer) + free(srcWizBuf); +} + +void Wiz::drawWizPolygonImage(uint8 *dst, const uint8 *src, const uint8 *mask, int dstpitch, int dstType, int dstw, int dsth, int wizW, int wizH, Common::Rect &bound, Common::Point *wp, uint8 bitDepth) { + int i, transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : 5; + + Common::Point bbox[4]; + bbox[0].x = 0; + bbox[0].y = 0; + bbox[1].x = wizW - 1; + bbox[1].y = 0; + bbox[2].x = wizW - 1; + bbox[2].y = wizH - 1; + bbox[3].x = 0; + bbox[3].y = wizH - 1; + + int16 xmin_p, xmax_p, ymin_p, ymax_p; + xmin_p = ymin_p = (int16)0x7FFF; + xmax_p = ymax_p = (int16)0x8000; + + for (i = 0; i < 4; ++i) { + xmin_p = MIN(wp[i].x, xmin_p); + xmax_p = MAX(wp[i].x, xmax_p); + ymin_p = MIN(wp[i].y, ymin_p); + ymax_p = MAX(wp[i].y, ymax_p); + } + + int16 xmin_b, xmax_b, ymin_b, ymax_b; + xmin_b = ymin_b = (int16)0x7FFF; + xmax_b = ymax_b = (int16)0x8000; + + for (i = 0; i < 4; ++i) { + xmin_b = MIN(bbox[i].x, xmin_b); + xmax_b = MAX(bbox[i].x, xmax_b); + ymin_b = MIN(bbox[i].y, ymin_b); + ymax_b = MAX(bbox[i].y, ymax_b); + } + + PolygonDrawData pdd(ymax_p - ymin_p + 1); + pdd.mat[0].x = xmin_p; + pdd.mat[0].y = ymin_p; + pdd.mat[1].x = xmax_p; + pdd.mat[1].y = ymax_p; + pdd.mat[2].x = xmin_b; + pdd.mat[2].y = ymin_b; + pdd.mat[3].x = xmax_b; + pdd.mat[3].y = ymax_b; + + // precompute the transformation which remaps 'bbox' pixels to 'wp' + for (i = 0; i < 3; ++i) { + pdd.transform(&wp[i], &wp[i + 1], &bbox[i], &bbox[i + 1]); + } + pdd.transform(&wp[3], &wp[0], &bbox[3], &bbox[0]); + + pdd.rAreasNum = 0; + PolygonDrawData::ResultArea *pra = &pdd.ra[0]; + int32 yoff = pdd.mat[0].y * dstpitch; + int16 y_start = pdd.mat[0].y; + for (i = 0; i < pdd.pAreasNum; ++i) { + PolygonDrawData::PolygonArea *ppa = &pdd.pa[i]; + if (y_start >= 0 && y_start < dsth) { + int16 x1 = ppa->xmin; + if (x1 < 0) { + x1 = 0; } - dstw = pvs->w; - dsth = pvs->h; - dstpitch = pvs->pitch; - } - - getWizImageDim(resNum, state, wizW, wizH); - - Common::Point bbox[4]; - bbox[0].x = 0; - bbox[0].y = 0; - bbox[1].x = wizW - 1; - bbox[1].y = 0; - bbox[2].x = wizW - 1; - bbox[2].y = wizH - 1; - bbox[3].x = 0; - bbox[3].y = wizH - 1; - - int16 xmin_p, xmax_p, ymin_p, ymax_p; - xmin_p = ymin_p = (int16)0x7FFF; - xmax_p = ymax_p = (int16)0x8000; - - for (i = 0; i < 4; ++i) { - xmin_p = MIN(wp[i].x, xmin_p); - xmax_p = MAX(wp[i].x, xmax_p); - ymin_p = MIN(wp[i].y, ymin_p); - ymax_p = MAX(wp[i].y, ymax_p); - } - - int16 xmin_b, xmax_b, ymin_b, ymax_b; - xmin_b = ymin_b = (int16)0x7FFF; - xmax_b = ymax_b = (int16)0x8000; - - for (i = 0; i < 4; ++i) { - xmin_b = MIN(bbox[i].x, xmin_b); - xmax_b = MAX(bbox[i].x, xmax_b); - ymin_b = MIN(bbox[i].y, ymin_b); - ymax_b = MAX(bbox[i].y, ymax_b); - } - - PolygonDrawData pdd(ymax_p - ymin_p + 1); - pdd.mat[0].x = xmin_p; - pdd.mat[0].y = ymin_p; - pdd.mat[1].x = xmax_p; - pdd.mat[1].y = ymax_p; - pdd.mat[2].x = xmin_b; - pdd.mat[2].y = ymin_b; - pdd.mat[3].x = xmax_b; - pdd.mat[3].y = ymax_b; - - // precompute the transformation which remaps 'bbox' pixels to 'wp' - for (i = 0; i < 3; ++i) { - pdd.transform(&wp[i], &wp[i + 1], &bbox[i], &bbox[i + 1]); - } - pdd.transform(&wp[3], &wp[0], &bbox[3], &bbox[0]); - - pdd.rAreasNum = 0; - PolygonDrawData::ResultArea *pra = &pdd.ra[0]; - int32 yoff = pdd.mat[0].y * dstpitch; - int16 y_start = pdd.mat[0].y; - for (i = 0; i < pdd.pAreasNum; ++i) { - PolygonDrawData::PolygonArea *ppa = &pdd.pa[i]; - if (y_start >= 0 && y_start < dsth) { - int16 x1 = ppa->xmin; - if (x1 < 0) { - x1 = 0; - } - int16 x2 = ppa->xmax; - if (x2 >= dstw) { - x2 = dstw - 1; - } - int16 w = x2 - x1 + 1; - if (w > 0) { - int16 width = ppa->xmax - ppa->xmin + 1; - pra->x_step = ((ppa->x2 - ppa->x1) << 16) / width; - pra->y_step = ((ppa->y2 - ppa->y1) << 16) / width; - pra->dst_offs = yoff + x1; - pra->w = w; - pra->x_s = ppa->x1 << 16; - pra->y_s = ppa->y1 << 16; - int16 tmp = x1 - ppa->xmin; - if (tmp != 0) { - pra->x_s += pra->x_step * tmp; - pra->y_s += pra->y_step * tmp; - } - ++pra; - ++pdd.rAreasNum; - } + int16 x2 = ppa->xmax; + if (x2 >= dstw) { + x2 = dstw - 1; } - ++ppa; - yoff += dstpitch; - ++y_start; - } - - pra = &pdd.ra[0]; - for (i = 0; i < pdd.rAreasNum; ++i, ++pra) { - uint8 *dstPtr = dst + pra->dst_offs; - int32 w = pra->w; - int32 x_acc = pra->x_s; - int32 y_acc = pra->y_s; - while (--w) { - int32 src_offs = (y_acc >> 16) * wizW + (x_acc >> 16); - assert(src_offs < wizW * wizH); - x_acc += pra->x_step; - y_acc += pra->y_step; - if (transColor == -1 || transColor != srcWizBuf[src_offs]) { - *dstPtr = srcWizBuf[src_offs]; + int16 w = x2 - x1 + 1; + if (w > 0) { + int16 width = ppa->xmax - ppa->xmin + 1; + pra->x_step = ((ppa->x2 - ppa->x1) << 16) / width; + pra->y_step = ((ppa->y2 - ppa->y1) << 16) / width; + pra->dst_offs = yoff + x1 * _vm->_bitDepth; + pra->w = w; + pra->x_s = ppa->x1 << 16; + pra->y_s = ppa->y1 << 16; + int16 tmp = x1 - ppa->xmin; + if (tmp != 0) { + pra->x_s += pra->x_step * tmp; + pra->y_s += pra->y_step * tmp; } - dstPtr++; + ++pra; + ++pdd.rAreasNum; } } - - Common::Rect bound(xmin_p, ymin_p, xmax_p + 1, ymax_p + 1); - if (flags & kWIFMarkBufferDirty) { - _vm->markRectAsDirty(kMainVirtScreen, bound); - } else { - _vm->restoreBackgroundHE(bound); + ++ppa; + yoff += dstpitch; + ++y_start; + } + + pra = &pdd.ra[0]; + for (i = 0; i < pdd.rAreasNum; ++i, ++pra) { + uint8 *dstPtr = dst + pra->dst_offs; + int32 w = pra->w; + int32 x_acc = pra->x_s; + int32 y_acc = pra->y_s; + while (--w) { + int32 src_offs = (y_acc >> 16) * wizW + (x_acc >> 16); + assert(src_offs < wizW * wizH); + x_acc += pra->x_step; + y_acc += pra->y_step; + if (bitDepth == 2) { + if (transColor == -1 || transColor != READ_LE_UINT16(src + src_offs * 2)) { + //if (transColor == -1 || READ_LE_UINT16(dstPtr) != transColor) + writeColor(dstPtr, dstType, READ_LE_UINT16(src + src_offs * 2)); + } + } else { + if (transColor == -1 || transColor != src[src_offs]) + *dstPtr = src[src_offs]; + } + dstPtr += bitDepth; } - - if (freeBuffer) - free(srcWizBuf); } + + bound.left = xmin_p; + bound.top = ymin_p; + bound.right = xmax_p + 1; + bound.bottom = ymax_p + 1; } void Wiz::flushWizBuffer() { @@ -1721,13 +1970,13 @@ void Wiz::flushWizBuffer() { drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags, pwi->shadow, 0, pwi->palette); } else { const Common::Rect *r = NULL; - drawWizImage(pwi->resNum, pwi->state, pwi->x1, pwi->y1, pwi->zorder, pwi->shadow, pwi->field_390, r, pwi->flags, 0, pwi->palette); + drawWizImage(pwi->resNum, pwi->state, 0, 0, pwi->x1, pwi->y1, pwi->zorder, pwi->shadow, pwi->field_390, r, pwi->flags, 0, _vm->getHEPaletteSlot(pwi->palette)); } } _imagesNum = 0; } -void Wiz::loadWizCursor(int resId) { +void Wiz::loadWizCursor(int resId, int palette) { int32 x, y; getWizImageSpot(resId, 0, x, y); if (x < 0) { @@ -1742,11 +1991,12 @@ void Wiz::loadWizCursor(int resId) { } const Common::Rect *r = NULL; - uint8 *cursor = drawWizImage(resId, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, 0); + uint8 *cursor = drawWizImage(resId, 0, 0, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, _vm->getHEPaletteSlot(palette)); + int32 cw, ch; getWizImageDim(resId, 0, cw, ch); _vm->setCursorHotspot(x, y); - _vm->setCursorFromBuffer(cursor, cw, ch, cw); + _vm->setCursorFromBuffer(cursor, cw, ch, cw * _vm->_bitDepth); // Since we set up cursor palette for default cursor, disable it now CursorMan.disableCursorPalette(true); @@ -1758,7 +2008,7 @@ void Wiz::displayWizComplexImage(const WizParameters *params) { int sourceImage = 0; if (params->processFlags & kWPFMaskImg) { sourceImage = params->sourceImage; - debug(0, "displayWizComplexImage() unhandled flag kWPFMaskImg"); + debug(0, "displayWizComplexImage() flag kWPFMaskImg"); } int palette = 0; if (params->processFlags & kWPFPaletteNum) { @@ -1826,15 +2076,14 @@ void Wiz::displayWizComplexImage(const WizParameters *params) { ++_imagesNum; } else { if (sourceImage != 0) { - // TODO: Add support for kWPFMaskImg - drawWizImage(params->sourceImage, state, po_x, po_y, params->img.zorder, shadow, field_390, r, flags, dstResNum, palette); + drawWizImage(params->sourceImage, 0, params->img.resNum, state, po_x, po_y, params->img.zorder, shadow, field_390, r, flags, dstResNum, _vm->getHEPaletteSlot(palette)); } else if (params->processFlags & (kWPFScaled | kWPFRotate)) { drawWizComplexPolygon(params->img.resNum, state, po_x, po_y, shadow, rotationAngle, scale, r, flags, dstResNum, palette); } else { if (flags & kWIFIsPolygon) { drawWizPolygon(params->img.resNum, state, po_x, flags, shadow, dstResNum, palette); } else { - drawWizImage(params->img.resNum, state, po_x, po_y, params->img.zorder, shadow, field_390, r, flags, dstResNum, palette); + drawWizImage(params->img.resNum, state, 0, 0, po_x, po_y, params->img.zorder, shadow, field_390, r, flags, dstResNum, _vm->getHEPaletteSlot(palette)); } } } @@ -1842,6 +2091,8 @@ void Wiz::displayWizComplexImage(const WizParameters *params) { void Wiz::createWizEmptyImage(int resNum, int img_x, int img_y, int img_w, int img_h) { const uint16 flags = 0xB; + const uint8 compType = (_vm->_game.features & GF_16BIT_COLOR) ? 2 : 0; + const uint8 bitDepth = (_vm->_game.features & GF_16BIT_COLOR) ? 2 : 1; int res_size = 0x1C; if (flags & 1) { res_size += 0x308; @@ -1852,11 +2103,11 @@ void Wiz::createWizEmptyImage(int resNum, int img_x, int img_y, int img_w, int i if (flags & 8) { res_size += 0x10C; } - res_size += 8 + img_w * img_h; + res_size += 8 + img_w * img_h * bitDepth; const uint8 *palPtr; if (_vm->_game.heversion >= 99) { - palPtr = _vm->_hePalettes + 1024; + palPtr = _vm->_hePalettes + _vm->_hePaletteSlot; } else { palPtr = _vm->_currentPalette; } @@ -1869,7 +2120,7 @@ void Wiz::createWizEmptyImage(int resNum, int img_x, int img_y, int img_w, int i WRITE_BE_UINT32(res_data, res_size); res_data += 4; WRITE_BE_UINT32(res_data, 'WIZH'); res_data += 4; WRITE_BE_UINT32(res_data, 0x14); res_data += 4; - WRITE_LE_UINT32(res_data, 0); res_data += 4; + WRITE_LE_UINT32(res_data, compType); res_data += 4; WRITE_LE_UINT32(res_data, img_w); res_data += 4; WRITE_LE_UINT32(res_data, img_h); res_data += 4; if (flags & 1) { @@ -1892,7 +2143,7 @@ void Wiz::createWizEmptyImage(int resNum, int img_x, int img_y, int img_w, int i } } WRITE_BE_UINT32(res_data, 'WIZD'); res_data += 4; - WRITE_BE_UINT32(res_data, 8 + img_w * img_h); res_data += 4; + WRITE_BE_UINT32(res_data, 8 + img_w * img_h * bitDepth); res_data += 4; } _vm->_res->setModified(rtImage, resNum); } @@ -1909,7 +2160,8 @@ void Wiz::fillWizRect(const WizParameters *params) { int c = READ_LE_UINT32(wizh + 0x0); int w = READ_LE_UINT32(wizh + 0x4); int h = READ_LE_UINT32(wizh + 0x8); - assert(c == 0); + assert(c == 0 || c == 2); + uint8 bitDepth = (c == 2) ? 2 : 1; Common::Rect areaRect, imageRect(w, h); if (params->processFlags & kWPFClipBox) { if (!imageRect.intersects(params->box)) { @@ -1932,10 +2184,15 @@ void Wiz::fillWizRect(const WizParameters *params) { assert(wizd); int dx = areaRect.width(); int dy = areaRect.height(); - wizd += areaRect.top * w + areaRect.left; + wizd += (areaRect.top * w + areaRect.left) * bitDepth; while (dy--) { - memset(wizd, color, dx); - wizd += w; + if (bitDepth == 2) { + for (int i = 0; i < dx; i++) + WRITE_LE_UINT16(wizd + i * 2, color); + } else { + memset(wizd, color, dx); + } + wizd += w * bitDepth; } } } @@ -1945,14 +2202,19 @@ void Wiz::fillWizRect(const WizParameters *params) { struct drawProcP { Common::Rect *imageRect; uint8 *wizd; - int width; + int pitch; + int depth; }; static void drawProc(int x, int y, int c, void *data) { drawProcP *param = (drawProcP *)data; if (param->imageRect->contains(x, y)) { - *(param->wizd + y * param->width + x) = c; + uint32 offs = y * param->pitch + x * param->depth; + if (param->depth == 2) + WRITE_LE_UINT16(param->wizd + offs, c); + else + *(param->wizd + offs) = c; } } @@ -1969,7 +2231,8 @@ void Wiz::fillWizLine(const WizParameters *params) { int c = READ_LE_UINT32(wizh + 0x0); int w = READ_LE_UINT32(wizh + 0x4); int h = READ_LE_UINT32(wizh + 0x8); - assert(c == 0); + assert(c == 0 || c == 2); + uint8 bitDepth = (c == 2) ? 2 : 1; Common::Rect imageRect(w, h); if (params->processFlags & kWPFClipBox) { if (!imageRect.intersects(params->box)) { @@ -1992,13 +2255,13 @@ void Wiz::fillWizLine(const WizParameters *params) { lineP.imageRect = &imageRect; lineP.wizd = wizd; - lineP.width = w; + lineP.pitch = w * bitDepth; + lineP.depth = bitDepth; if (params->processFlags & kWPFParams) { assert (params->params2 == 1); // Catch untested usage Graphics::drawThickLine(x1, y1, x2, y2, params->params1, color, drawProc, &lineP); } else { - Graphics::drawLine(x1, y1, x2, y2, color, drawProc, &lineP); } } @@ -2060,7 +2323,7 @@ void Wiz::remapWizImagePal(const WizParameters *params) { } void Wiz::processWizImage(const WizParameters *params) { - byte filename[260]; + byte buffer[260]; debug(3, "processWizImage: processMode %d", params->processMode); switch (params->processMode) { @@ -2075,18 +2338,28 @@ void Wiz::processWizImage(const WizParameters *params) { break; case 3: if (params->processFlags & kWPFUseFile) { - Common::File f; + Common::SeekableReadStream *f = NULL; + memcpy(buffer, params->filename, 260); + const char *filename = (char *)buffer + _vm->convertFilePath(buffer); - memcpy(filename, params->filename, 260); - _vm->convertFilePath(filename); + if (!_vm->_saveFileMan->listSavefiles(filename).empty()) { + f = _vm->_saveFileMan->openForLoading(filename); + } else { + Common::File *nf = new Common::File(); + nf->open(filename); + if (!nf->isOpen()) + delete nf; + else + f = nf; + } - if (f.open((const char *)filename)) { - uint32 id = f.readUint32BE(); + if (f) { + uint32 id = f->readUint32BE(); if (id == MKID_BE('AWIZ') || id == MKID_BE('MULT')) { - uint32 size = f.readUint32BE(); - f.seek(0, SEEK_SET); + uint32 size = f->readUint32BE(); + f->seek(0, SEEK_SET); byte *p = _vm->_res->createResource(rtImage, params->img.resNum, size); - if (f.read(p, size) != size) { + if (f->read(p, size) != size) { _vm->_res->nukeResource(rtImage, params->img.resNum); error("i/o error when reading '%s'", filename); _vm->VAR(_vm->VAR_GAME_LOADED) = -2; @@ -2100,7 +2373,7 @@ void Wiz::processWizImage(const WizParameters *params) { _vm->VAR(_vm->VAR_GAME_LOADED) = -1; _vm->VAR(119) = -1; } - f.close(); + delete f; } else { _vm->VAR(_vm->VAR_GAME_LOADED) = -3; _vm->VAR(119) = -3; @@ -2110,7 +2383,9 @@ void Wiz::processWizImage(const WizParameters *params) { break; case 4: if (params->processFlags & kWPFUseFile) { - Common::DumpFile f; + Common::OutSaveFile *f; + memcpy(buffer, params->filename, 260); + const char *filename = (char *)buffer + _vm->convertFilePath(buffer); switch (params->fileWriteMode) { case 2: @@ -2120,22 +2395,20 @@ void Wiz::processWizImage(const WizParameters *params) { // TODO Write image to file break; case 0: - memcpy(filename, params->filename, 260); - _vm->convertFilePath(filename); - - if (!f.open((const char *)filename)) { + if (!(f = _vm->_saveFileMan->openForSaving(filename))) { debug(0, "Unable to open for write '%s'", filename); _vm->VAR(119) = -3; } else { byte *p = _vm->getResourceAddress(rtImage, params->img.resNum); uint32 size = READ_BE_UINT32(p + 4); - if (f.write(p, size) != size) { - error("i/o error when writing '%s'", params->filename); + if (f->write(p, size) != size) { + error("i/o error when writing '%s'", filename); _vm->VAR(119) = -2; } else { _vm->VAR(119) = 0; } - f.close(); + f->finalize(); + delete f; } break; default: @@ -2148,9 +2421,7 @@ void Wiz::processWizImage(const WizParameters *params) { break; // HE 99+ case 7: - // Used in PuttsFunShop/SamsFunShop/soccer2004 - // TODO: Capture polygon - _vm->_res->setModified(rtImage, params->img.resNum); + captureWizPolygon(params->img.resNum, params->sourceImage, (params->processFlags & kWPFNewState) ? params->img.state : 0, params->polygonId1, params->polygonId2, params->compType); break; case 8: { int img_w = 640; @@ -2167,6 +2438,9 @@ void Wiz::processWizImage(const WizParameters *params) { img_x = params->img.x1; img_y = params->img.y1; } + if (params->processFlags & kWPFParams) { + debug(0, "Compression %d Color Depth %d", params->params1, params->params2); + } createWizEmptyImage(params->img.resNum, img_x, img_y, img_w, img_h); } break; @@ -2304,7 +2578,7 @@ int Wiz::isWizPixelNonTransparent(int resNum, int state, int x, int y, int flags ret = isWizPixelNonTransparent(wizd, x, y, w, h, 1); break; case 2: - ret = getRawWizPixelColor(wizd, x, y, w, h, 2, _vm->VAR(_vm->VAR_WIZ_TCOLOR)) != _vm->VAR(_vm->VAR_WIZ_TCOLOR) ? 1 : 0; + ret = getRawWizPixelColor(wizd, x, y, w, h, 2, _vm->VAR(_vm->VAR_WIZ_TCOLOR)) != _vm->VAR(_vm->VAR_WIZ_TCOLOR) ? 1 : 0; break; case 4: // TODO: Unknown image type diff --git a/engines/scumm/he/wiz_he.h b/engines/scumm/he/wiz_he.h index fe63457ead..d8f984f710 100644 --- a/engines/scumm/he/wiz_he.h +++ b/engines/scumm/he/wiz_he.h @@ -142,6 +142,12 @@ enum { kWizCopy }; +enum DstSurface { + kDstScreen = 0, + kDstMemory = 1, + kDstResource = 2 +}; + class ScummEngine_v71he; class Wiz { @@ -188,27 +194,37 @@ public: void flushWizBuffer(); void getWizImageSpot(int resId, int state, int32 &x, int32 &y); - void loadWizCursor(int resId); + void loadWizCursor(int resId, int palette); void captureWizImage(int resNum, const Common::Rect& r, bool frontBuffer, int compType); + void captureImage(uint8 *src, int srcPitch, int srcw, int srch, int resNum, const Common::Rect& r, int compType); + void captureWizPolygon(int resNum, int maskNum, int maskState, int id1, int id2, int compType); void displayWizComplexImage(const WizParameters *params); void displayWizImage(WizImage *pwi); void processWizImage(const WizParameters *params); - uint8 *drawWizImage(int resNum, int state, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, int palette); + uint8 *drawWizImage(int resNum, int state, int maskNum, int maskState, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, const uint8 *palPtr); void drawWizPolygon(int resNum, int state, int id, int flags, int shadow, int dstResNum, int palette); void drawWizComplexPolygon(int resNum, int state, int po_x, int po_y, int shadow, int angle, int zoom, const Common::Rect *r, int flags, int dstResNum, int palette); void drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int flags, int shadow, int dstResNum, int palette); + void drawWizPolygonImage(uint8 *dst, const uint8 *src, const uint8 *mask, int dstpitch, int dstType, int dstw, int dsth, int wizW, int wizH, Common::Rect &bound, Common::Point *wp, uint8 bitDepth); + + static void copyMaskWizImage(uint8 *dst, const uint8 *src, const uint8 *mask, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr); + + static void copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, uint8 bitdepth); + static void copyWizImageWithMask(uint8 *dst, const uint8 *src, int dstPitch, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int maskT, int maskP); + static void copyWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, const uint8 *xmapPtr, uint8 bitdepth); + static void copyRawWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor, uint8 bitdepth); + static void copy16BitWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *xmapPtr); + static void copyRaw16BitWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, int transColor); + template<int type> static void decompress16BitWizImage(uint8 *dst, int dstPitch, int dstType, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *xmapPtr = NULL); + template<int type> static void decompressWizImage(uint8 *dst, int dstPitch, int dstType, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr, const uint8 *xmapPtr, uint8 bitdepth); + template<int type> static void decompressRawWizImage(uint8 *dst, int dstPitch, int dstType, const uint8 *src, int srcPitch, int w, int h, int transColor, const uint8 *palPtr, uint8 bitdepth); + + template<int type> static void write16BitColor(uint8 *dst, const uint8 *src, int dstType, const uint8 *xmapPtr); + template<int type> static void write8BitColor(uint8 *dst, const uint8 *src, int dstType, const uint8 *palPtr, const uint8 *xmapPtr, uint8 bitDepth); + static void writeColor(uint8 *dstPtr, int dstType, uint16 color); - static void copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch); - static void copyWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags = 0, const uint8 *palPtr = NULL, const uint8 *xmapPtr = NULL); - static void copyWizImageWithMask(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int maskT, int maskP); - void copy16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags = 0, const uint8 *palPtr = NULL, const uint8 *xmapPtr = NULL); - static void copyRawWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor); - void copyRaw16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor); - template<int type> static void decompressWizImage(uint8 *dst, int dstPitch, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr = NULL, const uint8 *xmapPtr = NULL); - template<int type> void decompress16BitWizImage(uint8 *dst, int dstPitch, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr = NULL, const uint8 *xmapPtr = NULL); - template<int type> static void decompressRawWizImage(uint8 *dst, int dstPitch, const uint8 *src, int srcPitch, int w, int h, int transColor, const uint8 *palPtr = NULL); int isWizPixelNonTransparent(const uint8 *data, int x, int y, int w, int h, uint8 bitdepth); uint16 getWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 bitDepth, uint16 color); uint16 getRawWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 bitDepth, uint16 color); diff --git a/engines/scumm/palette.cpp b/engines/scumm/palette.cpp index c356e7a06c..f59b59b40f 100644 --- a/engines/scumm/palette.cpp +++ b/engines/scumm/palette.cpp @@ -310,9 +310,6 @@ void ScummEngine::setDirtyColors(int min, int max) { _palDirtyMin = min; if (_palDirtyMax < max) _palDirtyMax = max; - - if (_hePaletteCache) - memset(_hePaletteCache, -1, 65536); } void ScummEngine::initCycl(const byte *ptr) { @@ -799,16 +796,6 @@ void ScummEngine_v8::desaturatePalette(int hueScale, int satScale, int lightScal #endif -int ScummEngine::convert16BitColor(uint16 color, uint8 r, uint8 g, uint8 b) { - // HACK: Find the closest matching color, and store in - // cache for faster access. - if (_hePaletteCache[color] == -1) { - _hePaletteCache[color] = remapPaletteColor(r, g, b, -1); - } - - return _hePaletteCache[color]; -} - int ScummEngine::remapPaletteColor(int r, int g, int b, int threshold) { byte *pal; int ar, ag, ab, i; diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp index 88802a205f..8359675032 100644 --- a/engines/scumm/resource.cpp +++ b/engines/scumm/resource.cpp @@ -920,7 +920,11 @@ bool ScummEngine::isResourceInUse(int type, int i) const { case rtCostume: return isCostumeInUse(i); case rtSound: - return _sound->isSoundInUse(i); + // Sound resource 1 is used for queued speech + if (_game.heversion >= 60 && i == 1) + return true; + else + return _sound->isSoundInUse(i); case rtCharset: return _charset->getCurID() == i; case rtImage: diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index cef13341b5..051873e147 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -1505,7 +1505,7 @@ void ScummEngine_v90he::saveOrLoad(Serializer *s) { void ScummEngine_v99he::saveOrLoad(Serializer *s) { ScummEngine_v90he::saveOrLoad(s); - s->saveLoadArrayOf(_hePalettes, (_numPalettes + 1) * 1024, sizeof(_hePalettes[0]), sleUint8); + s->saveLoadArrayOf(_hePalettes, (_numPalettes + 1) * _hePaletteSlot, sizeof(_hePalettes[0]), sleUint8); } void ScummEngine_v100he::saveOrLoad(Serializer *s) { diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h index 29184ad023..49bfe39b21 100644 --- a/engines/scumm/saveload.h +++ b/engines/scumm/saveload.h @@ -50,7 +50,7 @@ namespace Scumm { * only saves/loads those which are valid for the version of the savegame * which is being loaded/saved currently. */ -#define CURRENT_VER 77 +#define CURRENT_VER 78 /** * An auxillary macro, used to specify savegame versions. We use this instead diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index dcbf95ef4b..c6ed7b71cc 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -109,7 +109,9 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _currentScript(0xFF), // Let debug() work on init stage _messageDialog(0), _pauseDialog(0), _scummMenuDialog(0), _versionDialog(0) { - if (_game.platform == Common::kPlatformNES) { + if (_game.features & GF_16BIT_COLOR) { + _gdi = new Gdi16Bit(this); + } else if (_game.platform == Common::kPlatformNES) { _gdi = new GdiNES(this); } else if (_game.version <= 1) { _gdi = new GdiV1(this); @@ -248,6 +250,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _switchRoomEffect2 = 0; _switchRoomEffect = 0; + _bitDepth = 0; _doEffect = false; _snapScroll = false; _currentLights = 0; @@ -264,8 +267,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _palManipPalette = NULL; _palManipIntermediatePal = NULL; memset(gfxUsageBits, 0, sizeof(gfxUsageBits)); - _hePaletteCache = NULL; _hePalettes = NULL; + _hePaletteSlot = 0; _shadowPalette = NULL; _shadowPaletteSize = 0; memset(_currentPalette, 0, sizeof(_currentPalette)); @@ -521,9 +524,11 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _screenHeight = 200; } + _bitDepth = (_game.features & GF_16BIT_COLOR) ? 2 : 1; + // Allocate gfx compositing buffer (not needed for V7/V8 games). if (_game.version < 7) - _compositeBuf = (byte *)malloc(_screenWidth * _screenHeight); + _compositeBuf = (byte *)malloc(_screenWidth * _screenHeight * _bitDepth); else _compositeBuf = 0; @@ -814,7 +819,6 @@ ScummEngine_v90he::~ScummEngine_v90he() { delete _logicHE; } if (_game.heversion >= 99) { - free(_hePaletteCache); free(_hePalettes); } } @@ -1079,6 +1083,15 @@ Common::Error ScummEngine::init() { // CJK FT and DIG use usual NUT fonts, not FM-TOWNS ROM, so // there is no text surface for them. This takes that into account (_screenWidth * _textSurfaceMultiplier > 320)); + } else if (_game.features & GF_16BIT_COLOR) { +#ifdef ENABLE_RGB_COLOR + Graphics::PixelFormat format = Graphics::PixelFormat::createFormatRGB555(); + initGraphics(_screenWidth, _screenHeight, _screenWidth > 320, &format); + if (format != _system->getScreenFormat()) + return Common::kUnsupportedColorMode; +#else + error("16bit color support is required for this game"); +#endif } else { initGraphics(_screenWidth, _screenHeight, _screenWidth > 320); } @@ -1182,7 +1195,7 @@ void ScummEngine::setupScumm() { int maxHeapThreshold = -1; if (_game.features & GF_16BIT_COLOR) { - // 16Bit color games require double the memory, due to increased resource sizes. + // 16bit color games require double the memory, due to increased resource sizes. maxHeapThreshold = 12 * 1024 * 1024; } else if (_game.features & GF_NEW_COSTUMES) { // Since the new costumes are very big, we increase the heap limit, to avoid having @@ -1204,7 +1217,7 @@ void ScummEngine::setupScumm() { } free(_compositeBuf); - _compositeBuf = (byte *)malloc(_screenWidth * _textSurfaceMultiplier * _screenHeight * _textSurfaceMultiplier); + _compositeBuf = (byte *)malloc(_screenWidth * _textSurfaceMultiplier * _screenHeight * _textSurfaceMultiplier * _bitDepth); } #ifdef ENABLE_SCUMM_7_8 @@ -1546,11 +1559,9 @@ void ScummEngine_v99he::resetScumm() { ScummEngine_v90he::resetScumm(); - _hePaletteCache = (int16 *)malloc(65536); - memset(_hePaletteCache, -1, 65536); - - _hePalettes = (uint8 *)malloc((_numPalettes + 1) * 1024); - memset(_hePalettes, 0, (_numPalettes + 1) * 1024); + _hePaletteSlot = (_game.features & GF_16BIT_COLOR) ? 1280 : 1024; + _hePalettes = (uint8 *)malloc((_numPalettes + 1) * _hePaletteSlot); + memset(_hePalettes, 0, (_numPalettes + 1) * _hePaletteSlot); // Array 129 is set to base name len = strlen(_filenamePattern.pattern); diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index e3be053810..badbb8ba9d 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -953,6 +953,7 @@ public: int _screenTop; Common::RenderMode _renderMode; + uint8 _bitDepth; protected: ColorCycle _colorCycle[16]; // Palette cycles @@ -972,7 +973,10 @@ protected: byte animate, animateIndex; int8 state; } _cursor; - byte _grabbedCursor[8192]; + + // HACK Double the array size to handle 16-bit images. + // this should be dynamically allocated based on game depth instead. + byte _grabbedCursor[16384]; byte _currentCursor; byte _newEffect, _switchRoomEffect2, _switchRoomEffect; @@ -1038,7 +1042,8 @@ protected: virtual void palManipulateInit(int resID, int start, int end, int time); void palManipulate(); public: - int convert16BitColor(uint16 color, uint8 r, uint8 g, uint8 b); + uint8 *getHEPaletteSlot(uint16 palSlot); + uint16 get16BitColor(uint8 r, uint8 g, uint8 b); int remapPaletteColor(int r, int g, int b, int threshold); // Used by Actor::remapActorPalette protected: void moveMemInPalRes(int start, int end, byte direction); @@ -1114,7 +1119,7 @@ public: // HE specific byte _HEV7ActorPalette[256]; uint8 *_hePalettes; - int16 *_hePaletteCache; + uint16 _hePaletteSlot; protected: int _shadowPaletteSize; diff --git a/graphics/conversion.cpp b/graphics/conversion.cpp new file mode 100644 index 0000000000..aa544ac718 --- /dev/null +++ b/graphics/conversion.cpp @@ -0,0 +1,139 @@ +/* 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. + * + * $URL$ + * $Id$ + */ + +#include "graphics/conversion.h" + +namespace Graphics { + +// TODO: YUV to RGB conversion function + +// Function to blit a rect from one color format to another +bool crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch, + int w, int h, Graphics::PixelFormat dstFmt, Graphics::PixelFormat srcFmt) { + // Error out if conversion is impossible + if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1) + || (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel) + || (srcFmt.bytesPerPixel > dstFmt.bytesPerPixel)) + return false; + + // Don't perform unnecessary conversion + if (srcFmt == dstFmt) + return true; + + // Faster, but larger, to provide optimized handling for each case. + int srcDelta, dstDelta; + srcDelta = (srcpitch - w * srcFmt.bytesPerPixel); + dstDelta = (dstpitch - w * dstFmt.bytesPerPixel); + + // TODO: optimized cases for dstDelta of 0 + uint8 r, g, b, a; + if (dstFmt.bytesPerPixel == 2) { + uint16 color; + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++, src += 2, dst += 2) { + color = *(uint16 *) src; + srcFmt.colorToARGB(color, a, r, g, b); + color = dstFmt.ARGBToColor(a, r, g, b); + *(uint16 *) dst = color; + } + src += srcDelta; + dst += dstDelta; + } + } else if (dstFmt.bytesPerPixel == 3) { + uint32 color; + uint8 *col = (uint8 *) &color; +#ifdef SCUMM_BIG_ENDIAN + col++; +#endif + if (srcFmt.bytesPerPixel == 2) { + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++, src += 2, dst += 3) { + color = *(uint16 *) src; + srcFmt.colorToARGB(color, a, r, g, b); + color = dstFmt.ARGBToColor(a, r, g, b); + memcpy(dst, col, 3); + } + src += srcDelta; + dst += dstDelta; + } + } else { + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++, src += 3, dst += 3) { + uint8 r, g, b, a; + memcpy(col, src, 3); + srcFmt.colorToARGB(color, a, r, g, b); + color = dstFmt.ARGBToColor(a, r, g, b); + memcpy(dst, col, 3); + } + src += srcDelta; + dst += dstDelta; + } + } + } else if (dstFmt.bytesPerPixel == 4) { + uint32 color; + if (srcFmt.bytesPerPixel == 2) { + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++, src += 2, dst += 4) { + color = *(uint16 *) src; + srcFmt.colorToARGB(color, a, r, g, b); + color = dstFmt.ARGBToColor(a, r, g, b); + *(uint32 *) dst = color; + } + src += srcDelta; + dst += dstDelta; + } + } else if (srcFmt.bytesPerPixel == 3) { + uint8 *col = (uint8 *)&color; +#ifdef SCUMM_BIG_ENDIAN + col++; +#endif + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++, src += 2, dst += 4) { + memcpy(col, src, 3); + srcFmt.colorToARGB(color, a, r, g, b); + color = dstFmt.ARGBToColor(a, r, g, b); + *(uint32 *) dst = color; + } + src += srcDelta; + dst += dstDelta; + } + } else { + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++, src += 4, dst += 4) { + color = *(uint32 *) src; + srcFmt.colorToARGB(color, a, r, g, b); + color = dstFmt.ARGBToColor(a, r, g, b); + *(uint32 *) dst = color; + } + src += srcDelta; + dst += dstDelta; + } + } + } else { + return false; + } + return true; +} + +} // end of namespace Graphics diff --git a/graphics/conversion.h b/graphics/conversion.h new file mode 100644 index 0000000000..3226c38817 --- /dev/null +++ b/graphics/conversion.h @@ -0,0 +1,73 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GRAPHICS_CONVERSION_H +#define GRAPHICS_CONVERSION_H + +#include "common/util.h" +#include "graphics/pixelformat.h" + +namespace Graphics { + +/** Converting a color from YUV to RGB colorspace. */ +inline static void YUV2RGB(byte y, byte u, byte v, byte &r, byte &g, byte &b) { + r = CLIP<int>(y + ((1357 * (v - 128)) >> 10), 0, 255); + g = CLIP<int>(y - (( 691 * (v - 128)) >> 10) - ((333 * (u - 128)) >> 10), 0, 255); + b = CLIP<int>(y + ((1715 * (u - 128)) >> 10), 0, 255); +} + +/** Converting a color from RGB to YUV colorspace. */ +inline static void RGB2YUV(byte r, byte g, byte b, byte &y, byte &u, byte &v) { + y = CLIP<int>( ((r * 306) >> 10) + ((g * 601) >> 10) + ((b * 117) >> 10) , 0, 255); + u = CLIP<int>(-((r * 172) >> 10) - ((g * 340) >> 10) + ((b * 512) >> 10) + 128, 0, 255); + v = CLIP<int>( ((r * 512) >> 10) - ((g * 429) >> 10) - ((b * 83) >> 10) + 128, 0, 255); +} + +// TODO: generic YUV to RGB blit + +/** + * Convert a rectangle from the one format to another, and blits it. + * + * @param dstbuf the buffer which will recieve the converted graphics data + * @param srcbuf the buffer containing the original graphics data + * @param dstpitch width in bytes of one full line of the dest buffer + * @param srcpitch width in bytes of one full line of the source buffer + * @param w the width of the graphics data + * @param h the height of the graphics data + * @param dstFmt the desired pixel format + * @param srcFmt the original pixel format + * @return true if conversion completes successfully, + * false if there is an error. + * + * @note This implementation currently requires the destination's + * format have at least as high a bitdepth as the source's. + * + */ +bool crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch, + int w, int h, Graphics::PixelFormat dstFmt, Graphics::PixelFormat srcFmt); + +} // end of namespace Graphics + +#endif // GRAPHICS_CONVERSION_H diff --git a/graphics/cursorman.cpp b/graphics/cursorman.cpp index 2e71b548bc..b77aac37cf 100644 --- a/graphics/cursorman.cpp +++ b/graphics/cursorman.cpp @@ -57,14 +57,14 @@ bool CursorManager::showMouse(bool visible) { return g_system->showMouse(visible); } -void CursorManager::pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor, int targetScale) { - Cursor *cur = new Cursor(buf, w, h, hotspotX, hotspotY, keycolor, targetScale); +void CursorManager::pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale, const Graphics::PixelFormat *format) { + Cursor *cur = new Cursor(buf, w, h, hotspotX, hotspotY, keycolor, targetScale, format); cur->_visible = isVisible(); _cursorStack.push(cur); if (buf) { - g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, targetScale); + g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, targetScale, format); } } @@ -77,7 +77,7 @@ void CursorManager::popCursor() { if (!_cursorStack.empty()) { cur = _cursorStack.top(); - g_system->setMouseCursor(cur->_data, cur->_width, cur->_height, cur->_hotspotX, cur->_hotspotY, cur->_keycolor, cur->_targetScale); + g_system->setMouseCursor(cur->_data, cur->_width, cur->_height, cur->_hotspotX, cur->_hotspotY, cur->_keycolor, cur->_targetScale, &cur->_format); } g_system->showMouse(isVisible()); @@ -100,15 +100,24 @@ void CursorManager::popAllCursors() { g_system->showMouse(isVisible()); } +void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale, const Graphics::PixelFormat *format) { -void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor, int targetScale) { if (_cursorStack.empty()) { - pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, targetScale); + pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, targetScale, format); return; } Cursor *cur = _cursorStack.top(); + +#ifdef ENABLE_RGB_COLOR + uint size; + if (!format) + size = w * h; + else + size = w * h * format->bytesPerPixel; +#else uint size = w * h; +#endif if (cur->_size < size) { delete[] cur->_data; @@ -125,8 +134,14 @@ void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, cur->_hotspotY = hotspotY; cur->_keycolor = keycolor; cur->_targetScale = targetScale; +#ifdef ENABLE_RGB_COLOR + if (format) + cur->_format = *format; + else + cur->_format = Graphics::PixelFormat::createFormatCLUT8(); +#endif - g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, targetScale); + g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, targetScale, format); } bool CursorManager::supportsCursorPalettes() { diff --git a/graphics/cursorman.h b/graphics/cursorman.h index f019e37b04..ba11c9ef96 100644 --- a/graphics/cursorman.h +++ b/graphics/cursorman.h @@ -28,6 +28,10 @@ #include "common/scummsys.h" #include "common/stack.h" #include "common/singleton.h" +#include "graphics/pixelformat.h" +#ifdef ENABLE_RGB_COLOR +#include "common/system.h" +#endif namespace Graphics { @@ -65,12 +69,13 @@ public: * @param hotspotY the hotspot Y coordinate * @param keycolor the index for the transparent color * @param targetScale the scale for which the cursor is designed + * @param format the pixel format which the cursor graphic uses * * @note It is ok for the buffer to be a NULL pointer. It is sometimes * useful to push a "dummy" cursor and modify it later. The * cursor will be added to the stack, but not to the backend. */ - void pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255, int targetScale = 1); + void pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 0xFFFFFFFF, int targetScale = 1, const Graphics::PixelFormat *format = NULL); /** * Pop a cursor from the stack, and restore the previous one to the @@ -90,8 +95,9 @@ public: * @param hotspotY the hotspot Y coordinate * @param keycolor the index for the transparent color * @param targetScale the scale for which the cursor is designed + * @param format the pixel format which the cursor graphic uses */ - void replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255, int targetScale = 1); + void replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 0xFFFFFFFF, int targetScale = 1, const Graphics::PixelFormat *format = NULL); /** * Pop all of the cursors and cursor palettes from their respective stacks. @@ -166,13 +172,24 @@ private: uint _height; int _hotspotX; int _hotspotY; - byte _keycolor; + uint32 _keycolor; + Graphics::PixelFormat _format; byte _targetScale; uint _size; - - Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255, int targetScale = 1) { + Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 0xFFFFFFFF, int targetScale = 1, const Graphics::PixelFormat *format = NULL) { +#ifdef ENABLE_RGB_COLOR + if (!format) + _format = Graphics::PixelFormat::createFormatCLUT8(); + else + _format = *format; + _size = w * h * _format.bytesPerPixel; + _keycolor &= ((1 << (_format.bytesPerPixel << 3)) - 1); +#else + _format = Graphics::PixelFormat::createFormatCLUT8(); _size = w * h; + _keycolor &= 0xFF; +#endif _data = new byte[_size]; if (data && _data) memcpy(_data, data, _size); @@ -180,7 +197,6 @@ private: _height = h; _hotspotX = hotspotX; _hotspotY = hotspotY; - _keycolor = keycolor; _targetScale = targetScale; } @@ -216,7 +232,6 @@ private: delete[] _data; } }; - Common::Stack<Cursor *> _cursorStack; Common::Stack<Palette *> _cursorPaletteStack; }; diff --git a/graphics/dither.cpp b/graphics/dither.cpp index 7a92441571..e671de265e 100644 --- a/graphics/dither.cpp +++ b/graphics/dither.cpp @@ -23,6 +23,7 @@ */ #include "common/endian.h" +#include "graphics/conversion.h" #include "graphics/dither.h" namespace Graphics { diff --git a/graphics/dither.h b/graphics/dither.h index e6d606cdd4..18f98ce4e0 100644 --- a/graphics/dither.h +++ b/graphics/dither.h @@ -43,19 +43,6 @@ public: kPaletteYUV //!< Palette in YUV colorspace }; - /** Converting a color from YUV to RGB colorspace. */ - inline static void YUV2RGB(byte y, byte u, byte v, byte &r, byte &g, byte &b) { - r = CLIP<int>(y + ((1357 * (v - 128)) >> 10), 0, 255); - g = CLIP<int>(y - (( 691 * (v - 128)) >> 10) - ((333 * (u - 128)) >> 10), 0, 255); - b = CLIP<int>(y + ((1715 * (u - 128)) >> 10), 0, 255); - } - /** Converting a color from RGB to YUV colorspace. */ - inline static void RGB2YUV(byte r, byte g, byte b, byte &y, byte &u, byte &v) { - y = CLIP<int>( ((r * 306) >> 10) + ((g * 601) >> 10) + ((b * 117) >> 10) , 0, 255); - u = CLIP<int>(-((r * 172) >> 10) - ((g * 340) >> 10) + ((b * 512) >> 10) + 128, 0, 255); - v = CLIP<int>( ((r * 512) >> 10) - ((g * 429) >> 10) - ((b * 83) >> 10) + 128, 0, 255); - } - /** Create a lookup table of a given depth and palette format. * * @param depth How many bits of each color component to consider. diff --git a/graphics/jpeg.cpp b/graphics/jpeg.cpp new file mode 100644 index 0000000000..ce0568816c --- /dev/null +++ b/graphics/jpeg.cpp @@ -0,0 +1,622 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "graphics/jpeg.h" + +#include "common/endian.h" +#include "common/util.h" + +namespace Graphics { + +// Order used to traverse the quantization tables +uint8 JPEG::_zigZagOrder[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +JPEG::JPEG() : + _str(NULL), _w(0), _h(0), _numComp(0), _components(NULL), _numScanComp(0), + _scanComp(NULL), _currentComp(NULL) { + + // Initialize the quantization tables + for (int i = 0; i < JPEG_MAX_QUANT_TABLES; i++) + _quant[i] = NULL; + + // Initialize the Huffman tables + for (int i = 0; i < 2 * JPEG_MAX_HUFF_TABLES; i++) { + _huff[i].count = 0; + _huff[i].values = NULL; + _huff[i].sizes = NULL; + _huff[i].codes = NULL; + } +} + +JPEG::~JPEG() { + reset(); +} + +void JPEG::reset() { + // Reset member variables + _str = NULL; + _w = _h = 0; + + // Free the components + for (int c = 0; c < _numComp; c++) + _components[c].surface.free(); + delete[] _components; _components = NULL; + _numComp = 0; + + // Free the scan components + delete[] _scanComp; _scanComp = NULL; + _numScanComp = 0; + _currentComp = NULL; + + // Free the quantization tables + for (int i = 0; i < JPEG_MAX_QUANT_TABLES; i++) { + delete[] _quant[i]; + _quant[i] = NULL; + } + + // Free the Huffman tables + for (int i = 0; i < 2 * JPEG_MAX_HUFF_TABLES; i++) { + _huff[i].count = 0; + delete[] _huff[i].values; _huff[i].values = NULL; + delete[] _huff[i].sizes; _huff[i].sizes = NULL; + delete[] _huff[i].codes; _huff[i].codes = NULL; + } +} + +bool JPEG::read(Common::SeekableReadStream *str) { + // Reset member variables and tables from previous reads + reset(); + + // Save the input stream + _str = str; + + bool ok = true; + bool done = false; + while (!_str->eos() && ok && !done) { + // Read the marker + uint16 marker = _str->readByte(); + if (marker != 0xFF) { + error("JPEG: Invalid marker[0]: 0x%02X", marker); + ok = false; + break; + } + + while (marker == 0xFF) + marker = _str->readByte(); + + // Process the marker data + switch (marker) { + case 0xC0: // Start Of Frame + ok = readSOF0(); + break; + case 0xC4: // Define Huffman Tables + ok = readDHT(); + break; + case 0xD8: // Start Of Image + break; + case 0xD9: // End Of Image + done = true; + break; + case 0xDA: // Start Of Scan + ok = readSOS(); + break; + case 0xDB: // Define Quantization Tables + ok = readDQT(); + break; + case 0xE0: // JFIF/JFXX segment + ok = readJFIF(); + break; + case 0xFE: // Comment + _str->seek(_str->readUint16BE() - 2, SEEK_CUR); + break; + default: { // Unknown marker + uint16 size = _str->readUint16BE(); + warning("JPEG: Unknown marker %02X, skipping %d bytes", marker, size - 2); + _str->seek(size - 2, SEEK_CUR); + } + } + } + return ok; +} + +bool JPEG::readJFIF() { + /* uint16 length = */ _str->readUint16BE(); + uint32 tag = _str->readUint32BE(); + if (tag != MKID_BE('JFIF')) + return false; + _str->readByte(); // NULL + /* byte majorVersion = */ _str->readByte(); + /* byte minorVersion = */ _str->readByte(); + /* byte densityUnits = */ _str->readByte(); + /* uint16 xDensity = */ _str->readUint16BE(); + /* uint16 yDensity = */ _str->readUint16BE(); + byte thumbW = _str->readByte(); + byte thumbH = _str->readByte(); + _str->seek(thumbW * thumbH * 3, SEEK_CUR); // Ignore thumbnail + return true; +} + +// Marker 0xC0 (Start Of Frame, Baseline DCT) +bool JPEG::readSOF0() { + debug(5, "JPEG: readSOF0"); + uint16 size = _str->readUint16BE(); + + // Read the sample precision + uint8 precision = _str->readByte(); + if (precision != 8) { + warning("JPEG: Just 8 bit precision supported at the moment"); + return false; + } + + // Image size + _h = _str->readUint16BE(); + _w = _str->readUint16BE(); + + // Number of components + _numComp = _str->readByte(); + if (size != 8 + 3 * _numComp) { + warning("JPEG: Invalid number of components"); + return false; + } + + // Allocate the new components + delete[] _components; + _components = new Component[_numComp]; + + // Read the components details + for (int c = 0; c < _numComp; c++) { + _components[c].id = _str->readByte(); + _components[c].factorH = _str->readByte(); + _components[c].factorV = _components[c].factorH & 0xF; + _components[c].factorH >>= 4; + _components[c].quantTableSelector = _str->readByte(); + } + + return true; +} + +// Marker 0xC4 (Define Huffman Tables) +bool JPEG::readDHT() { + debug(5, "JPEG: readDHT"); + uint16 size = _str->readUint16BE() - 2; + uint32 pos = _str->pos(); + + while ((uint32)_str->pos() < (size + pos)) { + // Read the table type and id + uint8 tableId = _str->readByte(); + uint8 tableType = tableId >> 4; // type 0: DC, 1: AC + tableId &= 0xF; + uint8 tableNum = (tableId << 1) + tableType; + + // Free the Huffman table + delete[] _huff[tableNum].values; _huff[tableNum].values = NULL; + delete[] _huff[tableNum].sizes; _huff[tableNum].sizes = NULL; + delete[] _huff[tableNum].codes; _huff[tableNum].codes = NULL; + + // Read the number of values for each length + uint8 numValues[16]; + _huff[tableNum].count = 0; + for (int len = 0; len < 16; len++) { + numValues[len] = _str->readByte(); + _huff[tableNum].count += numValues[len]; + } + + // Allocate memory for the current table + _huff[tableNum].values = new uint8[_huff[tableNum].count]; + _huff[tableNum].sizes = new uint8[_huff[tableNum].count]; + _huff[tableNum].codes = new uint16[_huff[tableNum].count]; + + // Read the table contents + int cur = 0; + for (int len = 0; len < 16; len++) { + for (int i = 0; i < numValues[len]; i++) { + _huff[tableNum].values[cur] = _str->readByte(); + _huff[tableNum].sizes[cur] = len + 1; + cur++; + } + } + + // Fill the table of Huffman codes + cur = 0; + uint16 curCode = 0; + uint8 curCodeSize = _huff[tableNum].sizes[0]; + while (cur < _huff[tableNum].count) { + // Increase the code size to fit the request + while (_huff[tableNum].sizes[cur] != curCodeSize) { + curCode <<= 1; + curCodeSize++; + } + + // Assign the current code + _huff[tableNum].codes[cur] = curCode; + curCode++; + cur++; + } + } + + return true; +} + +// Marker 0xDA (Start Of Scan) +bool JPEG::readSOS() { + debug(5, "JPEG: readSOS"); + uint16 size = _str->readUint16BE(); + + // Number of scan components + _numScanComp = _str->readByte(); + if (size != 6 + 2 * _numScanComp) { + warning("JPEG: Invalid number of components"); + return false; + } + + // Allocate the new scan components + delete[] _scanComp; + _scanComp = new Component *[_numScanComp]; + + // Reset the maximum sampling factors + _maxFactorV = 0; + _maxFactorH = 0; + + // Component-specification parameters + for (int c = 0; c < _numScanComp; c++) { + // Read the desired component id + uint8 id = _str->readByte(); + + // Search the component with the specified id + bool found = false; + for (int i = 0; !found && i < _numComp; i++) { + if (_components[i].id == id) { + // We found the desired component + found = true; + + // Assign the found component to the c'th scan component + _scanComp[c] = &_components[i]; + } + } + + if (!found) { + warning("JPEG: Invalid component"); + return false; + } + + // Read the entropy table selectors + _scanComp[c]->DCentropyTableSelector = _str->readByte(); + _scanComp[c]->ACentropyTableSelector = _scanComp[c]->DCentropyTableSelector & 0xF; + _scanComp[c]->DCentropyTableSelector >>= 4; + + // Calculate the maximum sampling factors + if (_scanComp[c]->factorV > _maxFactorV) + _maxFactorV = _scanComp[c]->factorV; + + if (_scanComp[c]->factorH > _maxFactorH) + _maxFactorH = _scanComp[c]->factorH; + + // Initialize the DC predictor + _scanComp[c]->DCpredictor = 0; + } + + // Initialize the scan surfaces + for (int c = 0; c < _numScanComp; c++) + _scanComp[c]->surface.create(_w, _h, 1); + + // Start of spectral selection + if (_str->readByte() != 0) { + warning("JPEG: Progressive scanning not supported"); + return false; + } + + // End of spectral selection + if (_str->readByte() != 63) { + warning("JPEG: Progressive scanning not supported"); + return false; + } + + // Successive approximation parameters + if (_str->readByte() != 0) { + warning("JPEG: Progressive scanning not supported"); + return false; + } + + // Entropy coded sequence starts, initialize Huffman decoder + _bitsNumber = 0; + + // Read all the scan MCUs + uint16 xMCU = _w / (_maxFactorH * 8); + uint16 yMCU = _h / (_maxFactorV * 8); + bool ok = true; + for (int y = 0; ok && (y < yMCU); y++) + for (int x = 0; ok && (x < xMCU); x++) + ok = readMCU(x, y); + + return ok; +} + +// Marker 0xDB (Define Quantization Tables) +bool JPEG::readDQT() { + debug(5, "JPEG: readDQT"); + uint16 size = _str->readUint16BE() - 2; + uint32 pos = _str->pos(); + + while ((uint32)_str->pos() < (pos + size)) { + // Read the table precision and id + uint8 tableId = _str->readByte(); + bool highPrecision = (tableId & 0xF0) != 0; + + // Validate the table id + tableId &= 0xF; + if (tableId > JPEG_MAX_QUANT_TABLES) { + warning("JPEG: Invalid number of components"); + return false; + } + + // Create the new table if necessary + if (!_quant[tableId]) + _quant[tableId] = new uint16[64]; + + // Read the table (stored in Zig-Zag order) + for (int i = 0; i < 64; i++) + _quant[tableId][i] = highPrecision ? _str->readUint16BE() : _str->readByte(); + } + + return true; +} + +bool JPEG::readMCU(uint16 xMCU, uint16 yMCU) { + bool ok = true; + for (int c = 0; ok && (c < _numComp); c++) { + // Set the current component + _currentComp = _scanComp[c]; + + // Read the data units of the current component + for (int y = 0; ok && (y < _scanComp[c]->factorV); y++) + for (int x = 0; ok && (x < _scanComp[c]->factorH); x++) + ok = readDataUnit(xMCU * _scanComp[c]->factorH + x, yMCU * _scanComp[c]->factorV + y); + } + + return ok; +} + +float JPEG::idct(int x, int y, int weight, int fx, int fy) { + float vx = cos((2 * x + 1) * fx * M_PI / 16); + float vy = cos((2 * y + 1) * fy * M_PI / 16); + float ret = (float)weight * vx * vy; + + if (fx == 0) + ret /= sqrt(2.0f); + + if (fy == 0) + ret /= sqrt(2.0f); + + return ret; +} + +bool JPEG::readDataUnit(uint16 x, uint16 y) { + // Prepare an empty data array + int16 readData[64]; + for (int i = 1; i < 64; i++) + readData[i] = 0; + + // Read the DC component + readData[0] = _currentComp->DCpredictor + readDC(); + _currentComp->DCpredictor = readData[0]; + + // Read the AC components (stored in Zig-Zag) + readAC(readData); + + // Calculate the DCT coefficients from the input sequence + int16 DCT[64]; + for (int i = 0; i < 64; i++) { + // Dequantize + int16 val = readData[i]; + int16 quant = _quant[_currentComp->quantTableSelector][i]; + val *= quant; + + // Store the normalized coefficients, undoing the Zig-Zag + DCT[_zigZagOrder[i]] = val; + } + + // Shortcut the IDCT for DC component + float result[64]; + for (int i = 0; i < 64; i++) + result[i] = DCT[0] / 2; + + // Apply the IDCT (PAG31) + for (int i = 1; i < 64; i++) { + if (DCT[i]) + for (int _y = 0; _y < 8; _y++) + for (int _x = 0; _x < 8; _x++) + result[_y * 8 + _x] += idct(_x, _y, DCT[i], i % 8, i / 8); + } + + // Level shift to make the values unsigned + // Divide by 4 is final part of IDCT + for (int i = 0; i < 64; i++) { + result[i] = result[i] / 4 + 128; + + if (result[i] < 0) + result[i] = 0; + + if (result[i] > 255) + result[i] = 255; + } + + // Paint the component surface + uint8 scalingV = _maxFactorV / _currentComp->factorV; + uint8 scalingH = _maxFactorH / _currentComp->factorH; + + // Convert coordinates from MCU blocks to pixels + x <<= 3; + y <<= 3; + for (int j = 0; j < 8; j++) { + for (int sV = 0; sV < scalingV; sV++) { + // Get the beginning of the block line + byte *ptr = (byte *)_currentComp->surface.getBasePtr(x * scalingH, (y + j) * scalingV + sV); + + for (int i = 0; i < 8; i++) { + for (uint8 sH = 0; sH < scalingH; sH++) { + *ptr = (byte)(result[j * 8 + i]); + ptr++; + } + } + } + } + + return true; +} + +int16 JPEG::readDC() { + // DC is type 0 + uint8 tableNum = _currentComp->DCentropyTableSelector << 1; + + // Get the number of bits to read + uint8 numBits = readHuff(tableNum); + + // Read the requested bits + return readSignedBits(numBits); +} + +void JPEG::readAC(int16 *out) { + // AC is type 1 + uint8 tableNum = (_currentComp->ACentropyTableSelector << 1) + 1; + + // Start reading AC element 1 + uint8 cur = 1; + while (cur < 64) { + uint8 s = readHuff(tableNum); + uint8 r = s >> 4; + s &= 0xF; + + if (s == 0) { + if (r == 15) { + // Skip 16 values + cur += 16; + } else { + // EOB: end of block + cur = 64; + } + } else { + // Skip r values + cur += r; + + // Read the next value + out[cur] = readSignedBits(s); + cur++; + } + } +} + +int16 JPEG::readSignedBits(uint8 numBits) { + uint16 ret = 0; + if (numBits > 16) error("requested %d bits", numBits); //XXX + + // MSB=0 for negatives, 1 for positives + for (int i = 0; i < numBits; i++) + ret = (ret << 1) + readBit(); + + // Extend sign bits (PAG109) + if (!(ret >> (numBits - 1))) + { + uint16 tmp = ((uint16)-1 << numBits) + 1; + ret = ret + tmp; + } + return ret; +} + +// TODO: optimize? +uint8 JPEG::readHuff(uint8 table) { + bool foundCode = false; + uint8 val = 0; + + uint8 cur = 0; + uint8 codeSize = 1; + uint16 code = readBit(); + while (!foundCode) { + // Prepare a code of the current size + while (codeSize < _huff[table].sizes[cur]) { + code = (code << 1) + readBit(); + codeSize++; + } + + // Compare the codes of the current size + while (!foundCode && (codeSize == _huff[table].sizes[cur])) { + if (code == _huff[table].codes[cur]) { + // Found the code + val = _huff[table].values[cur]; + foundCode = true; + } else { + // Continue reading + cur++; + } + } + } + + return val; +} + +uint8 JPEG::readBit() { + // Read a whole byte if necessary + if (_bitsNumber == 0) { + _bitsData = _str->readByte(); + _bitsNumber = 8; + + // Detect markers + if (_bitsData == 0xFF) { + uint8 byte2 = _str->readByte(); + + // A stuffed 0 validates the previous byte + if (byte2 != 0) { + if (byte2 == 0xDC) { + // DNL marker: Define Number of Lines + // TODO: terminate scan + printf("DNL marker detected: terminate scan\n"); + } else { + printf("Error: marker 0x%02X read in entropy data\n", byte2); + } + } + } + } + _bitsNumber--; + + return (_bitsData & (1 << _bitsNumber)) ? 1 : 0; +} + +Surface *JPEG::getComponent(uint c) { + for (int i = 0; i < _numComp; i++) + if (_components[i].id == c) // We found the desired component + return &_components[i].surface; + + return NULL; +} + +} // End of Graphics namespace diff --git a/graphics/jpeg.h b/graphics/jpeg.h new file mode 100644 index 0000000000..d9097055e1 --- /dev/null +++ b/graphics/jpeg.h @@ -0,0 +1,120 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GRAPHICS_JPEG_H +#define GRAPHICS_JPEG_H + +#define M_PI 3.141592f + +#include "common/stream.h" +#include "graphics/surface.h" + +namespace Graphics { + +#define JPEG_MAX_QUANT_TABLES 4 +#define JPEG_MAX_HUFF_TABLES 2 + +class JPEG { +public: + JPEG(); + ~JPEG(); + + bool read(Common::SeekableReadStream *str); + Surface *getComponent(uint c); + +private: + void reset(); + + Common::SeekableReadStream *_str; + uint16 _w, _h; + + // Image components + uint8 _numComp; + struct Component { + // Global values + uint8 id; + uint8 factorH; + uint8 factorV; + uint8 quantTableSelector; + + // Scan specific values + uint8 DCentropyTableSelector; + uint8 ACentropyTableSelector; + int16 DCpredictor; + + // Result image for this component + Surface surface; + } *_components; + + // Scan components + uint8 _numScanComp; + Component **_scanComp; + Component *_currentComp; + + // Maximum sampling factors, used to calculate the interleaving of the MCU + uint8 _maxFactorV; + uint8 _maxFactorH; + + // Zig-Zag order + static uint8 _zigZagOrder[64]; + + // Quantization tables + uint16 *_quant[JPEG_MAX_QUANT_TABLES]; + + // Huffman tables + struct HuffmanTable { + uint8 count; + uint8 *values; + uint8 *sizes; + uint16 *codes; + } _huff[2 * JPEG_MAX_HUFF_TABLES]; + + // Marker read functions + bool readJFIF(); + bool readSOF0(); + bool readDHT(); + bool readSOS(); + bool readDQT(); + + // Helper functions + bool readMCU(uint16 xMCU, uint16 yMCU); + bool readDataUnit(uint16 x, uint16 y); + int16 readDC(); + void readAC(int16 *out); + int16 readSignedBits(uint8 numBits); + + // Huffman decoding + uint8 readHuff(uint8 table); + uint8 readBit(); + uint8 _bitsData; + uint8 _bitsNumber; + + // Discrete Cosine Transformation + float idct(int x, int y, int weight, int fx, int fy); +}; + +} // End of Graphics namespace + +#endif // GRAPHICS_JPEG_H diff --git a/graphics/module.mk b/graphics/module.mk index bf93822bee..8d7f2031c0 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -1,6 +1,7 @@ MODULE := graphics MODULE_OBJS := \ + conversion.o \ cursorman.o \ dither.o \ font.o \ @@ -11,6 +12,7 @@ MODULE_OBJS := \ fonts/scummfont.o \ iff.o \ imagedec.o \ + jpeg.o \ primitives.o \ scaler.o \ scaler/thumbnail_intern.o \ diff --git a/graphics/pixelformat.h b/graphics/pixelformat.h index f59650e5cc..a1883291b9 100644 --- a/graphics/pixelformat.h +++ b/graphics/pixelformat.h @@ -27,6 +27,7 @@ #define GRAPHICS_PIXELFORMAT_H #include "common/scummsys.h" +#include "common/list.h" namespace Graphics { @@ -50,6 +51,77 @@ struct PixelFormat { byte rLoss, gLoss, bLoss, aLoss; /**< Precision loss of each color component. */ byte rShift, gShift, bShift, aShift; /**< Binary left shift of each color component in the pixel value. */ + inline PixelFormat() { + bytesPerPixel = + rLoss = gLoss = bLoss = aLoss = + rShift = gShift = bShift = aShift = 0; + } + + inline PixelFormat(int BytesPerPixel, + int RLoss, int GLoss, int BLoss, int ALoss, + int RShift, int GShift, int BShift, int AShift) { + bytesPerPixel = BytesPerPixel; + rLoss = RLoss, gLoss = GLoss, bLoss = BLoss, aLoss = ALoss; + rShift = RShift, gShift = GShift, bShift = BShift, aShift = AShift; + } + + // "Factory" methods for convenience + static inline PixelFormat createFormatCLUT8() { + return PixelFormat(1, 8, 8, 8, 8, 0, 0, 0, 0); + } + // 2 Bytes-per-pixel modes + static inline PixelFormat createFormatRGB555() { + return PixelFormat(2, 3, 3, 3, 8, 10, 5, 0, 0); + } + static inline PixelFormat createFormatBGR555() { + return PixelFormat(2, 3, 3, 3, 8, 0, 5, 10, 0); + } + static inline PixelFormat createFormatXRGB1555() { + // Special case, alpha bit is always high in this mode. + return PixelFormat(2, 3, 3, 3, 7, 10, 5, 0, 15); + } + static inline PixelFormat createFormatXBGR1555() { + // Special case, alpha bit is always high in this mode. + return PixelFormat(2, 3, 3, 3, 7, 0, 5, 10, 15); + } + static inline PixelFormat createFormatRGB565() { + return PixelFormat(2, 3, 2, 3, 8, 11, 5, 0, 0); + } + static inline PixelFormat createFormatBGR565() { + return PixelFormat(2, 3, 2, 3, 8, 0, 5, 11, 0); + } + static inline PixelFormat createFormatRGBA4444() { + return PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0); + } + static inline PixelFormat createFormatARGB4444() { + return PixelFormat(2, 4, 4, 4, 4, 8, 4, 0, 12); + } + static inline PixelFormat createFormatABGR4444() { + return PixelFormat(2, 4, 4, 4, 4, 0, 4, 8, 12); + } + static inline PixelFormat createFormatBGRA4444() { + return PixelFormat(2, 4, 4, 4, 4, 4, 8, 12, 0); + } + // 3 to 4 byte per pixel modes + static inline PixelFormat createFormatRGB888() { + return PixelFormat(3, 0, 0, 0, 8, 16, 8, 0, 0); + } + static inline PixelFormat createFormatBGR888() { + return PixelFormat(3, 0, 0, 0, 8, 0, 8, 16, 0); + } + static inline PixelFormat createFormatRGBA8888() { + return PixelFormat(4, 0, 0, 0, 0, 24, 16, 8, 0); + } + static inline PixelFormat createFormatARGB8888() { + return PixelFormat(4, 0, 0, 0, 0, 16 ,8, 0, 24); + } + static inline PixelFormat createFormatABGR8888() { + return PixelFormat(4, 0, 0, 0, 0, 0, 8, 16, 24); + } + static inline PixelFormat createFormatBGRA8888() { + return PixelFormat(4, 0, 0, 0, 0, 8, 16, 24, 0); + } + inline bool operator==(const PixelFormat &fmt) const { // TODO: If aLoss==8, then the value of aShift is irrelevant, and should be ignored. return 0 == memcmp(this, &fmt, sizeof(PixelFormat)); @@ -129,6 +201,18 @@ struct PixelFormat { } }; +inline PixelFormat findCompatibleFormat(Common::List<PixelFormat> backend, Common::List<PixelFormat> frontend) { +#ifdef ENABLE_RGB_COLOR + for (Common::List<PixelFormat>::iterator i = backend.begin(); i != backend.end(); ++i) { + for (Common::List<PixelFormat>::iterator j = frontend.begin(); j != frontend.end(); ++j) { + if (*i == *j) + return *i; + } + } +#endif + return PixelFormat::createFormatCLUT8(); +} + } // end of namespace Graphics #endif diff --git a/graphics/scaler.cpp b/graphics/scaler.cpp index 11767848ed..082258bfc0 100644 --- a/graphics/scaler.cpp +++ b/graphics/scaler.cpp @@ -30,18 +30,17 @@ int gBitFormat = 565; -static const Graphics::PixelFormat gPixelFormat555 = { +static const Graphics::PixelFormat gPixelFormat555( 2, 3, 3, 3, 8, 10, 5, 0, 0 - }; + ); -static const Graphics::PixelFormat gPixelFormat565 = { +static const Graphics::PixelFormat gPixelFormat565( 2, 3, 2, 3, 8, 11, 5, 0, 0 - }; - + ); #ifndef DISABLE_HQ_SCALERS diff --git a/graphics/scaler/thumbnail_intern.cpp b/graphics/scaler/thumbnail_intern.cpp index fabe07b031..a542fe2268 100644 --- a/graphics/scaler/thumbnail_intern.cpp +++ b/graphics/scaler/thumbnail_intern.cpp @@ -23,6 +23,7 @@ * */ +#include "common/endian.h" #include "common/scummsys.h" #include "common/system.h" @@ -98,7 +99,8 @@ static bool grabScreen565(Graphics::Surface *surf) { if (!screen) return false; - assert(screen->bytesPerPixel == 1 && screen->pixels != 0); + assert(screen->bytesPerPixel == 1 || screen->bytesPerPixel == 2); + assert(screen->pixels != 0); byte palette[256 * 4]; g_system->grabPalette(&palette[0], 0, 256); @@ -107,11 +109,17 @@ static bool grabScreen565(Graphics::Surface *surf) { for (uint y = 0; y < screen->h; ++y) { for (uint x = 0; x < screen->w; ++x) { - byte r, g, b; - r = palette[((uint8*)screen->pixels)[y * screen->pitch + x] * 4]; - g = palette[((uint8*)screen->pixels)[y * screen->pitch + x] * 4 + 1]; - b = palette[((uint8*)screen->pixels)[y * screen->pitch + x] * 4 + 2]; - + byte r, g, b; + if (screen->bytesPerPixel == 2) { + uint16 col = READ_UINT16(screen->getBasePtr(x, y)); + r = ((col >> 10) & 0x1F) << 3; + g = ((col >> 5) & 0x1F) << 3; + b = ((col >> 0) & 0x1F) << 3; + } else { + r = palette[((uint8*)screen->pixels)[y * screen->pitch + x] * 4]; + g = palette[((uint8*)screen->pixels)[y * screen->pitch + x] * 4 + 1]; + b = palette[((uint8*)screen->pixels)[y * screen->pitch + x] * 4 + 2]; + } ((uint16*)surf->pixels)[y * surf->w + x] = Graphics::RGBToColor<Graphics::ColorMasks<565> >(r, g, b); } } diff --git a/graphics/video/coktelvideo/coktelvideo.cpp b/graphics/video/coktelvideo/coktelvideo.cpp index 8603e125a6..9e0391ecc5 100644 --- a/graphics/video/coktelvideo/coktelvideo.cpp +++ b/graphics/video/coktelvideo/coktelvideo.cpp @@ -26,6 +26,7 @@ #include "common/endian.h" #include "common/system.h" +#include "graphics/conversion.h" #include "graphics/dither.h" #include "graphics/video/coktelvideo/coktelvideo.h" #include "graphics/video/coktelvideo/indeo3.h" @@ -1624,7 +1625,7 @@ void Vmd::blit16(byte *dest, byte *src, int16 srcPitch, int16 width, int16 heigh byte b = ((data & 0x001F) >> 0); byte dY, dU, dV; - Graphics::PaletteLUT::RGB2YUV(r << 3, g << 3, b << 3, dY, dU, dV); + Graphics::RGB2YUV(r << 3, g << 3, b << 3, dY, dU, dV); byte p = dither->dither(dY, dU, dV, j); @@ -1658,7 +1659,7 @@ void Vmd::blit24(byte *dest, byte *src, int16 srcPitch, int16 width, int16 heigh byte b = s[0]; byte dY, dU, dV; - Graphics::PaletteLUT::RGB2YUV(r, g, b, dY, dU, dV); + Graphics::RGB2YUV(r, g, b, dY, dU, dV); byte p = dither->dither(dY, dU, dV, j); diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp index 166b11afe3..a25c111da3 100644 --- a/gui/ThemeEngine.cpp +++ b/gui/ThemeEngine.cpp @@ -1169,6 +1169,12 @@ bool ThemeEngine::createCursor(const Common::String &filename, int hotspotX, int if (!cursor) return false; +#ifdef ENABLE_RGB_COLOR + _cursorFormat.bytesPerPixel = 1; + _cursorFormat.rLoss = _cursorFormat.gLoss = _cursorFormat.bLoss = _cursorFormat.aLoss = 8; + _cursorFormat.rShift = _cursorFormat.gShift = _cursorFormat.bShift = _cursorFormat.aShift = 0; +#endif + // Set up the cursor parameters _cursorHotspotX = hotspotX; _cursorHotspotY = hotspotY; diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h index fd2d9c65fd..f9226a81d8 100644 --- a/gui/ThemeEngine.h +++ b/gui/ThemeEngine.h @@ -574,6 +574,9 @@ protected: ImagesMap _bitmaps; Graphics::PixelFormat _overlayFormat; +#ifdef ENABLE_RGB_COLOR + Graphics::PixelFormat _cursorFormat; +#endif /** List of all the dirty screens that must be blitted to the overlay. */ Common::List<Common::Rect> _dirtyScreen; diff --git a/gui/themes/scummmodern/checkbox_empty.bmp b/gui/themes/scummmodern/checkbox_empty.bmp Binary files differdeleted file mode 100644 index 89ebdcbf41..0000000000 --- a/gui/themes/scummmodern/checkbox_empty.bmp +++ /dev/null diff --git a/gui/themes/scummmodern/search.bmp b/gui/themes/scummmodern/search.bmp Binary files differdeleted file mode 100644 index fa963f8f16..0000000000 --- a/gui/themes/scummmodern/search.bmp +++ /dev/null |