SCI32: Add bitmap segment and remove GC option from hunk segment

This commit is contained in:
Colin Snover 2016-07-29 15:48:14 -05:00
parent 4e31c9aaf4
commit 2071196f42
21 changed files with 419 additions and 266 deletions

View File

@ -1984,7 +1984,7 @@ bool Console::cmdShowSavedBits(int argc, const char **argv) {
byte bakMask = GFX_SCREEN_MASK_VISUAL | GFX_SCREEN_MASK_PRIORITY | GFX_SCREEN_MASK_CONTROL;
int bakSize = _engine->_gfxScreen->bitsGetDataSize(rect, bakMask);
reg_t bakScreen = segman->allocateHunkEntry("show_saved_bits backup", bakSize, true);
reg_t bakScreen = segman->allocateHunkEntry("show_saved_bits backup", bakSize);
byte* bakMemory = segman->getHunkPointer(bakScreen);
assert(bakMemory);
_engine->_gfxScreen->bitsSave(rect, bakMask, bakMemory);
@ -2080,6 +2080,10 @@ bool Console::cmdPrintSegmentTable(int argc, const char **argv) {
case SEG_TYPE_STRING:
debugPrintf("T SCI32 strings (%d)", (*(StringTable *)mobj).entries_used);
break;
case SEG_TYPE_BITMAP:
debugPrintf("T SCI32 bitmaps (%d)", (*(BitmapTable *)mobj).entries_used);
break;
#endif
default:
@ -2214,6 +2218,9 @@ bool Console::segmentInfo(int nr) {
case SEG_TYPE_ARRAY:
debugPrintf("SCI32 arrays\n");
break;
case SEG_TYPE_BITMAP:
debugPrintf("SCI32 bitmaps\n");
break;
#endif
default :
@ -2815,6 +2822,12 @@ bool Console::cmdViewReference(int argc, const char **argv) {
hexDumpReg(array->getRawData(), array->getSize(), 4, 0, true);
break;
}
case SEG_TYPE_BITMAP: {
debugPrintf("SCI32 bitmap:\n");
const SciBitmap *bitmap = _engine->_gamestate->_segMan->lookupBitmap(reg);
Common::hexdump((const byte *) bitmap->getRawData(), bitmap->getRawSize(), 16, 0);
break;
}
#endif
default: {
const SegmentRef block = _engine->_gamestate->_segMan->dereference(reg);

View File

@ -154,16 +154,18 @@ AddrSet *findAllActiveReferences(EngineState *s) {
}
}
// Init: Explicitly opted-out hunks
else if (heap[i]->getType() == SEG_TYPE_HUNK) {
HunkTable *ht = static_cast<HunkTable *>(heap[i]);
#ifdef ENABLE_SCI32
// Init: Explicitly opted-out bitmaps
else if (heap[i]->getType() == SEG_TYPE_BITMAP) {
BitmapTable *bt = static_cast<BitmapTable *>(heap[i]);
for (uint j = 0; j < ht->_table.size(); j++) {
if (!ht->_table[j].data.gc) {
for (uint j = 0; j < bt->_table.size(); j++) {
if (!bt->_table[j].data.getShouldGC()) {
wm.push(make_reg(i, j));
}
}
}
#endif
}
}

View File

@ -408,6 +408,7 @@ uint16 Kernel::findRegType(reg_t reg) {
#ifdef ENABLE_SCI32
case SEG_TYPE_ARRAY:
case SEG_TYPE_STRING:
case SEG_TYPE_BITMAP:
#endif
result |= SIG_TYPE_REFERENCE;
break;

View File

@ -536,13 +536,14 @@ reg_t kBitmapCreate(EngineState *s, int argc, reg_t *argv) {
int16 scaledHeight = argc > 5 ? argv[5].toSint16() : g_sci->_gfxText32->_scaledHeight;
bool useRemap = argc > 6 ? argv[6].toSint16() : false;
BitmapResource bitmap(s->_segMan, width, height, skipColor, 0, 0, scaledWidth, scaledHeight, 0, useRemap, true);
reg_t bitmapId;
SciBitmap &bitmap = *s->_segMan->allocateBitmap(&bitmapId, width, height, skipColor, 0, 0, scaledWidth, scaledHeight, 0, useRemap, true);
memset(bitmap.getPixels(), backColor, width * height);
return bitmap.getObject();
return bitmapId;
}
reg_t kBitmapDestroy(EngineState *s, int argc, reg_t *argv) {
s->_segMan->freeHunkEntry(argv[0]);
s->_segMan->freeBitmap(argv[0]);
return s->r_acc;
}
@ -552,7 +553,7 @@ reg_t kBitmapDrawLine(EngineState *s, int argc, reg_t *argv) {
}
reg_t kBitmapDrawView(EngineState *s, int argc, reg_t *argv) {
BitmapResource bitmap(argv[0]);
SciBitmap &bitmap = *s->_segMan->lookupBitmap(argv[0]);
CelObjView view(argv[1].toUint16(), argv[2].toSint16(), argv[3].toSint16());
const int16 x = argc > 4 ? argv[4].toSint16() : 0;
@ -582,7 +583,7 @@ reg_t kBitmapDrawView(EngineState *s, int argc, reg_t *argv) {
reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) {
// called e.g. from TextButton::createBitmap() in Torin's Passage, script 64894
BitmapResource bitmap(argv[0]);
SciBitmap &bitmap = *s->_segMan->lookupBitmap(argv[0]);
Common::String text = s->_segMan->getString(argv[1]);
Common::Rect textRect(
argv[2].toSint16(),
@ -609,7 +610,7 @@ reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) {
reg_t textBitmapObject = g_sci->_gfxText32->createFontBitmap(textRect.width(), textRect.height(), Common::Rect(textRect.width(), textRect.height()), text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, false, false);
CelObjMem textCel(textBitmapObject);
textCel.draw(bitmap.getBuffer(), textRect, Common::Point(textRect.left, textRect.top), false);
s->_segMan->freeHunkEntry(textBitmapObject);
s->_segMan->freeBitmap(textBitmapObject);
return s->r_acc;
}
@ -617,7 +618,7 @@ reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) {
reg_t kBitmapDrawColor(EngineState *s, int argc, reg_t *argv) {
// called e.g. from TextView::init() and TextView::draw() in Torin's Passage, script 64890
BitmapResource bitmap(argv[0]);
SciBitmap &bitmap = *s->_segMan->lookupBitmap(argv[0]);
Common::Rect fillRect(
argv[1].toSint16(),
argv[2].toSint16(),
@ -642,7 +643,7 @@ reg_t kBitmapInvert(EngineState *s, int argc, reg_t *argv) {
}
reg_t kBitmapSetDisplace(EngineState *s, int argc, reg_t *argv) {
BitmapResource bitmap(argv[0]);
SciBitmap &bitmap = *s->_segMan->lookupBitmap(argv[0]);
bitmap.setDisplace(Common::Point(argv[1].toSint16(), argv[2].toSint16()));
return s->r_acc;
}

View File

@ -40,7 +40,7 @@ reg_t kLoad(EngineState *s, int argc, reg_t *argv) {
// Request to dynamically allocate hunk memory for later use
if (restype == kResourceTypeMemory)
return s->_segMan->allocateHunkEntry("kLoad()", resnr, true);
return s->_segMan->allocateHunkEntry("kLoad()", resnr);
return make_reg(0, ((restype << 11) | resnr)); // Return the resource identifier as handle
}

View File

@ -158,6 +158,18 @@ void syncWithSerializer(Common::Serializer &s, SciString &obj) {
obj.setValue(i, value);
}
}
void syncWithSerializer(Common::Serializer &s, SciBitmap &obj) {
debug("TODO: Sync bitmap");
// if (s.isSaving()) {
// size = obj.getSize();
// s.syncAsUint32LE(size);
// } else {
// s.syncAsUint32LE(size);
// obj.setSize(size);
// }
}
#endif
#pragma mark -
@ -273,6 +285,8 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
} else if (type == SEG_TYPE_STRING) {
// Set the correct segment for SCI32 strings
_stringSegId = i;
} else if (s.getVersion() >= 36 && type == SEG_TYPE_BITMAP) {
_bitmapSegId = i;
#endif
}
@ -687,6 +701,14 @@ void StringTable::saveLoadWithSerializer(Common::Serializer &ser) {
sync_Table<StringTable>(ser, *this);
}
void BitmapTable::saveLoadWithSerializer(Common::Serializer &ser) {
if (ser.getVersion() < 36)
return;
// TODO: Should only include bitmaps with gc = true
sync_Table(ser, *this);
}
#endif
void GfxPalette::palVarySaveLoadPalette(Common::Serializer &s, Palette *palette) {

View File

@ -37,6 +37,7 @@ struct EngineState;
*
* Version - new/changed feature
* =============================
* 36 - SCI32 bitmap segment
* 35 - SCI32 remap
* 34 - SCI32 palettes, and store play time in ticks
* 33 - new overridePriority flag in MusicEntry
@ -60,7 +61,7 @@ struct EngineState;
*/
enum {
CURRENT_SAVEGAME_VERSION = 35,
CURRENT_SAVEGAME_VERSION = 36,
MINIMUM_SAVEGAME_VERSION = 14
};

View File

@ -43,6 +43,7 @@ SegManager::SegManager(ResourceManager *resMan, ScriptPatcher *scriptPatcher)
#ifdef ENABLE_SCI32
_arraysSegId = 0;
_stringSegId = 0;
_bitmapSegId = 0;
#endif
createClassTable();
@ -72,6 +73,7 @@ void SegManager::resetSegMan() {
#ifdef ENABLE_SCI32
_arraysSegId = 0;
_stringSegId = 0;
_bitmapSegId = 0;
#endif
// Reinitialize class table
@ -393,7 +395,7 @@ void SegManager::freeHunkEntry(reg_t addr) {
ht->freeEntryContents(addr.getOffset());
}
reg_t SegManager::allocateHunkEntry(const char *hunk_type, int size, bool gc) {
reg_t SegManager::allocateHunkEntry(const char *hunk_type, int size) {
HunkTable *table;
int offset;
@ -412,7 +414,6 @@ reg_t SegManager::allocateHunkEntry(const char *hunk_type, int size, bool gc) {
h->mem = malloc(size);
h->size = size;
h->type = hunk_type;
h->gc = gc;
return addr;
}
@ -942,6 +943,60 @@ void SegManager::freeString(reg_t addr) {
stringTable.freeEntry(addr.getOffset());
}
#pragma mark -
#pragma mark Bitmaps
SciBitmap *SegManager::allocateBitmap(reg_t *addr, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 paletteSize, const bool remap, const bool gc) {
BitmapTable *table;
int offset;
if (!_bitmapSegId) {
table = (BitmapTable *)allocSegment(new BitmapTable(), &(_bitmapSegId));
} else {
table = (BitmapTable *)_heap[_bitmapSegId];
}
offset = table->allocEntry();
*addr = make_reg(_bitmapSegId, offset);
SciBitmap *bitmap = &table->at(offset);
if (bitmap == nullptr) {
*addr = NULL_REG;
}
bitmap->create(width, height, skipColor, displaceX, displaceY, scaledWidth, scaledHeight, paletteSize, remap, gc);
return bitmap;
}
SciBitmap *SegManager::lookupBitmap(const reg_t addr) {
if (_heap[addr.getSegment()]->getType() != SEG_TYPE_BITMAP)
error("Attempt to use non-bitmap %04x:%04x as bitmap", PRINT_REG(addr));
BitmapTable &bitmapTable = *(BitmapTable *)_heap[addr.getSegment()];
if (!bitmapTable.isValidEntry(addr.getOffset()))
error("Attempt to use non-bitmap %04x:%04x as bitmap", PRINT_REG(addr));
return &(bitmapTable.at(addr.getOffset()));
}
void SegManager::freeBitmap(const reg_t addr) {
if (_heap[addr.getSegment()]->getType() != SEG_TYPE_BITMAP)
error("Attempt to use non-bitmap %04x:%04x as bitmap", PRINT_REG(addr));
BitmapTable &bitmapTable = *(BitmapTable *)_heap[addr.getSegment()];
if (!bitmapTable.isValidEntry(addr.getOffset()))
error("Attempt to use non-bitmap %04x:%04x as bitmap", PRINT_REG(addr));
bitmapTable.at(addr.getOffset()).destroy();
bitmapTable.freeEntry(addr.getOffset());
}
#pragma mark -
#endif
void SegManager::createClassTable() {

View File

@ -29,6 +29,10 @@
#include "sci/engine/vm.h"
#include "sci/engine/vm_types.h"
#include "sci/engine/segment.h"
#ifdef ENABLE_SCI32
// TODO: Baaaad?
#include "sci/graphics/celobj32.h"
#endif
namespace Sci {
@ -225,11 +229,9 @@ public:
* @param[in] size Number of bytes to allocate for the hunk entry
* @param[in] hunk_type A descriptive string for the hunk entry, for
* debugging purposes
* @param[in] gc Whether to make the hunk eligible for garbage
* collection
* @return The offset of the freshly allocated hunk entry
*/
reg_t allocateHunkEntry(const char *hunk_type, int size, bool gc);
reg_t allocateHunkEntry(const char *hunk_type, int size);
/**
* Deallocates a hunk entry
@ -435,10 +437,15 @@ public:
SciArray<reg_t> *allocateArray(reg_t *addr);
SciArray<reg_t> *lookupArray(reg_t addr);
void freeArray(reg_t addr);
SciString *allocateString(reg_t *addr);
SciString *lookupString(reg_t addr);
void freeString(reg_t addr);
SegmentId getStringSegmentId() { return _stringSegId; }
SciBitmap *allocateBitmap(reg_t *addr, const int16 width, const int16 height, const uint8 skipColor = kDefaultSkipColor, const int16 displaceX = 0, const int16 displaceY = 0, const int16 scaledWidth = kLowResX, const int16 scaledHeight = kLowResY, const uint32 paletteSize = 0, const bool remap = false, const bool gc = true);
SciBitmap *lookupBitmap(reg_t addr);
void freeBitmap(reg_t addr);
#endif
const Common::Array<SegmentObj *> &getSegments() const { return _heap; }
@ -464,6 +471,7 @@ private:
#ifdef ENABLE_SCI32
SegmentId _arraysSegId;
SegmentId _stringSegId;
SegmentId _bitmapSegId;
#endif
public:

View File

@ -70,6 +70,9 @@ SegmentObj *SegmentObj::createSegmentObj(SegmentType type) {
case SEG_TYPE_STRING:
mem = new StringTable();
break;
case SEG_TYPE_BITMAP:
mem = new BitmapTable();
break;
#endif
default:
error("Unknown SegmentObj type %d", type);
@ -310,6 +313,17 @@ SegmentRef StringTable::dereference(reg_t pointer) {
return ret;
}
#pragma mark -
#pragma mark Bitmaps
SegmentRef BitmapTable::dereference(reg_t pointer) {
SegmentRef ret;
ret.isRaw = true;
ret.maxSize = at(pointer.getOffset()).getRawSize();
ret.raw = at(pointer.getOffset()).getRawData();
return ret;
}
#endif
} // End of namespace Sci

View File

@ -71,6 +71,7 @@ enum SegmentType {
#ifdef ENABLE_SCI32
SEG_TYPE_ARRAY = 11,
SEG_TYPE_STRING = 12,
SEG_TYPE_BITMAP = 13,
#endif
SEG_TYPE_MAX // For sanity checking
@ -205,7 +206,6 @@ struct Hunk {
void *mem;
uint32 size;
const char *type;
bool gc;
};
template<typename T>
@ -520,6 +520,244 @@ struct StringTable : public SegmentObjTable<SciString> {
SegmentRef dereference(reg_t pointer);
};
#pragma mark -
#pragma mark Bitmaps
enum {
kDefaultSkipColor = 250
};
#define BITMAP_PROPERTY(size, property, offset)\
inline uint##size get##property() const {\
return READ_SCI11ENDIAN_UINT##size(_data + (offset));\
}\
inline void set##property(uint##size value) {\
WRITE_SCI11ENDIAN_UINT##size(_data + (offset), (value));\
}
/**
* A convenience class for creating and modifying in-memory
* bitmaps.
*/
class SciBitmap {
byte *_data;
int _dataSize;
Buffer _buffer;
bool _gc;
public:
enum BitmapFlags {
kBitmapRemap = 2
};
/**
* Gets the size of the bitmap header for the current
* engine version.
*/
static inline uint16 getBitmapHeaderSize() {
// TODO: These values are accurate for each engine, but there may be no reason
// to not simply just always use size 40, since SCI2.1mid does not seem to
// actually store any data above byte 40, and SCI2 did not allow bitmaps with
// scaling resolutions other than the default (320x200). Perhaps SCI3 used
// the extra bytes, or there is some reason why they tried to align the header
// size with other headers like pic headers?
// uint32 bitmapHeaderSize;
// if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
// bitmapHeaderSize = 46;
// } else if (getSciVersion() == SCI_VERSION_2_1_EARLY) {
// bitmapHeaderSize = 40;
// } else {
// bitmapHeaderSize = 36;
// }
// return bitmapHeaderSize;
return 46;
}
/**
* Gets the byte size of a bitmap with the given width
* and height.
*/
static inline uint32 getBitmapSize(const uint16 width, const uint16 height) {
return width * height + getBitmapHeaderSize();
}
inline SciBitmap() : _data(nullptr), _dataSize(0), _gc(true) {}
/**
* Allocates and initialises a new bitmap.
*/
inline void create(const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 paletteSize, const bool remap, const bool gc) {
_dataSize = getBitmapSize(width, height) + paletteSize;
_data = (byte *)realloc(_data, _dataSize);
_gc = gc;
const uint16 bitmapHeaderSize = getBitmapHeaderSize();
setWidth(width);
setHeight(height);
setDisplace(Common::Point(displaceX, displaceY));
setSkipColor(skipColor);
_data[9] = 0;
WRITE_SCI11ENDIAN_UINT16(_data + 10, 0);
setRemap(remap);
setDataSize(width * height);
WRITE_SCI11ENDIAN_UINT32(_data + 16, 0);
setHunkPaletteOffset(paletteSize > 0 ? (width * height) : 0);
setDataOffset(bitmapHeaderSize);
setUncompressedDataOffset(bitmapHeaderSize);
setControlOffset(0);
setScaledWidth(scaledWidth);
setScaledHeight(scaledHeight);
_buffer = Buffer(getWidth(), getHeight(), getPixels());
}
inline void destroy() {
free(_data);
_data = nullptr;
_dataSize = 0;
}
inline int getRawSize() const {
return _dataSize;
}
inline byte *getRawData() const {
return _data;
}
inline Buffer &getBuffer() {
return _buffer;
}
inline bool getShouldGC() const {
return _gc;
}
inline void enableGC() {
_gc = true;
}
inline void disableGC() {
_gc = false;
}
BITMAP_PROPERTY(16, Width, 0);
BITMAP_PROPERTY(16, Height, 2);
inline Common::Point getDisplace() const {
return Common::Point(
(int16)READ_SCI11ENDIAN_UINT16(_data + 4),
(int16)READ_SCI11ENDIAN_UINT16(_data + 6)
);
}
inline void setDisplace(const Common::Point &displace) {
WRITE_SCI11ENDIAN_UINT16(_data + 4, (uint16)displace.x);
WRITE_SCI11ENDIAN_UINT16(_data + 6, (uint16)displace.y);
}
inline uint8 getSkipColor() const {
return _data[8];
}
inline void setSkipColor(const uint8 skipColor) {
_data[8] = skipColor;
}
inline bool getRemap() const {
return READ_SCI11ENDIAN_UINT16(_data + 10) & kBitmapRemap;
}
inline void setRemap(const bool remap) {
uint16 flags = READ_SCI11ENDIAN_UINT16(_data + 10);
if (remap) {
flags |= kBitmapRemap;
} else {
flags &= ~kBitmapRemap;
}
WRITE_SCI11ENDIAN_UINT16(_data + 10, flags);
}
BITMAP_PROPERTY(32, DataSize, 12);
inline uint32 getHunkPaletteOffset() const {
return READ_SCI11ENDIAN_UINT32(_data + 20);
}
inline void setHunkPaletteOffset(uint32 hunkPaletteOffset) {
if (hunkPaletteOffset) {
hunkPaletteOffset += getBitmapHeaderSize();
}
WRITE_SCI11ENDIAN_UINT32(_data + 20, hunkPaletteOffset);
}
BITMAP_PROPERTY(32, DataOffset, 24);
// NOTE: This property is used as a "magic number" for
// validating that a block of memory is a valid bitmap,
// and so is always set to the size of the header.
BITMAP_PROPERTY(32, UncompressedDataOffset, 28);
// NOTE: This property always seems to be zero
BITMAP_PROPERTY(32, ControlOffset, 32);
inline uint16 getScaledWidth() const {
if (getDataOffset() >= 40) {
return READ_SCI11ENDIAN_UINT16(_data + 36);
}
// SCI2 bitmaps did not have scaling ability
return 320;
}
inline void setScaledWidth(uint16 scaledWidth) {
if (getDataOffset() >= 40) {
WRITE_SCI11ENDIAN_UINT16(_data + 36, scaledWidth);
}
}
inline uint16 getScaledHeight() const {
if (getDataOffset() >= 40) {
return READ_SCI11ENDIAN_UINT16(_data + 38);
}
// SCI2 bitmaps did not have scaling ability
return 200;
}
inline void setScaledHeight(uint16 scaledHeight) {
if (getDataOffset() >= 40) {
WRITE_SCI11ENDIAN_UINT16(_data + 38, scaledHeight);
}
}
inline byte *getPixels() {
return _data + getUncompressedDataOffset();
}
inline byte *getHunkPalette() {
if (getHunkPaletteOffset() == 0) {
return nullptr;
}
return _data + getHunkPaletteOffset();
}
};
struct BitmapTable : public SegmentObjTable<SciBitmap> {
BitmapTable() : SegmentObjTable<SciBitmap>(SEG_TYPE_BITMAP) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) {
at(sub_addr.getOffset()).destroy();
freeEntry(sub_addr.getOffset());
}
void saveLoadWithSerializer(Common::Serializer &ser);
SegmentRef dereference(reg_t pointer);
};
#endif

View File

@ -1088,7 +1088,7 @@ CelObjMem::CelObjMem(const reg_t bitmapObject) {
_celHeaderOffset = 0;
_transparent = true;
BitmapResource bitmap(bitmapObject);
SciBitmap &bitmap = *g_sci->getEngineState()->_segMan->lookupBitmap(bitmapObject);
_width = bitmap.getWidth();
_height = bitmap.getHeight();
_displace = bitmap.getDisplace();
@ -1104,7 +1104,7 @@ CelObjMem *CelObjMem::duplicate() const {
}
byte *CelObjMem::getResPointer() const {
return g_sci->getEngineState()->_segMan->getHunkPointer(_info.bitmap);
return g_sci->getEngineState()->_segMan->lookupBitmap(_info.bitmap)->getRawData();
}
#pragma mark -

View File

@ -309,7 +309,7 @@ reg_t GfxControls32::kernelEditText(const reg_t controlObject) {
g_sci->_gfxFrameout->frameOut(true);
}
_segMan->freeHunkEntry(editor.bitmap);
_segMan->freeBitmap(editor.bitmap);
if (textChanged) {
editor.text.trim();
@ -419,7 +419,7 @@ ScrollWindow::ScrollWindow(SegManager *segMan, const Common::Rect &gameRect, con
}
ScrollWindow::~ScrollWindow() {
_segMan->freeHunkEntry(_bitmap);
_segMan->freeBitmap(_bitmap);
// _screenItem will be deleted by GfxFrameout
}

View File

@ -334,7 +334,7 @@ reg_t GfxPaint16::bitsSave(const Common::Rect &rect, byte screenMask) {
// now actually ask _screen how much space it will need for saving
size = _screen->bitsGetDataSize(workerRect, screenMask);
memoryId = _segMan->allocateHunkEntry("SaveBits()", size, true);
memoryId = _segMan->allocateHunkEntry("SaveBits()", size);
memoryPtr = _segMan->getHunkPointer(memoryId);
if (memoryPtr)
_screen->bitsSave(workerRect, screenMask, memoryPtr);

View File

@ -37,11 +37,12 @@ reg_t GfxPaint32::kernelAddLine(const reg_t planeObject, const Common::Point &st
}
Common::Rect gameRect;
BitmapResource bitmap = makeLineBitmap(startPoint, endPoint, priority, color, style, pattern, thickness, gameRect);
reg_t bitmapId = makeLineBitmap(startPoint, endPoint, priority, color, style, pattern, thickness, gameRect);
SciBitmap &bitmap = *_segMan->lookupBitmap(bitmapId);
CelInfo32 celInfo;
celInfo.type = kCelTypeMem;
celInfo.bitmap = bitmap.getObject();
celInfo.bitmap = bitmapId;
// SSCI stores the line color on `celInfo`, even though
// this is not a `kCelTypeColor`, as a hack so that
// `kUpdateLine` can get the originally used color
@ -59,10 +60,10 @@ reg_t GfxPaint32::kernelAddLine(const reg_t planeObject, const Common::Point &st
void GfxPaint32::kernelUpdateLine(ScreenItem *screenItem, Plane *plane, const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, const uint16 pattern, const uint8 thickness) {
Common::Rect gameRect;
BitmapResource bitmap = makeLineBitmap(startPoint, endPoint, priority, color, style, pattern, thickness, gameRect);
reg_t bitmapId = makeLineBitmap(startPoint, endPoint, priority, color, style, pattern, thickness, gameRect);
_segMan->freeHunkEntry(screenItem->_celInfo.bitmap);
screenItem->_celInfo.bitmap = bitmap.getObject();
_segMan->freeBitmap(screenItem->_celInfo.bitmap);
screenItem->_celInfo.bitmap = bitmapId;
screenItem->_celInfo.color = color;
screenItem->_position = startPoint;
screenItem->_priority = priority;
@ -80,7 +81,7 @@ void GfxPaint32::kernelDeleteLine(const reg_t screenItemObject, const reg_t plan
return;
}
_segMan->freeHunkEntry(screenItem->_celInfo.bitmap);
_segMan->freeBitmap(screenItem->_celInfo.bitmap);
g_sci->_gfxFrameout->deleteScreenItem(*screenItem, *plane);
}
@ -116,7 +117,7 @@ void GfxPaint32::plotter(int x, int y, int color, void *data) {
}
}
BitmapResource GfxPaint32::makeLineBitmap(const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, uint16 pattern, uint8 thickness, Common::Rect &outRect) {
reg_t GfxPaint32::makeLineBitmap(const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, uint16 pattern, uint8 thickness, Common::Rect &outRect) {
const uint8 skipColor = color != kDefaultSkipColor ? kDefaultSkipColor : 0;
// Thickness is expected to be 2n+1
@ -128,7 +129,8 @@ BitmapResource GfxPaint32::makeLineBitmap(const Common::Point &startPoint, const
outRect.right = (startPoint.x > endPoint.x ? startPoint.x : endPoint.x) + halfThickness + 1;
outRect.bottom = (startPoint.y > endPoint.y ? startPoint.y : endPoint.y) + halfThickness + 1;
BitmapResource bitmap(_segMan, outRect.width(), outRect.height(), skipColor, 0, 0, g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth, g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight, 0, false, true);
reg_t bitmapId;
SciBitmap &bitmap = *_segMan->allocateBitmap(&bitmapId, outRect.width(), outRect.height(), skipColor, 0, 0, g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth, g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight, 0, false, true);
byte *pixels = bitmap.getPixels();
memset(pixels, skipColor, bitmap.getWidth() * bitmap.getHeight());
@ -174,7 +176,7 @@ BitmapResource GfxPaint32::makeLineBitmap(const Common::Point &startPoint, const
Graphics::drawThickLine2(drawRect.left, drawRect.top, drawRect.right, drawRect.bottom, thickness, color, plotter, &properties);
}
return bitmap;
return bitmapId;
}

View File

@ -24,8 +24,8 @@
#define SCI_GRAPHICS_PAINT32_H
namespace Sci {
class BitmapResource;
class Plane;
class SciBitmap;
class ScreenItem;
class SegManager;
@ -54,7 +54,7 @@ public:
private:
typedef struct {
BitmapResource *bitmap;
SciBitmap *bitmap;
bool pattern[16];
uint8 patternIndex;
bool solid;
@ -64,7 +64,7 @@ private:
static void plotter(int x, int y, int color, void *data);
BitmapResource makeLineBitmap(const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, const uint16 pattern, const uint8 thickness, Common::Rect &outRect);
reg_t makeLineBitmap(const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, const uint16 pattern, const uint8 thickness, Common::Rect &outRect);
};
} // End of namespace Sci

View File

@ -626,7 +626,7 @@ void GfxPalette::kernelAnimateSet() {
reg_t GfxPalette::kernelSave() {
SegManager *segMan = g_sci->getEngineState()->_segMan;
reg_t memoryId = segMan->allocateHunkEntry("kPalette(save)", 1024, true);
reg_t memoryId = segMan->allocateHunkEntry("kPalette(save)", 1024);
byte *memoryPtr = segMan->getHunkPointer(memoryId);
if (memoryPtr) {
for (int colorNr = 0; colorNr < 256; colorNr++) {

View File

@ -96,8 +96,7 @@ reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect
_textRect = Common::Rect();
}
BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false, gc);
_bitmap = bitmap.getObject();
_segMan->allocateBitmap(&_bitmap, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false, gc);
erase(bitmapRect, false);
@ -135,8 +134,7 @@ reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &
_textRect = Common::Rect();
}
BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false, gc);
_bitmap = bitmap.getObject();
SciBitmap &bitmap = *_segMan->allocateBitmap(&_bitmap, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false, gc);
// NOTE: The engine filled the bitmap pixels with 11 here, which is silly
// because then it just erased the bitmap using the skip color. So we don't
@ -180,8 +178,8 @@ void GfxText32::setFont(const GuiResourceId fontId) {
void GfxText32::drawFrame(const Common::Rect &rect, const int16 size, const uint8 color, const bool doScaling) {
Common::Rect targetRect = doScaling ? scaleRect(rect) : rect;
byte *bitmap = _segMan->getHunkPointer(_bitmap);
byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28) + rect.top * _width + rect.left;
SciBitmap &bitmap = *_segMan->lookupBitmap(_bitmap);
byte *pixels = bitmap.getPixels() + rect.top * _width + rect.left;
// NOTE: Not fully disassembled, but this should be right
int16 rectWidth = targetRect.width();
@ -210,8 +208,8 @@ void GfxText32::drawFrame(const Common::Rect &rect, const int16 size, const uint
}
void GfxText32::drawChar(const char charIndex) {
byte *bitmap = _segMan->getHunkPointer(_bitmap);
byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28);
SciBitmap &bitmap = *_segMan->lookupBitmap(_bitmap);
byte *pixels = bitmap.getPixels();
_font->drawToBuffer(charIndex, _drawPosition.y, _drawPosition.x, _foreColor, _dimmed, pixels, _width, _height);
_drawPosition.x += _font->getCharWidth(charIndex);
@ -328,14 +326,14 @@ void GfxText32::drawText(const uint index, uint length) {
}
}
void GfxText32::invertRect(const reg_t bitmap, int16 bitmapStride, const Common::Rect &rect, const uint8 foreColor, const uint8 backColor, const bool doScaling) {
void GfxText32::invertRect(const reg_t bitmapId, int16 bitmapStride, const Common::Rect &rect, const uint8 foreColor, const uint8 backColor, const bool doScaling) {
Common::Rect targetRect = rect;
if (doScaling) {
bitmapStride = bitmapStride * _scaledWidth / g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
targetRect = scaleRect(rect);
}
byte *bitmapData = _segMan->getHunkPointer(bitmap);
SciBitmap &bitmap = *_segMan->lookupBitmap(bitmapId);
// NOTE: SCI code is super weird here; it seems to be trying to look at the
// entire size of the bitmap including the header, instead of just the pixel
@ -345,14 +343,14 @@ void GfxText32::invertRect(const reg_t bitmap, int16 bitmapStride, const Common:
// function was never updated to match? Or maybe they exploit the
// configurable stride length somewhere else to do stair stepping inverts...
uint32 invertSize = targetRect.height() * bitmapStride + targetRect.width();
uint32 bitmapSize = READ_SCI11ENDIAN_UINT32(bitmapData + 12);
uint32 bitmapSize = bitmap.getDataSize();
if (invertSize >= bitmapSize) {
error("InvertRect too big: %u >= %u", invertSize, bitmapSize);
}
// NOTE: Actual engine just added the bitmap header size hardcoded here
byte *pixel = bitmapData + READ_SCI11ENDIAN_UINT32(bitmapData + 28) + bitmapStride * targetRect.top + targetRect.left;
byte *pixel = bitmap.getPixels() + bitmapStride * targetRect.top + targetRect.left;
int16 stride = bitmapStride - targetRect.width();
int16 targetHeight = targetRect.height();
@ -615,7 +613,7 @@ Common::Rect GfxText32::getTextSize(const Common::String &text, int16 maxWidth,
void GfxText32::erase(const Common::Rect &rect, const bool doScaling) {
Common::Rect targetRect = doScaling ? scaleRect(rect) : rect;
BitmapResource bitmap(_bitmap);
SciBitmap &bitmap = *_segMan->lookupBitmap(_bitmap);
bitmap.getBuffer().fillRect(targetRect, _backColor);
}
@ -652,7 +650,7 @@ int16 GfxText32::getTextCount(const Common::String &text, const uint index, cons
}
void GfxText32::scrollLine(const Common::String &lineText, int numLines, uint8 color, TextAlign align, GuiResourceId fontId, ScrollDirection dir) {
BitmapResource bmr(_bitmap);
SciBitmap &bmr = *_segMan->lookupBitmap(_bitmap);
byte *pixels = bmr.getPixels();
int h = _font->getHeight();

View File

@ -42,210 +42,6 @@ enum ScrollDirection {
kScrollDown
};
enum BitmapFlags {
kBitmapRemap = 2
};
enum {
kDefaultSkipColor = 250
};
#define BITMAP_PROPERTY(size, property, offset)\
inline uint##size get##property() const {\
return READ_SCI11ENDIAN_UINT##size(_bitmap + (offset));\
}\
inline void set##property(uint##size value) {\
WRITE_SCI11ENDIAN_UINT##size(_bitmap + (offset), (value));\
}
/**
* A convenience class for creating and modifying in-memory
* bitmaps.
*/
class BitmapResource {
byte *_bitmap;
reg_t _object;
Buffer _buffer;
/**
* Gets the size of the bitmap header for the current
* engine version.
*/
static inline uint16 getBitmapHeaderSize() {
// TODO: These values are accurate for each engine, but there may be no reason
// to not simply just always use size 40, since SCI2.1mid does not seem to
// actually store any data above byte 40, and SCI2 did not allow bitmaps with
// scaling resolutions other than the default (320x200). Perhaps SCI3 used
// the extra bytes, or there is some reason why they tried to align the header
// size with other headers like pic headers?
// uint32 bitmapHeaderSize;
// if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
// bitmapHeaderSize = 46;
// } else if (getSciVersion() == SCI_VERSION_2_1_EARLY) {
// bitmapHeaderSize = 40;
// } else {
// bitmapHeaderSize = 36;
// }
// return bitmapHeaderSize;
return 46;
}
/**
* Gets the byte size of a bitmap with the given width
* and height.
*/
static inline uint32 getBitmapSize(const uint16 width, const uint16 height) {
return width * height + getBitmapHeaderSize();
}
public:
/**
* Create a bitmap resource for an existing bitmap.
* Ownership of the bitmap is retained by the caller.
*/
inline BitmapResource(reg_t bitmap) :
_bitmap(g_sci->getEngineState()->_segMan->getHunkPointer(bitmap)),
_object(bitmap) {
if (_bitmap == nullptr || getUncompressedDataOffset() != getBitmapHeaderSize()) {
error("Invalid Text bitmap %04x:%04x", PRINT_REG(bitmap));
}
_buffer = Buffer(getWidth(), getHeight(), getPixels());
}
/**
* Allocates and initialises a new bitmap in the given
* segment manager.
*/
inline BitmapResource(SegManager *segMan, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 paletteSize, const bool remap, const bool gc) {
_object = segMan->allocateHunkEntry("Bitmap()", getBitmapSize(width, height) + paletteSize, gc);
_bitmap = segMan->getHunkPointer(_object);
const uint16 bitmapHeaderSize = getBitmapHeaderSize();
setWidth(width);
setHeight(height);
setDisplace(Common::Point(displaceX, displaceY));
setSkipColor(skipColor);
_bitmap[9] = 0;
WRITE_SCI11ENDIAN_UINT16(_bitmap + 10, 0);
setRemap(remap);
setDataSize(width * height);
WRITE_SCI11ENDIAN_UINT32(_bitmap + 16, 0);
setHunkPaletteOffset(paletteSize > 0 ? (width * height) : 0);
setDataOffset(bitmapHeaderSize);
setUncompressedDataOffset(bitmapHeaderSize);
setControlOffset(0);
setScaledWidth(scaledWidth);
setScaledHeight(scaledHeight);
_buffer = Buffer(getWidth(), getHeight(), getPixels());
}
inline reg_t getObject() const {
return _object;
}
inline Buffer &getBuffer() {
return _buffer;
}
BITMAP_PROPERTY(16, Width, 0);
BITMAP_PROPERTY(16, Height, 2);
inline Common::Point getDisplace() const {
return Common::Point(
(int16)READ_SCI11ENDIAN_UINT16(_bitmap + 4),
(int16)READ_SCI11ENDIAN_UINT16(_bitmap + 6)
);
}
inline void setDisplace(const Common::Point &displace) {
WRITE_SCI11ENDIAN_UINT16(_bitmap + 4, (uint16)displace.x);
WRITE_SCI11ENDIAN_UINT16(_bitmap + 6, (uint16)displace.y);
}
inline uint8 getSkipColor() const {
return _bitmap[8];
}
inline void setSkipColor(const uint8 skipColor) {
_bitmap[8] = skipColor;
}
inline bool getRemap() const {
return READ_SCI11ENDIAN_UINT16(_bitmap + 10) & kBitmapRemap;
}
inline void setRemap(const bool remap) {
uint16 flags = READ_SCI11ENDIAN_UINT16(_bitmap + 10);
if (remap) {
flags |= kBitmapRemap;
} else {
flags &= ~kBitmapRemap;
}
WRITE_SCI11ENDIAN_UINT16(_bitmap + 10, flags);
}
BITMAP_PROPERTY(32, DataSize, 12);
inline uint32 getHunkPaletteOffset() const {
return READ_SCI11ENDIAN_UINT32(_bitmap + 20);
}
inline void setHunkPaletteOffset(uint32 hunkPaletteOffset) {
if (hunkPaletteOffset) {
hunkPaletteOffset += getBitmapHeaderSize();
}
WRITE_SCI11ENDIAN_UINT32(_bitmap + 20, hunkPaletteOffset);
}
BITMAP_PROPERTY(32, DataOffset, 24);
// NOTE: This property is used as a "magic number" for
// validating that a block of memory is a valid bitmap,
// and so is always set to the size of the header.
BITMAP_PROPERTY(32, UncompressedDataOffset, 28);
// NOTE: This property always seems to be zero
BITMAP_PROPERTY(32, ControlOffset, 32);
inline uint16 getScaledWidth() const {
if (getDataOffset() >= 40) {
return READ_SCI11ENDIAN_UINT16(_bitmap + 36);
}
// SCI2 bitmaps did not have scaling ability
return 320;
}
inline void setScaledWidth(uint16 scaledWidth) {
if (getDataOffset() >= 40) {
WRITE_SCI11ENDIAN_UINT16(_bitmap + 36, scaledWidth);
}
}
inline uint16 getScaledHeight() const {
if (getDataOffset() >= 40) {
return READ_SCI11ENDIAN_UINT16(_bitmap + 38);
}
// SCI2 bitmaps did not have scaling ability
return 200;
}
inline void setScaledHeight(uint16 scaledHeight) {
if (getDataOffset() >= 40) {
WRITE_SCI11ENDIAN_UINT16(_bitmap + 38, scaledHeight);
}
}
inline byte *getPixels() {
return _bitmap + getUncompressedDataOffset();
}
};
class GfxFont;
/**

View File

@ -362,7 +362,7 @@ ShowStyleList::iterator GfxTransitions32::deleteShowStyle(const ShowStyleList::i
case kShowStyleDissolveNoMorph:
case kShowStyleDissolve:
if (getSciVersion() <= SCI_VERSION_2_1_EARLY) {
_segMan->freeHunkEntry(showStyle->bitmap);
_segMan->freeBitmap(showStyle->bitmap);
g_sci->_gfxFrameout->deleteScreenItem(*showStyle->bitmapScreenItem);
}
break;
@ -459,9 +459,10 @@ void GfxTransitions32::configure21EarlyIris(PlaneShowStyle &showStyle, const int
void GfxTransitions32::configure21EarlyDissolve(PlaneShowStyle &showStyle, const int16 priority, const Common::Rect &gameRect) {
BitmapResource bitmap(_segMan, showStyle.width, showStyle.height, kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false);
reg_t bitmapId;
SciBitmap &bitmap = *_segMan->allocateBitmap(&bitmapId, showStyle.width, showStyle.height, kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false);
showStyle.bitmap = bitmap.getObject();
showStyle.bitmap = bitmapId;
const Buffer &source = g_sci->_gfxFrameout->getCurrentBuffer();
Buffer target(showStyle.width, showStyle.height, bitmap.getPixels());
@ -471,7 +472,7 @@ void GfxTransitions32::configure21EarlyDissolve(PlaneShowStyle &showStyle, const
CelInfo32 celInfo;
celInfo.type = kCelTypeMem;
celInfo.bitmap = bitmap.getObject();
celInfo.bitmap = bitmapId;
showStyle.bitmapScreenItem = new ScreenItem(showStyle.plane, celInfo, Common::Point(0, 0), ScaleInfo());
showStyle.bitmapScreenItem->_priority = priority;
@ -608,7 +609,7 @@ bool GfxTransitions32::processPixelDissolve(PlaneShowStyle &showStyle) {
bool GfxTransitions32::processPixelDissolve21Early(PlaneShowStyle &showStyle) {
bool unchanged = true;
BitmapResource bitmap(showStyle.bitmap);
SciBitmap &bitmap = *_segMan->lookupBitmap(showStyle.bitmap);
Buffer buffer(showStyle.width, showStyle.height, bitmap.getPixels());
uint32 numPixels = showStyle.width * showStyle.height;

View File

@ -117,7 +117,7 @@ VMDPlayer::IOStatus VMDPlayer::close() {
if (!_planeIsOwned && _screenItem != nullptr) {
g_sci->_gfxFrameout->deleteScreenItem(*_screenItem);
g_sci->getEngineState()->_segMan->freeHunkEntry(_screenItem->_celInfo.bitmap);
g_sci->getEngineState()->_segMan->freeBitmap(_screenItem->_celInfo.bitmap);
_screenItem = nullptr;
} else if (_plane != nullptr) {
g_sci->_gfxFrameout->deletePlane(*_plane);
@ -232,14 +232,15 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
BitmapResource vmdBitmap(_segMan, vmdRect.width(), vmdRect.height(), 255, 0, 0, screenWidth, screenHeight, 0, false, false);
reg_t bitmapId;
SciBitmap &vmdBitmap = *_segMan->allocateBitmap(&bitmapId, vmdRect.width(), vmdRect.height(), 255, 0, 0, screenWidth, screenHeight, 0, false, false);
if (screenWidth != scriptWidth || screenHeight != scriptHeight) {
mulru(vmdRect, Ratio(scriptWidth, screenWidth), Ratio(scriptHeight, screenHeight), 1);
}
CelInfo32 vmdCelInfo;
vmdCelInfo.bitmap = vmdBitmap.getObject();
vmdCelInfo.bitmap = bitmapId;
_decoder->setSurfaceMemory(vmdBitmap.getPixels(), vmdBitmap.getWidth(), vmdBitmap.getHeight(), 1);
if (_planeIsOwned) {