Пример #1
0
void Script::load(ResourceManager *resMan) {
	Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, _nr), 0);
	assert(script != 0);

	uint extraLocalsWorkaround = 0;
	if (g_sci->getGameId() == GID_FANMADE && _nr == 1 && script->size == 11140) {
		// WORKAROUND: Script 1 in Ocean Battle doesn't have enough locals to
		// fit the string showing how many shots are left (a nasty script bug,
		// corrupting heap memory). We add 10 more locals so that it has enough
		// space to use as the target for its kFormat operation. Fixes bug
		// #3059871.
		extraLocalsWorkaround = 10;
	}
	_bufSize += extraLocalsWorkaround * 2;

	_buf = (byte *)malloc(_bufSize);
	assert(_buf);

	assert(_bufSize >= script->size);
	memcpy(_buf, script->data, script->size);

	// Check scripts for matching signatures and patch those, if found
	matchSignatureAndPatch(_nr, _buf, script->size);

	if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
		Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), 0);
		assert(heap != 0);

		_heapStart = _buf + _scriptSize;

		assert(_bufSize - _scriptSize <= heap->size);
		memcpy(_heapStart, heap->data, heap->size);
	}

	_exportTable = 0;
	_numExports = 0;
	_synonyms = 0;
	_numSynonyms = 0;
	
	if (getSciVersion() <= SCI_VERSION_1_LATE) {
		_exportTable = (const uint16 *)findBlockSCI0(SCI_OBJ_EXPORTS);
		if (_exportTable) {
			_numExports = READ_SCI11ENDIAN_UINT16(_exportTable + 1);
			_exportTable += 3;	// skip header plus 2 bytes (_exportTable is a uint16 pointer)
		}
		_synonyms = findBlockSCI0(SCI_OBJ_SYNONYMS);
		if (_synonyms) {
			_numSynonyms = READ_SCI11ENDIAN_UINT16(_synonyms + 2) / 4;
			_synonyms += 4;	// skip header
		}
		const byte* localsBlock = findBlockSCI0(SCI_OBJ_LOCALVARS);
		if (localsBlock) {
			_localsOffset = localsBlock - _buf + 4;
			_localsCount = (READ_LE_UINT16(_buf + _localsOffset - 2) - 4) >> 1;	// half block size
		}
	} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
Пример #2
0
void Script::load(ResourceManager *resMan) {
	Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, _nr), 0);
	assert(script != 0);

	_buf = (byte *)malloc(_bufSize);
	assert(_buf);

	assert(_bufSize >= script->size);
	memcpy(_buf, script->data, script->size);

	// Check scripts for matching signatures and patch those, if found
	matchSignatureAndPatch(_nr, _buf, script->size);

	if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
		Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), 0);
		assert(heap != 0);

		_heapStart = _buf + _scriptSize;

		assert(_bufSize - _scriptSize <= heap->size);
		memcpy(_heapStart, heap->data, heap->size);
	}

	_exportTable = 0;
	_numExports = 0;
	_synonyms = 0;
	_numSynonyms = 0;
	
	if (getSciVersion() <= SCI_VERSION_1_LATE) {
		_exportTable = (const uint16 *)findBlockSCI0(SCI_OBJ_EXPORTS);
		if (_exportTable) {
			_numExports = READ_SCI11ENDIAN_UINT16(_exportTable + 1);
			_exportTable += 3;	// skip header plus 2 bytes (_exportTable is a uint16 pointer)
		}
		_synonyms = findBlockSCI0(SCI_OBJ_SYNONYMS);
		if (_synonyms) {
			_numSynonyms = READ_SCI11ENDIAN_UINT16(_synonyms + 2) / 4;
			_synonyms += 4;	// skip header
		}
		const byte* localsBlock = findBlockSCI0(SCI_OBJ_LOCALVARS);
		if (localsBlock) {
			_localsOffset = localsBlock - _buf + 4;
			_localsCount = (READ_LE_UINT16(_buf + _localsOffset - 2) - 4) >> 1;	// half block size
		}
	} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
Пример #3
0
void GfxPicture::drawSci32Vga(int16 celNo, int16 drawX, int16 drawY, int16 pictureX, bool mirrored) {
	byte *inbuffer = _resource->data;
	int size = _resource->size;
	int header_size = READ_SCI11ENDIAN_UINT16(inbuffer);
	int palette_data_ptr = READ_SCI11ENDIAN_UINT32(inbuffer + 6);
//	int celCount = inbuffer[2];
	int cel_headerPos = header_size;
	int cel_RlePos, cel_LiteralPos;
	Palette palette;

	// HACK
	_mirroredFlag = mirrored;
	_addToFlag = false;
	_resourceType = SCI_PICTURE_TYPE_SCI32;

	if (celNo == 0) {
		// Create palette and set it
		_palette->createFromData(inbuffer + palette_data_ptr, size - palette_data_ptr, &palette);
		_palette->set(&palette, true);
	}

	// Header
	// [headerSize:WORD] [celCount:BYTE] [Unknown:BYTE] [Unknown:WORD] [paletteOffset:DWORD] [Unknown:DWORD]
	// cel-header follow afterwards, each is 42 bytes
	// Cel-Header
	// [width:WORD] [height:WORD] [displaceX:WORD] [displaceY:WORD] [clearColor:BYTE] [compressed:BYTE]
	//  offset 10-23 is unknown
	// [rleOffset:DWORD] [literalOffset:DWORD] [Unknown:WORD] [Unknown:WORD] [priority:WORD] [relativeXpos:WORD] [relativeYpos:WORD]

	cel_headerPos += 42 * celNo;

	if (mirrored) {
		// switch around relativeXpos
		Common::Rect displayArea = _coordAdjuster->pictureGetDisplayArea();
		drawX = displayArea.width() - drawX - READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 0);
	}

	cel_RlePos = READ_SCI11ENDIAN_UINT32(inbuffer + cel_headerPos + 24);
	cel_LiteralPos = READ_SCI11ENDIAN_UINT32(inbuffer + cel_headerPos + 28);

	drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, drawX, drawY, pictureX);
	cel_headerPos += 42;
}
Пример #4
0
	bool init() {
		if (_headerSize > _size)
			return false;

		// Read message count from last word in header
		_messageCount = READ_SCI11ENDIAN_UINT16(_data + _headerSize - 2);

		if (_messageCount * _recordSize + _headerSize > _size)
			return false;

		return true;
	}
