[Scummvm-git-logs] scummvm master -> 7e42ae4eecc32ca59cbb1834a8c29cab8f733171
dreammaster
dreammaster at scummvm.org
Thu Jul 8 05:08:35 UTC 2021
This automated email contains information about 8 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
41b1126aed AGS: Split SpriteCache, picking out read/write into SpriteFile class
7e322be394 AGS: Moved image (de)compression functions out from SpriteFile
bfabf7c94d AGS: Fixed infinite wait in Object_Move under specific conditions
e582a09612 AGS: Reprogram file/path functions to always use UTF-8 encoding
81f0088064 AGS: Start in the UTF-8 mode, switch encoding based on game data
5dc90dabc4 AGS: Added encoding hint to the TRS/TRA
93bc3a65d4 AGS: use text encoding hint from translation
7e42ae4eec MOHAWK: Revert incorrect format specifier changes
Commit: 41b1126aed5b68318081613794decf0bd3937df6
https://github.com/scummvm/scummvm/commit/41b1126aed5b68318081613794decf0bd3937df6
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-07T22:07:09-07:00
Commit Message:
AGS: Split SpriteCache, picking out read/write into SpriteFile class
>From upstream 565eaaf90e63ad444798cd949b1e4c60dfb4a0f8
Changed paths:
engines/ags/engine/ac/global_game.cpp
engines/ags/engine/ac/sprite.cpp
engines/ags/engine/ac/sprite.h
engines/ags/engine/ac/sprite_cache_engine.cpp
engines/ags/engine/main/engine.cpp
engines/ags/shared/ac/sprite_cache.cpp
engines/ags/shared/ac/sprite_cache.h
diff --git a/engines/ags/engine/ac/global_game.cpp b/engines/ags/engine/ac/global_game.cpp
index 2a32cdf1a5..6dea34994e 100644
--- a/engines/ags/engine/ac/global_game.cpp
+++ b/engines/ags/engine/ac/global_game.cpp
@@ -287,7 +287,7 @@ int RunAGSGame(const String &newgame, unsigned int mode, int data) {
quitprintf("!RunAGSGame: error loading new game file:\n%s", err->FullMessage().GetCStr());
_GP(spriteset).Reset();
- err = _GP(spriteset).InitFile(SpriteCache::DefaultSpriteFileName, SpriteCache::DefaultSpriteIndexName);
+ err = _GP(spriteset).InitFile(SpriteFile::DefaultSpriteFileName, SpriteFile::DefaultSpriteIndexName);
if (!err)
quitprintf("!RunAGSGame: error loading new sprites:\n%s", err->FullMessage().GetCStr());
diff --git a/engines/ags/engine/ac/sprite.cpp b/engines/ags/engine/ac/sprite.cpp
index 65ba472c43..802e75e63e 100644
--- a/engines/ags/engine/ac/sprite.cpp
+++ b/engines/ags/engine/ac/sprite.cpp
@@ -110,7 +110,7 @@ Bitmap *remove_alpha_channel(Bitmap *from) {
return to;
}
-void pre_save_sprite(int ee) {
+void pre_save_sprite(Bitmap *image) {
// not used, we don't save
}
diff --git a/engines/ags/engine/ac/sprite.h b/engines/ags/engine/ac/sprite.h
index 8995e76fec..1731c17586 100644
--- a/engines/ags/engine/ac/sprite.h
+++ b/engines/ags/engine/ac/sprite.h
@@ -31,7 +31,7 @@ void get_new_size_for_sprite(int ee, int ww, int hh, int &newwid, int &newhit);
void set_rgb_mask_using_alpha_channel(Shared::Bitmap *image);
// from is a 32-bit RGBA image, to is a 15/16/24-bit destination image
Shared::Bitmap *remove_alpha_channel(Shared::Bitmap *from);
-void pre_save_sprite(int ee);
+void pre_save_sprite(Shared::Bitmap *bitmap);
void initialize_sprite(int ee);
} // namespace AGS3
diff --git a/engines/ags/engine/ac/sprite_cache_engine.cpp b/engines/ags/engine/ac/sprite_cache_engine.cpp
index 52010c83bb..7b2a40b512 100644
--- a/engines/ags/engine/ac/sprite_cache_engine.cpp
+++ b/engines/ags/engine/ac/sprite_cache_engine.cpp
@@ -48,7 +48,6 @@ void SpriteCache::InitNullSpriteParams(sprkey_t index) {
_sprInfos[index].Width = _sprInfos[0].Width;
_sprInfos[index].Height = _sprInfos[0].Height;
_spriteData[index].Image = nullptr;
- _spriteData[index].Offset = _spriteData[0].Offset;
_spriteData[index].Size = _spriteData[0].Size;
_spriteData[index].Flags = SPRCACHEFLAG_REMAPPED;
}
diff --git a/engines/ags/engine/main/engine.cpp b/engines/ags/engine/main/engine.cpp
index 09eac0be40..657b4c1615 100644
--- a/engines/ags/engine/main/engine.cpp
+++ b/engines/ags/engine/main/engine.cpp
@@ -583,13 +583,13 @@ void show_preload() {
int engine_init_sprites() {
Debug::Printf(kDbgMsg_Info, "Initialize sprites");
- HError err = _GP(spriteset).InitFile(SpriteCache::DefaultSpriteFileName, SpriteCache::DefaultSpriteIndexName);
+ HError err = _GP(spriteset).InitFile(SpriteFile::DefaultSpriteFileName, SpriteFile::DefaultSpriteIndexName);
if (!err) {
sys_main_shutdown();
allegro_exit();
_G(proper_exit) = 1;
_G(platform)->DisplayAlert("Could not load sprite set file %s\n%s",
- SpriteCache::DefaultSpriteFileName.GetCStr(),
+ SpriteFile::DefaultSpriteFileName,
err->FullMessage().GetCStr());
return EXIT_ERROR;
}
diff --git a/engines/ags/shared/ac/sprite_cache.cpp b/engines/ags/shared/ac/sprite_cache.cpp
index 847283251e..a081c07ea9 100644
--- a/engines/ags/shared/ac/sprite_cache.cpp
+++ b/engines/ags/shared/ac/sprite_cache.cpp
@@ -33,6 +33,7 @@
#endif
#include "common/system.h"
+#include "ags/lib/std/algorithm.h"
#include "ags/shared/ac/common.h" // quit
#include "ags/shared/ac/game_struct_defines.h"
#include "ags/shared/ac/sprite_cache.h"
@@ -50,7 +51,7 @@ using namespace AGS::Shared;
// [IKM] We have to forward-declare these because their implementations are in the Engine
extern void initialize_sprite(int);
-extern void pre_save_sprite(int);
+extern void pre_save_sprite(Bitmap *image);
extern void get_new_size_for_sprite(int, int, int, int &, int &);
#define START_OF_LIST -1
@@ -59,9 +60,8 @@ extern void get_new_size_for_sprite(int, int, int, int &, int &);
const char *spindexid = "SPRINDEX";
// TODO: should not be part of SpriteCache, but rather some asset management class?
-const String SpriteCache::DefaultSpriteFileName = "acsprset.spr";
-const String SpriteCache::DefaultSpriteIndexName = "sprindex.dat";
-
+const char *const SpriteFile::DefaultSpriteFileName = "acsprset.spr";
+const char *const SpriteFile::DefaultSpriteIndexName = "sprindex.dat";
SpriteInfo::SpriteInfo()
: Flags(0)
@@ -70,8 +70,7 @@ SpriteInfo::SpriteInfo()
}
SpriteCache::SpriteData::SpriteData()
- : Offset(0)
- , Size(0)
+ : Size(0)
, Flags(0)
, Image(nullptr) {
}
@@ -82,9 +81,13 @@ SpriteCache::SpriteData::~SpriteData() {
}
+SpriteFile::SpriteFile() {
+ _compressed = false;
+ _curPos = -2;
+}
+
SpriteCache::SpriteCache(std::vector<SpriteInfo> &sprInfos)
: _sprInfos(sprInfos) {
- _compressed = false;
Init();
}
@@ -108,10 +111,10 @@ size_t SpriteCache::GetSpriteSlotCount() const {
return _spriteData.size();
}
-sprkey_t SpriteCache::FindTopmostSprite() const {
+sprkey_t SpriteFile::FindTopmostSprite(const std::vector<Bitmap *> &sprites) {
sprkey_t topmost = -1;
- for (sprkey_t i = 0; i < static_cast<sprkey_t>(_spriteData.size()); ++i)
- if (DoesSpriteExist(i))
+ for (sprkey_t i = 0; i < static_cast<sprkey_t>(sprites.size()); ++i)
+ if (sprites[i])
topmost = i;
return topmost;
}
@@ -126,11 +129,10 @@ void SpriteCache::Init() {
_maxCacheSize = (size_t)DEFAULTCACHESIZE_KB * 1024;
_liststart = -1;
_listend = -1;
- _lastLoad = -2;
}
void SpriteCache::Reset() {
- _stream.reset();
+ _file.Reset();
// TODO: find out if it's safe to simply always delete _spriteData.Image with array element
for (size_t i = 0; i < _spriteData.size(); ++i) {
if (_spriteData[i].Image) {
@@ -157,7 +159,6 @@ void SpriteCache::SetSprite(sprkey_t index, Bitmap *sprite) {
}
_spriteData[index].Image = sprite;
_spriteData[index].Flags = SPRCACHEFLAG_LOCKED; // NOT from asset file
- _spriteData[index].Offset = 0;
_spriteData[index].Size = 0;
#ifdef DEBUG_SPRITECACHE
Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Debug, "SetSprite: (external) %d", index);
@@ -174,7 +175,7 @@ void SpriteCache::SetEmptySprite(sprkey_t index, bool as_asset) {
RemapSpriteToSprite0(index);
}
-void SpriteCache::SubstituteBitmap(sprkey_t index, Shared::Bitmap *sprite) {
+void SpriteCache::SubstituteBitmap(sprkey_t index, Bitmap *sprite) {
if (!DoesSpriteExist(index)) {
Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Error, "SubstituteBitmap: attempt to set for non-existing sprite %d", index);
return;
@@ -223,7 +224,7 @@ sprkey_t SpriteCache::GetFreeIndex() {
bool SpriteCache::SpriteData::DoesSpriteExist() const {
return (Image != nullptr) || // HAS loaded bitmap
- ((Flags & SPRCACHEFLAG_ISASSET) != 0); // OR found in the game resources
+ ((Flags & SPRCACHEFLAG_ISASSET) != 0); // OR found in the game resources
}
bool SpriteCache::SpriteData::IsAssetSprite() const {
@@ -232,8 +233,8 @@ bool SpriteCache::SpriteData::IsAssetSprite() const {
bool SpriteCache::SpriteData::IsExternalSprite() const {
return (Image != nullptr) && // HAS loaded bitmap
- ((Flags & SPRCACHEFLAG_ISASSET) == 0) && // AND NOT found in game resources
- ((Flags & SPRCACHEFLAG_REMAPPED) == 0); // AND was NOT remapped to another sprite
+ ((Flags & SPRCACHEFLAG_ISASSET) == 0) && // AND NOT found in game resources
+ ((Flags & SPRCACHEFLAG_REMAPPED) == 0); // AND was NOT remapped to another sprite
}
bool SpriteCache::SpriteData::IsLocked() const {
@@ -244,7 +245,7 @@ bool SpriteCache::DoesSpriteExist(sprkey_t index) const {
return index >= 0 && (size_t)index < _spriteData.size() && _spriteData[index].DoesSpriteExist();
}
-Bitmap *SpriteCache::operator [](sprkey_t index) {
+Bitmap *SpriteCache::operator [] (sprkey_t index) {
// invalid sprite slot
if (index < 0 || (size_t)index >= _spriteData.size())
return nullptr;
@@ -327,7 +328,7 @@ void SpriteCache::DisposeOldest() {
// There must be a bug somewhere causing this, but for now
// let's just reset the cache
Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Error, "RUNTIME CACHE ERROR: CACHE INCONSISTENT: RESETTING\n\tAt size %d (of %d), start %d end %d fwdlink=%d",
- _cacheSize, _maxCacheSize, oldstart, _listend, _liststart);
+ _cacheSize, _maxCacheSize, oldstart, _listend, _liststart);
DisposeAll();
}
}
@@ -342,7 +343,8 @@ void SpriteCache::DisposeAll() {
_listend = -1;
for (size_t i = 0; i < _spriteData.size(); ++i) {
if (!_spriteData[i].IsLocked() && // not locked
- _spriteData[i].IsAssetSprite()) { // sprite from game resource
+ _spriteData[i].IsAssetSprite()) // sprite from game resource
+ {
delete _spriteData[i].Image;
_spriteData[i].Image = nullptr;
}
@@ -378,10 +380,12 @@ sprkey_t SpriteCache::GetDataIndex(sprkey_t index) {
return (_spriteData[index].Flags & SPRCACHEFLAG_REMAPPED) == 0 ? index : 0;
}
-void SpriteCache::SeekToSprite(sprkey_t index) {
+void SpriteFile::SeekToSprite(sprkey_t index) {
// If we didn't just load the previous sprite, seek to it
- if (index - 1 != _lastLoad)
+ if (index != _curPos) {
_stream->Seek(_spriteData[index].Offset, kSeekBegin);
+ _curPos = index;
+ }
}
size_t SpriteCache::LoadSprite(sprkey_t index) {
@@ -400,54 +404,21 @@ size_t SpriteCache::LoadSprite(sprkey_t index) {
quit("sprite cache array index out of bounds");
sprkey_t load_index = GetDataIndex(index);
- SeekToSprite(load_index);
-
- int coldep = _stream->ReadInt16();
-
- if (coldep == 0) {
- Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Error, "LoadSprite: asked to load sprite %d (for slot %d) which does not exist.", load_index, index);
- _lastLoad = load_index;
- return 0;
- }
-
- int wdd = _stream->ReadInt16();
- int htt = _stream->ReadInt16();
- Bitmap *image = BitmapHelper::CreateBitmap(wdd, htt, coldep * 8);
- if (image == nullptr) {
- Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Warn, "LoadSprite: failed to init sprite %d, remapping to sprite 0.", index);
+ Bitmap *image;
+ HError err = _file.LoadSprite(load_index, image);
+ if (!image) {
+ Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Warn,
+ "LoadSprite: failed to load sprite %d:\n%s\n - remapping to sprite 0.", index,
+ err ? err->FullMessage().GetCStr() : "Sprite does not exist.");
RemapSpriteToSprite0(index);
return 0;
}
- if (this->_compressed) {
- size_t data_size = _stream->ReadInt32();
- if (data_size == 0) {
- Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Warn, "LoadSprite: bad compressed data for sprite %d, remapping to sprite 0.", index);
- delete image;
- RemapSpriteToSprite0(index);
- return 0;
- }
- UnCompressSprite(image, _stream.get());
- } else {
- if (coldep == 1) {
- for (hh = 0; hh < htt; hh++)
- _stream->ReadArray(&image->GetScanLineForWriting(hh)[0], coldep, wdd);
- } else if (coldep == 2) {
- for (hh = 0; hh < htt; hh++)
- _stream->ReadArrayOfInt16((int16_t *)&image->GetScanLineForWriting(hh)[0], wdd);
- } else {
- for (hh = 0; hh < htt; hh++)
- _stream->ReadArrayOfInt32((int32_t *)&image->GetScanLineForWriting(hh)[0], wdd);
- }
- }
-
// update the stored width/height
- _sprInfos[index].Width = wdd;
- _sprInfos[index].Height = htt;
+ _sprInfos[index].Width = image->GetWidth();
+ _sprInfos[index].Height = image->GetHeight();
_spriteData[index].Image = image;
- _lastLoad = load_index;
-
// Stop it adding the sprite to the used list just because it's loaded
// TODO: this messy hack is required, because initialize_sprite calls operator[]
// which puts the sprite to the MRU list.
@@ -463,7 +434,8 @@ size_t SpriteCache::LoadSprite(sprkey_t index) {
// we need to store this because the main program might
// alter spritewidth/height if it resizes stuff
- size_t size = _sprInfos[index].Width * _sprInfos[index].Height * coldep;
+ size_t size = _sprInfos[index].Width * _sprInfos[index].Height *
+ _spriteData[index].Image->GetBPP();
_spriteData[index].Size = size;
_cacheSize += size;
@@ -479,7 +451,6 @@ void SpriteCache::RemapSpriteToSprite0(sprkey_t index) {
_sprInfos[index].Width = _sprInfos[0].Width;
_sprInfos[index].Height = _sprInfos[0].Height;
_spriteData[index].Image = nullptr;
- _spriteData[index].Offset = _spriteData[0].Offset;
_spriteData[index].Size = _spriteData[0].Size;
_spriteData[index].Flags |= SPRCACHEFLAG_REMAPPED;
#ifdef DEBUG_SPRITECACHE
@@ -489,47 +460,42 @@ void SpriteCache::RemapSpriteToSprite0(sprkey_t index) {
const char *spriteFileSig = " Sprite File ";
-void SpriteCache::CompressSprite(Bitmap *sprite, Stream *out) {
+void SpriteFile::CompressSprite(Bitmap *sprite, Stream *out) {
const int depth = sprite->GetBPP();
if (depth == 1) {
for (int y = 0; y < sprite->GetHeight(); y++)
cpackbitl(&sprite->GetScanLineForWriting(y)[0], sprite->GetWidth(), out);
} else if (depth == 2) {
for (int y = 0; y < sprite->GetHeight(); y++)
- cpackbitl16((const uint16_t *)&sprite->GetScanLine(y)[0], sprite->GetWidth(), out);
+ cpackbitl16((unsigned short *)&sprite->GetScanLine(y)[0], sprite->GetWidth(), out);
} else {
for (int y = 0; y < sprite->GetHeight(); y++)
- cpackbitl32((const uint32_t *)&sprite->GetScanLine(y)[0], sprite->GetWidth(), out);
+ cpackbitl32((unsigned int *)&sprite->GetScanLine(y)[0], sprite->GetWidth(), out);
}
}
-void SpriteCache::UnCompressSprite(Bitmap *sprite, Stream *in) {
+void SpriteFile::UnCompressSprite(Bitmap *sprite, Stream *in) {
const int depth = sprite->GetBPP();
if (depth == 1) {
for (int y = 0; y < sprite->GetHeight(); y++)
cunpackbitl(&sprite->GetScanLineForWriting(y)[0], sprite->GetWidth(), in);
} else if (depth == 2) {
for (int y = 0; y < sprite->GetHeight(); y++)
- cunpackbitl16((uint16_t *)&sprite->GetScanLineForWriting(y)[0], sprite->GetWidth(), in);
+ cunpackbitl16((unsigned short *)&sprite->GetScanLineForWriting(y)[0], sprite->GetWidth(), in);
} else {
for (int y = 0; y < sprite->GetHeight(); y++)
- cunpackbitl32((uint32_t *)&sprite->GetScanLineForWriting(y)[0], sprite->GetWidth(), in);
+ cunpackbitl32((unsigned int *)&sprite->GetScanLineForWriting(y)[0], sprite->GetWidth(), in);
}
}
-int SpriteCache::SaveToFile(const String &filename, bool compressOutput, SpriteFileIndex &index) {
- Stream *output = Shared::File::CreateFile(filename);
+int SpriteFile::SaveToFile(const String &save_to_file,
+ const std::vector<Bitmap *> &sprites,
+ SpriteFile *read_from_file,
+ bool compressOutput, SpriteFileIndex &index) {
+ std::unique_ptr<Stream> output(File::CreateFile(save_to_file));
if (output == nullptr)
return -1;
- if (compressOutput) {
- // re-open the file so that it can be seeked
- delete output;
- output = File::OpenFile(filename, Shared::kFile_Open, Shared::kFile_ReadWrite); // CHECKME why mode was "r+" here?
- if (output == nullptr)
- return -1;
- }
-
int spriteFileIDCheck = g_system->getMillis();
// sprite file version
@@ -540,7 +506,8 @@ int SpriteCache::SaveToFile(const String &filename, bool compressOutput, SpriteF
output->WriteInt8(compressOutput ? 1 : 0);
output->WriteInt32(spriteFileIDCheck);
- sprkey_t lastslot = FindTopmostSprite();
+ sprkey_t lastslot = read_from_file ? read_from_file->GetTopmostSprite() : 0;
+ lastslot = std::max(lastslot, FindTopmostSprite(sprites));
output->WriteInt32(lastslot);
// allocate buffers to store the indexing info
@@ -550,25 +517,32 @@ int SpriteCache::SaveToFile(const String &filename, bool compressOutput, SpriteF
spritewidths.resize(numsprits);
spriteheights.resize(numsprits);
spriteoffs.resize(numsprits);
+ std::unique_ptr<Bitmap> temp_bmp; // for disposing temp sprites
+ std::vector<char> membuf; // for loading raw sprite data
- const size_t memBufferSize = 100000;
- char *memBuffer = new char[memBufferSize];
+ const bool diff_compress =
+ read_from_file && read_from_file->IsFileCompressed() != compressOutput;
for (sprkey_t i = 0; i <= lastslot; ++i) {
- spriteoffs[i] = output->GetPosition();
+ soff_t sproff = output->GetPosition();
+
+ Bitmap *image = (size_t)i < sprites.size() ? sprites[i] : nullptr;
- // if compressing uncompressed sprites, load the sprite into memory
- if ((_spriteData[i].Image == nullptr) && (this->_compressed != compressOutput))
- (*this)[i];
+ // if compression setting is different, load the sprite into memory
+ // (otherwise we will be able to simply copy bytes from one file to another
+ if ((image == nullptr) && diff_compress) {
+ read_from_file->LoadSprite(i, image);
+ temp_bmp.reset(image);
+ }
- if (_spriteData[i].Image != nullptr) {
+ // if managed to load an image - save it according the new compression settings
+ if (image != nullptr) {
// image in memory -- write it out
- pre_save_sprite(i);
- Bitmap *image = _spriteData[i].Image;
- int bpss = image->GetColorDepth() / 8;
+ int bpp = image->GetColorDepth() / 8;
+ spriteoffs[i] = sproff;
spritewidths[i] = image->GetWidth();
spriteheights[i] = image->GetHeight();
- output->WriteInt16(bpss);
+ output->WriteInt16(bpp);
output->WriteInt16(spritewidths[i]);
output->WriteInt16(spriteheights[i]);
@@ -577,7 +551,7 @@ int SpriteCache::SaveToFile(const String &filename, bool compressOutput, SpriteF
// write some space for the length data
output->WriteInt32(0);
- CompressSprite(image, output);
+ CompressSprite(image, output.get());
soff_t fileSizeSoFar = output->GetPosition();
// write the length of the compressed data
@@ -585,71 +559,37 @@ int SpriteCache::SaveToFile(const String &filename, bool compressOutput, SpriteF
output->WriteInt32((fileSizeSoFar - lenloc) - 4);
output->Seek(0, kSeekEnd);
} else {
- output->WriteArray(image->GetDataForWriting(), spritewidths[i] * bpss, spriteheights[i]);
+ output->WriteArray(image->GetDataForWriting(), spritewidths[i] * bpp, spriteheights[i]);
}
continue;
- }
-
- if (_spriteData[i].Offset == 0) {
+ } else if (diff_compress) {
// sprite doesn't exist
output->WriteInt16(0); // colour depth
- spritewidths[i] = 0;
- spriteheights[i] = 0;
- spriteoffs[i] = 0;
- continue;
- }
-
- // not in memory -- seek to it in the source file
- sprkey_t load_index = GetDataIndex(i);
- SeekToSprite(load_index);
- _lastLoad = load_index;
-
- short colDepth = _stream->ReadInt16();
- output->WriteInt16(colDepth);
-
- if (colDepth == 0)
continue;
-
- if (this->_compressed != compressOutput) {
- // shouldn't be able to get here
- delete[] memBuffer;
- delete output;
- return -2;
}
- // and copy the data across
- int width = _stream->ReadInt16();
- int height = _stream->ReadInt16();
-
- spritewidths[i] = width;
- spriteheights[i] = height;
+ // Not in memory - and same compression option;
+ // Directly copy the sprite bytes from the input file to the output
+ Size metric;
+ int bpp;
+ read_from_file->LoadSpriteData(i, metric, bpp, membuf);
- output->WriteInt16(width);
- output->WriteInt16(height);
-
- size_t sizeToCopy;
- if (this->_compressed) {
- sizeToCopy = _stream->ReadInt32();
- output->WriteInt32(sizeToCopy);
- if (sizeToCopy == 0)
- continue; // bad data?
- } else {
- sizeToCopy = width * height * (int)colDepth;
- }
-
- while (sizeToCopy > memBufferSize) {
- _stream->ReadArray(memBuffer, memBufferSize, 1);
- output->WriteArray(memBuffer, memBufferSize, 1);
- sizeToCopy -= memBufferSize;
- }
+ output->WriteInt16(bpp);
+ if (bpp == 0)
+ continue; // empty slot
- _stream->ReadArray(memBuffer, sizeToCopy, 1);
- output->WriteArray(memBuffer, sizeToCopy, 1);
+ spriteoffs[i] = sproff;
+ spritewidths[i] = metric.Width;
+ spriteheights[i] = metric.Height;
+ output->WriteInt16(metric.Width);
+ output->WriteInt16(metric.Height);
+ if (compressOutput)
+ output->WriteInt32(membuf.size());
+ if (membuf.size() == 0)
+ continue; // bad data?
+ output->Write(&membuf[0], membuf.size());
}
- delete[] memBuffer;
- delete output;
-
index.SpriteFileIDCheck = spriteFileIDCheck;
index.LastSlot = lastslot;
index.SpriteCount = numsprits;
@@ -659,7 +599,21 @@ int SpriteCache::SaveToFile(const String &filename, bool compressOutput, SpriteF
return 0;
}
-int SpriteCache::SaveSpriteIndex(const String &filename, const SpriteFileIndex &index) {
+int SpriteCache::SaveToFile(const String &filename, bool compressOutput, SpriteFileIndex &index) {
+ std::vector<Bitmap *> sprites;
+ for (const auto &data : _spriteData) {
+ // NOTE: this is a horrible hack:
+ // because Editor expects slightly different RGB order, it swaps colors
+ // when loading them (call to initialize_sprite), so here we basically
+ // unfix that fix to save the data in a way that engine will expect.
+ // TODO: perhaps adjust the editor to NOT need this?!
+ pre_save_sprite(data.Image);
+ sprites.push_back(data.Image);
+ }
+ return _file.SaveToFile(filename, sprites, &_file, compressOutput, index);
+}
+
+int SpriteFile::SaveSpriteIndex(const String &filename, const SpriteFileIndex &index) {
// write the sprite index file
Stream *out = File::CreateFile(filename);
if (!out)
@@ -683,79 +637,40 @@ int SpriteCache::SaveSpriteIndex(const String &filename, const SpriteFileIndex &
}
HError SpriteCache::InitFile(const String &filename, const String &sprindex_filename) {
- SpriteFileVersion vers;
- char buff[20];
- soff_t spr_initial_offs = 0;
- int spriteFileID = 0;
-
- _stream.reset(_GP(AssetMgr)->OpenAsset(filename));
- if (_stream == nullptr)
- return new Error(String::FromFormat("Failed to open spriteset file '%s'.", filename.GetCStr()));
-
- spr_initial_offs = _stream->GetPosition();
-
- vers = (SpriteFileVersion)_stream->ReadInt16();
- // read the "Sprite File" signature
- _stream->ReadArray(&buff[0], 13, 1);
-
- if (vers < kSprfVersion_Uncompressed || vers > kSprfVersion_Current) {
- _stream.reset();
- return new Error(String::FromFormat("Unsupported _GP(spriteset) format (requested %d, supported %d - %d).", vers, kSprfVersion_Uncompressed, kSprfVersion_Current));
- }
-
- // unknown version
- buff[13] = 0;
- if (strcmp(buff, spriteFileSig)) {
- _stream.reset();
- return new Error("Uknown _GP(spriteset) format.");
- }
-
- if (vers == kSprfVersion_Uncompressed) {
- this->_compressed = false;
- } else if (vers == kSprfVersion_Compressed) {
- this->_compressed = true;
- } else if (vers >= kSprfVersion_Last32bit) {
- this->_compressed = (_stream->ReadInt8() == 1);
- spriteFileID = _stream->ReadInt32();
- }
-
- if (vers < kSprfVersion_Compressed) {
- // skip the palette
- _stream->Seek(256 * 3); // sizeof(RGB) * 256
- }
-
- sprkey_t topmost;
- if (vers < kSprfVersion_HighSpriteLimit)
- topmost = (uint16_t)_stream->ReadInt16();
- else
- topmost = _stream->ReadInt32();
- if (vers < kSprfVersion_Uncompressed)
- topmost = 200;
+ std::vector<Size> metrics;
+ HError err = _file.OpenFile(filename, sprindex_filename, metrics);
+ if (!err)
+ return err;
- EnlargeTo(topmost);
-
- // if there is a sprite index file, use it
- if (LoadSpriteIndexFile(sprindex_filename, spriteFileID, spr_initial_offs, topmost)) {
- // Succeeded
- return HError::None();
+ // Initialize sprite infos
+ size_t newsize = metrics.size();
+ _sprInfos.resize(newsize);
+ _spriteData.resize(newsize);
+ _mrulist.resize(newsize);
+ _mrubacklink.resize(newsize);
+ for (size_t i = 0; i < metrics.size(); ++i) {
+ if (!metrics[i].IsNull()) {
+ // Existing sprite
+ _spriteData[i].Flags = SPRCACHEFLAG_ISASSET;
+ _spriteData[i].Image = nullptr;
+ get_new_size_for_sprite(i, metrics[i].Width, metrics[i].Height, _sprInfos[i].Width, _sprInfos[i].Height);
+ } else {
+ // Handle empty slot: remap to sprite 0
+ if (i > 0) // FIXME: optimize
+ InitNullSpriteParams(i);
+ }
}
-
- // Failed, index file is invalid; index sprites manually
- return RebuildSpriteIndex(_stream.get(), topmost, vers);
+ return HError::None();
}
-HError SpriteCache::RebuildSpriteIndex(AGS::Shared::Stream *in, sprkey_t topmost, SpriteFileVersion vers) {
+HError SpriteFile::RebuildSpriteIndex(Stream *in, sprkey_t topmost,
+ SpriteFileVersion vers, std::vector<Size> &metrics) {
for (sprkey_t i = 0; i <= topmost; ++i) {
_spriteData[i].Offset = in->GetPosition();
- _spriteData[i].Flags = 0;
int coldep = in->ReadInt16();
if (coldep == 0) {
- // Empty slot
- if (i > 0)
- InitNullSpriteParams(i);
-
if (in->EOS())
break;
continue;
@@ -767,14 +682,10 @@ HError SpriteCache::RebuildSpriteIndex(AGS::Shared::Stream *in, sprkey_t topmost
if ((size_t)i >= _spriteData.size())
break;
- _spriteData[i].Flags = SPRCACHEFLAG_ISASSET;
- _spriteData[i].Image = nullptr;
-
int wdd = in->ReadInt16();
int htt = in->ReadInt16();
- _sprInfos[i].Width = wdd;
- _sprInfos[i].Height = htt;
- get_new_size_for_sprite(i, wdd, htt, _sprInfos[i].Width, _sprInfos[i].Height);
+ metrics[i].Width = wdd;
+ metrics[i].Height = htt;
size_t spriteDataSize;
if (vers == kSprfVersion_Compressed) {
@@ -789,7 +700,8 @@ HError SpriteCache::RebuildSpriteIndex(AGS::Shared::Stream *in, sprkey_t topmost
return HError::None();
}
-bool SpriteCache::LoadSpriteIndexFile(const String &filename, int expectedFileID, soff_t spr_initial_offs, sprkey_t topmost) {
+bool SpriteFile::LoadSpriteIndexFile(const String &filename, int expectedFileID,
+ soff_t spr_initial_offs, sprkey_t topmost, std::vector<Size> &metrics) {
Stream *fidx = _GP(AssetMgr)->OpenAsset(filename);
if (fidx == nullptr) {
return false;
@@ -829,50 +741,190 @@ bool SpriteCache::LoadSpriteIndexFile(const String &filename, int expectedFileID
}
sprkey_t numsprits = topmost_index + 1;
- short *rspritewidths = new short[numsprits];
- short *rspriteheights = new short[numsprits];
- soff_t *spriteoffs = new soff_t[numsprits];
+ std::vector<int16_t> rspritewidths; rspritewidths.resize(numsprits);
+ std::vector<int16_t> rspriteheights; rspriteheights.resize(numsprits);
+ std::vector<soff_t> spriteoffs; spriteoffs.resize(numsprits);
fidx->ReadArrayOfInt16(&rspritewidths[0], numsprits);
fidx->ReadArrayOfInt16(&rspriteheights[0], numsprits);
if (vers <= kSpridxfVersion_Last32bit) {
for (sprkey_t i = 0; i < numsprits; ++i)
spriteoffs[i] = fidx->ReadInt32();
- } else { // large file support
- fidx->ReadArrayOfInt64(spriteoffs, numsprits);
+ } else // large file support
+ {
+ fidx->ReadArrayOfInt64(&spriteoffs[0], numsprits);
}
+ delete fidx;
for (sprkey_t i = 0; i <= topmost_index; ++i) {
if (spriteoffs[i] != 0) {
- _spriteData[i].Flags = SPRCACHEFLAG_ISASSET;
_spriteData[i].Offset = spriteoffs[i] + spr_initial_offs;
- get_new_size_for_sprite(i, rspritewidths[i], rspriteheights[i], _sprInfos[i].Width, _sprInfos[i].Height);
- } else if (i > 0) {
- InitNullSpriteParams(i);
+ metrics[i].Width = rspritewidths[i];
+ metrics[i].Height = rspriteheights[i];
}
}
-
- delete[] rspritewidths;
- delete[] rspriteheights;
- delete[] spriteoffs;
- delete fidx;
return true;
}
void SpriteCache::DetachFile() {
+ _file.Reset();
+}
+
+bool SpriteFile::IsFileCompressed() const {
+ return _compressed;
+}
+
+sprkey_t SpriteFile::GetTopmostSprite() const {
+ return (sprkey_t)_spriteData.size() - 1;
+}
+
+void SpriteFile::Reset() {
_stream.reset();
- _lastLoad = -2;
+ _curPos = -2;
+}
+
+HAGSError SpriteFile::LoadSprite(sprkey_t index, Shared::Bitmap *&sprite) {
+ sprite = nullptr;
+ if (index < 0 || (size_t)index >= _spriteData.size())
+ new Error(String::FromFormat("LoadSprite: slot index %d out of bounds (%d - %d).",
+ index, 0, _spriteData.size() - 1));
+
+ SeekToSprite(index);
+ _curPos = -2; // mark undefined pos
+
+ int coldep = _stream->ReadInt16();
+ if (coldep == 0) { // empty slot, this is normal
+ return HError::None();
+ }
+
+ int wdd = _stream->ReadInt16();
+ int htt = _stream->ReadInt16();
+ Bitmap *image = BitmapHelper::CreateBitmap(wdd, htt, coldep * 8);
+ if (image == nullptr) {
+ return new Error(String::FromFormat("LoadSprite: failed to allocate bitmap %d (%dx%d%d).",
+ index, wdd, htt, coldep * 8));
+ }
+
+ if (_compressed) {
+ size_t data_size = _stream->ReadInt32();
+ if (data_size == 0) {
+ delete image;
+ return new Error(String::FromFormat("LoadSprite: bad compressed data for sprite %d.", index));
+ }
+ UnCompressSprite(image, _stream.get());
+ } else {
+ if (coldep == 1) {
+ for (int h = 0; h < htt; ++h)
+ _stream->ReadArray(&image->GetScanLineForWriting(h)[0], coldep, wdd);
+ } else if (coldep == 2) {
+ for (int h = 0; h < htt; ++h)
+ _stream->ReadArrayOfInt16((int16_t *)&image->GetScanLineForWriting(h)[0], wdd);
+ } else {
+ for (int h = 0; h < htt; ++h)
+ _stream->ReadArrayOfInt32((int32_t *)&image->GetScanLineForWriting(h)[0], wdd);
+ }
+ }
+ sprite = image;
+ _curPos = index + 1; // mark correct pos
+ return HError::None();
+}
+
+HError SpriteFile::LoadSpriteData(sprkey_t index, Size &metric, int &bpp,
+ std::vector<char> &data) {
+ if (index < 0 || (size_t)index >= _spriteData.size())
+ new Error(String::FromFormat("LoadSprite: slot index %d out of bounds (%d - %d).",
+ index, 0, _spriteData.size() - 1));
+
+ SeekToSprite(index);
+ _curPos = -2; // mark undefined pos
+
+ int coldep = _stream->ReadInt16();
+ if (coldep == 0) { // empty slot, this is normal
+ metric = Size();
+ bpp = 0;
+ data.resize(0);
+ return HError::None();
+ }
+
+ int width = _stream->ReadInt16();
+ int height = _stream->ReadInt16();
+
+ size_t data_size;
+ if (_compressed)
+ data_size = _stream->ReadInt32();
+ else
+ data_size = width * height * coldep;
+ data.resize(data_size);
+ _stream->Read(&data[0], data_size);
+ metric = Size(width, height);
+ bpp = coldep;
+ _curPos = index + 1; // mark correct pos
+ return HError::None();
}
-int SpriteCache::AttachFile(const String &filename) {
+HAGSError SpriteFile::OpenFile(const String &filename, const String &sprindex_filename,
+ std::vector<Size> &metrics) {
+ SpriteFileVersion vers;
+ char buff[20];
+ soff_t spr_initial_offs = 0;
+ int spriteFileID = 0;
+
_stream.reset(_GP(AssetMgr)->OpenAsset(filename));
if (_stream == nullptr)
- return -1;
- return 0;
-}
+ return new Error(String::FromFormat("Failed to open spriteset file '%s'.", filename.GetCStr()));
-bool SpriteCache::IsFileCompressed() const {
- return _compressed;
+ spr_initial_offs = _stream->GetPosition();
+
+ vers = (SpriteFileVersion)_stream->ReadInt16();
+ // read the "Sprite File" signature
+ _stream->ReadArray(&buff[0], 13, 1);
+
+ if (vers < kSprfVersion_Uncompressed || vers > kSprfVersion_Current) {
+ _stream.reset();
+ return new Error(String::FromFormat("Unsupported spriteset format (requested %d, supported %d - %d).", vers, kSprfVersion_Uncompressed, kSprfVersion_Current));
+ }
+
+ // unknown version
+ buff[13] = 0;
+ if (strcmp(buff, spriteFileSig)) {
+ _stream.reset();
+ return new Error("Uknown spriteset format.");
+ }
+
+ if (vers == kSprfVersion_Uncompressed) {
+ this->_compressed = false;
+ } else if (vers == kSprfVersion_Compressed) {
+ this->_compressed = true;
+ } else if (vers >= kSprfVersion_Last32bit) {
+ this->_compressed = (_stream->ReadInt8() == 1);
+ spriteFileID = _stream->ReadInt32();
+ }
+
+ if (vers < kSprfVersion_Compressed) {
+ // skip the palette
+ _stream->Seek(256 * 3); // sizeof(RGB) * 256
+ }
+
+ sprkey_t topmost;
+ if (vers < kSprfVersion_HighSpriteLimit)
+ topmost = (uint16_t)_stream->ReadInt16();
+ else
+ topmost = _stream->ReadInt32();
+ if (vers < kSprfVersion_Uncompressed)
+ topmost = 200;
+
+ _spriteData.resize(topmost + 1);
+ metrics.resize(topmost + 1);
+
+ // if there is a sprite index file, use it
+ if (LoadSpriteIndexFile(sprindex_filename, spriteFileID,
+ spr_initial_offs, topmost, metrics)) {
+ // Succeeded
+ return HError::None();
+ }
+
+ // Failed, index file is invalid; index sprites manually
+ return RebuildSpriteIndex(_stream.get(), topmost, vers, metrics);
}
} // namespace AGS3
diff --git a/engines/ags/shared/ac/sprite_cache.h b/engines/ags/shared/ac/sprite_cache.h
index 67bd74b4d2..0eb9ee89c0 100644
--- a/engines/ags/shared/ac/sprite_cache.h
+++ b/engines/ags/shared/ac/sprite_cache.h
@@ -23,11 +23,9 @@
//
// Sprite caching system.
//
-// TODO: split out sprite serialization into something like "SpriteFile" class.
-// SpriteCache should only manage caching and provide bitmaps by demand.
-// There should be a separate unit which manages streaming and decompressing.
-// Perhaps an interface which would allow multiple implementation depending
-// on compression type.
+// SpriteFile handles sprite serialization and streaming.
+// SpriteCache provides bitmaps by demand; it uses SpriteFile to load sprites
+// and does MRU (most-recent-use) caching.
//
// TODO: store sprite data in a specialized container type that is optimized
// for having most keys allocated in large continious sequences by default.
@@ -48,6 +46,7 @@
#include "ags/lib/std/vector.h"
#include "ags/shared/core/platform.h"
#include "ags/shared/util/error.h"
+#include "ags/shared/util/geometry.h"
namespace AGS3 {
@@ -109,6 +108,64 @@ struct SpriteFileIndex {
std::vector<soff_t> Offsets;
};
+class SpriteFile {
+public:
+ // Standart sprite file and sprite index names
+ static const char *const DefaultSpriteFileName;
+ static const char *const DefaultSpriteIndexName;
+
+ SpriteFile();
+ // Loads sprite reference information and inits sprite stream
+ HAGSError OpenFile(const Shared::String &filename, const Shared::String &sprindex_filename,
+ std::vector<Size> &metrics);
+ void Reset();
+
+ // Tells if bitmaps in the file are compressed
+ bool IsFileCompressed() const;
+ // Tells the highest known sprite index
+ sprkey_t GetTopmostSprite() const;
+
+ // Loads sprite index file
+ bool LoadSpriteIndexFile(const Shared::String &filename, int expectedFileID,
+ soff_t spr_initial_offs, sprkey_t topmost, std::vector<Size> &metrics);
+ // Rebuilds sprite index from the main sprite file
+ HAGSError RebuildSpriteIndex(AGS::Shared::Stream *in, sprkey_t topmost, SpriteFileVersion vers,
+ std::vector<Size> &metrics);
+
+ HAGSError LoadSprite(sprkey_t index, Shared::Bitmap *&sprite);
+ HAGSError LoadSpriteData(sprkey_t index, Size &metric, int &bpp, std::vector<char> &data);
+
+ // Saves all sprites to file; fills in index data for external use
+ // TODO: refactor to be able to save main file and index file separately (separate function for gather data?)
+ static int SaveToFile(const Shared::String &save_to_file,
+ const std::vector<Shared::Bitmap *> &sprites, // available sprites (may contain nullptrs)
+ SpriteFile *read_from_file, // optional file to read missing sprites from
+ bool compressOutput, SpriteFileIndex &index);
+ // Saves sprite index table in a separate file
+ static int SaveSpriteIndex(const Shared::String &filename, const SpriteFileIndex &index);
+
+private:
+ // Finds the topmost occupied slot index. Warning: may be slow.
+ static sprkey_t FindTopmostSprite(const std::vector<Shared::Bitmap *> &sprites);
+ // Seek stream to sprite
+ void SeekToSprite(sprkey_t index);
+ // Writes compressed sprite to the stream
+ static void CompressSprite(Shared::Bitmap *sprite, Shared::Stream *out);
+ // Uncompresses sprite from stream into the given bitmap
+ static void UnCompressSprite(Shared::Bitmap *sprite, Shared::Stream *in);
+
+ // Internal sprite reference
+ struct SpriteRef {
+ soff_t Offset = 0; // data offset
+ size_t Size = 0; // cache size of element, in bytes
+ };
+
+ // Array of sprite references
+ std::vector<SpriteRef> _spriteData;
+ std::unique_ptr<Shared::Stream> _stream; // the sprite stream
+ bool _compressed; // are sprites compressed
+ sprkey_t _curPos; // current stream position (sprite slot)
+};
class SpriteCache {
public:
@@ -116,13 +173,20 @@ public:
static const sprkey_t MAX_SPRITE_INDEX = INT32_MAX - 1;
static const size_t MAX_SPRITE_SLOTS = INT32_MAX;
- // Standart sprite file and sprite index names
- static const Shared::String DefaultSpriteFileName;
- static const Shared::String DefaultSpriteIndexName;
-
SpriteCache(std::vector<SpriteInfo> &sprInfos);
~SpriteCache();
+ // Loads sprite reference information and inits sprite stream
+ HAGSError InitFile(const Shared::String &filename, const Shared::String &sprindex_filename);
+ // Saves current cache contents to the file
+ int SaveToFile(const Shared::String &filename, bool compressOutput, SpriteFileIndex &index);
+ // Closes an active sprite file stream
+ void DetachFile();
+
+ inline bool IsFileCompressed() const {
+ return _file.IsFileCompressed();
+ }
+
// Tells if there is a sprite registered for the given index;
// this includes sprites that were explicitly assigned but failed to init and were remapped
bool DoesSpriteExist(sprkey_t index) const;
@@ -139,8 +203,6 @@ public:
size_t GetMaxCacheSize() const;
// Returns number of sprite slots in the bank (this includes both actual sprites and free slots)
size_t GetSpriteSlotCount() const;
- // Finds the topmost occupied slot index. Warning: may be slow.
- sprkey_t FindTopmostSprite() const;
// Loads sprite and and locks in memory (so it cannot get removed implicitly)
void Precache(sprkey_t index);
// Remap the given index to the sprite 0
@@ -162,40 +224,23 @@ public:
// Sets max cache size in bytes
void SetMaxCacheSize(size_t size);
- // Loads sprite reference information and inits sprite stream
- HAGSError InitFile(const Shared::String &filename, const Shared::String &sprindex_filename);
- // Tells if bitmaps in the file are compressed
- bool IsFileCompressed() const;
- // Opens file stream
- int AttachFile(const Shared::String &filename);
- // Closes file stream
- void DetachFile();
- // Saves all sprites to file; fills in index data for external use
- // TODO: refactor to be able to save main file and index file separately (separate function for gather data?)
- int SaveToFile(const Shared::String &filename, bool compressOutput, SpriteFileIndex &index);
- // Saves sprite index table in a separate file
- int SaveSpriteIndex(const Shared::String &filename, const SpriteFileIndex &index);
-
// Loads (if it's not in cache yet) and returns bitmap by the sprite index
- Shared::Bitmap *operator[](sprkey_t index);
+ Shared::Bitmap *operator[] (sprkey_t index);
private:
void Init();
+ // Load sprite from game resource
+ size_t LoadSprite(sprkey_t index);
// Gets the index of a sprite which data is used for the given slot;
// in case of remapped sprite this will return the one given sprite is remapped to
sprkey_t GetDataIndex(sprkey_t index);
- // Load sprite from game resource
- size_t LoadSprite(sprkey_t index);
- // Seek stream to sprite
- void SeekToSprite(sprkey_t index);
// Delete the oldest image in cache
void DisposeOldest();
// Information required for the sprite streaming
// TODO: split into sprite cache and sprite stream data
struct SpriteData {
- soff_t Offset; // data offset
- soff_t Size; // cache size of element, in bytes
+ size_t Size; // to track cache size
uint32_t Flags;
// TODO: investigate if we may safely use unique_ptr here
// (some of these bitmaps may be assigned from outside of the cache)
@@ -218,10 +263,8 @@ private:
std::vector<SpriteInfo> &_sprInfos;
// Array of sprite references
std::vector<SpriteData> _spriteData;
- bool _compressed; // are sprites compressed
- std::unique_ptr<Shared::Stream> _stream; // the sprite stream
- sprkey_t _lastLoad; // last loaded sprite index
+ SpriteFile _file;
size_t _maxCacheSize; // cache size limit
size_t _lockedSize; // size in bytes of currently locked images
@@ -235,15 +278,6 @@ private:
int _liststart;
int _listend;
- // Loads sprite index file
- bool LoadSpriteIndexFile(const Shared::String &filename, int expectedFileID, soff_t spr_initial_offs, sprkey_t topmost);
- // Rebuilds sprite index from the main sprite file
- HAGSError RebuildSpriteIndex(AGS::Shared::Stream *in, sprkey_t topmost, SpriteFileVersion vers);
- // Writes compressed sprite to the stream
- void CompressSprite(Shared::Bitmap *sprite, Shared::Stream *out);
- // Uncompresses sprite from stream into the given bitmap
- void UnCompressSprite(Shared::Bitmap *sprite, Shared::Stream *in);
-
// Initialize the empty sprite slot
void InitNullSpriteParams(sprkey_t index);
};
Commit: 7e322be3945f948f17883083b44e425dd7bf7177
https://github.com/scummvm/scummvm/commit/7e322be3945f948f17883083b44e425dd7bf7177
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-07T22:07:09-07:00
Commit Message:
AGS: Moved image (de)compression functions out from SpriteFile
>From upstream a3c6e7cfded18daadab00474ff6d148904581f08
Changed paths:
engines/ags/shared/ac/sprite_cache.cpp
engines/ags/shared/ac/sprite_cache.h
engines/ags/shared/util/compress.cpp
engines/ags/shared/util/compress.h
diff --git a/engines/ags/shared/ac/sprite_cache.cpp b/engines/ags/shared/ac/sprite_cache.cpp
index a081c07ea9..945a26c5ac 100644
--- a/engines/ags/shared/ac/sprite_cache.cpp
+++ b/engines/ags/shared/ac/sprite_cache.cpp
@@ -460,34 +460,6 @@ void SpriteCache::RemapSpriteToSprite0(sprkey_t index) {
const char *spriteFileSig = " Sprite File ";
-void SpriteFile::CompressSprite(Bitmap *sprite, Stream *out) {
- const int depth = sprite->GetBPP();
- if (depth == 1) {
- for (int y = 0; y < sprite->GetHeight(); y++)
- cpackbitl(&sprite->GetScanLineForWriting(y)[0], sprite->GetWidth(), out);
- } else if (depth == 2) {
- for (int y = 0; y < sprite->GetHeight(); y++)
- cpackbitl16((unsigned short *)&sprite->GetScanLine(y)[0], sprite->GetWidth(), out);
- } else {
- for (int y = 0; y < sprite->GetHeight(); y++)
- cpackbitl32((unsigned int *)&sprite->GetScanLine(y)[0], sprite->GetWidth(), out);
- }
-}
-
-void SpriteFile::UnCompressSprite(Bitmap *sprite, Stream *in) {
- const int depth = sprite->GetBPP();
- if (depth == 1) {
- for (int y = 0; y < sprite->GetHeight(); y++)
- cunpackbitl(&sprite->GetScanLineForWriting(y)[0], sprite->GetWidth(), in);
- } else if (depth == 2) {
- for (int y = 0; y < sprite->GetHeight(); y++)
- cunpackbitl16((unsigned short *)&sprite->GetScanLineForWriting(y)[0], sprite->GetWidth(), in);
- } else {
- for (int y = 0; y < sprite->GetHeight(); y++)
- cunpackbitl32((unsigned int *)&sprite->GetScanLineForWriting(y)[0], sprite->GetWidth(), in);
- }
-}
-
int SpriteFile::SaveToFile(const String &save_to_file,
const std::vector<Bitmap *> &sprites,
SpriteFile *read_from_file,
@@ -551,7 +523,7 @@ int SpriteFile::SaveToFile(const String &save_to_file,
// write some space for the length data
output->WriteInt32(0);
- CompressSprite(image, output.get());
+ rle_compress(image, output.get());
soff_t fileSizeSoFar = output->GetPosition();
// write the length of the compressed data
@@ -811,7 +783,7 @@ HAGSError SpriteFile::LoadSprite(sprkey_t index, Shared::Bitmap *&sprite) {
delete image;
return new Error(String::FromFormat("LoadSprite: bad compressed data for sprite %d.", index));
}
- UnCompressSprite(image, _stream.get());
+ rle_decompress(image, _stream.get());
} else {
if (coldep == 1) {
for (int h = 0; h < htt; ++h)
diff --git a/engines/ags/shared/ac/sprite_cache.h b/engines/ags/shared/ac/sprite_cache.h
index 0eb9ee89c0..9d39b472ee 100644
--- a/engines/ags/shared/ac/sprite_cache.h
+++ b/engines/ags/shared/ac/sprite_cache.h
@@ -149,10 +149,6 @@ private:
static sprkey_t FindTopmostSprite(const std::vector<Shared::Bitmap *> &sprites);
// Seek stream to sprite
void SeekToSprite(sprkey_t index);
- // Writes compressed sprite to the stream
- static void CompressSprite(Shared::Bitmap *sprite, Shared::Stream *out);
- // Uncompresses sprite from stream into the given bitmap
- static void UnCompressSprite(Shared::Bitmap *sprite, Shared::Stream *in);
// Internal sprite reference
struct SpriteRef {
diff --git a/engines/ags/shared/util/compress.cpp b/engines/ags/shared/util/compress.cpp
index c94bc9cf13..6af5f03ea6 100644
--- a/engines/ags/shared/util/compress.cpp
+++ b/engines/ags/shared/util/compress.cpp
@@ -40,6 +40,10 @@ namespace AGS3 {
using namespace AGS::Shared;
+//-----------------------------------------------------------------------------
+// RLE
+//-----------------------------------------------------------------------------
+
void cpackbitl(const uint8_t *line, int size, Stream *out) {
int cnt = 0; // bytes encoded
@@ -286,7 +290,37 @@ int cunpackbitl32(uint32_t *line, int size, Stream *in) {
return in->HasErrors() ? -1 : 0;
}
-//=============================================================================
+void rle_compress(Bitmap *bmp, Shared::Stream *out) {
+ const int depth = bmp->GetBPP();
+ if (depth == 1) {
+ for (int y = 0; y < bmp->GetHeight(); y++)
+ cpackbitl(&bmp->GetScanLineForWriting(y)[0], bmp->GetWidth(), out);
+ } else if (depth == 2) {
+ for (int y = 0; y < bmp->GetHeight(); y++)
+ cpackbitl16((unsigned short *)&bmp->GetScanLine(y)[0], bmp->GetWidth(), out);
+ } else {
+ for (int y = 0; y < bmp->GetHeight(); y++)
+ cpackbitl32((unsigned int *)&bmp->GetScanLine(y)[0], bmp->GetWidth(), out);
+ }
+}
+
+void rle_decompress(Bitmap *bmp, Shared::Stream *in) {
+ const int depth = bmp->GetBPP();
+ if (depth == 1) {
+ for (int y = 0; y < bmp->GetHeight(); y++)
+ cunpackbitl(&bmp->GetScanLineForWriting(y)[0], bmp->GetWidth(), in);
+ } else if (depth == 2) {
+ for (int y = 0; y < bmp->GetHeight(); y++)
+ cunpackbitl16((unsigned short *)&bmp->GetScanLineForWriting(y)[0], bmp->GetWidth(), in);
+ } else {
+ for (int y = 0; y < bmp->GetHeight(); y++)
+ cunpackbitl32((unsigned int *)&bmp->GetScanLineForWriting(y)[0], bmp->GetWidth(), in);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// LZW
+//-----------------------------------------------------------------------------
const char *lztempfnm = "~aclzw.tmp";
diff --git a/engines/ags/shared/util/compress.h b/engines/ags/shared/util/compress.h
index 568d0673b9..17c9cb0827 100644
--- a/engines/ags/shared/util/compress.h
+++ b/engines/ags/shared/util/compress.h
@@ -37,18 +37,10 @@ class Bitmap;
using namespace AGS; // FIXME later
-void csavecompressed(Shared::Stream *out, const unsigned char *tobesaved, const RGB pala[256]);
-// RLE compression
-void cpackbitl(const uint8_t *line, int size, Shared::Stream *out);
-void cpackbitl16(const uint16_t *line, int size, Shared::Stream *out);
-void cpackbitl32(const uint32_t *line, int size, Shared::Stream *out);
-// RLE decompression
-int cunpackbitl(uint8_t *line, int size, Shared::Stream *in);
-int cunpackbitl16(uint16_t *line, int size, Shared::Stream *in);
-int cunpackbitl32(uint32_t *line, int size, Shared::Stream *in);
-
-//=============================================================================
+void rle_compress(Shared::Bitmap *, Shared::Stream *);
+void rle_decompress(Shared::Bitmap *, Shared::Stream *);
+// LZW compression
void save_lzw(Shared::Stream *out, const Shared::Bitmap *bmpp, const RGB *pall);
void load_lzw(Shared::Stream *in, Shared::Bitmap **bmm, int dst_bpp, RGB *pall);
void savecompressed_allegro(Shared::Stream *out, const Shared::Bitmap *bmpp, const RGB *pall);
Commit: bfabf7c94dc16dbebf45f10efd6bf72afb48d8cb
https://github.com/scummvm/scummvm/commit/bfabf7c94dc16dbebf45f10efd6bf72afb48d8cb
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-07T22:07:10-07:00
Commit Message:
AGS: Fixed infinite wait in Object_Move under specific conditions
>From upstream 9dbdfe423c870e010a887cada725a8bbdf2de16e
Changed paths:
engines/ags/engine/ac/object.cpp
diff --git a/engines/ags/engine/ac/object.cpp b/engines/ags/engine/ac/object.cpp
index 462328332f..5cd1e0416d 100644
--- a/engines/ags/engine/ac/object.cpp
+++ b/engines/ags/engine/ac/object.cpp
@@ -292,7 +292,7 @@ void Object_Move(ScriptObject *objj, int x, int y, int speed, int blocking, int
move_object(objj->id, x, y, speed, direct);
if ((blocking == BLOCKING) || (blocking == 1))
- GameLoopUntilValueIsZero(&_G(objs)[objj->id].moving);
+ GameLoopUntilNotMoving(&_G(objs)[objj->id].moving);
else if ((blocking != IN_BACKGROUND) && (blocking != 0))
quit("Object.Move: invalid BLOCKING paramter");
}
Commit: e582a09612adfd7d27def3e7f04ec8725da7ac34
https://github.com/scummvm/scummvm/commit/e582a09612adfd7d27def3e7f04ec8725da7ac34
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-07T22:07:10-07:00
Commit Message:
AGS: Reprogram file/path functions to always use UTF-8 encoding
>From upstream d9fba3fba3ec5f012297f1ec7dd0d1d5a55f3255
This only applies most of this commit, since it changes Allegro
code which I don't fully implement for ScummVM anyway, since all
path and file operations go via the ScummVM API anyway
Changed paths:
engines/ags/lib/allegro/file.cpp
engines/ags/lib/allegro/unicode.cpp
engines/ags/lib/allegro/unicode.h
diff --git a/engines/ags/lib/allegro/file.cpp b/engines/ags/lib/allegro/file.cpp
index b8c02fba76..a2656ad3f2 100644
--- a/engines/ags/lib/allegro/file.cpp
+++ b/engines/ags/lib/allegro/file.cpp
@@ -102,6 +102,17 @@ int PACKFILE::pack_fputs(AL_CONST char *p) {
/*------------------------------------------------------------------*/
+/* Use strictly UTF-8 encoding for the file paths
+ */
+#define U_CURRENT U_UTF8
+#define ugetc utf8_getc
+#define ugetx utf8_getx
+#define ugetxc utf8_getx
+#define usetc utf8_setc
+#define uwidth utf8_width
+#define ucwidth utf8_cwidth
+#define uisok utf8_isok
+
char *fix_filename_case(char *path) {
return path;
}
diff --git a/engines/ags/lib/allegro/unicode.cpp b/engines/ags/lib/allegro/unicode.cpp
index 1ddd069067..7b77879477 100644
--- a/engines/ags/lib/allegro/unicode.cpp
+++ b/engines/ags/lib/allegro/unicode.cpp
@@ -33,4 +33,151 @@ size_t ustrsize(const char *s) {
return strlen(s);
}
+/* utf8_getc:
+ * Reads a character from a UTF - 8 string.
+ */
+/*static*/ int utf8_getc(const char *s) {
+ int c = *((unsigned char *)(s++));
+ int n, t;
+
+ if (c & 0x80) {
+ n = 1;
+ while (c & (0x80 >> n))
+ n++;
+
+ c &= (1 << (8 - n)) - 1;
+
+ while (--n > 0) {
+ t = *((unsigned char *)(s++));
+
+ if ((!(t & 0x80)) || (t & 0x40))
+ return '^';
+
+ c = (c << 6) | (t & 0x3F);
+ }
+ }
+
+ return c;
+}
+
+
+
+/* utf8_getx:
+ * Reads a character from a UTF-8 string, advancing the pointer position.
+ */
+/*static*/ int utf8_getx(char **s) {
+ int c = *((unsigned char *)((*s)++));
+ int n, t;
+
+ if (c & 0x80) {
+ n = 1;
+ while (c & (0x80 >> n))
+ n++;
+
+ c &= (1 << (8 - n)) - 1;
+
+ while (--n > 0) {
+ t = *((unsigned char *)((*s)++));
+
+ if ((!(t & 0x80)) || (t & 0x40)) {
+ (*s)--;
+ return '^';
+ }
+
+ c = (c << 6) | (t & 0x3F);
+ }
+ }
+
+ return c;
+}
+
+
+
+/* utf8_setc:
+ * Sets a character in a UTF-8 string.
+ */
+/*static*/ int utf8_setc(char *s, int c) {
+ int size, bits, b, i;
+
+ if (c < 128) {
+ *s = c;
+ return 1;
+ }
+
+ bits = 7;
+ while (c >= (1 << bits))
+ bits++;
+
+ size = 2;
+ b = 11;
+
+ while (b < bits) {
+ size++;
+ b += 5;
+ }
+
+ b -= (7 - size);
+ s[0] = c >> b;
+
+ for (i = 0; i < size; i++)
+ s[0] |= (0x80 >> i);
+
+ for (i = 1; i < size; i++) {
+ b -= 6;
+ s[i] = 0x80 | ((c >> b) & 0x3F);
+ }
+
+ return size;
+}
+
+
+
+/* utf8_width:
+ * Returns the width of a UTF-8 character.
+ */
+/*static*/ int utf8_width(const char *s) {
+ int c = *((unsigned char *)s);
+ int n = 1;
+
+ if (c & 0x80) {
+ while (c & (0x80 >> n))
+ n++;
+ }
+
+ return n;
+}
+
+
+
+/* utf8_cwidth:
+ * Returns the width of a UTF-8 character.
+ */
+/*static*/ int utf8_cwidth(int c) {
+ int size, bits, b;
+
+ if (c < 128)
+ return 1;
+
+ bits = 7;
+ while (c >= (1 << bits))
+ bits++;
+
+ size = 2;
+ b = 11;
+
+ while (b < bits) {
+ size++;
+ b += 5;
+ }
+
+ return size;
+}
+
+/* utf8_isok:
+ * Checks whether this character can be encoded in UTF-8 format.
+ */
+/*static*/ int utf8_isok(int c) {
+ return true;
+}
+
} // namespace AGS3
diff --git a/engines/ags/lib/allegro/unicode.h b/engines/ags/lib/allegro/unicode.h
index a17ab6d9f7..c87f8e0dc9 100644
--- a/engines/ags/lib/allegro/unicode.h
+++ b/engines/ags/lib/allegro/unicode.h
@@ -36,6 +36,15 @@ namespace AGS3 {
extern void set_uformat(int format);
extern size_t ustrsize(const char *s);
+/* UTF-8 support functions
+ */
+int utf8_getc(const char *s);
+int utf8_getx(char **s);
+int utf8_setc(char *s, int c);
+int utf8_width(const char *s);
+int utf8_cwidth(int c);
+int utf8_isok(int c);
+
} // namespace AGS3
#endif
Commit: 81f008806458aa9b31ead550d141054bb4e0549e
https://github.com/scummvm/scummvm/commit/81f008806458aa9b31ead550d141054bb4e0549e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-07T22:07:10-07:00
Commit Message:
AGS: Start in the UTF-8 mode, switch encoding based on game data
>From upstream 1d8a47d494a5211645ca2883b7c1f4931e1cc34a
Changed paths:
engines/ags/engine/ac/translation.cpp
engines/ags/engine/main/engine.cpp
engines/ags/engine/main/main.cpp
engines/ags/lib/allegro/file.cpp
engines/ags/lib/allegro/file.h
diff --git a/engines/ags/engine/ac/translation.cpp b/engines/ags/engine/ac/translation.cpp
index 35c9bb9895..d04f80e3be 100644
--- a/engines/ags/engine/ac/translation.cpp
+++ b/engines/ags/engine/ac/translation.cpp
@@ -45,6 +45,9 @@ void close_translation() {
_GP(trans) = Translation();
_G(trans_name) = "";
_G(trans_filename) = "";
+
+ // Return back to default game's encoding
+ set_uformat(U_ASCII);
}
bool init_translation(const String &lang, const String &fallback_lang, bool quit_on_error) {
@@ -101,6 +104,9 @@ bool init_translation(const String &lang, const String &fallback_lang, bool quit
_GP(game).options[OPT_RIGHTLEFTWRITE] = 1;
}
+ // Setup a text encoding mode depending on the translation data hint
+ set_uformat(U_ASCII);
+
Debug::Printf("Translation initialized: %s", _G(trans_filename).GetCStr());
return true;
}
diff --git a/engines/ags/engine/main/engine.cpp b/engines/ags/engine/main/engine.cpp
index 657b4c1615..fd6a77fd59 100644
--- a/engines/ags/engine/main/engine.cpp
+++ b/engines/ags/engine/main/engine.cpp
@@ -102,7 +102,6 @@ bool engine_init_backend() {
}
// Initialize stripped allegro library
- set_uformat(U_ASCII);
if (install_allegro()) {
_G(platform)->DisplayAlert("Internal error: unable to initialize stripped Allegro 4 library.");
return false;
@@ -601,6 +600,9 @@ void engine_init_game_settings() {
_G(our_eip) = -7;
Debug::Printf("Initialize game settings");
+ // Setup a text encoding mode depending on the game data hint
+ set_uformat(U_ASCII);
+
int ee;
for (ee = 0; ee < MAX_ROOM_OBJECTS + _GP(game).numcharacters; ee++)
diff --git a/engines/ags/engine/main/main.cpp b/engines/ags/engine/main/main.cpp
index b1a81ac888..20465c447a 100644
--- a/engines/ags/engine/main/main.cpp
+++ b/engines/ags/engine/main/main.cpp
@@ -76,6 +76,10 @@ void main_create_platform_driver() {
#define SVG_VERSION_FWCOMPAT_REVISION 1111
void main_init(int argc, const char *argv[]) {
+ // Init libraries: set text encoding
+ set_uformat(U_UTF8);
+ set_filename_encoding(U_UNICODE);
+
_G(EngineVersion) = Version(ACI_VERSION_STR " " SPECIAL_VERSION);
#if defined (BUILD_STR)
_G(EngineVersion).BuildInfo = BUILD_STR;
diff --git a/engines/ags/lib/allegro/file.cpp b/engines/ags/lib/allegro/file.cpp
index a2656ad3f2..4f35a7442d 100644
--- a/engines/ags/lib/allegro/file.cpp
+++ b/engines/ags/lib/allegro/file.cpp
@@ -113,6 +113,10 @@ int PACKFILE::pack_fputs(AL_CONST char *p) {
#define ucwidth utf8_cwidth
#define uisok utf8_isok
+void set_filename_encoding(int) {
+ // No implementation
+}
+
char *fix_filename_case(char *path) {
return path;
}
diff --git a/engines/ags/lib/allegro/file.h b/engines/ags/lib/allegro/file.h
index 1fab2c3bd2..2d9b6328d6 100644
--- a/engines/ags/lib/allegro/file.h
+++ b/engines/ags/lib/allegro/file.h
@@ -198,6 +198,7 @@ public:
}
};
+extern void set_filename_encoding(int);
extern char *fix_filename_case(char *path);
extern char *fix_filename_slashes(char *path);
extern char *append_filename(char *dest, const char *path, const char *filename, int size);
Commit: 5dc90dabc448514ed6b90db0caa3954da740f36b
https://github.com/scummvm/scummvm/commit/5dc90dabc448514ed6b90db0caa3954da740f36b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-07T22:07:10-07:00
Commit Message:
AGS: Added encoding hint to the TRS/TRA
>From upstream 37efe963fd6f3bd62de248a71e8a7aa97a1ba1c2
Changed paths:
engines/ags/shared/game/tra_file.cpp
engines/ags/shared/game/tra_file.h
engines/ags/shared/util/string_utils.cpp
engines/ags/shared/util/string_utils.h
diff --git a/engines/ags/shared/game/tra_file.cpp b/engines/ags/shared/game/tra_file.cpp
index 964bd96a60..a78cc9d7a2 100644
--- a/engines/ags/shared/game/tra_file.cpp
+++ b/engines/ags/shared/game/tra_file.cpp
@@ -73,7 +73,7 @@ HError OpenTraFile(Stream *in) {
return HError::None();
}
-HError ReadTraBlock(Translation &tra, Stream *in, TraFileBlock block, soff_t block_len) {
+HError ReadTraBlock(Translation &tra, Stream *in, TraFileBlock block, const String &ext_id, soff_t block_len) {
switch (block) {
case kTraFblk_Dict:
{
@@ -87,26 +87,36 @@ HError ReadTraBlock(Translation &tra, Stream *in, TraFileBlock block, soff_t blo
break;
tra.Dict.insert(std::make_pair(String(original), String(translation)));
}
+ return HError::None();
}
- break;
case kTraFblk_GameID:
{
char gamename[256];
tra.GameUid = in->ReadInt32();
read_string_decrypt(in, gamename, sizeof(gamename));
tra.GameName = gamename;
+ return HError::None();
}
- break;
case kTraFblk_TextOpts:
tra.NormalFont = in->ReadInt32();
tra.SpeechFont = in->ReadInt32();
tra.RightToLeft = in->ReadInt32();
+ return HError::None();
+ case (TraFileBlock)0:
+ // continue reading extensions with string ID
break;
default:
return new TraFileError(kTraFileErr_UnknownBlockType,
String::FromFormat("Type: %d, known range: %d - %d.", block, kTraFblk_Dict, kTraFblk_TextOpts));
}
- return HError::None();
+
+ if (ext_id.CompareNoCase("ext_sopts") == 0) {
+ StrUtil::ReadStringMap(tra.StrOptions, in);
+ return HError::None();
+ }
+
+ return new TraFileError(kTraFileErr_UnknownBlockType,
+ String::FromFormat("Type: %s", ext_id.GetCStr()));
}
static Translation *reader_tra;
@@ -114,7 +124,7 @@ HError TestTraGameIDReader(Stream *in, int block_id, const String &ext_id,
soff_t block_len, bool &read_next) {
if (block_id == kTraFblk_GameID) {
read_next = false;
- return ReadTraBlock(*reader_tra, in, (TraFileBlock)block_id, block_len);
+ return ReadTraBlock(*reader_tra, in, (TraFileBlock)block_id, ext_id, block_len);
}
in->Seek(block_len); // skip block
return HError::None();
@@ -144,7 +154,7 @@ HError TestTraGameID(int game_uid, const String &game_name, Stream *in) {
// and read compatible data into the given Translation object
HError ReadTraDataReader(Stream *in, int block_id, const String &ext_id,
soff_t block_len, bool &read_next) {
- return ReadTraBlock(*reader_tra, in, (TraFileBlock)block_id, block_len);
+ return ReadTraBlock(*reader_tra, in, (TraFileBlock)block_id, ext_id, block_len);
}
HError ReadTraData(Translation &tra, Stream *in) {
@@ -204,6 +214,10 @@ void WriteTextOpts(const Translation &tra, Stream *out) {
static const Translation *writer_tra;
static void(*writer_writer)(const Translation &tra, Stream *out);
+void WriteStrOptions(const Translation &tra, Stream *out) {
+ StrUtil::WriteStringMap(tra.StrOptions, out);
+}
+
static void WriteTraBlockWriter(Stream *out) {
writer_writer(*writer_tra, out);
}
@@ -217,6 +231,15 @@ inline void WriteTraBlock(const Translation &tra, TraFileBlock block,
kDataExt_NumID32 | kDataExt_File32, out);
}
+inline void WriteTraBlock(const Translation &tra, const String &ext_id,
+ void(*writer)(const Translation &tra, Stream *out), Stream *out) {
+ writer_tra = &tra;
+ writer_writer = writer;
+
+ WriteExtBlock(ext_id, WriteTraBlockWriter,
+ kDataExt_NumID32 | kDataExt_File32, out);
+}
+
void WriteTraData(const Translation &tra, Stream *out) {
// Write header
out->Write(TRASignature, strlen(TRASignature) + 1);
@@ -225,6 +248,7 @@ void WriteTraData(const Translation &tra, Stream *out) {
WriteTraBlock(tra, kTraFblk_GameID, WriteGameID, out);
WriteTraBlock(tra, kTraFblk_Dict, WriteDict, out);
WriteTraBlock(tra, kTraFblk_TextOpts, WriteTextOpts, out);
+ WriteTraBlock(tra, "ext_sopts", WriteStrOptions, out);
// Write ending
out->WriteInt32(kTraFile_EOF);
diff --git a/engines/ags/shared/game/tra_file.h b/engines/ags/shared/game/tra_file.h
index a649b96ddc..6060465d8e 100644
--- a/engines/ags/shared/game/tra_file.h
+++ b/engines/ags/shared/game/tra_file.h
@@ -71,6 +71,7 @@ struct Translation {
int NormalFont = -1; // replacement for normal font, or -1 for default
int SpeechFont = -1; // replacement for speech font, or -1 for default
int RightToLeft = -1; // r2l text mode (0, 1), or -1 for default
+ StringMap StrOptions; // to store extended options with string values
};
diff --git a/engines/ags/shared/util/string_utils.cpp b/engines/ags/shared/util/string_utils.cpp
index 0043049013..134a1845cf 100644
--- a/engines/ags/shared/util/string_utils.cpp
+++ b/engines/ags/shared/util/string_utils.cpp
@@ -198,6 +198,23 @@ void StrUtil::WriteCStr(const String &s, Stream *out) {
out->Write(s.GetCStr(), s.GetLength() + 1);
}
+void StrUtil::ReadStringMap(StringMap &map, Stream *in) {
+ size_t count = in->ReadInt32();
+ for (size_t i = 0; i < count; ++i) {
+ String key = StrUtil::ReadString(in);
+ String value = StrUtil::ReadString(in);
+ map.insert(std::make_pair(key, value));
+ }
+}
+
+void StrUtil::WriteStringMap(const StringMap &map, Stream *out) {
+ out->WriteInt32(map.size());
+ for (const auto &kv : map) {
+ StrUtil::WriteString(kv._key, out);
+ StrUtil::WriteString(kv._value, out);
+ }
+}
+
} // namespace Shared
} // namespace AGS
} // namespace AGS3
diff --git a/engines/ags/shared/util/string_utils.h b/engines/ags/shared/util/string_utils.h
index 9276f56242..6980aac684 100644
--- a/engines/ags/shared/util/string_utils.h
+++ b/engines/ags/shared/util/string_utils.h
@@ -23,7 +23,7 @@
#ifndef AGS_SHARED_UTIL_STRING_UTILS_H
#define AGS_SHARED_UTIL_STRING_UTILS_H
-#include "ags/shared/util/string.h"
+#include "ags/shared/util/string_types.h"
namespace AGS3 {
@@ -82,6 +82,10 @@ void SkipCStr(Stream *in);
void WriteCStr(const char *cstr, Stream *out);
void WriteCStr(const String &s, Stream *out);
+// Serialize and unserialize a string map, both keys and values are read using ReadString
+void ReadStringMap(StringMap &map, Stream *in);
+void WriteStringMap(const StringMap &map, Stream *out);
+
} // namespace StrUtil
} // namespace Shared
} // namespace AGS
Commit: 93bc3a65d4146917579b4b7b38b8ce9e6af98f90
https://github.com/scummvm/scummvm/commit/93bc3a65d4146917579b4b7b38b8ce9e6af98f90
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-07T22:07:10-07:00
Commit Message:
AGS: use text encoding hint from translation
>From upstream f77000a5ef7a7188022c6d5d8f25941ae1e19ef6
Changed paths:
engines/ags/engine/ac/translation.cpp
diff --git a/engines/ags/engine/ac/translation.cpp b/engines/ags/engine/ac/translation.cpp
index d04f80e3be..e91e250d07 100644
--- a/engines/ags/engine/ac/translation.cpp
+++ b/engines/ags/engine/ac/translation.cpp
@@ -105,7 +105,11 @@ bool init_translation(const String &lang, const String &fallback_lang, bool quit
}
// Setup a text encoding mode depending on the translation data hint
- set_uformat(U_ASCII);
+ String encoding = _GP(trans).StrOptions["encoding"];
+ if (encoding.CompareNoCase("utf-8") == 0)
+ set_uformat(U_UTF8);
+ else
+ set_uformat(U_ASCII);
Debug::Printf("Translation initialized: %s", _G(trans_filename).GetCStr());
return true;
Commit: 7e42ae4eecc32ca59cbb1834a8c29cab8f733171
https://github.com/scummvm/scummvm/commit/7e42ae4eecc32ca59cbb1834a8c29cab8f733171
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-07T22:07:10-07:00
Commit Message:
MOHAWK: Revert incorrect format specifier changes
Changed paths:
engines/mohawk/livingbooks_code.cpp
diff --git a/engines/mohawk/livingbooks_code.cpp b/engines/mohawk/livingbooks_code.cpp
index a1c3f01e96..e4179c414f 100644
--- a/engines/mohawk/livingbooks_code.cpp
+++ b/engines/mohawk/livingbooks_code.cpp
@@ -139,7 +139,7 @@ Common::Point LBValue::toPoint() const {
case kLBValueString:
{
Common::Point ret;
- sscanf(string.c_str(), "%d , %d", &ret.x, &ret.y);
+ sscanf(string.c_str(), "%hd , %hd", &ret.x, &ret.y);
return ret;
}
case kLBValueInteger:
@@ -158,7 +158,7 @@ Common::Rect LBValue::toRect() const {
case kLBValueString:
{
Common::Rect ret;
- sscanf(string.c_str(), "%d , %d , %d , %d", &ret.left, &ret.top, &ret.right, &ret.bottom);
+ sscanf(string.c_str(), "%hd , %hd , %hd , %hd", &ret.left, &ret.top, &ret.right, &ret.bottom);
return ret;
}
case kLBValueInteger:
More information about the Scummvm-git-logs
mailing list