ScummVM API documentation
segment.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef SCI_ENGINE_SEGMENT_H
23 #define SCI_ENGINE_SEGMENT_H
24 
25 #include "common/serializer.h"
26 #include "common/str.h"
27 #include "sci/engine/object.h"
28 #include "sci/engine/vm.h"
29 #include "sci/engine/vm_types.h" // for reg_t
30 #include "sci/util.h"
31 #ifdef ENABLE_SCI32
32 #include "sci/graphics/palette32.h"
33 #endif
34 
35 namespace Sci {
36 
37 struct SegmentRef {
38  bool isRaw;
39  union {
40  byte *raw;
41  reg_t *reg;
42  };
43  int maxSize;
44 
45  // FIXME: Perhaps a generic 'offset' is more appropriate here
46  bool skipByte;
47 
48  // TODO: Add this?
49  //reg_t pointer; // Original pointer
50 
51  // TODO: Add this?
52  //SegmentType type;
53 
54  SegmentRef() : isRaw(true), raw(0), maxSize(0), skipByte(false) {}
55 
56  bool isValid() const { return (isRaw ? raw != 0 : reg != 0); }
57 };
58 
59 
60 enum SegmentType {
61  SEG_TYPE_INVALID = 0,
62  SEG_TYPE_SCRIPT = 1,
63  SEG_TYPE_CLONES = 2,
64  SEG_TYPE_LOCALS = 3,
65  SEG_TYPE_STACK = 4,
66  // 5 used to be system strings, now obsolete
67  SEG_TYPE_LISTS = 6,
68  SEG_TYPE_NODES = 7,
69  SEG_TYPE_HUNK = 8,
70  SEG_TYPE_DYNMEM = 9,
71  // 10 used to be string fragments, now obsolete
72 
73 #ifdef ENABLE_SCI32
74  SEG_TYPE_ARRAY = 11,
75  // 12 used to be string, now obsolete
76  SEG_TYPE_BITMAP = 13,
77 #endif
78 
79  SEG_TYPE_MAX // For sanity checking
80 };
81 
83  SegmentType _type;
84 
85 public:
86  static SegmentObj *createSegmentObj(SegmentType type);
87 
88 public:
89  SegmentObj(SegmentType type) : _type(type) {}
90  ~SegmentObj() override {}
91 
92  inline SegmentType getType() const { return _type; }
93 
98  virtual bool isValidOffset(uint32 offset) const = 0;
99 
105  virtual SegmentRef dereference(reg_t pointer);
106 
116  virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const { return sub_addr; }
117 
123  virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) {}
124 
130  virtual Common::Array<reg_t> listAllDeallocatable(SegmentId segId) const {
131  return Common::Array<reg_t>();
132  }
133 
143  return Common::Array<reg_t>();
144  }
145 };
146 
147 struct LocalVariables : public SegmentObj {
148  int script_id;
149  Common::Array<reg_t> _locals;
150 
151 public:
152  LocalVariables(): SegmentObj(SEG_TYPE_LOCALS), script_id(0) { }
153 
154  bool isValidOffset(uint32 offset) const override {
155  return offset < _locals.size() * 2;
156  }
157  SegmentRef dereference(reg_t pointer) override;
158  reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const override;
159  Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const override;
160 
161  void saveLoadWithSerializer(Common::Serializer &ser) override;
162 };
163 
166  uint _capacity;
167  reg_t *_entries;
168 
169 public:
170  DataStack() : SegmentObj(SEG_TYPE_STACK), _capacity(0), _entries(NULL) { }
171  ~DataStack() override {
172  free(_entries);
173  _entries = NULL;
174  }
175 
176  bool isValidOffset(uint32 offset) const override {
177  return offset < _capacity * 2;
178  }
179  SegmentRef dereference(reg_t pointer) override;
180  reg_t findCanonicAddress(SegManager *segMan, reg_t addr) const override {
181  return make_reg(addr.getSegment(), 0);
182  }
183  Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const override;
184 
185  void saveLoadWithSerializer(Common::Serializer &ser) override;
186 };
187 
188 enum {
189  CLONE_USED = -1,
190  CLONE_NONE = -1
191 };
192 
193 typedef Object Clone;
194 
195 struct Node {
198  reg_t key;
199  reg_t value;
200 }; /* List nodes */
201 
202 struct List {
203  reg_t first;
204  reg_t last;
205 
206 #ifdef ENABLE_SCI32
207 
211  reg_t nextNodes[10];
212 
216  int numRecursions;
217 #endif
218 
219  List() : first(NULL_REG), last(NULL_REG) {
220 #ifdef ENABLE_SCI32
221  memset(nextNodes, 0, sizeof(nextNodes));
222  numRecursions = 0;
223 #endif
224  }
225 };
226 
227 struct Hunk {
228  void *mem;
229  uint32 size;
230  const char *type;
231 };
232 
233 template<typename T>
234 struct SegmentObjTable : public SegmentObj {
235  typedef T value_type;
236  struct Entry {
237  T *data;
238  int next_free; /* Only used for free entries */
239  };
240  enum { HEAPENTRY_INVALID = -1 };
241 
246  ArrayType _table;
247 
248 public:
249  SegmentObjTable(SegmentType type) : SegmentObj(type) {
250  initTable();
251  }
252 
253  ~SegmentObjTable() override {
254  for (uint i = 0; i < _table.size(); i++) {
255  if (isValidEntry(i)) {
256  freeEntry(i);
257  }
258  }
259  }
260 
261  void initTable() {
262  entries_used = 0;
263  first_free = HEAPENTRY_INVALID;
264  _table.clear();
265  }
266 
267  int allocEntry() {
268  entries_used++;
269  if (first_free != HEAPENTRY_INVALID) {
270  int oldff = first_free;
271  first_free = _table[oldff].next_free;
272 
273  _table[oldff].next_free = oldff;
274  assert(_table[oldff].data == nullptr);
275  _table[oldff].data = new T;
276  return oldff;
277  } else {
278  uint newIdx = _table.size();
279  _table.push_back(Entry());
280  _table.back().data = new T;
281  _table[newIdx].next_free = newIdx; // Tag as 'valid'
282  return newIdx;
283  }
284  }
285 
286  bool isValidOffset(uint32 offset) const override {
287  return isValidEntry(offset);
288  }
289 
290  bool isValidEntry(int idx) const {
291  return idx >= 0 && (uint)idx < _table.size() && _table[idx].next_free == idx;
292  }
293 
294  virtual void freeEntry(int idx) {
295  if (idx < 0 || (uint)idx >= _table.size())
296  ::error("Table::freeEntry: Attempt to release invalid table index %d", idx);
297 
298  _table[idx].next_free = first_free;
299  delete _table[idx].data;
300  _table[idx].data = nullptr;
301  first_free = idx;
302  entries_used--;
303  }
304 
305  Common::Array<reg_t> listAllDeallocatable(SegmentId segId) const override {
307  for (uint i = 0; i < _table.size(); i++)
308  if (isValidEntry(i))
309  tmp.push_back(make_reg(segId, i));
310  return tmp;
311  }
312 
313  uint size() const { return _table.size(); }
314 
315  T &at(uint index) { return *_table[index].data; }
316  const T &at(uint index) const { return *_table[index].data; }
317 
318  T &operator[](uint index) { return at(index); }
319  const T &operator[](uint index) const { return at(index); }
320 };
321 
322 
323 /* CloneTable */
324 struct CloneTable : public SegmentObjTable<Clone> {
325  CloneTable() : SegmentObjTable<Clone>(SEG_TYPE_CLONES) {}
326 
327  void freeAtAddress(SegManager *segMan, reg_t sub_addr) override;
328  Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const override;
329 
330  void saveLoadWithSerializer(Common::Serializer &ser) override;
331 };
332 
333 
334 /* NodeTable */
335 struct NodeTable : public SegmentObjTable<Node> {
336  NodeTable() : SegmentObjTable<Node>(SEG_TYPE_NODES) {}
337 
338  void freeAtAddress(SegManager *segMan, reg_t sub_addr) override {
339  freeEntry(sub_addr.getOffset());
340  }
341  Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const override;
342 
343  void saveLoadWithSerializer(Common::Serializer &ser) override;
344 };
345 
346 
347 /* ListTable */
348 struct ListTable : public SegmentObjTable<List> {
349  ListTable() : SegmentObjTable<List>(SEG_TYPE_LISTS) {}
350 
351  void freeAtAddress(SegManager *segMan, reg_t sub_addr) override {
352  freeEntry(sub_addr.getOffset());
353  }
354  Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const override;
355 
356  void saveLoadWithSerializer(Common::Serializer &ser) override;
357 };
358 
359 
360 /* HunkTable */
361 struct HunkTable : public SegmentObjTable<Hunk> {
362  HunkTable() : SegmentObjTable<Hunk>(SEG_TYPE_HUNK) {}
363  ~HunkTable() override {
364  for (uint i = 0; i < _table.size(); i++) {
365  if (isValidEntry(i))
366  freeEntryContents(i);
367  }
368  }
369 
370  void freeEntryContents(int idx) {
371  free(at(idx).mem);
372  at(idx).mem = 0;
373  }
374 
375  void freeEntry(int idx) override {
376  freeEntryContents(idx);
378  }
379 
380  void freeAtAddress(SegManager *segMan, reg_t sub_addr) override {
381  freeEntry(sub_addr.getOffset());
382  }
383 
384  void saveLoadWithSerializer(Common::Serializer &ser) override;
385 };
386 
387 
388 // Free-style memory
389 struct DynMem : public SegmentObj {
390  uint _size;
391  Common::String _description;
392  byte *_buf;
393 
394 public:
395  DynMem() : SegmentObj(SEG_TYPE_DYNMEM), _size(0), _buf(0) {}
396  ~DynMem() override {
397  free(_buf);
398  _buf = NULL;
399  }
400 
401  bool isValidOffset(uint32 offset) const override {
402  return offset < _size;
403  }
404  SegmentRef dereference(reg_t pointer) override;
405  reg_t findCanonicAddress(SegManager *segMan, reg_t addr) const override {
406  return make_reg(addr.getSegment(), 0);
407  }
408  Common::Array<reg_t> listAllDeallocatable(SegmentId segId) const override {
409  const reg_t r = make_reg(segId, 0);
410  return Common::Array<reg_t>(&r, 1);
411  }
412 
413  void saveLoadWithSerializer(Common::Serializer &ser) override;
414 };
415 
416 #ifdef ENABLE_SCI32
417 
418 #pragma mark -
419 #pragma mark Arrays
420 
421 enum SciArrayType {
422  kArrayTypeInt16 = 0,
423  kArrayTypeID = 1,
424  kArrayTypeByte = 2,
425  kArrayTypeString = 3,
426  // Type 4 was for 32-bit integers; never used
427  kArrayTypeInvalid = 5
428 };
429 
430 enum SciArrayTrim {
431  kArrayTrimRight = 1,
432  kArrayTrimCenter = 2,
433  kArrayTrimLeft = 4
434 };
435 
436 class SciArray : public Common::Serializable {
437 public:
438  SciArray() :
439  _type(kArrayTypeInvalid),
440  _size(0),
441  _data(nullptr),
442  _elementSize(0) {}
443 
444  SciArray(const SciArray &array) {
445  _type = array._type;
446  _size = array._size;
447  _elementSize = array._elementSize;
448  _data = malloc(_elementSize * _size);
449  assert(_data);
450  memcpy(_data, array._data, _elementSize * _size);
451  }
452 
453  SciArray &operator=(const SciArray &array) {
454  if (this == &array)
455  return *this;
456 
457  free(_data);
458  _type = array._type;
459  _size = array._size;
460  _elementSize = array._elementSize;
461  _data = malloc(_elementSize * _size);
462  assert(_data);
463  memcpy(_data, array._data, _elementSize * _size);
464 
465  return *this;
466  }
467 
468  ~SciArray() override {
469  free(_data);
470  _size = 0;
471  _type = kArrayTypeInvalid;
472  }
473 
474  void saveLoadWithSerializer(Common::Serializer &s) override;
475 
479  SciArrayType getType() const {
480  return _type;
481  }
482 
486  void setType(const SciArrayType type) {
487  assert(_type == kArrayTypeInvalid);
488  switch(type) {
489  case kArrayTypeInt16:
490  case kArrayTypeID:
491  _elementSize = sizeof(reg_t);
492  break;
493  case kArrayTypeString:
494  _elementSize = sizeof(char);
495  break;
496  case kArrayTypeByte:
497  _elementSize = sizeof(byte);
498  break;
499  default:
500  error("Invalid array type %d", type);
501  }
502  _type = type;
503  }
504 
508  uint16 size() const {
509  return _size;
510  }
511 
515  uint16 byteSize() const {
516  uint16 size1 = _size;
517  if (_type == kArrayTypeID || _type == kArrayTypeInt16) {
518  size1 *= sizeof(uint16);
519  }
520  return size1;
521  }
522 
528  void resize(uint16 newSize, const bool force = false) {
529  if (force || newSize > _size) {
530  _data = realloc(_data, _elementSize * newSize);
531  if (newSize > _size) {
532  memset((byte *)_data + _elementSize * _size, 0, (newSize - _size) * _elementSize);
533  }
534  _size = newSize;
535  }
536  }
537 
541  void *getRawData() { return _data; }
542  const void *getRawData() const { return _data; }
543 
547  reg_t getAsID(const uint16 index) {
548  if (getSciVersion() >= SCI_VERSION_3) {
549  // SCI3 resizes arrays automatically when out-of-bounds indices are
550  // passed, but it has an off-by-one error, always passing the index
551  // instead of `index + 1` on a read. This happens to work in SSCI
552  // only because the resize method there actually allocates memory
553  // for `index + 25` elements when growing the array, and it always
554  // grows the array on its first resize because it decides whether to
555  // grow based on byte size including an extra array header.
556  resize(index + 1);
557  } else {
558  assert(index < _size);
559  }
560 
561  switch(_type) {
562  case kArrayTypeInt16:
563  case kArrayTypeID:
564  return ((reg_t *)_data)[index];
565  case kArrayTypeByte:
566  case kArrayTypeString: {
567  int16 value;
568 
569  if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
570  value = ((int8 *)_data)[index];
571  } else {
572  value = ((uint8 *)_data)[index];
573  }
574 
575  return make_reg(0, value);
576  }
577  default:
578  error("Invalid array type %d", _type);
579  }
580  }
581 
585  void setFromID(const uint16 index, const reg_t value) {
586  if (getSciVersion() >= SCI_VERSION_3) {
587  // This code is different from SSCI; see getAsID for an explanation
588  resize(index + 1);
589  } else {
590  assert(index < _size);
591  }
592 
593  switch(_type) {
594  case kArrayTypeInt16:
595  case kArrayTypeID:
596  ((reg_t *)_data)[index] = value;
597  break;
598  case kArrayTypeByte:
599  case kArrayTypeString:
600  ((byte *)_data)[index] = value.toSint16();
601  break;
602  default:
603  error("Invalid array type %d", _type);
604  }
605  }
606 
610  int16 getAsInt16(const uint16 index) {
611  assert(_type == kArrayTypeInt16);
612 
613  if (getSciVersion() >= SCI_VERSION_3) {
614  // This code is different from SSCI; see getAsID for an explanation
615  resize(index + 1);
616  } else {
617  assert(index < _size);
618  }
619 
620  const reg_t value = ((reg_t *)_data)[index];
621  assert(value.isNumber());
622  return value.toSint16();
623  }
624 
628  void setFromInt16(const uint16 index, const int16 value) {
629  assert(_type == kArrayTypeInt16);
630 
631  if (getSciVersion() >= SCI_VERSION_3) {
632  // This code is different from SSCI; see getAsID for an explanation
633  resize(index + 1);
634  } else {
635  assert(index < _size);
636  }
637 
638  ((reg_t *)_data)[index] = make_reg(0, value);
639  }
640 
645  byte &byteAt(const uint16 index) {
646  assert(_type == kArrayTypeString || _type == kArrayTypeByte);
647 
648  if (getSciVersion() >= SCI_VERSION_3) {
649  // This code is different from SSCI; see getAsID for an explanation
650  resize(index + 1);
651  } else {
652  assert(index < _size);
653  }
654 
655  return ((byte *)_data)[index];
656  }
657 
662  char &charAt(const uint16 index) {
663  assert(_type == kArrayTypeString || _type == kArrayTypeByte);
664 
665  if (getSciVersion() >= SCI_VERSION_3) {
666  // This code is different from SSCI; see getAsID for an explanation
667  resize(index + 1);
668  } else {
669  assert(index < _size);
670  }
671 
672  return ((char *)_data)[index];
673  }
674 
679  reg_t &IDAt(const uint16 index) {
680  assert(_type == kArrayTypeID || _type == kArrayTypeInt16);
681 
682  if (getSciVersion() >= SCI_VERSION_3) {
683  // This code is different from SSCI; see getAsID for an explanation
684  resize(index + 1);
685  } else {
686  assert(index < _size);
687  }
688 
689  return ((reg_t *)_data)[index];
690  }
691 
696  void setElements(const uint16 index, uint16 count, const reg_t *values) {
697  resize(index + count);
698 
699  switch (_type) {
700  case kArrayTypeInt16:
701  case kArrayTypeID: {
702  const reg_t *source = values;
703  reg_t *target = (reg_t *)_data + index;
704  while (count--) {
705  *target++ = *source++;
706  }
707  break;
708  }
709  case kArrayTypeByte:
710  case kArrayTypeString: {
711  const reg_t *source = values;
712  byte *target = (byte *)_data + index;
713  while (count--) {
714  if (!source->isNumber()) {
715  error("Non-number %04x:%04x sent to byte or string array", PRINT_REG(*source));
716  }
717  *target++ = source->getOffset();
718  ++source;
719  }
720  break;
721  }
722  default:
723  error("Attempted write to SciArray with invalid type %d", _type);
724  }
725  }
726 
731  void fill(const uint16 index, uint16 count, const reg_t value) {
732  if (count == 65535 /* -1 */) {
733  count = size() - index;
734  }
735 
736  if (!count) {
737  return;
738  }
739 
740  resize(index + count);
741 
742  switch (_type) {
743  case kArrayTypeInt16:
744  case kArrayTypeID: {
745  reg_t *target = (reg_t *)_data + index;
746  while (count--) {
747  *target++ = value;
748  }
749  break;
750  }
751  case kArrayTypeByte:
752  case kArrayTypeString: {
753  byte *target = (byte *)_data + index;
754  const byte fillValue = value.getOffset();
755  while (count--) {
756  *target++ = fillValue;
757  }
758  break;
759  }
760 
761  case kArrayTypeInvalid:
762  default:
763  error("Attempted write to uninitialized SciArray");
764  break;
765  }
766  }
767 
772  void copy(SciArray &source, const uint16 sourceIndex, const uint16 targetIndex, int16 count) {
773  if (count == -1) {
774  count = source.size() - sourceIndex;
775  }
776 
777  if (count < 1) {
778  return;
779  }
780 
781  resize(targetIndex + count);
782  source.resize(sourceIndex + count);
783 
784  assert(source._elementSize == _elementSize);
785 
786  const byte *sourceData = (byte *)source._data + sourceIndex * source._elementSize;
787  byte *targetData = (byte *)_data + targetIndex * _elementSize;
788  memmove(targetData, sourceData, count * _elementSize);
789  }
790 
791  void byteCopy(const SciArray &source, const uint16 sourceOffset, const uint16 targetOffset, const uint16 count) {
792  error("SciArray::byteCopy not implemented");
793  }
794 
798  void trim(const int8 flags, const char showChar) {
799  enum {
800  kWhitespaceBoundary = 32,
801  kAsciiBoundary = 128
802  };
803 
804  byte *data = (byte *)_data;
805  byte *end = data + _size;
806  byte *source;
807  byte *target;
808 
809  if (flags & kArrayTrimLeft) {
810  target = data;
811  source = data;
812  while (source < end && *source != '\0' && *source != showChar && *source <= kWhitespaceBoundary) {
813  ++source;
814  }
815  memmove(target, source, Common::strnlen((char *)source, _size - 1) + 1);
816  }
817 
818  if (flags & kArrayTrimRight) {
819  source = data + Common::strnlen((char *)data, _size) - 1;
820  while (source > data && *source != showChar && *source <= kWhitespaceBoundary) {
821  *source = '\0';
822  --source;
823  }
824  }
825 
826  if (flags & kArrayTrimCenter) {
827  target = data;
828  while (target < end && *target != '\0' && *target <= kWhitespaceBoundary && *target != showChar) {
829  ++target;
830  }
831 
832  if (*target != '\0') {
833  while (target < end && *target != '\0' && (*target > kWhitespaceBoundary || *target == showChar)) {
834  ++target;
835  }
836 
837  if (*target != '\0') {
838  source = target;
839  while (*source != '\0') {
840  while (source < end && *source != '\0' && *source <= kWhitespaceBoundary && *source != showChar) {
841  ++source;
842  }
843 
844  while (source < end && *source != '\0' && (*source > kWhitespaceBoundary || *source == showChar)) {
845  *target++ = *source++;
846  }
847  }
848 
849  --source;
850  while (source >= data && source > target && (*source <= kWhitespaceBoundary || *source >= kAsciiBoundary) && *source != showChar) {
851  --source;
852  }
853  ++source;
854 
855  memmove(target, source, Common::strnlen((char *)source, _size - 1) + 1);
856  }
857  }
858  }
859  }
860 
864  Common::String toString() const {
865  assert(_type == kArrayTypeString);
866  return Common::String((char *)_data);
867  }
868 
872  void fromString(const Common::String &string) {
873  // At least LSL6hires uses a byte-type array to hold string data
874  assert(_type == kArrayTypeString || _type == kArrayTypeByte);
875  resize(string.size() + 1, true);
876  Common::strlcpy((char *)_data, string.c_str(), string.size() + 1);
877  }
878 
879  Common::String toDebugString() const {
880  const char *type;
881  switch(_type) {
882  case kArrayTypeID:
883  type = "reg_t";
884  break;
885  case kArrayTypeByte:
886  type = "byte";
887  break;
888  case kArrayTypeInt16:
889  type = "int16";
890  break;
891  case kArrayTypeString:
892  type = "string";
893  break;
894  case kArrayTypeInvalid:
895  default:
896  type = "invalid";
897  break;
898  }
899 
900  return Common::String::format("type %s; %u entries", type, size());
901  }
902 
903 protected:
904  void *_data;
905  SciArrayType _type;
906  uint16 _size;
907  uint8 _elementSize;
908 };
909 
910 struct ArrayTable : public SegmentObjTable<SciArray> {
911  ArrayTable() : SegmentObjTable<SciArray>(SEG_TYPE_ARRAY) {}
912 
913  Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const override;
914 
915  void saveLoadWithSerializer(Common::Serializer &ser) override;
916  SegmentRef dereference(reg_t pointer) override;
917 };
918 
919 #pragma mark -
920 #pragma mark Bitmaps
921 
922 enum {
923  kDefaultSkipColor = 250
924 };
925 
926 #define BITMAP_PROPERTY(size, property, offset)\
927 inline uint##size get##property() const {\
928  return READ_SCI11ENDIAN_UINT##size(_data + (offset));\
929 }\
930 inline void set##property(uint##size value) {\
931  WRITE_SCI11ENDIAN_UINT##size(_data + (offset), (value));\
932 }
933 
934 struct BitmapTable;
935 
940 class SciBitmap : public Common::Serializable {
941  byte *_data;
942  int _dataSize;
943  Buffer _buffer;
944  bool _gc;
945 
946 public:
947  enum BitmapFlags {
948  kBitmapRemap = 2
949  };
950 
955  static inline uint16 getBitmapHeaderSize() {
956  // TODO: These values are accurate for each engine, but there may be no reason
957  // to not simply just always use size 40, since SCI2.1mid does not seem to
958  // actually store any data above byte 40, and SCI2 did not allow bitmaps with
959  // scaling resolutions other than the default (320x200). Perhaps SCI3 used
960  // the extra bytes, or there is some reason why they tried to align the header
961  // size with other headers like pic headers?
962 // uint32 bitmapHeaderSize;
963 // if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
964 // bitmapHeaderSize = 46;
965 // } else if (getSciVersion() == SCI_VERSION_2_1_EARLY) {
966 // bitmapHeaderSize = 40;
967 // } else {
968 // bitmapHeaderSize = 36;
969 // }
970 // return bitmapHeaderSize;
971  return 46;
972  }
973 
978  static inline uint32 getBitmapSize(const uint16 width, const uint16 height) {
979  return width * height + getBitmapHeaderSize();
980  }
981 
982  inline SciBitmap() : _data(nullptr), _dataSize(0), _gc(true) {}
983 
984  inline SciBitmap(const SciBitmap &other) {
985  _dataSize = other._dataSize;
986  _data = (byte *)malloc(other._dataSize);
987  memcpy(_data, other._data, other._dataSize);
988  if (_dataSize) {
989  _buffer.init(getWidth(), getHeight(), getWidth(), getPixels(), Graphics::PixelFormat::createFormatCLUT8());
990  }
991  _gc = other._gc;
992  }
993 
994  inline ~SciBitmap() override {
995  free(_data);
996  _data = nullptr;
997  _dataSize = 0;
998  }
999 
1000  inline SciBitmap &operator=(const SciBitmap &other) {
1001  if (this == &other) {
1002  return *this;
1003  }
1004 
1005  free(_data);
1006  _dataSize = other._dataSize;
1007  _data = (byte *)malloc(other._dataSize);
1008  memcpy(_data, other._data, _dataSize);
1009  if (_dataSize) {
1010  _buffer.init(getWidth(), getHeight(), getWidth(), getPixels(), Graphics::PixelFormat::createFormatCLUT8());
1011  }
1012  _gc = other._gc;
1013 
1014  return *this;
1015  }
1016 
1020  inline void create(const int16 width, const int16 height, const uint8 skipColor, const int16 originX, const int16 originY, const int16 xResolution, const int16 yResolution, const uint32 paletteSize, const bool remap, const bool gc) {
1021 
1022  _dataSize = getBitmapSize(width, height) + paletteSize;
1023  _data = (byte *)realloc(_data, _dataSize);
1024  _gc = gc;
1025 
1026  const uint16 bitmapHeaderSize = getBitmapHeaderSize();
1027 
1028  setWidth(width);
1029  setHeight(height);
1030  setOrigin(Common::Point(originX, originY));
1031  setSkipColor(skipColor);
1032  _data[9] = 0;
1033  WRITE_SCI11ENDIAN_UINT16(_data + 10, 0);
1034  setRemap(remap);
1035  setDataSize(width * height);
1036  WRITE_SCI11ENDIAN_UINT32(_data + 16, 0);
1037  setHunkPaletteOffset(paletteSize > 0 ? (bitmapHeaderSize + width * height) : 0);
1038  setDataOffset(bitmapHeaderSize);
1039  setUncompressedDataOffset(bitmapHeaderSize);
1040  setControlOffset(0);
1041  setXResolution(xResolution);
1042  setYResolution(yResolution);
1043 
1044  _buffer.init(getWidth(), getHeight(), getWidth(), getPixels(), Graphics::PixelFormat::createFormatCLUT8());
1045  }
1046 
1047  inline int getRawSize() const {
1048  return _dataSize;
1049  }
1050 
1051  inline byte *getRawData() const {
1052  return _data;
1053  }
1054 
1055  inline Buffer &getBuffer() {
1056  return _buffer;
1057  }
1058 
1059  inline bool getShouldGC() const {
1060  return _gc;
1061  }
1062 
1063  inline void enableGC() {
1064  _gc = true;
1065  }
1066 
1067  inline void disableGC() {
1068  _gc = false;
1069  }
1070 
1071  BITMAP_PROPERTY(16, Width, 0);
1072  BITMAP_PROPERTY(16, Height, 2);
1073 
1074  inline Common::Point getOrigin() const {
1075  return Common::Point(
1076  (int16)READ_SCI11ENDIAN_UINT16(_data + 4),
1077  (int16)READ_SCI11ENDIAN_UINT16(_data + 6)
1078  );
1079  }
1080 
1081  inline void setOrigin(const Common::Point &origin) {
1082  WRITE_SCI11ENDIAN_UINT16(_data + 4, (uint16)origin.x);
1083  WRITE_SCI11ENDIAN_UINT16(_data + 6, (uint16)origin.y);
1084  }
1085 
1086  inline uint8 getSkipColor() const {
1087  return _data[8];
1088  }
1089 
1090  inline void setSkipColor(const uint8 skipColor) {
1091  _data[8] = skipColor;
1092  }
1093 
1094  inline bool getRemap() const {
1095  return READ_SCI11ENDIAN_UINT16(_data + 10) & kBitmapRemap;
1096  }
1097 
1098  inline void setRemap(const bool remap) {
1099  uint16 flags = READ_SCI11ENDIAN_UINT16(_data + 10);
1100  if (remap) {
1101  flags |= kBitmapRemap;
1102  } else {
1103  flags &= ~kBitmapRemap;
1104  }
1105  WRITE_SCI11ENDIAN_UINT16(_data + 10, flags);
1106  }
1107 
1108  BITMAP_PROPERTY(32, DataSize, 12);
1109 
1110  BITMAP_PROPERTY(32, HunkPaletteOffset, 20);
1111 
1112  BITMAP_PROPERTY(32, DataOffset, 24);
1113 
1114  // This property is used as a "magic number" for validating that a block of
1115  // memory is a valid bitmap, and so is always set to the size of the header.
1116  BITMAP_PROPERTY(32, UncompressedDataOffset, 28);
1117 
1118  // This property always seems to be zero in SSCI
1119  BITMAP_PROPERTY(32, ControlOffset, 32);
1120 
1121  inline uint16 getXResolution() const {
1122  if (getDataOffset() >= 40) {
1123  return READ_SCI11ENDIAN_UINT16(_data + 36);
1124  }
1125 
1126  // SCI2 bitmaps did not have scaling ability
1127  return 320;
1128  }
1129 
1130  inline void setXResolution(uint16 xResolution) {
1131  if (getDataOffset() >= 40) {
1132  WRITE_SCI11ENDIAN_UINT16(_data + 36, xResolution);
1133  }
1134  }
1135 
1136  inline uint16 getYResolution() const {
1137  if (getDataOffset() >= 40) {
1138  return READ_SCI11ENDIAN_UINT16(_data + 38);
1139  }
1140 
1141  // SCI2 bitmaps did not have scaling ability
1142  return 200;
1143  }
1144 
1145  inline void setYResolution(uint16 yResolution) {
1146  if (getDataOffset() >= 40) {
1147  WRITE_SCI11ENDIAN_UINT16(_data + 38, yResolution);
1148  }
1149  }
1150 
1151  inline byte *getPixels() {
1152  return _data + getUncompressedDataOffset();
1153  }
1154 
1155  inline byte *getHunkPalette() {
1156  if (getHunkPaletteOffset() == 0) {
1157  return nullptr;
1158  }
1159  return _data + getHunkPaletteOffset();
1160  }
1161 
1162  inline void setPalette(const Palette &palette) {
1163  byte *paletteData = getHunkPalette();
1164  if (paletteData != nullptr) {
1165  SciSpan<byte> paletteSpan(paletteData, getRawSize() - getHunkPaletteOffset());
1166  HunkPalette::write(paletteSpan, palette);
1167  }
1168  }
1169 
1170  void saveLoadWithSerializer(Common::Serializer &ser) override;
1171 
1172  void applyRemap(SciArray &clut) {
1173  const int length = getWidth() * getHeight();
1174  uint8 *pixel = getPixels();
1175  for (int i = 0; i < length; ++i) {
1176  const int16 color = clut.getAsInt16(*pixel);
1177  assert(color >= 0 && color <= 255);
1178  *pixel++ = (uint8)color;
1179  }
1180  }
1181 
1182  Common::String toString() const {
1183  return Common::String::format("%dx%d; res %dx%d; origin %dx%d; skip color %u; %s; %s)",
1184  getWidth(), getHeight(),
1185  getXResolution(), getYResolution(),
1186  getOrigin().x, getOrigin().y,
1187  getSkipColor(),
1188  getRemap() ? "remap" : "no remap",
1189  getShouldGC() ? "GC" : "no GC");
1190  }
1191 };
1192 
1193 #undef BITMAP_PROPERTY
1194 
1195 struct BitmapTable : public SegmentObjTable<SciBitmap> {
1196  BitmapTable() : SegmentObjTable<SciBitmap>(SEG_TYPE_BITMAP) {}
1197 
1198  SegmentRef dereference(reg_t pointer) override {
1199  SegmentRef ret;
1200  ret.isRaw = true;
1201  ret.maxSize = at(pointer.getOffset()).getRawSize();
1202  ret.raw = at(pointer.getOffset()).getRawData();
1203  return ret;
1204  }
1205 
1206  void saveLoadWithSerializer(Common::Serializer &ser) override;
1207 };
1208 
1209 #endif
1210 
1211 
1212 } // End of namespace Sci
1213 
1214 #endif // SCI_ENGINE_SEGMENT_H
int first_free
Definition: segment.h:242
bool skipByte
true if referencing the 2nd data byte of *reg, false otherwise
Definition: segment.h:46
bool isValidOffset(uint32 offset) const override
Definition: segment.h:154
Definition: str.h:59
static String format(MSVC_PRINTF const char *fmt,...) GCC_PRINTF(1
const T * data() const
Definition: array.h:207
virtual Common::Array< reg_t > listAllDeallocatable(SegmentId segId) const
Definition: segment.h:130
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: segment.h:227
Definition: segment.h:37
void clear()
Definition: array.h:320
Definition: segment.h:348
void freeAtAddress(SegManager *segMan, reg_t sub_addr) override
Definition: segment.h:338
Definition: segment.h:361
int entries_used
Definition: segment.h:243
bool isValidOffset(uint32 offset) const override
Definition: segment.h:176
Definition: segment.h:234
Definition: serializer.h:79
Definition: segment.h:389
void freeAtAddress(SegManager *segMan, reg_t sub_addr) override
Definition: segment.h:380
Definition: segment.h:202
reg_t succ
Definition: segment.h:197
void freeAtAddress(SegManager *segMan, reg_t sub_addr) override
Definition: segment.h:351
Definition: segment.h:324
Out copy(In first, In last, Out dst)
Definition: algorithm.h:52
virtual Common::Array< reg_t > listAllOutgoingReferences(reg_t object) const
Definition: segment.h:142
Common::Array< reg_t > listAllDeallocatable(SegmentId segId) const override
Definition: segment.h:408
bool isValidOffset(uint32 offset) const override
Definition: segment.h:286
int maxSize
number of available bytes
Definition: segment.h:43
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr)
Definition: segment.h:123
void push_back(const T &element)
Definition: array.h:180
Definition: segment.h:82
Definition: segment.h:147
Definition: segment.h:236
Definition: object.h:69
Definition: segment.h:335
Definition: rect.h:45
reg_t pred
Definition: segment.h:196
int script_id
Definition: segment.h:148
reg_t findCanonicAddress(SegManager *segMan, reg_t addr) const override
Definition: segment.h:180
Definition: console.h:28
Definition: serializer.h:308
bool isRaw
true if data is raw, false if it is a reg_t sequence
Definition: segment.h:38
Common::Array< reg_t > listAllDeallocatable(SegmentId segId) const override
Definition: segment.h:305
size_type size() const
Definition: array.h:315
void NORETURN_PRE error(MSVC_PRINTF const char *s,...) GCC_PRINTF(1
Definition: seg_manager.h:48
int16 x
Definition: rect.h:46
signed char * fill(signed char *first, signed char *last, Value val)
Definition: algorithm.h:168
int16 y
Definition: rect.h:47
reg_t findCanonicAddress(SegManager *segMan, reg_t addr) const override
Definition: segment.h:405
Definition: display_client.h:113
size_t strnlen(const char *src, size_t maxSize)
Definition: helpers.h:247
virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const
Definition: segment.h:116
Definition: segment.h:195
static PixelFormat createFormatCLUT8()
Definition: pixelformat.h:184
Definition: vm_types.h:39
Definition: segment.h:165
T & back()
Definition: array.h:229
bool isValidOffset(uint32 offset) const override
Definition: segment.h:401
uint _capacity
Definition: segment.h:166