Пример #5
0
const HunkPalette::EntryHeader HunkPalette::getEntryHeader() const {
    const byte *const data = getPalPointer();

    EntryHeader header;
    header.startColor = data[10];
    header.numColors = READ_SCI11ENDIAN_UINT16(data + 14);
    header.used = data[16];
    header.sharedUsed = data[17];
    header.version = READ_SCI11ENDIAN_UINT32(data + kEntryVersionOffset);

    return header;
}
Пример #6
0
	bool findRecord(const MessageTuple &tuple, MessageRecord &record) {
		const byte *recordPtr = _data + _headerSize;

		for (uint i = 0; i < _messageCount; i++) {
			if ((recordPtr[0] == tuple.noun) && (recordPtr[1] == tuple.verb)
				&& (recordPtr[2] == tuple.cond) && (recordPtr[3] == tuple.seq)) {
				record.tuple = tuple;
				record.refTuple = MessageTuple(recordPtr[7], recordPtr[8], recordPtr[9]);
				record.talker = recordPtr[4];
				record.string = (const char *)_data + READ_SCI11ENDIAN_UINT16(recordPtr + 5);
				return true;
			}
			recordPtr += _recordSize;
		}

		return false;
	}
Пример #7
0
void RobotDecoder::readPaletteChunk(uint16 chunkSize) {
	byte *paletteData = new byte[chunkSize];
	_fileStream->read(paletteData, chunkSize);

	// SCI1.1 palette
	byte palFormat = paletteData[32];
	uint16 palColorStart = paletteData[25];
	uint16 palColorCount = READ_SCI11ENDIAN_UINT16(paletteData + 29);

	int palOffset = 37;
	memset(_palette, 0, 256 * 3);

	for (uint16 colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) {
		if (palFormat == kRobotPalVariable)
			palOffset++;
		_palette[colorNo * 3 + 0] = paletteData[palOffset++];
		_palette[colorNo * 3 + 1] = paletteData[palOffset++];
		_palette[colorNo * 3 + 2] = paletteData[palOffset++];
	}

	_dirtyPalette = true;
	delete[] paletteData;
}
Пример #8
0
int16 GfxPicture::getSci32celPriority(int16 celNo) {
	byte *inbuffer = _resource->data;
	int header_size = READ_SCI11ENDIAN_UINT16(inbuffer);
	int cel_headerPos = header_size + 42 * celNo;
	return READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 36);
}
Пример #9
0
bool Object::initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass) {
	const Object *baseObj = segMan->getObject(getSpeciesSelector());

	if (baseObj) {
		uint originalVarCount = _variables.size();

		if (_variables.size() != baseObj->getVarCount())
			_variables.resize(baseObj->getVarCount());
		// Copy base from species class, as we need its selector IDs
		_baseObj = baseObj->_baseObj;
		assert(_baseObj);
		if (doInitSuperClass)
			initSuperClass(segMan, addr);

		if (_variables.size() != originalVarCount) {
			// These objects are probably broken.
			// An example is 'witchCage' in script 200 in KQ5 (#3034714),
			// but also 'girl' in script 216 and 'door' in script 22.
			// In LSL3 a number of sound objects trigger this right away.
			// SQ4-floppy's bug #3037938 also seems related.

			// The effect is that a number of its method selectors may be
			// treated as variable selectors, causing unpredictable effects.
			int objScript = segMan->getScript(_pos.getSegment())->getScriptNumber();

			// We have to do a little bit of work to get the name of the object
			// before any relocations are done.
			reg_t nameReg = getNameSelector();
			const char *name;
			if (nameReg.isNull()) {
				name = "<no name>";
			} else {
				nameReg.setSegment(_pos.getSegment());
				name = segMan->derefString(nameReg);
				if (!name)
					name = "<invalid name>";
			}

			debugC(kDebugLevelVM, "Object %04x:%04x (name %s, script %d) "
			        "varnum doesn't match baseObj's: obj %d, base %d",
			        PRINT_REG(_pos), name, objScript,
			        originalVarCount, baseObj->getVarCount());

#if 0
			// We enumerate the methods selectors which could be hidden here
			if (getSciVersion() <= SCI_VERSION_2_1) {
				const SegmentRef objRef = segMan->dereference(baseObj->_pos);
				assert(objRef.isRaw);
				uint segBound = objRef.maxSize/2 - baseObj->getVarCount();
				const byte* buf = (const byte *)baseObj->_baseVars;
				if (!buf) {
					// While loading this may happen due to objects being loaded
					// out of order, and we can't proceed then, unfortunately.
					segBound = 0;
				}
				for (uint i = baseObj->getVarCount();
				         i < originalVarCount && i < segBound; ++i) {
					uint16 slc = READ_SCI11ENDIAN_UINT16(buf + 2*i);
					// Skip any numbers which happen to be varselectors too
					bool found = false;
					for (uint j = 0; j < baseObj->getVarCount() && !found; ++j)
						found = READ_SCI11ENDIAN_UINT16(buf + 2*j) == slc;
					if (found) continue;
					// Skip any selectors which aren't method selectors,
					// so couldn't be mistaken for varselectors
					if (lookupSelector(segMan, _pos, slc, 0, 0) != kSelectorMethod) continue;
					warning("    Possibly affected selector: %02x (%s)", slc,
					        g_sci->getKernel()->getSelectorName(slc).c_str());
				}
			}
#endif
		}

		return true;
	}

	return false;
}
Пример #10
0
// Disassembles one command from the heap, returns address of next command or 0 if a ret was encountered.
reg_t disassemble(EngineState *s, reg32_t pos, reg_t objAddr, bool printBWTag, bool printBytecode) {
	SegmentObj *mobj = s->_segMan->getSegment(pos.getSegment(), SEG_TYPE_SCRIPT);
	Script *script_entity = NULL;
	reg_t retval;
	retval.setSegment(pos.getSegment());
	retval.setOffset(pos.getOffset() + 1);
	uint16 param_value = 0xffff; // Suppress GCC warning by setting default value, chose value as invalid to getKernelName etc.
	uint i = 0;
	Kernel *kernel = g_sci->getKernel();

	if (!mobj) {
		warning("Disassembly failed: Segment %04x non-existent or not a script", pos.getSegment());
		return retval;
	} else
		script_entity = (Script *)mobj;

	uint scr_size = script_entity->getBufSize();

	if (pos.getOffset() >= scr_size) {
		warning("Trying to disassemble beyond end of script");
		return NULL_REG;
	}

	const byte *scr = script_entity->getBuf();

	int16 opparams[4];
	byte opsize;
	uint bytecount = readPMachineInstruction(scr + pos.getOffset(), opsize, opparams);
	const byte opcode = opsize >> 1;

	debugN("%04x:%04x: ", PRINT_REG(pos));

	if (printBytecode) {
		if (pos.getOffset() + bytecount > scr_size) {
			warning("Operation arguments extend beyond end of script");
			return retval;
		}

		for (i = 0; i < bytecount; i++)
			debugN("%02x ", scr[pos.getOffset() + i]);

		for (i = bytecount; i < 5; i++)
			debugN("   ");
	}

	opsize &= 1; // byte if true, word if false

	if (printBWTag)
		debugN("[%c] ", opsize ? 'B' : 'W');

	if (opcode == op_pushSelf && opsize && g_sci->getGameId() != GID_FANMADE) { // 0x3e (62)
		// Debug opcode op_file
		debugN("file \"%s\"\n", scr + pos.getOffset() + 1);	// +1: op_pushSelf size
		retval.incOffset(bytecount - 1);
		return retval;
	}

#ifndef REDUCE_MEMORY_USAGE
	debugN("%-5s", opcodeNames[opcode]);
#endif

	static const char *defaultSeparator = "\t\t; ";

	i = 0;
	while (g_sci->_opcode_formats[opcode][i]) {
		switch (g_sci->_opcode_formats[opcode][i++]) {
		case Script_Invalid:
			warning("-Invalid operation-");
			break;

		case Script_SByte:
		case Script_Byte:
			param_value = scr[retval.getOffset()];
			debugN("\t%02x", param_value);
			if (param_value > 9) {
				debugN("%s%u", defaultSeparator, param_value);
			}
			retval.incOffset(1);
			break;

		case Script_Word:
		case Script_SWord:
			param_value = READ_SCI11ENDIAN_UINT16(&scr[retval.getOffset()]);
			debugN("\t%04x", param_value);
			if (param_value > 9) {
				debugN("%s%u", defaultSeparator, param_value);
			}

			retval.incOffset(2);
			break;

		case Script_SVariable:
		case Script_Variable:
		case Script_Property:
		case Script_Global:
		case Script_Local:
		case Script_Temp:
		case Script_Param:
			if (opsize) {
				param_value = scr[retval.getOffset()];
				retval.incOffset(1);
			} else {
				param_value = READ_SCI11ENDIAN_UINT16(&scr[retval.getOffset()]);
				retval.incOffset(2);
			}

			if (opcode == op_callk) {
				debugN("\t%s[%x],", (param_value < kernel->_kernelFuncs.size()) ?
							((param_value < kernel->getKernelNamesSize()) ? kernel->getKernelName(param_value).c_str() : "[Unknown(postulated)]")
							: "<invalid>", param_value);
			} else if (opcode == op_class) {
				const reg_t classAddr = s->_segMan->getClassAddress(param_value, SCRIPT_GET_DONT_LOAD, retval.getSegment());
				if (!classAddr.isNull()) {
					debugN("\t%s", s->_segMan->getObjectName(classAddr));
					debugN(opsize ? "[%02x]" : "[%04x]", param_value);
				} else {
					debugN(opsize ? "\t%02x" : "\t%04x", param_value);
				}
			} else if (opcode == op_super) {
				Object *obj;
				if (objAddr != NULL_REG && (obj = s->_segMan->getObject(objAddr)) != nullptr) {
					debugN("\t%s", s->_segMan->getObjectName(obj->getSuperClassSelector()));
					debugN(opsize ? "[%02x]" : "[%04x]", param_value);
				} else {
					debugN(opsize ? "\t%02x" : "\t%04x", param_value);
				}

				debugN(",");
#ifdef ENABLE_SCI32
			} else if (getSciVersion() == SCI_VERSION_3 && (
				opcode == op_pToa || opcode == op_aTop ||
				opcode == op_pTos || opcode == op_sTop ||
				opcode == op_ipToa || opcode == op_dpToa ||
				opcode == op_ipTos || opcode == op_dpTos)) {

				const char *selectorName = "<invalid>";

				if (param_value < kernel->getSelectorNamesSize()) {
					selectorName = kernel->getSelectorName(param_value).c_str();
				}

				debugN("\t%s[%x]", selectorName, param_value);
#endif
			} else {
				const char *separator = defaultSeparator;

				debugN(opsize ? "\t%02x" : "\t%04x", param_value);
				if (param_value > 9) {
					debugN("%s%u", separator, param_value);
					separator = ", ";
				}

				if (param_value >= 0x20 && param_value <= 0x7e) {
					debugN("%s'%c'", separator, param_value);
					separator = ", ";
				}

				if (opcode == op_pushi && param_value < kernel->getSelectorNamesSize()) {
					debugN("%s%s", separator, kernel->getSelectorName(param_value).c_str());
				}
			}

			break;

		case Script_Offset: {
			assert(opcode == op_lofsa || opcode == op_lofss);

			if (opsize) {
				param_value = scr[retval.getOffset()];
				retval.incOffset(1);
			} else {
				param_value = READ_SCI11ENDIAN_UINT16(&scr[retval.getOffset()]);
				retval.incOffset(2);
			}

			const uint32 offset = findOffset(param_value, script_entity, retval.getOffset());
			reg_t addr;
			addr.setSegment(retval.getSegment());
			addr.setOffset(offset);
			debugN("\t%s", s->_segMan->getObjectName(addr));
			debugN(opsize ? "[%02x]" : "[%04x]", offset);
			break;
		}

		case Script_SRelative:
			if (opsize) {
				int8 offset = (int8)scr[retval.getOffset()];
				retval.incOffset(1);
				debugN("\t%02x  [%04x]", 0xff & offset, kOffsetMask & (retval.getOffset() + offset));
			} else {
				int16 offset = (int16)READ_SCI11ENDIAN_UINT16(&scr[retval.getOffset()]);
				retval.incOffset(2);
				debugN("\t%04x  [%04x]", 0xffff & offset, kOffsetMask & (retval.getOffset() + offset));
			}
			break;

		case Script_End:
			retval = NULL_REG;
			break;

		default:
			error("Internal assertion failed in disassemble()");

		}
	}

	if (pos == s->xs->addr.pc) { // Extra information if debugging the current opcode
		if ((opcode == op_pTos) || (opcode == op_sTop) || (opcode == op_pToa) || (opcode == op_aTop) ||
		        (opcode == op_dpToa) || (opcode == op_ipToa) || (opcode == op_dpTos) || (opcode == op_ipTos)) {
			const Object *obj = s->_segMan->getObject(s->xs->objp);
			if (!obj) {
				warning("Attempted to reference on non-object at %04x:%04x", PRINT_REG(s->xs->objp));
			} else {
				if (getSciVersion() == SCI_VERSION_3)
					debugN("\t(%s)", g_sci->getKernel()->getSelectorName(param_value).c_str());
				else
					debugN("\t(%s)", g_sci->getKernel()->getSelectorName(obj->propertyOffsetToId(s->_segMan, param_value)).c_str());
			}
		}
	}

	debugN("\n");

	if (pos == s->xs->addr.pc) { // Extra information if debugging the current opcode
		if (opcode == op_callk) {
			int stackframe = (scr[pos.getOffset() + 2] >> 1) + (s->r_rest);
			int argc = ((s->xs->sp)[- stackframe - 1]).getOffset();
			bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);

			if (!oldScriptHeader)
				argc += (s->r_rest);

			debugN(" Kernel params: (");

			for (int j = 0; j < argc; j++) {
				debugN("%04x:%04x", PRINT_REG((s->xs->sp)[j - stackframe]));
				if (j + 1 < argc)
					debugN(", ");
			}
			debugN(")\n");
		} else if ((opcode == op_send) || (opcode == op_self)) {
Пример #11
0
void RobotDecoder::preallocateCelMemory(const byte *rawVideoData, const int16 numCels) {
	for (CelHandleList::size_type i = 0; i < _celHandles.size(); ++i) {
		CelHandleInfo &celHandle = _celHandles[i];

		if (celHandle.status == CelHandleInfo::kFrameLifetime) {
			_segMan->freeBitmap(celHandle.bitmapId);
			celHandle.bitmapId = NULL_REG;
			celHandle.status = CelHandleInfo::kNoCel;
			celHandle.area = 0;
		}
	}
	_celHandles.resize(numCels);

	const int numFixedCels = MIN(numCels, (int16)kFixedCelListSize);
	for (int i = 0; i < numFixedCels; ++i) {
		CelHandleInfo &celHandle = _celHandles[i];

		// NOTE: There was a check to see if the cel handle was not allocated
		// here, for some reason, which would mean that nothing was ever
		// allocated from fixed cels, because the _celHandles array just got
		// deleted and recreated...
		if (celHandle.bitmapId == NULL_REG) {
			break;
		}

		celHandle.bitmapId = _fixedCels[i];
		celHandle.status = CelHandleInfo::kRobotLifetime;
		celHandle.area = _maxCelArea[i];
	}

	uint maxFrameArea = 0;
	for (int i = 0; i < numCels; ++i) {
		const int16 celWidth = (int16)READ_SCI11ENDIAN_UINT16(rawVideoData + 2);
		const int16 celHeight = (int16)READ_SCI11ENDIAN_UINT16(rawVideoData + 4);
		const uint16 dataSize = READ_SCI11ENDIAN_UINT16(rawVideoData + 14);
		const uint area = celWidth * celHeight;

		if (area > maxFrameArea) {
			maxFrameArea = area;
		}

		CelHandleInfo &celHandle = _celHandles[i];
		if (celHandle.status == CelHandleInfo::kRobotLifetime) {
			if (_maxCelArea[i] < area) {
				_segMan->freeBitmap(celHandle.bitmapId);
				_segMan->allocateBitmap(&celHandle.bitmapId, celWidth, celHeight, 255, 0, 0, _xResolution, _yResolution, kRawPaletteSize, false, false);
				celHandle.area = area;
				celHandle.status = CelHandleInfo::kFrameLifetime;
			}
		} else if (celHandle.status == CelHandleInfo::kNoCel) {
			_segMan->allocateBitmap(&celHandle.bitmapId, celWidth, celHeight, 255, 0, 0, _xResolution, _yResolution, kRawPaletteSize, false, false);
			celHandle.area = area;
			celHandle.status = CelHandleInfo::kFrameLifetime;
		} else {
			error("Cel Handle has bad status");
		}

		rawVideoData += kCelHeaderSize + dataSize;
	}

	if (maxFrameArea > _celDecompressionBuffer.size()) {
		_celDecompressionBuffer.resize(maxFrameArea);
	}
}
Пример #12
0
uint32 RobotDecoder::createCel5(const byte *rawVideoData, const int16 screenItemIndex, const bool usePalette) {
	_verticalScaleFactor = rawVideoData[1];
	const int16 celWidth = (int16)READ_SCI11ENDIAN_UINT16(rawVideoData + 2);
	const int16 celHeight = (int16)READ_SCI11ENDIAN_UINT16(rawVideoData + 4);
	const Common::Point celPosition((int16)READ_SCI11ENDIAN_UINT16(rawVideoData + 10),
									(int16)READ_SCI11ENDIAN_UINT16(rawVideoData + 12));
	const uint16 dataSize = READ_SCI11ENDIAN_UINT16(rawVideoData + 14);
	const int16 numDataChunks = (int16)READ_SCI11ENDIAN_UINT16(rawVideoData + 16);

	rawVideoData += kCelHeaderSize;

	const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
	const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
	const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
	const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;

	Common::Point origin;
	if (scriptWidth == kLowResX && scriptHeight == kLowResY) {
		const Ratio lowResToScreenX(screenWidth, kLowResX);
		const Ratio lowResToScreenY(screenHeight, kLowResY);
		const Ratio screenToLowResX(kLowResX, screenWidth);
		const Ratio screenToLowResY(kLowResY, screenHeight);

		const int16 scaledX = celPosition.x + (_position.x * lowResToScreenX).toInt();
		const int16 scaledY1 = celPosition.y + (_position.y * lowResToScreenY).toInt();
		const int16 scaledY2 = scaledY1 + celHeight - 1;

		const int16 lowResX = (scaledX * screenToLowResX).toInt();
		const int16 lowResY = (scaledY2 * screenToLowResY).toInt();

		origin.x = (scaledX - (lowResX * lowResToScreenX).toInt()) * -1;
		origin.y = (lowResY * lowResToScreenY).toInt() - scaledY1;
		_screenItemX[screenItemIndex] = lowResX;
		_screenItemY[screenItemIndex] = lowResY;

		debugC(kDebugLevelVideo, "Low resolution position c: %d %d l: %d/%d %d/%d d: %d %d s: %d/%d %d/%d x: %d y: %d", celPosition.x, celPosition.y, lowResX, scriptWidth, lowResY, scriptHeight, origin.x, origin.y, scaledX, screenWidth, scaledY2, screenHeight, scaledX - origin.x, scaledY2 - origin.y);
	} else {
		const int16 highResX = celPosition.x + _position.x;
		const int16 highResY = celPosition.y + _position.y + celHeight - 1;

		origin.x = 0;
		origin.y = celHeight - 1;
		_screenItemX[screenItemIndex] = highResX;
		_screenItemY[screenItemIndex] = highResY;

		debugC(kDebugLevelVideo, "High resolution position c: %d %d s: %d %d d: %d %d", celPosition.x, celPosition.y, highResX, highResY, origin.x, origin.y);
	}

	_originalScreenItemX[screenItemIndex] = celPosition.x;
	_originalScreenItemY[screenItemIndex] = celPosition.y;

	assert(_celHandles[screenItemIndex].area >= celWidth * celHeight);

	SciBitmap &bitmap = *_segMan->lookupBitmap(_celHandles[screenItemIndex].bitmapId);
	assert(bitmap.getWidth() == celWidth && bitmap.getHeight() == celHeight);
	assert(bitmap.getXResolution() == _xResolution && bitmap.getYResolution() == _yResolution);
	assert(bitmap.getHunkPaletteOffset() == (uint32)bitmap.getWidth() * bitmap.getHeight() + SciBitmap::getBitmapHeaderSize());
	bitmap.setOrigin(origin);

	byte *targetBuffer = nullptr;
	if (_verticalScaleFactor == 100) {
		// direct copy to bitmap
		targetBuffer = bitmap.getPixels();
	} else {
		// go through squashed cel decompressor
		_celDecompressionBuffer.resize(_celDecompressionArea >= celWidth * (celHeight * _verticalScaleFactor / 100));
		targetBuffer = _celDecompressionBuffer.begin();
	}

	for (int i = 0; i < numDataChunks; ++i) {
		uint compressedSize = READ_SCI11ENDIAN_UINT32(rawVideoData);
		uint decompressedSize = READ_SCI11ENDIAN_UINT32(rawVideoData + 4);
		uint16 compressionType = READ_SCI11ENDIAN_UINT16(rawVideoData + 8);
		rawVideoData += 10;

		switch (compressionType) {
		case kCompressionLZS: {
			Common::MemoryReadStream videoDataStream(rawVideoData, compressedSize, DisposeAfterUse::NO);
			_decompressor.unpack(&videoDataStream, targetBuffer, compressedSize, decompressedSize);
			break;
		}
		case kCompressionNone:
			Common::copy(rawVideoData, rawVideoData + decompressedSize, targetBuffer);
			break;
		default:
			error("Unknown compression type %d!", compressionType);
		}

		rawVideoData += compressedSize;
		targetBuffer += decompressedSize;
	}

	if (_verticalScaleFactor != 100) {
		expandCel(bitmap.getPixels(), _celDecompressionBuffer.begin(), celWidth, celHeight);
	}

	if (usePalette) {
		Common::copy(_rawPalette, _rawPalette + kRawPaletteSize, bitmap.getHunkPalette());
	}

	return kCelHeaderSize + dataSize;
}
Пример #13
0
void RobotDecoder::doVersion5(const bool shouldSubmitAudio) {
	const RobotScreenItemList::size_type oldScreenItemCount = _screenItemList.size();
	const int videoSize = _videoSizes[_currentFrameNo];
	_doVersion5Scratch.resize(videoSize);

	byte *videoFrameData = _doVersion5Scratch.begin();

	if (!_stream->read(videoFrameData, videoSize)) {
		error("RobotDecoder::doVersion5: Read error");
	}

	const RobotScreenItemList::size_type screenItemCount = READ_SCI11ENDIAN_UINT16(videoFrameData);

	if (screenItemCount > kScreenItemListSize) {
		return;
	}

	if (_hasAudio &&
		(getSciVersion() < SCI_VERSION_3 || shouldSubmitAudio)) {
		int audioPosition, audioSize;
		if (readAudioDataFromRecord(_currentFrameNo, _audioBuffer, audioPosition, audioSize)) {
			_audioList.addBlock(audioPosition, audioSize, _audioBuffer);
		}
	}

	if (screenItemCount > oldScreenItemCount) {
		_screenItemList.resize(screenItemCount);
		_screenItemX.resize(screenItemCount);
		_screenItemY.resize(screenItemCount);
		_originalScreenItemX.resize(screenItemCount);
		_originalScreenItemY.resize(screenItemCount);
	}

	createCels5(videoFrameData + 2, screenItemCount, true);
	for (RobotScreenItemList::size_type i = 0; i < screenItemCount; ++i) {
		Common::Point position(_screenItemX[i], _screenItemY[i]);

// TODO: Version 6 robot?
//		int scaleXRemainder;
		if (_scaleInfo.signal == kScaleSignalManual) {
			position.x = (position.x * _scaleInfo.x) / 128;
// TODO: Version 6 robot?
//			scaleXRemainder = (position.x * _scaleInfo.x) % 128;
			position.y = (position.y * _scaleInfo.y) / 128;
		}

		if (_screenItemList[i] == nullptr) {
			CelInfo32 celInfo;
			celInfo.bitmap = _celHandles[i].bitmapId;
			ScreenItem *screenItem = new ScreenItem(_plane->_object, celInfo, position, _scaleInfo);
			_screenItemList[i] = screenItem;
			// TODO: Version 6 robot?
			// screenItem->_field_30 = scaleXRemainder;

			if (_priority == -1) {
				screenItem->_fixedPriority = false;
			} else {
				screenItem->_fixedPriority = true;
				screenItem->_priority = _priority;
			}
			g_sci->_gfxFrameout->addScreenItem(*screenItem);
		} else {
			ScreenItem *screenItem = _screenItemList[i];
			screenItem->_celInfo.bitmap = _celHandles[i].bitmapId;
			screenItem->_position = position;
			// TODO: Version 6 robot?
			// screenItem->_field_30 = scaleXRemainder;

			if (_priority == -1) {
				screenItem->_fixedPriority = false;
			} else {
				screenItem->_fixedPriority = true;
				screenItem->_priority = _priority;
			}
			g_sci->_gfxFrameout->updateScreenItem(*screenItem);
		}
	}

	for (RobotScreenItemList::size_type i = screenItemCount; i < oldScreenItemCount; ++i) {
		if (_screenItemList[i] != nullptr) {
			g_sci->_gfxFrameout->deleteScreenItem(*_screenItemList[i]);
			_screenItemList[i] = nullptr;
		}
	}

	if (screenItemCount < oldScreenItemCount) {
		_screenItemList.resize(screenItemCount);
		_screenItemX.resize(screenItemCount);
		_screenItemY.resize(screenItemCount);
		_originalScreenItemX.resize(screenItemCount);
		_originalScreenItemY.resize(screenItemCount);
	}
}
Пример #14
0
void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptPatcher) {
	freeScript();

	Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
	if (!script)
		error("Script %d not found", script_nr);

	_nr = script_nr;
	_bufSize = _scriptSize = script->size;

	if (getSciVersion() == SCI_VERSION_0_EARLY) {
		_bufSize += READ_LE_UINT16(script->data) * 2;
	} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
		// In SCI1.1 - SCI2.1, the heap was in a separate space from the script. We append
		// it to the end of the script, and adjust addressing accordingly.
		// However, since we address the heap with a 16-bit pointer, the
		// combined size of the stack and the heap must be 64KB. So far this has
		// worked for SCI11, SCI2 and SCI21 games. SCI3 games use a different
		// script format, and theoretically they can exceed the 64KB boundary
		// using relocation.
		Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
		_bufSize += heap->size;
		_heapSize = heap->size;

		// Ensure that the start of the heap resource can be word-aligned.
		if (script->size & 2) {
			_bufSize++;
			_scriptSize++;
		}

		// As mentioned above, the script and the heap together should not exceed 64KB
		if (script->size + heap->size > 65535)
			error("Script and heap sizes combined exceed 64K. This means a fundamental "
					"design bug was made regarding SCI1.1 and newer games.\n"
					"Please report this error to the ScummVM team");
	} else if (getSciVersion() == SCI_VERSION_3) {
		// Check for scripts over 64KB. These won't work with the current 16-bit address
		// scheme. We need an overlaying mechanism, or a mechanism to split script parts
		// in different segments to handle these. For now, simply stop when such a script
		// is found.
		//
		// Known large SCI 3 scripts are:
		// Lighthouse: 9, 220, 270, 351, 360, 490, 760, 765, 800
		// LSL7: 240, 511, 550
		// Phantasmagoria 2: none (hooray!)
		// RAMA: 70
		//
		// TODO: Remove this once such a mechanism is in place
		if (script->size > 65535)
			error("TODO: SCI script %d is over 64KB - it's %d bytes long. This can't "
			      "be handled at the moment, thus stopping", script_nr, script->size);
	}

	uint extraLocalsWorkaround = 0;
	if (g_sci->getGameId() == GID_FANMADE && _nr == 1 && script->size == 11140) {
		// WORKAROUND: Script 1 in Ocean Battle doesn't have enough locals to
		// fit the string showing how many shots are left (a nasty script bug,
		// corrupting heap memory). We add 10 more locals so that it has enough
		// space to use as the target for its kFormat operation. Fixes bug
		// #3059871.
		extraLocalsWorkaround = 10;
	}
	_bufSize += extraLocalsWorkaround * 2;

	_buf = (byte *)malloc(_bufSize);
	assert(_buf);

	assert(_bufSize >= script->size);
	memcpy(_buf, script->data, script->size);

	if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
		Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), 0);
		assert(heap != 0);

		_heapStart = _buf + _scriptSize;

		assert(_bufSize - _scriptSize >= heap->size);
		memcpy(_heapStart, heap->data, heap->size);
	}

	// Check scripts (+ possibly SCI 1.1 heap) for matching signatures and patch those, if found
	scriptPatcher->processScript(_nr, _buf, _bufSize);

	if (getSciVersion() <= SCI_VERSION_1_LATE) {
		_exportTable = (const uint16 *)findBlockSCI0(SCI_OBJ_EXPORTS);
		if (_exportTable) {
			_numExports = READ_SCI11ENDIAN_UINT16(_exportTable + 1);
			_exportTable += 3;	// skip header plus 2 bytes (_exportTable is a uint16 pointer)
		}
		_synonyms = findBlockSCI0(SCI_OBJ_SYNONYMS);
		if (_synonyms) {
			_numSynonyms = READ_SCI11ENDIAN_UINT16(_synonyms + 2) / 4;
			_synonyms += 4;	// skip header
		}
		const byte* localsBlock = findBlockSCI0(SCI_OBJ_LOCALVARS);
		if (localsBlock) {
			_localsOffset = localsBlock - _buf + 4;
			_localsCount = (READ_LE_UINT16(_buf + _localsOffset - 2) - 4) >> 1;	// half block size
		}
	} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
