aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/midi/timidity.cpp2
-rw-r--r--engines/hopkins/computer.cpp14
-rw-r--r--engines/hopkins/detection.cpp4
-rw-r--r--engines/hopkins/globals.cpp2
-rw-r--r--engines/hopkins/globals.h1
-rw-r--r--engines/hopkins/hopkins.h1
-rw-r--r--engines/hopkins/saveload.cpp13
-rw-r--r--engines/hopkins/saveload.h3
-rw-r--r--engines/tony/detection.cpp29
-rw-r--r--engines/tony/game.cpp3
-rw-r--r--engines/tony/gfxcore.h4
-rw-r--r--engines/tony/mpal/mpal.cpp16
-rw-r--r--engines/tony/sound.cpp6
-rw-r--r--engines/tony/window.cpp8
-rw-r--r--engines/tsage/ringworld2/ringworld2_logic.cpp25
-rw-r--r--engines/tsage/ringworld2/ringworld2_logic.h19
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes0.cpp13
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes0.h4
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes1.cpp428
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes1.h18
-rw-r--r--engines/wintermute/base/base_sprite.h9
-rw-r--r--engines/wintermute/base/base_sub_frame.cpp32
-rw-r--r--engines/wintermute/base/file/base_disk_file.cpp6
-rw-r--r--engines/wintermute/base/gfx/base_surface.cpp4
-rw-r--r--engines/wintermute/base/gfx/base_surface.h7
-rw-r--r--engines/wintermute/base/gfx/osystem/base_render_osystem.cpp44
-rw-r--r--engines/wintermute/base/gfx/osystem/base_render_osystem.h5
-rw-r--r--engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp87
-rw-r--r--engines/wintermute/base/gfx/osystem/base_surface_osystem.h13
-rw-r--r--engines/wintermute/base/gfx/osystem/render_ticket.cpp59
-rw-r--r--engines/wintermute/base/gfx/osystem/render_ticket.h20
-rw-r--r--engines/wintermute/detection_tables.h22
-rw-r--r--engines/wintermute/graphics/transform_struct.cpp93
-rw-r--r--engines/wintermute/graphics/transform_struct.h83
-rw-r--r--engines/wintermute/graphics/transform_tools.cpp74
-rw-r--r--engines/wintermute/graphics/transform_tools.h53
-rw-r--r--engines/wintermute/graphics/transparent_surface.cpp181
-rw-r--r--engines/wintermute/graphics/transparent_surface.h15
-rw-r--r--engines/wintermute/math/floatpoint.h52
-rw-r--r--engines/wintermute/math/rect32.h27
-rw-r--r--engines/wintermute/module.mk2
-rw-r--r--graphics/scaler.h6
-rw-r--r--graphics/scaler/thumbnail_intern.cpp175
-rw-r--r--graphics/surface.cpp12
44 files changed, 1411 insertions, 283 deletions
diff --git a/backends/midi/timidity.cpp b/backends/midi/timidity.cpp
index 5cefe668cd..d2c60bec9d 100644
--- a/backends/midi/timidity.cpp
+++ b/backends/midi/timidity.cpp
@@ -148,7 +148,7 @@ MidiDriver_TIMIDITY::MidiDriver_TIMIDITY() {
int MidiDriver_TIMIDITY::open() {
char *res;
- char timidity_host[MAXHOSTNAMELEN];
+ char timidity_host[NI_MAXHOST];
int timidity_port, data_port, i;
/* count ourselves open */
diff --git a/engines/hopkins/computer.cpp b/engines/hopkins/computer.cpp
index 82e0dd0a06..c09d748b97 100644
--- a/engines/hopkins/computer.cpp
+++ b/engines/hopkins/computer.cpp
@@ -578,7 +578,11 @@ void ComputerManager::displayGamesSubMenu() {
* Load Highscore from file
*/
void ComputerManager::loadHiscore() {
- const byte *ptr = _vm->_globals->_highScoreData;
+ byte *ptr = _vm->_globals->allocMemory(100);
+ memset(ptr, 0, 100);
+
+ if (_vm->_saveLoad->saveExists(_vm->getTargetName() + "-highscore.dat"))
+ _vm->_saveLoad->load(_vm->getTargetName() + "-highscore.dat", ptr);
for (int scoreIndex = 0; scoreIndex < 6; ++scoreIndex) {
_score[scoreIndex]._name = " ";
@@ -600,6 +604,7 @@ void ComputerManager::loadHiscore() {
}
_lowestHiScore = atol(_score[5]._score.c_str());
+ _vm->_globals->freeMemory(ptr);
}
/**
@@ -985,8 +990,8 @@ void ComputerManager::saveScore() {
}
}
- byte *ptr = _vm->_globals->_highScoreData;
- memset(ptr, 0, 99);
+ byte *ptr = _vm->_globals->allocMemory(100);
+ memset(ptr, 0, 100);
for (int scorePlaceIdx = 0; scorePlaceIdx <= 5; scorePlaceIdx++) {
int curBufPtr = 16 * scorePlaceIdx;
for (int namePos = 0; namePos < 6; namePos++) {
@@ -1006,6 +1011,9 @@ void ComputerManager::saveScore() {
};
ptr[curBufPtr + 15] = 0;
}
+
+ _vm->_saveLoad->saveFile(_vm->getTargetName() + "-highscore.dat", ptr, 100);
+ _vm->_globals->freeMemory(ptr);
}
/**
diff --git a/engines/hopkins/detection.cpp b/engines/hopkins/detection.cpp
index 9d16b0ab51..c617a5aacf 100644
--- a/engines/hopkins/detection.cpp
+++ b/engines/hopkins/detection.cpp
@@ -56,6 +56,10 @@ bool HopkinsEngine::getIsDemo() const {
return _gameDescription->desc.flags & ADGF_DEMO;
}
+const Common::String &HopkinsEngine::getTargetName() const {
+ return _targetName;
+}
+
} // End of namespace Hopkins
static const PlainGameDescriptor hopkinsGames[] = {
diff --git a/engines/hopkins/globals.cpp b/engines/hopkins/globals.cpp
index 97d6c4046c..a9a0a81f08 100644
--- a/engines/hopkins/globals.cpp
+++ b/engines/hopkins/globals.cpp
@@ -70,8 +70,6 @@ Globals::Globals(HopkinsEngine *vm) {
for (int i = 0; i < 36; ++i)
_inventory[i] = 0;
- Common::fill(&_highScoreData[0], &_highScoreData[100], 0);
-
// Initialize fields
_language = LANG_EN;
diff --git a/engines/hopkins/globals.h b/engines/hopkins/globals.h
index a76323bb50..94512c3d26 100644
--- a/engines/hopkins/globals.h
+++ b/engines/hopkins/globals.h
@@ -206,7 +206,6 @@ public:
Common::String _zoneFilename;
Common::String _textFilename;
byte *_levelSpriteBuf;
- byte _highScoreData[100];
EventMode _eventMode;
diff --git a/engines/hopkins/hopkins.h b/engines/hopkins/hopkins.h
index 398e41a4d2..d8c30e5004 100644
--- a/engines/hopkins/hopkins.h
+++ b/engines/hopkins/hopkins.h
@@ -164,6 +164,7 @@ public:
Common::Platform getPlatform() const;
uint16 getVersion() const;
bool getIsDemo() const;
+ const Common::String &getTargetName() const;
int getRandomNumber(int maxNumber);
Common::String generateSaveName(int slotNumber);
diff --git a/engines/hopkins/saveload.cpp b/engines/hopkins/saveload.cpp
index 14b166294d..c514df6943 100644
--- a/engines/hopkins/saveload.cpp
+++ b/engines/hopkins/saveload.cpp
@@ -55,6 +55,13 @@ bool SaveLoadManager::save(const Common::String &file, const void *buf, size_t n
return false;
}
+bool SaveLoadManager::saveExists(const Common::String &file) {
+ Common::InSaveFile *savefile = g_system->getSavefileManager()->openForLoading(file);
+ bool result = savefile != NULL;
+ delete savefile;
+ return result;
+}
+
// Save File
bool SaveLoadManager::saveFile(const Common::String &file, const void *buf, size_t n) {
return save(file, buf, n);
@@ -251,9 +258,9 @@ void SaveLoadManager::createThumbnail(Graphics::Surface *s) {
}
void SaveLoadManager::syncSavegameData(Common::Serializer &s, int version) {
- if (version >= 3)
- // Sync embedded Breakout game high score data
- s.syncBytes(&_vm->_globals->_highScoreData[0], 100);
+ // The brief version 3 had the highscores embedded. They're in a separate file now, so skip
+ if (version == 3 && s.isLoading())
+ s.skip(100);
s.syncBytes(&_vm->_globals->_saveData->_data[0], 2050);
syncCharacterLocation(s, _vm->_globals->_saveData->_cloneHopkins);
diff --git a/engines/hopkins/saveload.h b/engines/hopkins/saveload.h
index e4ee3aaeda..5b77c11f12 100644
--- a/engines/hopkins/saveload.h
+++ b/engines/hopkins/saveload.h
@@ -35,7 +35,7 @@ namespace Hopkins {
class HopkinsEngine;
-#define HOPKINS_SAVEGAME_VERSION 3
+#define HOPKINS_SAVEGAME_VERSION 4
struct hopkinsSavegameHeader {
uint8 _version;
@@ -56,6 +56,7 @@ private:
public:
SaveLoadManager(HopkinsEngine *vm);
+ bool saveExists(const Common::String &file);
bool save(const Common::String &file, const void *buf, size_t n);
bool saveFile(const Common::String &file, const void *buf, size_t n);
void load(const Common::String &file, byte *buf);
diff --git a/engines/tony/detection.cpp b/engines/tony/detection.cpp
index 1094950e2c..2a443c4097 100644
--- a/engines/tony/detection.cpp
+++ b/engines/tony/detection.cpp
@@ -154,26 +154,16 @@ void TonyMetaEngine::removeSaveState(const char *target, int slot) const {
SaveStateDescriptor TonyMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::String saveName;
byte difficulty;
- byte thumbData[160 * 120 * 2];
-
- if (Tony::RMOptionScreen::loadThumbnailFromSaveState(slot, thumbData, saveName, difficulty)) {
- // Convert the 565 thumbnail data to the needed overlay format
- Common::MemoryReadStream thumbStream(thumbData, 160 * 120 * 2);
- Graphics::PixelFormat destFormat = g_system->getOverlayFormat();
- Graphics::Surface *to = new Graphics::Surface();
- to->create(160, 120, destFormat);
-
- OverlayColor *pixels = (OverlayColor *)to->pixels;
- for (int y = 0; y < to->h; ++y) {
- for (int x = 0; x < to->w; ++x) {
- uint8 r, g, b;
- Graphics::colorToRGB<Graphics::ColorMasks<555> >(thumbStream.readUint16LE(), r, g, b);
-
- // converting to current OSystem Color
- *pixels++ = destFormat.RGBToColor(r, g, b);
- }
- }
+ Graphics::Surface *to = new Graphics::Surface();
+ to->create(160, 120, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
+
+ if (Tony::RMOptionScreen::loadThumbnailFromSaveState(slot, (byte *)to->pixels, saveName, difficulty)) {
+#ifdef SCUMM_BIG_ENDIAN
+ uint16 *pixels = (uint16 *)to->pixels;
+ for (int i = 0; i < to->w * to->h; ++i)
+ pixels[i] = READ_LE_UINT16(pixels + i);
+#endif
// Create the return descriptor
SaveStateDescriptor desc(slot, saveName);
desc.setDeletableFlag(true);
@@ -183,6 +173,7 @@ SaveStateDescriptor TonyMetaEngine::querySaveMetaInfos(const char *target, int s
return desc;
}
+ delete to;
return SaveStateDescriptor();
}
diff --git a/engines/tony/game.cpp b/engines/tony/game.cpp
index 501a588ff5..ca7c07ad8c 100644
--- a/engines/tony/game.cpp
+++ b/engines/tony/game.cpp
@@ -508,7 +508,8 @@ void RMOptionScreen::refreshThumbnails() {
_curThumb[i] = NULL;
_curThumbName[i].clear();
_curThumbDiff[i] = 11;
- }
+ } else
+ _curThumb[i]->prepareImage();
}
}
diff --git a/engines/tony/gfxcore.h b/engines/tony/gfxcore.h
index 2548968e81..9e8f5225c0 100644
--- a/engines/tony/gfxcore.h
+++ b/engines/tony/gfxcore.h
@@ -208,8 +208,10 @@ public:
* 16-bit color source
*/
class RMGfxSourceBuffer16 : public RMGfxSourceBuffer {
-protected:
+public:
virtual void prepareImage();
+
+protected:
bool _bTrasp0;
public:
diff --git a/engines/tony/mpal/mpal.cpp b/engines/tony/mpal/mpal.cpp
index fff8676a89..5e6d44f0a3 100644
--- a/engines/tony/mpal/mpal.cpp
+++ b/engines/tony/mpal/mpal.cpp
@@ -2035,7 +2035,13 @@ int mpalGetSaveStateSize() {
void mpalSaveState(byte *buf) {
lockVar();
WRITE_LE_UINT32(buf, GLOBALS._nVars);
- memcpy(buf + 4, (byte *)GLOBALS._lpmvVars, GLOBALS._nVars * sizeof(MpalVar));
+ buf += 4;
+ for (uint i = 0; i < GLOBALS._nVars; ++i) {
+ LpMpalVar var = &GLOBALS._lpmvVars[i];
+ WRITE_LE_UINT32(buf, var->_dwVal);
+ memcpy(buf + 4, var->_lpszVarName, sizeof(var->_lpszVarName));
+ buf += (4 + sizeof(var->_lpszVarName));
+ }
unlockVar();
}
@@ -2050,10 +2056,16 @@ int mpalLoadState(byte *buf) {
globalFree(GLOBALS._hVars);
GLOBALS._nVars = READ_LE_UINT32(buf);
+ buf += 4;
GLOBALS._hVars = globalAllocate(GMEM_ZEROINIT | GMEM_MOVEABLE, GLOBALS._nVars * sizeof(MpalVar));
lockVar();
- memcpy((byte *)GLOBALS._lpmvVars, buf + 4, GLOBALS._nVars * sizeof(MpalVar));
+ for (uint i = 0; i < GLOBALS._nVars; ++i) {
+ LpMpalVar var = &GLOBALS._lpmvVars[i];
+ var->_dwVal = READ_LE_UINT32(buf);
+ memcpy(var->_lpszVarName, buf + 4, sizeof(var->_lpszVarName));
+ buf += (4 + sizeof(var->_lpszVarName));
+ }
unlockVar();
return GLOBALS._nVars * sizeof(MpalVar) + 4;
diff --git a/engines/tony/sound.cpp b/engines/tony/sound.cpp
index 90ae241db0..547f31906e 100644
--- a/engines/tony/sound.cpp
+++ b/engines/tony/sound.cpp
@@ -500,7 +500,13 @@ bool FPStream::loadFile(const Common::String &fileName, uint32 codec, int bufSiz
break;
case FPCODEC_ADPCM:
+#ifdef __amigaos4__
+ // HACK: AmigaOS 4 has weird performance problems with reading in the audio thread,
+ // so we read the whole stream into memory.
+ _rewindableStream = Audio::makeADPCMStream(_file.readStream(_size), DisposeAfterUse::YES, 0, Audio::kADPCMDVI, 44100, 2);
+#else
_rewindableStream = Audio::makeADPCMStream(&_file, DisposeAfterUse::NO, 0, Audio::kADPCMDVI, 44100, 2);
+#endif
break;
default:
diff --git a/engines/tony/window.cpp b/engines/tony/window.cpp
index 61497a8066..a732862854 100644
--- a/engines/tony/window.cpp
+++ b/engines/tony/window.cpp
@@ -330,6 +330,14 @@ void RMSnapshot::grabScreenshot(byte *lpBuf, int dezoom, uint16 *lpDestBuf) {
src += RM_BBX * dezoom;
}
}
+
+#ifdef SCUMM_BIG_ENDIAN
+ if (lpDestBuf != NULL) {
+ for (int i = 0; i < dimx * dimy; i++) {
+ lpDestBuf[i] = SWAP_BYTES_16(lpDestBuf[i]);
+ }
+ }
+#endif
}
} // End of namespace Tony
diff --git a/engines/tsage/ringworld2/ringworld2_logic.cpp b/engines/tsage/ringworld2/ringworld2_logic.cpp
index ac6ba523f6..f872d8edd2 100644
--- a/engines/tsage/ringworld2/ringworld2_logic.cpp
+++ b/engines/tsage/ringworld2/ringworld2_logic.cpp
@@ -108,7 +108,8 @@ Scene *Ringworld2Game::createScene(int sceneNumber) {
/* Scene group #1 */
//
case 1000:
- error("Missing scene %d from group 1", sceneNumber);
+ // Cutscene: Ship moving
+ return new Scene1000();
case 1010:
// Cutscene - trip in space
return new Scene1010();
@@ -2454,6 +2455,28 @@ void ScannerDialog::proc12(int visage, int stripFrameNum, int frameNum, int posX
}
}
+/*--------------------------------------------------------------------------*/
+
+DataManager::DataManager(): EventHandler() {
+
+}
+
+void DataManager::synchronize(Serializer &s) {
+ EventHandler::synchronize(s);
+
+}
+
+void DataManager::load(int v) {
+ warning("TODO");
+}
+
+void DataManager::remove() {
+ if (_endHandler)
+ _endHandler->signal();
+
+ _endHandler = NULL;
+}
+
} // End of namespace Ringworld2
} // End of namespace TsAGE
diff --git a/engines/tsage/ringworld2/ringworld2_logic.h b/engines/tsage/ringworld2/ringworld2_logic.h
index 2cf48f3cf3..9ea2494124 100644
--- a/engines/tsage/ringworld2/ringworld2_logic.h
+++ b/engines/tsage/ringworld2/ringworld2_logic.h
@@ -514,6 +514,25 @@ public:
void proc12(int visage, int stripFrameNum, int frameNum, int posX, int posY);
};
+class DataManager: public EventHandler {
+public:
+ int _field3C;
+ int _field56;
+
+ int _palStart;
+ int _palLength;
+ byte _palData[256 * 3];
+ EventHandler *_endHandler;
+public:
+ DataManager();
+
+ virtual Common::String getClassName() { return "DataManager"; }
+ virtual void synchronize(Serializer &s);
+ virtual void remove();
+
+ void load(int v);
+};
+
} // End of namespace Ringworld2
} // End of namespace TsAGE
diff --git a/engines/tsage/ringworld2/ringworld2_scenes0.cpp b/engines/tsage/ringworld2/ringworld2_scenes0.cpp
index 4018921791..b977ea1516 100644
--- a/engines/tsage/ringworld2/ringworld2_scenes0.cpp
+++ b/engines/tsage/ringworld2/ringworld2_scenes0.cpp
@@ -2312,19 +2312,6 @@ void Scene205::Action1::textLoop() {
/*--------------------------------------------------------------------------*/
-Scene205::Object::Object(): SceneObject() {
- _x100 = _y100 = 0;
-}
-
-void Scene205::Object::synchronize(Serializer &s) {
- EventHandler::synchronize(s);
-
- s.syncAsSint32LE(_x100);
- s.syncAsSint32LE(_y100);
-}
-
-/*--------------------------------------------------------------------------*/
-
Scene205::Scene205(): SceneExt() {
_yp = 0;
_textIndex = 1;
diff --git a/engines/tsage/ringworld2/ringworld2_scenes0.h b/engines/tsage/ringworld2/ringworld2_scenes0.h
index 80dab89b32..bad946fbd6 100644
--- a/engines/tsage/ringworld2/ringworld2_scenes0.h
+++ b/engines/tsage/ringworld2/ringworld2_scenes0.h
@@ -277,9 +277,7 @@ class Scene205: public SceneExt {
public:
int _x100, _y100;
public:
- Object();
-
- virtual void synchronize(Serializer &s);
+ // TODO: Check if this derives from DataManager? and flesh out
};
private:
void setup();
diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.cpp b/engines/tsage/ringworld2/ringworld2_scenes1.cpp
index ba62a119a8..ffc491725e 100644
--- a/engines/tsage/ringworld2/ringworld2_scenes1.cpp
+++ b/engines/tsage/ringworld2/ringworld2_scenes1.cpp
@@ -30,9 +30,437 @@ namespace TsAGE {
namespace Ringworld2 {
/*--------------------------------------------------------------------------
+ * Scene 1000 - Cutscene: Ship moving
+ *
+ *--------------------------------------------------------------------------*/
+
+Scene1000::Scene1000(): SceneExt() {
+ R2_GLOBALS._sceneManager._hasPalette = false;
+ R2_GLOBALS._uiElements._active = false;
+ _gameTextSpeaker._displayMode = 9;
+ _fieldD2E = 0;
+}
+
+void Scene1000::postInit(SceneObjectList *OwnerList) {
+ SceneExt::postInit();
+
+ _stripManager.addSpeaker(&_gameTextSpeaker);
+ R2_GLOBALS._player.postInit();
+ R2_GLOBALS._player.hide();
+ R2_GLOBALS._player.disableControl();
+
+ switch (R2_GLOBALS._sceneManager._previousScene) {
+ case 300:
+ _sceneMode = R2_GLOBALS.getFlag(57) ? 40 : 0;
+ break;
+ case 1010:
+ _sceneMode = 30;
+ break;
+ case 1100:
+ _sceneMode = 10;
+ break;
+ case 1530:
+ _sceneMode = 20;
+ break;
+ case 2500:
+ _sceneMode = 100;
+ break;
+ case 2800:
+ _sceneMode = 2800;
+ break;
+ case 3100:
+ if (R2_GLOBALS._player._oldCharacterScene[R2_QUINN] == 1000)
+ _sceneMode = 90;
+ else
+ _sceneMode = 80;
+ break;
+ case 3500:
+ _sceneMode = 50;
+ break;
+ case 3700:
+ _sceneMode = 60;
+ break;
+ default:
+ _sceneMode = 999;
+ break;
+ }
+
+ setAction(&_sequenceManager1, this, 1, &R2_GLOBALS._player, NULL);
+}
+
+void Scene1000::remove() {
+ R2_GLOBALS._scenePalette.loadPalette(0);
+ R2_GLOBALS._scenePalette.setEntry(255, 0xff, 0xff, 0xff);
+ SceneExt::remove();
+}
+
+void Scene1000::signal() {
+ ScenePalette scenePalette1, scenePalette2;
+ uint32 black = 0;
+
+ switch (R2_GLOBALS._sceneManager._previousScene) {
+ case 0:
+ // TODO: Sort out values
+ R2_GLOBALS._gfxColors.foreground = 191;
+ R2_GLOBALS._gfxColors.background = 144;
+ R2_GLOBALS._fontColors.background = 224;
+ R2_GLOBALS._fontColors.foreground = 119;
+
+ _dataManager._field56 = 2;
+ _dataManager._field3C = 2;
+ _dataManager.load(5);
+ R2_GLOBALS._scenePalette.loadPalette(_dataManager._palData, 0, 256);
+ R2_GLOBALS._sceneManager._hasPalette = false;
+
+ _dataManager.dispatch();
+ _fieldD2E = 1;
+
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, 0);
+ for (int percent = 0; percent < 100; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+
+ R2_GLOBALS._sound1.play(67);
+ break;
+
+ case 1:
+ R2_GLOBALS._sound1.fadeOut2(NULL);
+
+ // TODO: Sort out values
+ R2_GLOBALS._gfxColors.foreground = 191;
+ R2_GLOBALS._gfxColors.background = 144;
+ R2_GLOBALS._fontColors.background = 224;
+ R2_GLOBALS._fontColors.foreground = 119;
+
+ R2_GLOBALS._scenePalette.loadPalette(0);
+ loadScene(9999);
+
+ R2_GLOBALS._player.setup(1140, 1, 1);
+ R2_GLOBALS._player.setPosition(Common::Point(160, 100));
+ R2_GLOBALS._player.show();
+
+ _field412 = 0;
+ _stripManager.start(29, this);
+ break;
+
+ case 2:
+ if (R2_GLOBALS._speechSubtitles & SPEECH_TEXT) {
+ setAction(&_sequenceManager1, this, &R2_GLOBALS._player, NULL);
+ } else {
+ if (++_field412 < 3)
+ _sceneMode = 2;
+
+ setAction(&_sequenceManager1, this, &R2_GLOBALS._player, NULL);
+ }
+ break;
+
+ case 3:
+ // TODO: Sort out values
+ R2_GLOBALS._gfxColors.foreground = 191;
+ R2_GLOBALS._gfxColors.background = 144;
+ R2_GLOBALS._fontColors.background = 224;
+ R2_GLOBALS._fontColors.foreground = 119;
+
+ for (int percent = 100; percent >= 0; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+
+ _dataManager._field3C = 2;
+ _dataManager._field56 = 2;
+ _dataManager.load(7);
+ R2_GLOBALS._scenePalette.loadPalette(_dataManager._palData, 0, 256);
+ R2_GLOBALS._sceneManager._hasPalette = false;
+
+ _dataManager.dispatch();
+
+ _fieldD2E = 1;
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0);
+ for (int percent = 0; percent < 100; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+
+ R2_GLOBALS._sound2.play(81);
+ R2_GLOBALS._sound1.play(80);
+ break;
+
+ case 4:
+ // TODO: Sort out values
+ R2_GLOBALS._gfxColors.foreground = 191;
+ R2_GLOBALS._gfxColors.background = 144;
+ R2_GLOBALS._fontColors.background = 224;
+ R2_GLOBALS._fontColors.foreground = 119;
+
+ R2_GLOBALS._sound2.fadeOut2(NULL);
+ R2_GLOBALS._sound1.fadeOut2(NULL);
+ R2_GLOBALS._sceneManager.changeScene(1100);
+ break;
+
+ case 10:
+ _dataManager._field3C = 2;
+ _dataManager._field56 = 2;
+ _dataManager.load(6);
+
+ R2_GLOBALS._scenePalette.loadPalette(_dataManager._palData, 0, 256);
+ R2_GLOBALS._sceneManager._hasPalette = false;
+ _dataManager.dispatch();
+
+ _fieldD2E = 1;
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0);
+ for (int percent = 0; percent < 100; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+
+ R2_GLOBALS._sound1.play(55);
+ break;
+
+ case 11:
+ R2_GLOBALS._scenePalette.loadPalette(NULL);
+ R2_GLOBALS._sceneManager.changeScene(300);
+ break;
+
+ case 20:
+ _dataManager._field3C = 2;
+ _dataManager._field56 = 2;
+ _dataManager.load(8);
+
+ R2_GLOBALS._scenePalette.loadPalette(_dataManager._palData, 0, 256);
+ R2_GLOBALS._sceneManager._hasPalette = false;
+ _dataManager.dispatch();
+
+ _fieldD2E = 1;
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0);
+ for (int percent = 0; percent < 100; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+ break;
+
+ case 21:
+ R2_GLOBALS._scenePalette.loadPalette(NULL);
+ R2_GLOBALS._sceneManager.changeScene(1530);
+ break;
+
+ case 30:
+ _dataManager._field3C = 2;
+ _dataManager._field56 = 2;
+ _dataManager.load(17);
+
+ R2_GLOBALS._scenePalette.loadPalette(_dataManager._palData, 0, 256);
+ R2_GLOBALS._sceneManager._hasPalette = false;
+ _dataManager.dispatch();
+
+ _fieldD2E = 1;
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0);
+ for (int percent = 0; percent < 100; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+
+ R2_GLOBALS._sound2.play(91);
+ break;
+
+ case 31:
+ R2_GLOBALS._sound2.fadeOut2(NULL);
+ R2_GLOBALS._sound1.fadeOut2(NULL);
+ R2_GLOBALS._scenePalette.loadPalette(0);
+ R2_GLOBALS.setFlag(51);
+ R2_GLOBALS._sceneManager.changeScene(300);
+ break;
+
+ case 40:
+ _dataManager._field3C = 2;
+ _dataManager._field56 = 2;
+ _dataManager.load(18);
+
+ R2_GLOBALS._scenePalette.loadPalette(_dataManager._palData, 0, 256);
+ R2_GLOBALS._sceneManager._hasPalette = false;
+ _dataManager.dispatch();
+
+ _fieldD2E = 1;
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0);
+ for (int percent = 0; percent < 100; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+
+ R2_GLOBALS._sound2.play(90);
+ break;
+
+ case 41:
+ R2_GLOBALS._scenePalette.loadPalette(0);
+ R2_GLOBALS._sceneManager.changeScene(1010);
+ break;
+
+ case 50:
+ R2_GLOBALS._sound2.play(306);
+ for (int percent = 100; percent >= 0; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+
+ _dataManager._field3C = 2;
+ _dataManager._field56 = 2;
+ _dataManager.load(13);
+
+ R2_GLOBALS._scenePalette.loadPalette(_dataManager._palData, 0, 256);
+ R2_GLOBALS._sceneManager._hasPalette = false;
+ _dataManager.dispatch();
+
+ _fieldD2E = 1;
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0);
+ for (int percent = 0; percent < 100; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+ break;
+
+ case 51:
+ R2_GLOBALS._sound2.stop();
+ R2_GLOBALS._sound2.play(307);
+ R2_GLOBALS._sound1.play(308);
+
+ for (int percent = 100; percent >= 0; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+
+ _dataManager._field3C = 2;
+ _dataManager._field56 = 2;
+ _dataManager.load(14);
+
+ R2_GLOBALS._scenePalette.loadPalette(_dataManager._palData, 0, 256);
+ R2_GLOBALS._sceneManager._hasPalette = false;
+ _dataManager.dispatch();
+
+ _fieldD2E = 1;
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0);
+ for (int percent = 0; percent < 100; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+ break;
+
+ case 52:
+ R2_GLOBALS._sound2.fadeOut2(NULL);
+ R2_GLOBALS._sound1.fadeOut2(NULL);
+ R2_GLOBALS._scenePalette.loadPalette(0);
+ R2_GLOBALS._sceneManager.changeScene(3350);
+ break;
+
+ case 60:
+ R2_GLOBALS._sound1.play(333);
+
+ for (int percent = 100; percent >= 0; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+
+ _dataManager._field3C = 2;
+ _dataManager._field56 = 2;
+ _dataManager.load(12);
+
+ R2_GLOBALS._scenePalette.loadPalette(_dataManager._palData, 0, 256);
+ R2_GLOBALS._sceneManager._hasPalette = false;
+ _dataManager.dispatch();
+
+ _fieldD2E = 1;
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0);
+ for (int percent = 0; percent < 100; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+ break;
+
+ case 61:
+ R2_GLOBALS._sound1.fadeOut2(NULL);
+ R2_GLOBALS._scenePalette.loadPalette(0);
+ R2_GLOBALS._sceneManager.changeScene(160);
+ break;
+
+ case 70:
+ R2_GLOBALS._sound2.play(113);
+ for (int percent = 100; percent >= 0; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+
+ _dataManager._field3C = 2;
+ _dataManager._field56 = 2;
+ _dataManager.load(9);
+
+ R2_GLOBALS._scenePalette.loadPalette(_dataManager._palData, 0, 256);
+ R2_GLOBALS._sceneManager._hasPalette = false;
+ _dataManager.dispatch();
+
+ _fieldD2E = 1;
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0);
+ for (int percent = 0; percent < 100; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+ break;
+
+ case 71:
+ case 81:
+ R2_GLOBALS._sound1.fadeOut2(NULL);
+ R2_GLOBALS._sound2.fadeOut2(NULL);
+ R2_GLOBALS._scenePalette.loadPalette(0);
+ R2_GLOBALS._sceneManager.changeScene(3100);
+ break;
+
+ case 80:
+ _dataManager._field3C = 2;
+ _dataManager._field56 = 2;
+ _dataManager.load(10);
+
+ R2_GLOBALS._scenePalette.loadPalette(_dataManager._palData, 0, 256);
+ R2_GLOBALS._sceneManager._hasPalette = false;
+ _dataManager.dispatch();
+
+ _fieldD2E = 1;
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0);
+ for (int percent = 0; percent < 100; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+
+ R2_GLOBALS._sound1.play(242);
+ R2_GLOBALS._sound2.play(286);
+ break;
+
+ case 90:
+ _dataManager._field3C = 2;
+ _dataManager._field56 = 2;
+ _dataManager.load(11);
+
+ R2_GLOBALS._scenePalette.loadPalette(_dataManager._palData, 0, 256);
+ R2_GLOBALS._sceneManager._hasPalette = false;
+ _dataManager.dispatch();
+
+ _fieldD2E = 1;
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0);
+ for (int percent = 0; percent < 100; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+
+ R2_GLOBALS._sound1.play(277);
+ break;
+
+ case 91:
+ R2_GLOBALS._sound1.fadeOut2(NULL);
+ R2_GLOBALS._player._characterIndex = R2_SEEKER;
+ R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 3100;
+ R2_GLOBALS._sceneManager.changeScene(2500);
+ break;
+
+ case 100:
+ R2_GLOBALS._sound1.play(304);
+ R2_GLOBALS._sound2.play(82);
+
+ _dataManager._field3C = 2;
+ _dataManager._field56 = 2;
+ _dataManager.load(19);
+
+ R2_GLOBALS._scenePalette.loadPalette(_dataManager._palData, 0, 256);
+ R2_GLOBALS._sceneManager._hasPalette = false;
+ _dataManager.dispatch();
+
+ _fieldD2E = 1;
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0);
+ for (int percent = 0; percent < 100; percent += 5)
+ R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent);
+ break;
+
+ case 101:
+ R2_GLOBALS._sound1.fadeOut2(NULL);
+ R2_GLOBALS._sound2.fadeOut2(NULL);
+ R2_GLOBALS._scenePalette.loadPalette(0);
+ R2_GLOBALS._sceneManager.changeScene(3500);
+ break;
+ }
+}
+
+void Scene1000::dispatch() {
+
+}
+
+
+/*--------------------------------------------------------------------------
* Scene 1010 - Cutscene: A pixel lost in space!
*
*--------------------------------------------------------------------------*/
+
void Scene1010::postInit(SceneObjectList *OwnerList) {
SceneExt::postInit();
loadScene(1010);
diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.h b/engines/tsage/ringworld2/ringworld2_scenes1.h
index 0da6b3f93d..4ee0c29f4f 100644
--- a/engines/tsage/ringworld2/ringworld2_scenes1.h
+++ b/engines/tsage/ringworld2/ringworld2_scenes1.h
@@ -39,6 +39,24 @@ namespace Ringworld2 {
using namespace TsAGE;
+class Scene1000 : public SceneExt {
+public:
+ SequenceManager _sequenceManager1;
+ SequenceManager _sequenceManager2;
+ SpeakerGameText _gameTextSpeaker;
+ DataManager _dataManager;
+
+ int _field412;
+ int _fieldD2E;
+public:
+ Scene1000();
+
+ virtual void postInit(SceneObjectList *OwnerList = NULL);
+ virtual void remove();
+ virtual void signal();
+ virtual void dispatch();
+};
+
class Scene1010 : public SceneExt {
public:
SequenceManager _sequenceManager;
diff --git a/engines/wintermute/base/base_sprite.h b/engines/wintermute/base/base_sprite.h
index 05cb9fc936..d464899b04 100644
--- a/engines/wintermute/base/base_sprite.h
+++ b/engines/wintermute/base/base_sprite.h
@@ -32,6 +32,7 @@
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/base/base_script_holder.h"
+#include "engines/wintermute/graphics/transform_tools.h"
namespace Wintermute {
class BaseFrame;
@@ -44,17 +45,17 @@ public:
void setDefaults();
DECLARE_PERSISTENT(BaseSprite, BaseScriptHolder)
- bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = 100, float scaleY = 100);
+ bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = kDefaultZoomX, float scaleY = kDefaultZoomY);
int32 _moveY;
int32 _moveX;
- bool display(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, uint32 alpha = 0xFFFFFFFF, float rotate = 0.0f, TSpriteBlendMode blendMode = BLEND_NORMAL);
- bool getCurrentFrame(float zoomX = 100, float zoomY = 100);
+ bool display(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY, uint32 alpha = kDefaultRgbaMod, float rotate = kDefaultAngle, TSpriteBlendMode blendMode = BLEND_NORMAL);
+ bool getCurrentFrame(float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY);
void reset();
bool isChanged();
bool isFinished();
bool loadBuffer(byte *buffer, bool compete = true, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL);
bool loadFile(const Common::String &filename, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL);
- bool draw(int x, int y, BaseObject *Register = nullptr, float zoomX = 100, float zoomY = 100, uint32 alpha = 0xFFFFFFFF);
+ bool draw(int x, int y, BaseObject *Register = nullptr, float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY, uint32 alpha = kDefaultRgbaMod);
bool _looping;
int32 _currentFrame;
bool addFrame(const char *filename, uint32 delay = 0, int hotspotX = 0, int hotspotY = 0, Rect32 *rect = nullptr);
diff --git a/engines/wintermute/base/base_sub_frame.cpp b/engines/wintermute/base/base_sub_frame.cpp
index d93cf667f1..7012c28feb 100644
--- a/engines/wintermute/base/base_sub_frame.cpp
+++ b/engines/wintermute/base/base_sub_frame.cpp
@@ -38,6 +38,8 @@
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
+#include "engines/wintermute/graphics/transform_tools.h"
+#include "engines/wintermute/graphics/transform_struct.h"
namespace Wintermute {
@@ -46,8 +48,9 @@ IMPLEMENT_PERSISTENT(BaseSubFrame, false)
//////////////////////////////////////////////////////////////////////////
BaseSubFrame::BaseSubFrame(BaseGame *inGame) : BaseScriptable(inGame, true) {
_surface = nullptr;
- _hotspotX = _hotspotY = 0;
- _alpha = 0xFFFFFFFF;
+ _hotspotX = kDefaultHotspotX;
+ _hotspotY = kDefaultHotspotY;
+ _alpha = kDefaultRgbaMod;
_transparent = 0xFFFF00FF;
_wantsDefaultRect = false;
@@ -233,12 +236,18 @@ const char* BaseSubFrame::getSurfaceFilename() {
//////////////////////////////////////////////////////////////////////
bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, bool precise, uint32 alpha, float rotate, TSpriteBlendMode blendMode) {
+
+ rotate = fmod(rotate, 360.0f);
+ if (rotate < 0) {
+ rotate += 360.0f;
+ }
+
if (!_surface) {
return STATUS_OK;
}
if (registerOwner != nullptr && !_decoration) {
- if (zoomX == 100 && zoomY == 100) {
+ if (zoomX == kDefaultZoomX && zoomY == kDefaultZoomY) {
BaseEngine::getRenderer()->addRectToList(new BaseActiveRect(_gameRef, registerOwner, this, x - _hotspotX + getRect().left, y - _hotspotY + getRect().top, getRect().right - getRect().left, getRect().bottom - getRect().top, zoomX, zoomY, precise));
} else {
BaseEngine::getRenderer()->addRectToList(new BaseActiveRect(_gameRef, registerOwner, this, (int)(x - (_hotspotX + getRect().left) * (zoomX / 100)), (int)(y - (_hotspotY + getRect().top) * (zoomY / 100)), (int)((getRect().right - getRect().left) * (zoomX / 100)), (int)((getRect().bottom - getRect().top) * (zoomY / 100)), zoomX, zoomY, precise));
@@ -251,17 +260,24 @@ bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, fl
bool res;
//if (Alpha==0xFFFFFFFF) Alpha = _alpha; // TODO: better (combine owner's and self alpha)
- if (_alpha != 0xFFFFFFFF) {
+ if (_alpha != kDefaultRgbaMod) {
alpha = _alpha;
}
- if (rotate != 0.0f) {
- res = _surface->displayTransform((int)(x - _hotspotX * (zoomX / 100)), (int)(y - _hotspotY * (zoomY / 100)), _hotspotX, _hotspotY, getRect(), zoomX, zoomY, alpha, rotate, blendMode, _mirrorX, _mirrorY);
+ if (rotate != kDefaultAngle) {
+ Point32 boxOffset, rotatedHotspot, hotspotOffset, newOrigin;
+ Point32 origin(x, y);
+ Rect32 oldRect = getRect();
+ Point32 newHotspot;
+ TransformStruct transform = TransformStruct(zoomX, zoomY, rotate, _hotspotX, _hotspotY, blendMode, alpha, _mirrorX, _mirrorY, 0, 0);
+ Rect32 newRect = TransformTools::newRect (oldRect, transform, &newHotspot);
+ newOrigin = origin - newHotspot;
+ res = _surface->displayTransform(newOrigin.x, newOrigin.y, oldRect, newRect, transform);
} else {
- if (zoomX == 100 && zoomY == 100) {
+ if (zoomX == kDefaultZoomX && zoomY == kDefaultZoomY) {
res = _surface->displayTrans(x - _hotspotX, y - _hotspotY, getRect(), alpha, blendMode, _mirrorX, _mirrorY);
} else {
- res = _surface->displayTransZoom((int)(x - _hotspotX * (zoomX / 100)), (int)(y - _hotspotY * (zoomY / 100)), getRect(), zoomX, zoomY, alpha, blendMode, _mirrorX, _mirrorY);
+ res = _surface->displayTransZoom((int)(x - _hotspotX * (zoomX / kDefaultZoomX)), (int)(y - _hotspotY * (zoomY / kDefaultZoomY)), getRect(), zoomX, zoomY, alpha, blendMode, _mirrorX, _mirrorY);
}
}
diff --git a/engines/wintermute/base/file/base_disk_file.cpp b/engines/wintermute/base/file/base_disk_file.cpp
index 3c1ecc7a73..5ffb06f854 100644
--- a/engines/wintermute/base/file/base_disk_file.cpp
+++ b/engines/wintermute/base/file/base_disk_file.cpp
@@ -66,12 +66,6 @@ static Common::FSNode getNodeForRelativePath(const Common::String &filename) {
const Common::FSNode gameDataDir(ConfMan.get("path"));
Common::FSNode curNode = gameDataDir;
- Common::String fixedPath = "";
- while (!path.empty()) {
- fixedPath += path.nextToken() + "/";
- }
- fixedPath.deleteLastChar();
-
// Parse all path-elements
while (!path.empty()) {
// Get the next path-component by slicing on '\\'
diff --git a/engines/wintermute/base/gfx/base_surface.cpp b/engines/wintermute/base/gfx/base_surface.cpp
index 2002463ea4..42ec51f39e 100644
--- a/engines/wintermute/base/gfx/base_surface.cpp
+++ b/engines/wintermute/base/gfx/base_surface.cpp
@@ -75,8 +75,8 @@ bool BaseSurface::displayHalfTrans(int x, int y, Rect32 rect) {
}
//////////////////////////////////////////////////////////////////////////
-bool BaseSurface::displayTransform(int x, int y, int hotX, int hotY, Rect32 rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
- return displayTransZoom(x, y, rect, zoomX, zoomY, alpha, blendMode, mirrorX, mirrorY);
+bool BaseSurface::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) {
+ return displayTransform(x, y, rect, newRect, transform);
}
//////////////////////////////////////////////////////////////////////////
diff --git a/engines/wintermute/base/gfx/base_surface.h b/engines/wintermute/base/gfx/base_surface.h
index b83efa0bb8..e308b29996 100644
--- a/engines/wintermute/base/gfx/base_surface.h
+++ b/engines/wintermute/base/gfx/base_surface.h
@@ -32,6 +32,7 @@
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/math/rect32.h"
#include "graphics/surface.h"
+#include "engines/wintermute/graphics/transform_struct.h"
namespace Wintermute {
@@ -49,12 +50,12 @@ public:
virtual bool displayHalfTrans(int x, int y, Rect32 rect);
virtual bool isTransparentAt(int x, int y);
- virtual bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
+ virtual bool displayTransZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
virtual bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
virtual bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) = 0;
virtual bool display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
- virtual bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
- virtual bool displayTransform(int x, int y, int hotX, int hotY, Rect32 rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
+ virtual bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) = 0;
+ virtual bool displayZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
virtual bool repeatLastDisplayOp(int offsetX, int offsetY, int numTimesX, int numTimesY) = 0;
virtual bool restore();
virtual bool create(const Common::String &filename, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime = -1, bool keepLoaded = false) = 0;
diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
index eca2998da5..7905184190 100644
--- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
+++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
@@ -60,8 +60,7 @@ BaseRenderOSystem::BaseRenderOSystem(BaseGame *inGame) : BaseRenderer(inGame) {
_borderLeft = _borderRight = _borderTop = _borderBottom = 0;
_ratioX = _ratioY = 1.0f;
- setAlphaMod(255);
- setColorMod(255, 255, 255);
+ _colorMod = kDefaultRgbaMod;
_dirtyRect = nullptr;
_disableDirtyRects = false;
_tempDisableDirtyRects = 0;
@@ -150,18 +149,6 @@ bool BaseRenderOSystem::initRenderer(int width, int height, bool windowed) {
return STATUS_OK;
}
-void BaseRenderOSystem::setAlphaMod(byte alpha) {
- byte r = RGBCOLGetR(_colorMod);
- byte g = RGBCOLGetB(_colorMod);
- byte b = RGBCOLGetB(_colorMod);
- _colorMod = BS_ARGB(alpha, r, g, b);
-}
-
-void BaseRenderOSystem::setColorMod(byte r, byte g, byte b) {
- byte alpha = RGBCOLGetA(_colorMod);
- _colorMod = BS_ARGB(alpha, r, g, b);
-}
-
bool BaseRenderOSystem::indicatorFlip() {
g_system->copyRectToScreen((byte *)_renderSurface->getBasePtr(_indicatorX, _indicatorY), _renderSurface->pitch, _indicatorX, _indicatorY, _indicatorWidthDrawn, _indicatorHeight);
g_system->updateScreen();
@@ -256,7 +243,6 @@ void BaseRenderOSystem::fade(uint16 alpha) {
return fadeToColor(0, 0, 0, dwAlpha);
}
-
//////////////////////////////////////////////////////////////////////////
void BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a, Common::Rect *rect) {
Common::Rect fillRect;
@@ -279,14 +265,14 @@ void BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a, Common::Rect
//TODO: This is only here until I'm sure about the final pixelformat
uint32 col = _renderSurface->format.ARGBToColor(a, r, g, b);
- setAlphaMod(255);
- setColorMod(255, 255, 255);
Graphics::Surface surf;
surf.create((uint16)fillRect.width(), (uint16)fillRect.height(), _renderSurface->format);
Common::Rect sizeRect(fillRect);
sizeRect.translate(-fillRect.top, -fillRect.left);
surf.fillRect(fillRect, col);
- drawSurface(nullptr, &surf, &sizeRect, &fillRect, false, false);
+ TransformStruct temp = TransformStruct();
+ temp._alphaDisable = false;
+ drawSurface(nullptr, &surf, &sizeRect, &fillRect, temp);
surf.free();
//SDL_SetRenderDrawColor(_renderer, r, g, b, a);
@@ -298,16 +284,18 @@ Graphics::PixelFormat BaseRenderOSystem::getPixelFormat() const {
return _renderSurface->format;
}
-void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY, bool disableAlpha) {
+void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform) {
+
if (_tempDisableDirtyRects || _disableDirtyRects) {
- RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, mirrorX, mirrorY, disableAlpha);
- ticket->_colorMod = _colorMod;
+ RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform);
+ ticket->_transform._rgbaMod = _colorMod;
ticket->_wantsDraw = true;
_renderQueue.push_back(ticket);
_previousTicket = ticket;
drawFromSurface(ticket);
return;
}
+
// Start searching from the beginning for the first and second items (since it's empty the first time around
// then keep incrementing the start-position, to avoid comparing against already used tickets.
if (_drawNum == 0 || _drawNum == 1) {
@@ -320,12 +308,11 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S
}
if (owner) { // Fade-tickets are owner-less
- RenderTicket compare(owner, nullptr, srcRect, dstRect, mirrorX, mirrorY, disableAlpha);
+ RenderTicket compare(owner, nullptr, srcRect, dstRect, transform);
compare._batchNum = _batchNum;
if (_spriteBatch) {
_batchNum++;
}
- compare._colorMod = _colorMod;
RenderQueueIterator it;
// Avoid calling end() and operator* every time, when potentially going through
// LOTS of tickets.
@@ -334,7 +321,7 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S
for (it = _lastAddedTicket; it != endIterator; ++it) {
compareTicket = *it;
if (*(compareTicket) == compare && compareTicket->_isValid) {
- compareTicket->_colorMod = _colorMod;
+ compareTicket->_transform._rgbaMod = transform._rgbaMod;
if (_disableDirtyRects) {
drawFromSurface(compareTicket);
} else {
@@ -349,8 +336,7 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S
}
}
}
- RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, mirrorX, mirrorY, disableAlpha);
- ticket->_colorMod = _colorMod;
+ RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform);
if (!_disableDirtyRects) {
drawFromTicket(ticket);
_previousTicket = ticket;
@@ -385,12 +371,14 @@ void BaseRenderOSystem::repeatLastDraw(int offsetX, int offsetY, int numTimesX,
int initLeft = dstRect.left;
int initRight = dstRect.right;
+ TransformStruct temp = TransformStruct(kDefaultZoomX, kDefaultZoomY, kDefaultAngle, kDefaultHotspotX, kDefaultHotspotY, BLEND_NORMAL, kDefaultRgbaMod, false, false, kDefaultOffsetX, kDefaultOffsetY);
+
for (int i = 0; i < numTimesY; i++) {
if (i == 0) {
dstRect.translate(offsetX, 0);
}
for (int j = (i == 0 ? 1 : 0); j < numTimesX; j++) {
- drawSurface(origTicket->_owner, origTicket->getSurface(), &srcRect, &dstRect, false, false);
+ drawSurface(origTicket->_owner, origTicket->getSurface(), &srcRect, &dstRect, temp);
dstRect.translate(offsetX, 0);
}
dstRect.left = initLeft;
@@ -535,7 +523,7 @@ void BaseRenderOSystem::drawTickets() {
// convert from screen-coords to surface-coords.
dstClip.translate(-offsetX, -offsetY);
- _colorMod = ticket->_colorMod;
+ _colorMod = ticket->_transform._rgbaMod;
drawFromSurface(ticket, &pos, &dstClip);
_needsFlip = true;
}
diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.h b/engines/wintermute/base/gfx/osystem/base_render_osystem.h
index 3cb0fa82a3..5531961623 100644
--- a/engines/wintermute/base/gfx/osystem/base_render_osystem.h
+++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.h
@@ -33,6 +33,7 @@
#include "common/rect.h"
#include "graphics/surface.h"
#include "common/list.h"
+#include "engines/wintermute/graphics/transform_struct.h"
namespace Wintermute {
class BaseSurfaceOSystem;
@@ -56,8 +57,6 @@ public:
BaseImage *takeScreenshot() override;
- void setAlphaMod(byte alpha);
- void setColorMod(byte r, byte g, byte b);
void invalidateTicket(RenderTicket *renderTicket);
void invalidateTicketsFromSurface(BaseSurfaceOSystem *surf);
void drawFromTicket(RenderTicket *renderTicket);
@@ -80,7 +79,7 @@ public:
virtual bool startSpriteBatch() override;
virtual bool endSpriteBatch() override;
void endSaveLoad();
- void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY, bool disableAlpha = false) ;
+ void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform);
void repeatLastDraw(int offsetX, int offsetY, int numTimesX, int numTimesY);
BaseSurface *createSurface() override;
private:
diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
index 87bb2fdb53..b809318133 100644
--- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
+++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
@@ -52,6 +52,7 @@ BaseSurfaceOSystem::BaseSurfaceOSystem(BaseGame *inGame) : BaseSurface(inGame) {
_lockPixels = nullptr;
_lockPitch = 0;
_loaded = false;
+ _rotation = 0;
}
//////////////////////////////////////////////////////////////////////////
@@ -319,39 +320,56 @@ bool BaseSurfaceOSystem::endPixelOp() {
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
- return drawSprite(x, y, &rect, 100, 100, 0xFFFFFFFF, true, blendMode, mirrorX, mirrorY);
+ _rotation = 0;
+ return drawSprite(x, y, &rect, nullptr, TransformStruct(kDefaultZoomX, kDefaultZoomY, mirrorX, mirrorY));
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::displayTrans(int x, int y, Rect32 rect, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
- return drawSprite(x, y, &rect, 100, 100, alpha, false, blendMode, mirrorX, mirrorY);
+ _rotation = 0;
+ return drawSprite(x, y, &rect, nullptr, TransformStruct(kDefaultZoomX, kDefaultZoomY, blendMode, alpha, mirrorX, mirrorY));
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::displayTransOffset(int x, int y, Rect32 rect, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) {
- return drawSprite(x, y, &rect, 100, 100, alpha, false, blendMode, mirrorX, mirrorY, offsetX, offsetY);
+ _rotation = 0;
+ return drawSprite(x, y, &rect, nullptr, TransformStruct(kDefaultZoomX, kDefaultZoomY, kDefaultAngle, kDefaultHotspotX, kDefaultHotspotY, blendMode, alpha, mirrorX, mirrorY, offsetX, offsetY));
}
//////////////////////////////////////////////////////////////////////////
-bool BaseSurfaceOSystem::displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
- return drawSprite(x, y, &rect, zoomX, zoomY, alpha, false, blendMode, mirrorX, mirrorY);
+bool BaseSurfaceOSystem::displayTransZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
+ _rotation = 0;
+ return drawSprite(x, y, &rect, nullptr, TransformStruct(zoomX, zoomY, blendMode, alpha, mirrorX, mirrorY));
}
//////////////////////////////////////////////////////////////////////////
-bool BaseSurfaceOSystem::displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, bool transparent, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
- return drawSprite(x, y, &rect, zoomX, zoomY, alpha, !transparent, blendMode, mirrorX, mirrorY);
+bool BaseSurfaceOSystem::displayZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha, bool transparent, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
+ _rotation = 0;
+ TransformStruct transform;
+ if (transparent) {
+ transform = TransformStruct(zoomX, zoomY, kDefaultAngle, kDefaultHotspotX, kDefaultHotspotY, blendMode, alpha, mirrorX, mirrorY);
+ } else {
+ transform = TransformStruct(zoomX, zoomY, mirrorX, mirrorY);
+ }
+ return drawSprite(x, y, &rect, nullptr, transform);
}
//////////////////////////////////////////////////////////////////////////
-bool BaseSurfaceOSystem::displayTransform(int x, int y, int hotX, int hotY, Rect32 rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
- return drawSprite(x, y, &rect, zoomX, zoomY, alpha, false, blendMode, mirrorX, mirrorY);
+bool BaseSurfaceOSystem::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) {
+ _rotation = (uint32)transform._angle;
+ if (transform._angle < 0.0f) {
+ warning("Negative rotation: %d %d", transform._angle, _rotation);
+ _rotation = (uint32)(360.0f + transform._angle);
+ warning("Negative post rotation: %d %d", transform._angle, _rotation);
+ }
+ return drawSprite(x, y, &rect, &newRect, transform);
}
//////////////////////////////////////////////////////////////////////////
-bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, float zoomY, uint32 alpha, bool alphaDisable, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) {
+bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, TransformStruct transform) {
BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_gameRef->_renderer);
if (!_loaded) {
@@ -359,17 +377,9 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, flo
}
if (renderer->_forceAlphaColor != 0) {
- alpha = renderer->_forceAlphaColor;
+ transform._rgbaMod = renderer->_forceAlphaColor;
}
- byte r = RGBCOLGetR(alpha);
- byte g = RGBCOLGetG(alpha);
- byte b = RGBCOLGetB(alpha);
- byte a = RGBCOLGetA(alpha);
-
- renderer->setAlphaMod(a);
- renderer->setColorMod(r, g, b);
-
#if 0 // These are kept for reference if BlendMode is reimplemented at some point.
if (alphaDisable) {
SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_NONE);
@@ -386,8 +396,8 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, flo
srcRect.setHeight(rect->bottom - rect->top);
Common::Rect position;
- position.left = x + offsetX;
- position.top = y + offsetY;
+ position.left = x + transform._offset.x;
+ position.top = y + transform._offset.y;
// Crop off-by-ones:
if (position.left == -1) {
@@ -396,31 +406,34 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, flo
if (position.top == -1) {
position.top = 0; // TODO: Something is wrong
}
-
- position.setWidth((int16)((float)srcRect.width() * zoomX / 100.f));
- position.setHeight((int16)((float)srcRect.height() * zoomX / 100.f));
-
+ if (newRect) {
+ position.top = y;
+ position.left = x;
+ position.right = x + newRect->width();
+ position.bottom = y + newRect->height();
+ position.setWidth(newRect->width());
+ position.setHeight(newRect->height());
+ } else {
+ position.setWidth((int16)((float)srcRect.width() * transform._zoom.x / kDefaultZoomX));
+ position.setHeight((int16)((float)srcRect.height() * transform._zoom.y / kDefaultZoomY));
+ }
renderer->modTargetRect(&position);
- /* position.left += offsetX;
- position.top += offsetY;*/
-
// TODO: This actually requires us to have the SAME source-offsets every time,
// But no checking is in place for that yet.
// TODO: Optimize by not doing alpha-blits if we lack or disable alpha
- bool hasAlpha;
- if (_hasAlpha && !alphaDisable) {
+
+ bool hasAlpha = false;
+
+ if (_hasAlpha && !transform._alphaDisable) {
hasAlpha = true;
- } else {
- hasAlpha = false;
- }
- if (alphaDisable) {
+ }
+
+ if (transform._alphaDisable) {
warning("BaseSurfaceOSystem::drawSprite - AlphaDisable ignored");
}
-
- renderer->drawSurface(this, _surface, &srcRect, &position, mirrorX, mirrorY, !hasAlpha);
-
+ renderer->drawSurface(this, _surface, &srcRect, &position, transform);
return STATUS_OK;
}
diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h
index 9091ec65b1..5290170db8 100644
--- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h
+++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h
@@ -51,12 +51,12 @@ public:
bool endPixelOp() override;
- bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
- bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
- bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) override;
+ bool displayTransZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
+ bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
+ bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) override;
bool display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
- bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
- bool displayTransform(int x, int y, int hotX, int hotY, Rect32 Rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
+ bool displayZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha = kDefaultRgbaMod, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
+ bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) override;
bool repeatLastDisplayOp(int offsetX, int offsetY, int numTimesX, int numTimesY) override;
virtual bool putSurface(const Graphics::Surface &surface, bool hasAlpha = false) override;
/* static unsigned DLL_CALLCONV ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle);
@@ -85,10 +85,11 @@ private:
Graphics::Surface *_surface;
bool _loaded;
bool finishLoad();
- bool drawSprite(int x, int y, Rect32 *rect, float zoomX, float zoomY, uint32 alpha, bool alphaDisable, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX = 0, int offsetY = 0);
+ bool drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, TransformStruct transformStruct);
void genAlphaMask(Graphics::Surface *surface);
uint32 getPixelAt(Graphics::Surface *surface, int x, int y);
+ uint32 _rotation;
bool _hasAlpha;
void *_lockPixels;
int _lockPitch;
diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.cpp b/engines/wintermute/base/gfx/osystem/render_ticket.cpp
index 98c5be62a8..8d9d5325c4 100644
--- a/engines/wintermute/base/gfx/osystem/render_ticket.cpp
+++ b/engines/wintermute/base/gfx/osystem/render_ticket.cpp
@@ -26,22 +26,22 @@
* Copyright (c) 2011 Jan Nedoma
*/
-#include "engines/wintermute/graphics/transparent_surface.h"
+
#include "engines/wintermute/base/gfx/osystem/render_ticket.h"
+#include "engines/wintermute/graphics/transform_tools.h"
+#include "common/textconsole.h"
namespace Wintermute {
-RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY, bool disableAlpha) : _owner(owner),
-_srcRect(*srcRect), _dstRect(*dstRect), _drawNum(0), _isValid(true), _wantsDraw(true), _hasAlpha(!disableAlpha) {
- _colorMod = 0;
+RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct transform) :
+ _owner(owner),
+ _srcRect(*srcRect),
+ _dstRect(*dstRect),
+ _drawNum(0),
+ _isValid(true),
+ _wantsDraw(true),
+ _transform(transform) {
_batchNum = 0;
- _mirror = TransparentSurface::FLIP_NONE;
- if (mirrorX) {
- _mirror |= TransparentSurface::FLIP_V;
- }
- if (mirrorY) {
- _mirror |= TransparentSurface::FLIP_H;
- }
if (surf) {
_surface = new Graphics::Surface();
_surface->create((uint16)srcRect->width(), (uint16)srcRect->height(), surf->format);
@@ -51,7 +51,13 @@ _srcRect(*srcRect), _dstRect(*dstRect), _drawNum(0), _isValid(true), _wantsDraw(
memcpy(_surface->getBasePtr(0, i), surf->getBasePtr(srcRect->left, srcRect->top + i), srcRect->width() * _surface->format.bytesPerPixel);
}
// Then scale it if necessary
- if (dstRect->width() != srcRect->width() || dstRect->height() != srcRect->height()) {
+ if (_transform._angle != kDefaultAngle) {
+ TransparentSurface src(*_surface, false);
+ Graphics::Surface *temp = src.rotoscale(transform);
+ _surface->free();
+ delete _surface;
+ _surface = temp;
+ } else if (dstRect->width() != srcRect->width() || dstRect->height() != srcRect->height()) {
TransparentSurface src(*_surface, false);
Graphics::Surface *temp = src.scale(dstRect->width(), dstRect->height());
_surface->free();
@@ -60,6 +66,14 @@ _srcRect(*srcRect), _dstRect(*dstRect), _drawNum(0), _isValid(true), _wantsDraw(
}
} else {
_surface = nullptr;
+
+ if (transform._angle != kDefaultAngle) { // Make sure comparison-tickets get the correct width
+ Rect32 newDstRect;
+ Point32 newHotspot;
+ newDstRect = TransformTools::newRect(_srcRect, transform, &newHotspot);
+ _dstRect.setWidth(newDstRect.right - newDstRect.left);
+ _dstRect.setHeight(newDstRect.bottom - newDstRect.top);
+ }
}
}
@@ -70,32 +84,31 @@ RenderTicket::~RenderTicket() {
}
}
-bool RenderTicket::operator==(RenderTicket &t) {
+bool RenderTicket::operator==(const RenderTicket &t) const {
if ((t._owner != _owner) ||
(t._batchNum != _batchNum) ||
- (t._hasAlpha != _hasAlpha) ||
- (t._mirror != _mirror) ||
- (t._colorMod != _colorMod) ||
+ (t._transform != _transform) ||
(t._dstRect != _dstRect) ||
- (t._srcRect != _srcRect)) {
+ (t._srcRect != _srcRect)
+ ) {
return false;
}
return true;
}
// Replacement for SDL2's SDL_RenderCopy
-void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) {
+void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) const {
TransparentSurface src(*getSurface(), false);
Common::Rect clipRect;
clipRect.setWidth(getSurface()->w);
clipRect.setHeight(getSurface()->h);
- src._enableAlphaBlit = _hasAlpha;
- src.blit(*_targetSurface, _dstRect.left, _dstRect.top, _mirror, &clipRect, _colorMod, clipRect.width(), clipRect.height());
+ src._enableAlphaBlit = !_transform._alphaDisable;
+ src.blit(*_targetSurface, _dstRect.left, _dstRect.top, _transform._flip, &clipRect, _transform._rgbaMod, clipRect.width(), clipRect.height());
}
-void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) {
+void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const {
TransparentSurface src(*getSurface(), false);
bool doDelete = false;
if (!clipRect) {
@@ -105,8 +118,8 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect
clipRect->setHeight(getSurface()->h);
}
- src._enableAlphaBlit = _hasAlpha;
- src.blit(*_targetSurface, dstRect->left, dstRect->top, _mirror, clipRect, _colorMod, clipRect->width(), clipRect->height());
+ src._enableAlphaBlit = !_transform._alphaDisable;
+ src.blit(*_targetSurface, dstRect->left, dstRect->top, _transform._flip, clipRect, _transform._rgbaMod, clipRect->width(), clipRect->height());
if (doDelete) {
delete clipRect;
}
diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.h b/engines/wintermute/base/gfx/osystem/render_ticket.h
index 64df3590a1..ec1412b032 100644
--- a/engines/wintermute/base/gfx/osystem/render_ticket.h
+++ b/engines/wintermute/base/gfx/osystem/render_ticket.h
@@ -29,6 +29,7 @@
#ifndef WINTERMUTE_RENDER_TICKET_H
#define WINTERMUTE_RENDER_TICKET_H
+#include "engines/wintermute/graphics/transparent_surface.h"
#include "graphics/surface.h"
#include "common/rect.h"
@@ -37,14 +38,14 @@ namespace Wintermute {
class BaseSurfaceOSystem;
class RenderTicket {
public:
- RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, bool mirrorX = false, bool mirrorY = false, bool disableAlpha = false);
- RenderTicket() : _isValid(true), _wantsDraw(false), _drawNum(0) {}
+ RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, TransformStruct transform);
+ RenderTicket() : _isValid(true), _wantsDraw(false), _drawNum(0), _transform(TransformStruct()) {}
~RenderTicket();
- const Graphics::Surface *getSurface() { return _surface; }
+ const Graphics::Surface *getSurface() const { return _surface; }
// Non-dirty-rects:
- void drawToSurface(Graphics::Surface *_targetSurface);
+ void drawToSurface(Graphics::Surface *_targetSurface) const;
// Dirty-rects:
- void drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect);
+ void drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const;
Common::Rect _dstRect;
uint32 _batchNum;
@@ -52,16 +53,15 @@ public:
bool _isValid;
bool _wantsDraw;
uint32 _drawNum;
- uint32 _colorMod;
+ TransformStruct _transform;
+
BaseSurfaceOSystem *_owner;
- bool operator==(RenderTicket &a);
- const Common::Rect *getSrcRect() { return &_srcRect; }
+ bool operator==(const RenderTicket &a) const;
+ const Common::Rect *getSrcRect() const { return &_srcRect; }
private:
Graphics::Surface *_surface;
Common::Rect _srcRect;
- bool _hasAlpha;
- uint32 _mirror;
};
} // end of namespace Wintermute
diff --git a/engines/wintermute/detection_tables.h b/engines/wintermute/detection_tables.h
index 1dff3622ec..3d9afe7c97 100644
--- a/engines/wintermute/detection_tables.h
+++ b/engines/wintermute/detection_tables.h
@@ -297,6 +297,26 @@ static const ADGameDescription gameDescriptions[] = {
// James Peris: No License Nor Control (English)
{
"jamesperis",
+ "",
+ AD_ENTRY1s("data.dcp", "a420961e170cb7d168a0d2bae2fe5218", 225294032),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE,
+ GUIO0()
+ },
+ // James Peris: No License Nor Control (Spanish)
+ {
+ "jamesperis",
+ "",
+ AD_ENTRY1s("data.dcp", "a420961e170cb7d168a0d2bae2fe5218", 225294032),
+ Common::ES_ESP,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE,
+ GUIO0()
+ },
+ // James Peris: No License Nor Control (Demo) (English)
+ {
+ "jamesperis",
"Demo",
AD_ENTRY1s("data.dcp", "edb9f9c7a08993c1e28f4e477b5f9830", 116113507),
Common::EN_ANY,
@@ -305,7 +325,7 @@ static const ADGameDescription gameDescriptions[] = {
ADGF_DEMO,
GUIO0()
},
- // James Peris: No License Nor Control (Spanish)
+ // James Peris: No License Nor Control (Demo) (Spanish)
{
"jamesperis",
"Demo",
diff --git a/engines/wintermute/graphics/transform_struct.cpp b/engines/wintermute/graphics/transform_struct.cpp
new file mode 100644
index 0000000000..8edbf765b5
--- /dev/null
+++ b/engines/wintermute/graphics/transform_struct.cpp
@@ -0,0 +1,93 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "engines/wintermute/graphics/transform_struct.h"
+#include "engines/wintermute/graphics/transparent_surface.h"
+
+namespace Wintermute {
+void TransformStruct::init(Point32 zoom, uint32 angle, Point32 hotspot, bool alphaDisable, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, Point32 offset) {
+ _zoom = zoom;
+ _angle = angle;
+ _hotspot = hotspot;
+ _blendMode = blendMode;
+ _rgbaMod = rgbaMod;
+ _alphaDisable = alphaDisable;
+ _flip = 0;
+ _flip += TransparentSurface::FLIP_H * mirrorX;
+ _flip += TransparentSurface::FLIP_V * mirrorY;
+ _offset = offset;
+}
+
+
+TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, int32 offsetX, int32 offsetY) {
+ init(Point32(zoomX, zoomY),
+ angle,
+ Point32(hotspotX, hotspotY),
+ false,
+ blendMode,
+ rgbaMod,
+ mirrorX, mirrorY,
+ Point32(offsetX, offsetY));
+}
+
+TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY) {
+ init(Point32(zoomX, zoomY),
+ kDefaultAngle,
+ Point32(kDefaultHotspotX, kDefaultHotspotY),
+ false,
+ blendMode,
+ rgbaMod,
+ mirrorX,
+ mirrorY,
+ Point32(kDefaultOffsetX, kDefaultOffsetY));
+}
+
+TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY) {
+ init(Point32(zoomX, zoomY),
+ angle,
+ Point32(hotspotX, hotspotY),
+ true,
+ BLEND_NORMAL,
+ kDefaultRgbaMod,
+ false, false,
+ Point32(kDefaultOffsetX, kDefaultOffsetY));
+}
+
+TransformStruct::TransformStruct() {
+ init(Point32(kDefaultZoomX, kDefaultZoomY),
+ kDefaultAngle,
+ Point32(kDefaultHotspotX, kDefaultHotspotY),
+ true,
+ BLEND_NORMAL,
+ kDefaultRgbaMod,
+ false, false,
+ Point32(kDefaultOffsetX, kDefaultOffsetY));
+}
+
+bool TransformStruct::getMirrorX() const {
+ return (bool)(_flip & TransparentSurface::FLIP_H);
+}
+
+bool TransformStruct::getMirrorY() const {
+ return (bool)(_flip & TransparentSurface::FLIP_V);
+}
+} // End of namespace Wintermute
diff --git a/engines/wintermute/graphics/transform_struct.h b/engines/wintermute/graphics/transform_struct.h
new file mode 100644
index 0000000000..acde410e89
--- /dev/null
+++ b/engines/wintermute/graphics/transform_struct.h
@@ -0,0 +1,83 @@
+/* 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.
+ *
+ */
+
+#ifndef WINTERMUTE_TRANSFORM_STRUCT_H
+#define WINTERMUTE_TRANSFORM_STRUCT_H
+
+#include "engines/wintermute/math/rect32.h"
+#include "engines/wintermute/dctypes.h"
+
+namespace Wintermute {
+/**
+ * Contains all the required information that define a transform.
+ * Same source sprite + same TransformStruct = Same resulting sprite.
+ * Has a number of overloaded constructors to accomodate various argument lists.
+ */
+
+const uint32 kDefaultZoomX = 100;
+const uint32 kDefaultZoomY = 100;
+const uint32 kDefaultRgbaMod = 0xFFFFFFFF;
+const int32 kDefaultHotspotX = 0;
+const int32 kDefaultHotspotY = 0;
+const int32 kDefaultOffsetX = 0;
+const int32 kDefaultOffsetY = 0;
+const int32 kDefaultAngle = 0;
+
+struct TransformStruct {
+private:
+ void init(Point32 zoom, uint32 angle, Point32 hotspot, bool alphaDisable, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX, bool mirrorY, Point32 offset);
+
+public:
+ TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false, int32 offsetX = 0, int32 offsetY = 0);
+ TransformStruct(int32 zoomX, int32 zoomY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false);
+ TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX = 0, int32 hotspotY = 0);
+ TransformStruct();
+
+ Point32 _zoom; ///< Zoom; 100 = no zoom
+ Point32 _hotspot; ///< Position of the hotspot
+ uint32 _angle; ///< Rotation angle, in degrees
+ byte _flip; ///< Bitflag: see TransparentSurface::FLIP_XXX
+ bool _alphaDisable;
+ TSpriteBlendMode _blendMode;
+ uint32 _rgbaMod; ///< RGBa
+ Point32 _offset;
+
+ bool getMirrorX() const;
+ bool getMirrorY() const;
+
+ bool operator==(const TransformStruct &compare) const {
+ return (compare._angle == _angle &&
+ compare._flip == _flip &&
+ compare._zoom == _zoom &&
+ compare._offset == _offset &&
+ compare._alphaDisable == _alphaDisable &&
+ compare._rgbaMod == _rgbaMod &&
+ compare._blendMode == _blendMode
+ );
+ }
+
+ bool operator!=(const TransformStruct &compare) const {
+ return !(compare == *this);
+ }
+};
+} // End of namespace Wintermute
+#endif
diff --git a/engines/wintermute/graphics/transform_tools.cpp b/engines/wintermute/graphics/transform_tools.cpp
new file mode 100644
index 0000000000..4f05e19a92
--- /dev/null
+++ b/engines/wintermute/graphics/transform_tools.cpp
@@ -0,0 +1,74 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include "engines/wintermute/graphics/transform_tools.h"
+#include <math.h>
+
+namespace Wintermute {
+
+FloatPoint TransformTools::transformPoint(const FloatPoint &point, const float rotate, const Point32 &zoom, const bool mirrorX, const bool mirrorY) {
+ float rotateRad = rotate * M_PI / 180.0f;
+ FloatPoint newPoint;
+ newPoint.x = (point.x * cos(rotateRad) - point.y * sin(rotateRad)) * zoom.x / kDefaultZoomX;
+ newPoint.y = (point.x * sin(rotateRad) + point.y * cos(rotateRad)) * zoom.y / kDefaultZoomY;
+ if (mirrorX) {
+ newPoint.x *= -1;
+ }
+ if (mirrorY) {
+ newPoint.y *= -1;
+ }
+ return newPoint;
+}
+
+Rect32 TransformTools::newRect (const Rect32 &oldRect, const TransformStruct &transform, Point32 *newHotspot) {
+
+ Point32 nw(oldRect.left, oldRect.top);
+ Point32 ne(oldRect.right, oldRect.top);
+ Point32 sw(oldRect.left, oldRect.bottom);
+ Point32 se(oldRect.right, oldRect.bottom);
+
+ FloatPoint nw1, ne1, sw1, se1;
+
+ nw1 = transformPoint(nw - transform._hotspot, transform._angle, transform._zoom);
+ ne1 = transformPoint(ne - transform._hotspot, transform._angle, transform._zoom);
+ sw1 = transformPoint(sw - transform._hotspot, transform._angle, transform._zoom);
+ se1 = transformPoint(se - transform._hotspot, transform._angle, transform._zoom);
+
+ float top = MIN(nw1.y, MIN(ne1.y, MIN(sw1.y, se1.y)));
+ float bottom = MAX(nw1.y, MAX(ne1.y, MAX(sw1.y, se1.y)));
+ float left = MIN(nw1.x, MIN(ne1.x, MIN(sw1.x, se1.x)));
+ float right = MAX(nw1.x, MAX(ne1.x, MAX(sw1.x, se1.x)));
+
+ Rect32 res;
+ newHotspot->y = (uint32)(-floor(top));
+ newHotspot->x = (uint32)(-floor(left));
+
+ res.top = (int32)(floor(top)) + transform._hotspot.y;
+ res.bottom = (int32)(ceil(bottom)) + transform._hotspot.y;
+ res.left = (int32)(floor(left)) + transform._hotspot.x;
+ res.right = (int32)(ceil(right)) + transform._hotspot.x;
+
+ return res;
+}
+
+} // End of namespace Wintermute
diff --git a/engines/wintermute/graphics/transform_tools.h b/engines/wintermute/graphics/transform_tools.h
new file mode 100644
index 0000000000..e59c47272a
--- /dev/null
+++ b/engines/wintermute/graphics/transform_tools.h
@@ -0,0 +1,53 @@
+/* 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.
+ *
+ */
+
+#ifndef WINTERMUTE_TRANSFORM_TOOLS_H
+#define WINTERMUTE_TRANSFORM_TOOLS_H
+
+#include "engines/wintermute/math/rect32.h"
+#include "engines/wintermute/math/floatpoint.h"
+#include "engines/wintermute/graphics/transform_struct.h"
+
+namespace Wintermute {
+
+class TransformTools {
+public:
+ /**
+ * Basic transform (scale + rotate) for a single point
+ */
+ static FloatPoint transformPoint(const FloatPoint &point, const float rotate, const Point32 &zoom, const bool mirrorX = false, const bool mirrorY = false);
+
+ /**
+ * @param &point the point on which the transform is to be applied
+ * @param rotate the angle in degrees
+ * @param &zoom zoom x,y in percent
+ * @param mirrorX flip along the vertical axis?
+ * @param mirrorY flip along the horizontal axis?
+ * @return the smallest rect that can contain the transformed sprite
+ * and, as a side-effect, "newHotspot" will tell you where the hotspot will
+ * have ended up in the new rect, for centering.
+ */
+ static Rect32 newRect (const Rect32 &oldRect, const TransformStruct &transform, Point32 *newHotspot);
+};
+
+} // End of namespace Wintermute
+#endif
diff --git a/engines/wintermute/graphics/transparent_surface.cpp b/engines/wintermute/graphics/transparent_surface.cpp
index dcdcbf247e..5b7c416ee9 100644
--- a/engines/wintermute/graphics/transparent_surface.cpp
+++ b/engines/wintermute/graphics/transparent_surface.cpp
@@ -23,12 +23,124 @@
#include "common/endian.h"
#include "common/util.h"
#include "common/rect.h"
+#include "common/math.h"
#include "common/textconsole.h"
#include "graphics/primitives.h"
#include "engines/wintermute/graphics/transparent_surface.h"
+#include "engines/wintermute/graphics/transform_tools.h"
namespace Wintermute {
+
+#if ENABLE_BILINEAR
+void TransparentSurface::copyPixelBilinear(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst) {
+
+ int srcW = srcRect.width();
+ int srcH = srcRect.height();
+ int dstW = dstRect.width();
+ int dstH = dstRect.height();
+
+ assert(dstX >= 0 && dstX < dstW);
+ assert(dstY >= 0 && dstY < dstH);
+
+ float x1 = floor(projX);
+ float x2 = ceil(projX);
+ float y1 = floor(projY);
+ float y2 = ceil(projY);
+
+ uint32 Q11, Q12, Q21, Q22;
+
+ if (x1 >= srcW || x1 < 0 || y1 >= srcH || y1 < 0) {
+ Q11 = 0;
+ } else {
+ Q11 = READ_UINT32((const byte *)src->getBasePtr((int)(x1 + srcRect.left),(int)(y1 + srcRect.top)));
+ }
+
+ if (x1 >= srcW || x1 < 0 || y2 >= srcH || y2 < 0) {
+ Q12 = 0;
+ } else {
+ Q12 = READ_UINT32((const byte *)src->getBasePtr((int)(x1 + srcRect.left), (int)(y2 + srcRect.top)));
+ }
+
+ if (x2 >= srcW || x2 < 0 || y1 >= srcH || y1 < 0) {
+ Q21 = 0;
+ } else {
+ Q21 = READ_UINT32((const byte *)src->getBasePtr((int)(x2 + srcRect.left), (int)(y1 + srcRect.top)));
+ }
+
+ if (x2 >= srcW || x2 < 0 || y2 >= srcH || y2 < 0) {
+ Q22 = 0;
+ } else {
+ Q22 = READ_UINT32((const byte *)src->getBasePtr((int)(x2 + srcRect.left), (int)(y2 + srcRect.top)));
+ }
+
+ byte *Q11s = (byte *)&Q11;
+ byte *Q12s = (byte *)&Q12;
+ byte *Q21s = (byte *)&Q21;
+ byte *Q22s = (byte *)&Q22;
+
+ uint32 color;
+ byte *dest = (byte *)&color;
+
+ float q11x = (x2 - projX);
+ float q11y = (y2 - projY);
+ float q21x = (projX - x1);
+ float q21y = (y2 - projY);
+ float q12x = (x2 - projX);
+ float q12y = (projY - y1);
+
+ if (x1 == x2 && y1 == y2) {
+ for (int c = 0; c < 4; c++) {
+ dest[c] = ((float)Q11s[c]);
+ }
+ } else {
+
+ if (x1 == x2) {
+ q11x = 0.5;
+ q12x = 0.5;
+ q21x = 0.5;
+ } else if (y1 == y2) {
+ q11y = 0.5;
+ q12y = 0.5;
+ q21y = 0.5;
+ }
+
+ for (int c = 0; c < 4; c++) {
+ dest[c] = (byte)(
+ ((float)Q11s[c]) * q11x * q11y +
+ ((float)Q21s[c]) * q21x * q21y +
+ ((float)Q12s[c]) * q12x * q12y +
+ ((float)Q22s[c]) * (1.0 -
+ q11x * q11y -
+ q21x * q21y -
+ q12x * q12y)
+ );
+ }
+ }
+ WRITE_UINT32((byte *)dst->getBasePtr(dstX + dstRect.left, dstY + dstRect.top), color);
+}
+#else
+void TransparentSurface::copyPixelNearestNeighbor(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst) {
+ int srcW = srcRect.width();
+ int srcH = srcRect.height();
+ int dstW = dstRect.width();
+ int dstH = dstRect.height();
+
+ assert(dstX >= 0 && dstX < dstW);
+ assert(dstY >= 0 && dstY < dstH);
+
+ uint32 color;
+
+ if (projX >= srcW || projX < 0 || projY >= srcH || projY < 0) {
+ color = 0;
+ } else {
+ color = READ_UINT32((const byte *)src->getBasePtr((int)projX, (int)projY));
+ }
+
+ WRITE_UINT32((byte *)dst->getBasePtr(dstX, dstY), color);
+}
+#endif
+
byte *TransparentSurface::_lookup = nullptr;
void TransparentSurface::destroyLookup() {
@@ -250,12 +362,12 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p
int inStep = 4;
int inoStep = img->pitch;
- if (flipping & TransparentSurface::FLIP_V) {
+ if (flipping & TransparentSurface::FLIP_H) {
inStep = -inStep;
xp = img->w - 1;
}
- if (flipping & TransparentSurface::FLIP_H) {
+ if (flipping & TransparentSurface::FLIP_V) {
inoStep = -inoStep;
yp = img->h - 1;
}
@@ -383,16 +495,54 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p
return retSize;
}
-TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight) const {
+TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transform) const {
+
+ assert(transform._angle != 0); // This would not be ideal; rotoscale() should never be called in conditional branches where angle = 0 anyway.
+
+ Point32 newHotspot;
Common::Rect srcRect(0, 0, (int16)w, (int16)h);
- Common::Rect dstRect(0, 0, (int16)newWidth, (int16)newHeight);
- return scale(srcRect, dstRect);
+ Rect32 rect = TransformTools::newRect(Rect32 (srcRect), transform, &newHotspot);
+ Common::Rect dstRect(0, 0, (int16)(rect.right - rect.left), (int16)(rect.bottom - rect.top));
+
+ TransparentSurface *target = new TransparentSurface();
+ assert(format.bytesPerPixel == 4);
+
+ int dstW = dstRect.width();
+ int dstH = dstRect.height();
+
+ target->create((uint16)dstW, (uint16)dstH, this->format);
+
+ uint32 invAngle = 360 - (transform._angle % 360);
+ float invCos = cos(invAngle * M_PI / 180.0);
+ float invSin = sin(invAngle * M_PI / 180.0);
+ float targX;
+ float targY;
+
+ for (int y = 0; y < dstH; y++) {
+ for (int x = 0; x < dstW; x++) {
+ int x1 = x - newHotspot.x;
+ int y1 = y - newHotspot.y;
+
+ targX = ((x1 * invCos - y1 * invSin)) * kDefaultZoomX / transform._zoom.x + srcRect.left;
+ targY = ((x1 * invSin + y1 * invCos)) * kDefaultZoomY / transform._zoom.y + srcRect.top;
+
+ targX += transform._hotspot.x;
+ targY += transform._hotspot.y;
+
+#if ENABLE_BILINEAR
+ copyPixelBilinear(targX, targY, x, y, srcRect, dstRect, this, target);
+#else
+ copyPixelNearestNeighbor(targX, targY, x, y, srcRect, dstRect, this, target);
+#endif
+ }
+ }
+ return target;
}
-// Copied from clone2727's https://github.com/clone2727/scummvm/blob/pegasus/engines/pegasus/surface.cpp#L247
-TransparentSurface *TransparentSurface::scale(const Common::Rect &srcRect, const Common::Rect &dstRect) const {
- // I'm doing simple linear scaling here
- // dstRect(x, y) = srcRect(x * srcW / dstW, y * srcH / dstH);
+TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight) const {
+ Common::Rect srcRect(0, 0, (int16)w, (int16)h);
+ Common::Rect dstRect(0, 0, (int16)newWidth, (int16)newHeight);
+
TransparentSurface *target = new TransparentSurface();
assert(format.bytesPerPixel == 4);
@@ -404,11 +554,18 @@ TransparentSurface *TransparentSurface::scale(const Common::Rect &srcRect, const
target->create((uint16)dstW, (uint16)dstH, this->format);
+
+ float projX;
+ float projY;
for (int y = 0; y < dstH; y++) {
for (int x = 0; x < dstW; x++) {
- uint32 color = READ_UINT32((const byte *)getBasePtr(x * srcW / dstW + srcRect.left,
- y * srcH / dstH + srcRect.top));
- WRITE_UINT32((byte *)target->getBasePtr(x + dstRect.left, y + dstRect.top), color);
+ projX = x / (float)dstW * srcW;
+ projY = y / (float)dstH * srcH;
+#if ENABLE_BILINEAR
+ copyPixelBilinear(projX, projY, x, y, srcRect, dstRect, this, target);
+#else
+ copyPixelNearestNeighbor(projX, projY, x, y, srcRect, dstRect, this, target);
+#endif
}
}
return target;
diff --git a/engines/wintermute/graphics/transparent_surface.h b/engines/wintermute/graphics/transparent_surface.h
index dc079a1fbc..7b5579f389 100644
--- a/engines/wintermute/graphics/transparent_surface.h
+++ b/engines/wintermute/graphics/transparent_surface.h
@@ -23,6 +23,10 @@
#define GRAPHICS_TRANSPARENTSURFACE_H
#include "graphics/surface.h"
+#include "engines/wintermute/graphics/transform_struct.h"
+
+#define ENABLE_BILINEAR 0
+
/*
* This code is based on Broken Sword 2.5 engine
@@ -49,6 +53,11 @@ struct TransparentSurface : public Graphics::Surface {
void setColorKey(char r, char g, char b);
void disableColorKey();
+#if ENABLE_BILINEAR
+ static void copyPixelBilinear(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst);
+#else
+ static void copyPixelNearestNeighbor(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst);
+#endif
// Enums
/**
@brief The possible flipping parameters for the blit methode.
@@ -102,9 +111,9 @@ struct TransparentSurface : public Graphics::Surface {
uint color = BS_ARGB(255, 255, 255, 255),
int width = -1, int height = -1);
void applyColorKey(uint8 r, uint8 g, uint8 b, bool overwriteAlpha = false);
- // The following scale-code supports arbitrary scaling (i.e. no repeats of column 0 at the end of lines)
- TransparentSurface *scale(uint16 newWidth, uint16 newHeight) const;
- TransparentSurface *scale(const Common::Rect &srcRect, const Common::Rect &dstRect) const;
+
+ TransparentSurface *scale (uint16 newWidth, uint16 newHeight) const;
+ TransparentSurface *rotoscale (const TransformStruct &transform) const;
static byte *_lookup;
static void destroyLookup();
private:
diff --git a/engines/wintermute/math/floatpoint.h b/engines/wintermute/math/floatpoint.h
new file mode 100644
index 0000000000..0c47ef09d7
--- /dev/null
+++ b/engines/wintermute/math/floatpoint.h
@@ -0,0 +1,52 @@
+/* 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.
+ *
+ */
+
+#ifndef WINTERMUTE_FLOATPOINT_H
+#define WINTERMUTE_FLOATPOINT_H
+
+namespace Wintermute {
+
+struct FloatPoint {
+ float x;
+ float y;
+ FloatPoint() : x(0), y(0) {}
+ FloatPoint(float x1, float y1) : x(x1), y(y1) {}
+ bool operator==(const FloatPoint &p) const { return x == p.x && y == p.y; }
+ bool operator!=(const FloatPoint &p) const { return x != p.x || y != p.y; }
+ FloatPoint operator+(const FloatPoint &delta) const { return FloatPoint (x + delta.x, y + delta.y); }
+ FloatPoint operator-(const FloatPoint &delta) const { return FloatPoint (x - delta.x, y - delta.y); }
+
+ FloatPoint& operator+=(const FloatPoint &delta) {
+ x += delta.x;
+ y += delta.y;
+ return *this;
+ }
+ FloatPoint& operator-=(const FloatPoint &delta) {
+ x -= delta.x;
+ y -= delta.y;
+ return *this;
+ }
+};
+
+} // End of namespace Wintermute
+
+#endif
diff --git a/engines/wintermute/math/rect32.h b/engines/wintermute/math/rect32.h
index 190c1135cf..79d6e80017 100644
--- a/engines/wintermute/math/rect32.h
+++ b/engines/wintermute/math/rect32.h
@@ -24,12 +24,38 @@
#define WINTERMUTE_RECT32_H
#include "common/system.h"
+#include "engines/wintermute/math/floatpoint.h"
+#include "common/rect.h"
namespace Wintermute {
struct Point32 {
int32 x;
int32 y;
+ Point32() : x(0), y(0) {}
+ Point32(int32 x1, int32 y1) : x(x1), y(y1) {}
+ bool operator==(const Point32 &p) const { return x == p.x && y == p.y; }
+ bool operator!=(const Point32 &p) const { return x != p.x || y != p.y; }
+ Point32 operator+(const Point32 &delta) const { return Point32(x + delta.x, y + delta.y); }
+ Point32 operator-(const Point32 &delta) const { return Point32(x - delta.x, y - delta.y); }
+
+ Point32 &operator+=(const Point32 &delta) {
+ x += delta.x;
+ y += delta.y;
+ return *this;
+ }
+
+ Point32 &operator-=(const Point32 &delta) {
+ x -= delta.x;
+ y -= delta.y;
+ return *this;
+ }
+
+ operator FloatPoint() {
+ return FloatPoint(x,y);
+ }
+
+
};
struct Rect32 {
@@ -38,6 +64,7 @@ struct Rect32 {
Rect32() : top(0), left(0), bottom(0), right(0) {}
Rect32(int32 w, int32 h) : top(0), left(0), bottom(h), right(w) {}
+ Rect32(const Common::Rect &rect) : top(rect.top), left(rect.left), bottom(rect.bottom), right(rect.right) {}
Rect32(int32 x1, int32 y1, int32 x2, int32 y2) : top(y1), left(x1), bottom(y2), right(x2) {
assert(isValidRect());
}
diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk
index 32931bf05f..95f9ba2ffb 100644
--- a/engines/wintermute/module.mk
+++ b/engines/wintermute/module.mk
@@ -89,6 +89,8 @@ MODULE_OBJS := \
base/save_thumb_helper.o \
base/timer.o \
detection.o \
+ graphics/transform_struct.o \
+ graphics/transform_tools.o \
graphics/transparent_surface.o \
math/math_util.o \
math/matrix4.o \
diff --git a/graphics/scaler.h b/graphics/scaler.h
index 54d022d202..1e5b796631 100644
--- a/graphics/scaler.h
+++ b/graphics/scaler.h
@@ -89,10 +89,4 @@ extern bool createThumbnailFromScreen(Graphics::Surface *surf);
*/
extern bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h, const uint8 *palette);
-/**
- * Downscale screenshot to thumbnale size.
- *
- */
-extern bool createThumbnail(Graphics::Surface &out, Graphics::Surface &in);
-
#endif
diff --git a/graphics/scaler/thumbnail_intern.cpp b/graphics/scaler/thumbnail_intern.cpp
index 8a98263eee..2756e4026a 100644
--- a/graphics/scaler/thumbnail_intern.cpp
+++ b/graphics/scaler/thumbnail_intern.cpp
@@ -42,8 +42,10 @@ uint16 quadBlockInterpolate(const uint8 *src, uint32 srcPitch) {
template<int bitFormat>
void createThumbnail_2(const uint8 *src, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
- assert(width % 2 == 0);
- assert(height % 2 == 0);
+ // Make sure the width and height is a multiple of 2.
+ width &= ~1;
+ height &= ~1;
+
for (int y = 0; y < height; y += 2) {
for (int x = 0; x < width; x += 2, dstPtr += 2) {
*((uint16 *)dstPtr) = quadBlockInterpolate<bitFormat>(src + 2 * x, srcPitch);
@@ -55,8 +57,10 @@ void createThumbnail_2(const uint8 *src, uint32 srcPitch, uint8 *dstPtr, uint32
template<int bitFormat>
void createThumbnail_4(const uint8 *src, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
- assert(width % 4 == 0);
- assert(height % 4 == 0);
+ // Make sure the width and height is a multiple of 4
+ width &= ~3;
+ height &= ~3;
+
for (int y = 0; y < height; y += 4) {
for (int x = 0; x < width; x += 4, dstPtr += 2) {
uint16 upleft = quadBlockInterpolate<bitFormat>(src + 2 * x, srcPitch);
@@ -71,17 +75,88 @@ void createThumbnail_4(const uint8 *src, uint32 srcPitch, uint8 *dstPtr, uint32
}
}
-static void createThumbnail(const uint8 *src, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
- // only 1/2 and 1/4 downscale supported
- if (width != 320 && width != 640)
- return;
+static void scaleThumbnail(Graphics::Surface &in, Graphics::Surface &out) {
+ while (in.w / out.w >= 4 || in.h / out.h >= 4) {
+ createThumbnail_4<565>((const uint8 *)in.pixels, in.pitch, (uint8 *)in.pixels, in.pitch, in.w, in.h);
+ in.w /= 4;
+ in.h /= 4;
+ }
+
+ while (in.w / out.w >= 2 || in.h / out.h >= 2) {
+ createThumbnail_2<565>((const uint8 *)in.pixels, in.pitch, (uint8 *)in.pixels, in.pitch, in.w, in.h);
+ in.w /= 2;
+ in.h /= 2;
+ }
+
+ if ((in.w == out.w && in.h < out.h) || (in.w < out.w && in.h == out.h)) {
+ // In this case we simply center the input surface in the output
+ uint8 *dst = (uint8 *)out.getBasePtr((out.w - in.w) / 2, (out.h - in.h) / 2);
+ const uint8 *src = (const uint8 *)in.getBasePtr(0, 0);
+
+ for (int y = 0; y < in.h; ++y) {
+ memcpy(dst, src, in.w * in.format.bytesPerPixel);
+ src += in.pitch;
+ dst += out.pitch;
+ }
+ } else {
+ // Assure the aspect of the scaled image still matches the original.
+ int targetWidth = out.w, targetHeight = out.h;
+
+ const float inputAspect = (float)in.w / in.h;
+ const float outputAspect = (float)out.w / out.h;
+
+ if (inputAspect > outputAspect) {
+ targetHeight = int(targetWidth / inputAspect);
+ } else if (inputAspect < outputAspect) {
+ targetWidth = int(targetHeight * inputAspect);
+ }
+
+ // Make sure we are still in the bounds of the output
+ assert(targetWidth <= out.w);
+ assert(targetHeight <= out.h);
+
+ // Center the image on the output surface
+ byte *dst = (byte *)out.getBasePtr((out.w - targetWidth) / 2, (out.h - targetHeight) / 2);
+ const uint dstLineIncrease = out.pitch - targetWidth * out.format.bytesPerPixel;
+
+ const float scaleFactorX = (float)targetWidth / in.w;
+ const float scaleFactorY = (float)targetHeight / in.h;
+
+ for (int y = 0; y < targetHeight; ++y) {
+ const float yFrac = (y / scaleFactorY);
+ const int y1 = (int)yFrac;
+ const int y2 = (y1 + 1 < in.h) ? (y1 + 1) : (in.h - 1);
+
+ for (int x = 0; x < targetWidth; ++x) {
+ const float xFrac = (x / scaleFactorX);
+ const int x1 = (int)xFrac;
+ const int x2 = (x1 + 1 < in.w) ? (x1 + 1) : (in.w - 1);
+
+ // Look up colors at the points
+ uint8 p1R, p1G, p1B;
+ Graphics::colorToRGB<Graphics::ColorMasks<565> >(READ_UINT16(in.getBasePtr(x1, y1)), p1R, p1G, p1B);
+ uint8 p2R, p2G, p2B;
+ Graphics::colorToRGB<Graphics::ColorMasks<565> >(READ_UINT16(in.getBasePtr(x2, y1)), p2R, p2G, p2B);
+ uint8 p3R, p3G, p3B;
+ Graphics::colorToRGB<Graphics::ColorMasks<565> >(READ_UINT16(in.getBasePtr(x1, y2)), p3R, p3G, p3B);
+ uint8 p4R, p4G, p4B;
+ Graphics::colorToRGB<Graphics::ColorMasks<565> >(READ_UINT16(in.getBasePtr(x2, y2)), p4R, p4G, p4B);
+
+ const float xDiff = xFrac - x1;
+ const float yDiff = yFrac - y1;
+
+ uint8 pR = ((1 - yDiff) * ((1 - xDiff) * p1R + xDiff * p2R) + yDiff * ((1 - xDiff) * p3R + xDiff * p4R));
+ uint8 pG = ((1 - yDiff) * ((1 - xDiff) * p1G + xDiff * p2G) + yDiff * ((1 - xDiff) * p3G + xDiff * p4G));
+ uint8 pB = ((1 - yDiff) * ((1 - xDiff) * p1B + xDiff * p2B) + yDiff * ((1 - xDiff) * p3B + xDiff * p4B));
- int downScaleMode = (width == 320) ? 2 : 4;
- if (downScaleMode == 2) {
- createThumbnail_2<565>(src, srcPitch, dstPtr, dstPitch, width, height);
- } else if (downScaleMode == 4) {
- createThumbnail_4<565>(src, srcPitch, dstPtr, dstPitch, width, height);
+ WRITE_UINT16(dst, Graphics::RGBToColor<Graphics::ColorMasks<565> >(pR, pG, pB));
+ dst += 2;
+ }
+
+ // Move to the next line
+ dst = (byte *)dst + dstLineIncrease;
+ }
}
}
@@ -134,75 +209,17 @@ static bool grabScreen565(Graphics::Surface *surf) {
return true;
}
-bool createThumbnail(Graphics::Surface &out, Graphics::Surface &in) {
- uint16 width = in.w;
- uint16 inHeight = in.h;
-
- if (width < 320) {
- // Special case to handle MM NES (uses a screen width of 256)
- width = 320;
-
- // center MM NES screen
- Graphics::Surface newscreen;
- newscreen.create(width, in.h, in.format);
-
- uint8 *dst = (uint8 *)newscreen.getBasePtr((320 - in.w) / 2, 0);
- const uint8 *src = (const uint8 *)in.getBasePtr(0, 0);
- uint16 height = in.h;
-
- while (height--) {
- memcpy(dst, src, in.pitch);
- dst += newscreen.pitch;
- src += in.pitch;
- }
-
- in.free();
- in = newscreen;
- } else if (width == 720) {
- // Special case to handle Hercules mode
- //
- // NOTE: This code is pretty SCUMM specific.
- // For other games this code might cut off
- // not only the menu, but also other graphics.
- width = 640;
- inHeight = 400;
-
- // cut off menu and so on..
- Graphics::Surface newscreen;
- newscreen.create(width, 400, in.format);
-
- uint8 *dst = (uint8 *)newscreen.getBasePtr(0, (400 - 240) / 2);
- const uint8 *src = (const uint8 *)in.getBasePtr(41, 28);
-
- for (int y = 0; y < 240; ++y) {
- memcpy(dst, src, 640 * in.format.bytesPerPixel);
- dst += newscreen.pitch;
- src += in.pitch;
- }
-
- in.free();
- in = newscreen;
- } else if (width == 640 && inHeight == 440) {
- // Special case to handle KQ6 Windows: resize the screen to 640x480,
- // adding a black band in the bottom.
- inHeight = 480;
-
- Graphics::Surface newscreen;
- newscreen.create(width, 480, in.format);
-
- memcpy(newscreen.getBasePtr(0, 0), in.getBasePtr(0, 0), width * 440 * in.format.bytesPerPixel);
-
- in.free();
- in = newscreen;
+static bool createThumbnail(Graphics::Surface &out, Graphics::Surface &in) {
+ int height;
+ if ((in.w == 320 && in.h == 200) || (in.w == 640 && in.h == 400)) {
+ height = kThumbnailHeight1;
+ } else {
+ height = kThumbnailHeight2;
}
- uint16 newHeight = !(inHeight % 240) ? kThumbnailHeight2 : kThumbnailHeight1;
-
- out.create(kThumbnailWidth, newHeight, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
- createThumbnail((const uint8 *)in.pixels, width * sizeof(uint16), (uint8 *)out.pixels, out.pitch, width, inHeight);
-
+ out.create(kThumbnailWidth, height, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
+ scaleThumbnail(in, out);
in.free();
-
return true;
}
diff --git a/graphics/surface.cpp b/graphics/surface.cpp
index 41ae8dcebb..010389c9fa 100644
--- a/graphics/surface.cpp
+++ b/graphics/surface.cpp
@@ -84,7 +84,17 @@ void Surface::free() {
void Surface::copyFrom(const Surface &surf) {
create(surf.w, surf.h, surf.format);
- memcpy(pixels, surf.pixels, h * pitch);
+ if (surf.pitch == pitch) {
+ memcpy(pixels, surf.pixels, h * pitch);
+ } else {
+ const byte *src = (const byte *)surf.pixels;
+ byte *dst = (byte *)pixels;
+ for (int y = h; y > 0; --y) {
+ memcpy(dst, src, w * format.bytesPerPixel);
+ src += surf.pitch;
+ dst += pitch;
+ }
+ }
}
void Surface::hLine(int x, int y, int x2, uint32 color) {