Пример #15
0
void ScreenItem::setFromObject(SegManager *segMan, const reg_t object, const bool updateCel, const bool updateBitmap) {
	_position.x = readSelectorValue(segMan, object, SELECTOR(x));
	_position.y = readSelectorValue(segMan, object, SELECTOR(y));
	_scale.x = readSelectorValue(segMan, object, SELECTOR(scaleX));
	_scale.y = readSelectorValue(segMan, object, SELECTOR(scaleY));
	_scale.max = readSelectorValue(segMan, object, SELECTOR(maxScale));
	_scale.signal = (ScaleSignals32)(readSelectorValue(segMan, object, SELECTOR(scaleSignal)) & 3);

	if (updateCel) {
		_celInfo.resourceId = (GuiResourceId)readSelectorValue(segMan, object, SELECTOR(view));
		_celInfo.loopNo = readSelectorValue(segMan, object, SELECTOR(loop));
		_celInfo.celNo = readSelectorValue(segMan, object, SELECTOR(cel));

		if (_celInfo.resourceId <= kPlanePic) {
			// TODO: Enhance GfxView or ResourceManager to allow
			// metadata for resources to be retrieved once, from a
			// single location
			Resource *view = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _celInfo.resourceId), false);
			if (!view) {
				error("Failed to load resource %d", _celInfo.resourceId);
			}

			// NOTE: +2 because the header size field itself is excluded from
			// the header size in the data
			const uint16 headerSize = READ_SCI11ENDIAN_UINT16(view->data) + 2;
			const uint8 loopCount = view->data[2];
			const uint8 loopSize = view->data[12];

			if (_celInfo.loopNo >= loopCount) {
				const int maxLoopNo = loopCount - 1;
				_celInfo.loopNo = maxLoopNo;
				writeSelectorValue(segMan, object, SELECTOR(loop), maxLoopNo);
			}

			byte *loopData = view->data + headerSize + (_celInfo.loopNo * loopSize);
			const int8 seekEntry = loopData[0];
			if (seekEntry != -1) {
				loopData = view->data + headerSize + (seekEntry * loopSize);
			}
			const uint8 celCount = loopData[2];
			if (_celInfo.celNo >= celCount) {
				const int maxCelNo = celCount - 1;
				_celInfo.celNo = maxCelNo;
				writeSelectorValue(segMan, object, SELECTOR(cel), maxCelNo);
			}
		}
	}

	if (updateBitmap) {
		const reg_t bitmap = readSelector(segMan, object, SELECTOR(bitmap));
		if (!bitmap.isNull()) {
			_celInfo.bitmap = bitmap;
			_celInfo.type = kCelTypeMem;
		} else {
			_celInfo.bitmap = NULL_REG;
			_celInfo.type = kCelTypeView;
		}
	}

	if (updateCel || updateBitmap) {
		delete _celObj;
		_celObj = nullptr;
	}

	if (readSelectorValue(segMan, object, SELECTOR(fixPriority))) {
		_fixedPriority = true;
		_priority = readSelectorValue(segMan, object, SELECTOR(priority));
	} else {
		_fixedPriority = false;
		writeSelectorValue(segMan, object, SELECTOR(priority), _position.y);
	}

	_z = readSelectorValue(segMan, object, SELECTOR(z));
	_position.y -= _z;

	if (readSelectorValue(segMan, object, SELECTOR(useInsetRect))) {
		_useInsetRect = true;
		_insetRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft));
		_insetRect.top = readSelectorValue(segMan, object, SELECTOR(inTop));
		_insetRect.right = readSelectorValue(segMan, object, SELECTOR(inRight)) + 1;
		_insetRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom)) + 1;
	} else {
		_useInsetRect = false;
	}

	segMan->getObject(object)->clearInfoSelectorFlag(kInfoFlagViewVisible);
}
Пример #16
0
void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 drawX, int16 drawY, int16 pictureX) {
	byte *celBitmap = NULL;
	byte *ptr = NULL;
	byte *headerPtr = inbuffer + headerPos;
	byte *rlePtr = inbuffer + rlePos;
	int16 displaceX, displaceY;
	byte priority = _addToFlag ? _priority : 0;
	byte clearColor;
	bool compression = true;
	byte curByte;
	int16 y, lastY, x, leftX, rightX;
	int pixelCount;
	uint16 width, height;

#ifdef ENABLE_SCI32
	if (_resourceType != SCI_PICTURE_TYPE_SCI32) {
#endif
		// Width/height here are always LE, even in Mac versions
		width = READ_LE_UINT16(headerPtr + 0);
		height = READ_LE_UINT16(headerPtr + 2);
		displaceX = (signed char)headerPtr[4];
		displaceY = (unsigned char)headerPtr[5];
		if (_resourceType == SCI_PICTURE_TYPE_SCI11)
			// SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise
			clearColor = _screen->getColorWhite();
		else
			clearColor = headerPtr[6];
#ifdef ENABLE_SCI32
	} else {
		width = READ_SCI11ENDIAN_UINT16(headerPtr + 0);
		height = READ_SCI11ENDIAN_UINT16(headerPtr + 2);
		displaceX = READ_SCI11ENDIAN_UINT16(headerPtr + 4); // probably signed?!?
		displaceY = READ_SCI11ENDIAN_UINT16(headerPtr + 6); // probably signed?!?
		clearColor = headerPtr[8];
		if (headerPtr[9] == 0)
			compression = false;
	}
#endif

	if (displaceX || displaceY)
		error("unsupported embedded cel-data in picture");

	// We will unpack cel-data into a temporary buffer and then plot it to screen
	//  That needs to be done cause a mirrored picture may be requested
	pixelCount = width * height;
	celBitmap = new byte[pixelCount];
	if (!celBitmap)
		error("Unable to allocate temporary memory for picture drawing");

	if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2) {
		// See GfxView::unpackCel() for why this black/white swap is done
		// This picture swap is only needed in SCI32, not SCI1.1
		if (clearColor == 0)
			clearColor = 0xff;
		else if (clearColor == 0xff)
			clearColor = 0;
	}

	if (compression)
		unpackCelData(inbuffer, celBitmap, clearColor, pixelCount, rlePos, literalPos, _resMan->getViewType(), width, false);
	else
		// No compression (some SCI32 pictures)
		memcpy(celBitmap, rlePtr, pixelCount);

	if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2) {
		// See GfxView::unpackCel() for why this black/white swap is done
		// This picture swap is only needed in SCI32, not SCI1.1
		for (int i = 0; i < pixelCount; i++) {
			if (celBitmap[i] == 0)
				celBitmap[i] = 0xff;
			else if (celBitmap[i] == 0xff)
				celBitmap[i] = 0;
		}
	}

	Common::Rect displayArea = _coordAdjuster->pictureGetDisplayArea();

	uint16 skipCelBitmapPixels = 0;
	int16 displayWidth = width;
	if (pictureX) {
		// scroll position for picture active, we need to adjust drawX accordingly
		drawX -= pictureX;
		if (drawX < 0) {
			skipCelBitmapPixels = -drawX;
			displayWidth -= skipCelBitmapPixels;
			drawX = 0;
		}
	}

	if (displayWidth > 0) {
		y = displayArea.top + drawY;
		lastY = MIN<int16>(height + y, displayArea.bottom);
		leftX = displayArea.left + drawX;
		rightX = MIN<int16>(displayWidth + leftX, displayArea.right);

		uint16 sourcePixelSkipPerRow = 0;
		if (width > rightX - leftX)
			sourcePixelSkipPerRow = width - (rightX - leftX);

		// Change clearcolor to white, if we dont add to an existing picture. That way we will paint everything on screen
		// but white and that won't matter because the screen is supposed to be already white. It seems that most (if not all)
		// SCI1.1 games use color 0 as transparency and SCI1 games use color 255 as transparency. Sierra SCI seems to paint
		// the whole data to screen and wont skip over transparent pixels. So this will actually make it work like Sierra.
		// SCI32 doesn't use _addToFlag at all.
		if (!_addToFlag && _resourceType != SCI_PICTURE_TYPE_SCI32)
			clearColor = _screen->getColorWhite();

		byte drawMask = priority > 15 ? GFX_SCREEN_MASK_VISUAL : GFX_SCREEN_MASK_VISUAL | GFX_SCREEN_MASK_PRIORITY;

		ptr = celBitmap;
		ptr += skipCelBitmapPixels;
		if (!_mirroredFlag) {
			// Draw bitmap to screen
			x = leftX;
			while (y < lastY) {
				curByte = *ptr++;
				if ((curByte != clearColor) && (priority >= _screen->getPriority(x, y)))
					_screen->putPixel(x, y, drawMask, curByte, priority, 0);

				x++;

				if (x >= rightX) {
					ptr += sourcePixelSkipPerRow;
					x = leftX;
					y++;
				}
			}
		} else {
			// Draw bitmap to screen (mirrored)
			x = rightX - 1;
			while (y < lastY) {
				curByte = *ptr++;
				if ((curByte != clearColor) && (priority >= _screen->getPriority(x, y)))
					_screen->putPixel(x, y, drawMask, curByte, priority, 0);

				if (x == leftX) {
					ptr += sourcePixelSkipPerRow;
					x = rightX;
					y++;
				}

				x--;
			}
		}
	}

	delete[] celBitmap;
}
Пример #17
0
void GfxPalette::createFromData(byte *data, int bytesLeft, Palette *paletteOut) const {
	int palFormat = 0;
	int palOffset = 0;
	int palColorStart = 0;
	int palColorCount = 0;
	int colorNo = 0;

	memset(paletteOut, 0, sizeof(Palette));

	// Setup 1:1 mapping
	for (colorNo = 0; colorNo < 256; colorNo++) {
		paletteOut->mapping[colorNo] = colorNo;
	}

	if (bytesLeft < 37) {
		// This happens when loading palette of picture 0 in sq5 - the resource is broken and doesn't contain a full
		//  palette
		debugC(kDebugLevelResMan, "GfxPalette::createFromData() - not enough bytes in resource (%d), expected palette header", bytesLeft);
		return;
	}

	// palette formats in here are not really version exclusive, we can not use sci-version to differentiate between them
	//  they were just called that way, because they started appearing in sci1.1 for example
	if ((data[0] == 0 && data[1] == 1) || (data[0] == 0 && data[1] == 0 && READ_SCI11ENDIAN_UINT16(data + 29) == 0)) {
		// SCI0/SCI1 palette
		palFormat = SCI_PAL_FORMAT_VARIABLE; // CONSTANT;
		palOffset = 260;
		palColorStart = 0; palColorCount = 256;
		//memcpy(&paletteOut->mapping, data, 256);
	} else {
		// SCI1.1 palette
		palFormat = data[32];
		palOffset = 37;
		palColorStart = data[25];
		palColorCount = READ_SCI11ENDIAN_UINT16(data + 29);
	}

	switch (palFormat) {
		case SCI_PAL_FORMAT_CONSTANT:
			// Check, if enough bytes left
			if (bytesLeft < palOffset + (3 * palColorCount)) {
				warning("GfxPalette::createFromData() - not enough bytes in resource, expected palette colors");
				return;
			}

			for (colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) {
				paletteOut->colors[colorNo].used = 1;
				paletteOut->colors[colorNo].r = data[palOffset++];
				paletteOut->colors[colorNo].g = data[palOffset++];
				paletteOut->colors[colorNo].b = data[palOffset++];
			}
			break;
		case SCI_PAL_FORMAT_VARIABLE:
			if (bytesLeft < palOffset + (4 * palColorCount)) {
				warning("GfxPalette::createFromData() - not enough bytes in resource, expected palette colors");
				return;
			}

			for (colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) {
				paletteOut->colors[colorNo].used = data[palOffset++];
				paletteOut->colors[colorNo].r = data[palOffset++];
				paletteOut->colors[colorNo].g = data[palOffset++];
				paletteOut->colors[colorNo].b = data[palOffset++];
			}
			break;
	}
}
Пример #18
0
void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 drawX, int16 drawY, int16 pictureX) {
	byte *celBitmap = NULL;
	byte *ptr = NULL;
	byte *headerPtr = inbuffer + headerPos;
	byte *rlePtr = inbuffer + rlePos;
	byte *literalPtr = inbuffer + literalPos;
	int16 displaceX, displaceY;
	byte priority = _addToFlag ? _priority : 0;
	byte clearColor;
	bool compression = true;
	byte curByte, runLength;
	int16 y, lastY, x, leftX, rightX;
	int pixelNr, pixelCount;
	uint16 width, height;

#ifdef ENABLE_SCI32
	if (_resourceType != SCI_PICTURE_TYPE_SCI32) {
#endif
		// Width/height here are always LE, even in Mac versions
		width = READ_LE_UINT16(headerPtr + 0);
		height = READ_LE_UINT16(headerPtr + 2);
		displaceX = (signed char)headerPtr[4];
		displaceY = (unsigned char)headerPtr[5];
		if (_resourceType == SCI_PICTURE_TYPE_SCI11) {
			// SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise
			clearColor = _screen->getColorWhite();
		} else {
			clearColor = headerPtr[6];
		}
#ifdef ENABLE_SCI32
	} else {
		width = READ_SCI11ENDIAN_UINT16(headerPtr + 0);
		height = READ_SCI11ENDIAN_UINT16(headerPtr + 2);
		displaceX = READ_SCI11ENDIAN_UINT16(headerPtr + 4); // probably signed?!?
		displaceY = READ_SCI11ENDIAN_UINT16(headerPtr + 6); // probably signed?!?
		clearColor = headerPtr[8];
		if (headerPtr[9] == 0)
			compression = false;
	}
#endif

	if (displaceX || displaceY)
		error("unsupported embedded cel-data in picture");

	pixelCount = width * height;
	celBitmap = new byte[pixelCount];
	if (!celBitmap)
		error("Unable to allocate temporary memory for picture drawing");

	if (compression) {
		// We will unpack cel-data into a temporary buffer and then plot it to screen
		//  That needs to be done cause a mirrored picture may be requested
		memset(celBitmap, clearColor, pixelCount);
		pixelNr = 0;
		ptr = celBitmap;
		if (literalPos == 0) {
			// decompression for data that has only one stream (vecor embedded view data)
			switch (_resMan->getViewType()) {
			case kViewEga:
				while (pixelNr < pixelCount) {
					curByte = *rlePtr++;
					runLength = curByte >> 4;
					memset(ptr + pixelNr, curByte & 0x0F, MIN<uint16>(runLength, pixelCount - pixelNr));
					pixelNr += runLength;
				}
				break;
			case kViewVga:
			case kViewVga11:
				while (pixelNr < pixelCount) {
					curByte = *rlePtr++;
					runLength = curByte & 0x3F;
					switch (curByte & 0xC0) {
					case 0: // copy bytes as-is
						while (runLength-- && pixelNr < pixelCount)
							ptr[pixelNr++] = *rlePtr++;
						break;
					case 0x80: // fill with color
						memset(ptr + pixelNr, *rlePtr++, MIN<uint16>(runLength, pixelCount - pixelNr));
						pixelNr += runLength;
						break;
					case 0xC0: // fill with transparent
						pixelNr += runLength;
						break;
					}
				}
				break;
			case kViewAmiga:
				while (pixelNr < pixelCount) {
					curByte = *rlePtr++;
					if (curByte & 0x07) { // fill with color
						runLength = curByte & 0x07;
						curByte = curByte >> 3;
						while (runLength-- && pixelNr < pixelCount) {
							ptr[pixelNr++] = curByte;
						}
					} else { // fill with transparent
						runLength = curByte >> 3;
						pixelNr += runLength;
					}
				}
				break;

			default:
				error("Unsupported picture viewtype");
			}
		} else {