Beispiel #1
0
// -----------------------------------------------------------------------------
// Writes Chasm bin archive to a MemChunk
// Returns true if successful, false otherwise
// -----------------------------------------------------------------------------
bool ChasmBinArchive::write(MemChunk& mc, bool update)
{
	// Clear current data
	mc.clear();

	// Get archive tree as a list
	vector<ArchiveEntry*> entries;
	getEntryTreeAsList(entries);

	// Check limit of entries count
	const uint16_t num_entries = static_cast<uint16_t>(entries.size());

	if (num_entries > MAX_ENTRY_COUNT)
	{
		LOG_MESSAGE(1, "ChasmBinArchive::write: Bin archive can contain no more than %u entries", MAX_ENTRY_COUNT);
		Global::error = "Maximum number of entries exceeded for Chasm: The Rift bin archive";
		return false;
	}

	// Init data size
	static const uint32_t HEADER_TOC_SIZE = HEADER_SIZE + ENTRY_SIZE * MAX_ENTRY_COUNT;
	mc.reSize(HEADER_TOC_SIZE, false);
	mc.fillData(0);

	// Write header
	const char magic[4] = { 'C', 'S', 'i', 'd' };
	mc.seek(0, SEEK_SET);
	mc.write(magic, 4);
	mc.write(&num_entries, sizeof num_entries);

	// Write directory
	uint32_t offset = HEADER_TOC_SIZE;

	for (uint16_t i = 0; i < num_entries; ++i)
	{
		ArchiveEntry* const entry = entries[i];

		// Update entry
		if (update)
		{
			entry->setState(0);
			entry->exProp("Offset") = static_cast<int>(offset);
		}

		// Check entry name
		string  name        = entry->getName();
		uint8_t name_length = static_cast<uint8_t>(name.Length());

		if (name_length > NAME_SIZE - 1)
		{
			LOG_MESSAGE(1, "Warning: Entry %s name is too long, it will be truncated", name);
			name.Truncate(NAME_SIZE - 1);
			name_length = static_cast<uint8_t>(NAME_SIZE - 1);
		}

		// Write entry name
		char name_data[NAME_SIZE] = {};
		memcpy(name_data, &name_length, 1);
		memcpy(name_data + 1, CHR(name), name_length);
		mc.write(name_data, NAME_SIZE);

		// Write entry size
		const uint32_t size = entry->getSize();
		mc.write(&size, sizeof size);

		// Write entry offset
		mc.write(&offset, sizeof offset);

		// Increment/update offset
		offset += size;
	}

	// Write entry data
	mc.reSize(offset);
	mc.seek(HEADER_TOC_SIZE, SEEK_SET);

	for (uint16_t i = 0; i < num_entries; ++i)
	{
		ArchiveEntry* const entry = entries[i];
		mc.write(entry->getData(), entry->getSize());
	}

	return true;
}
Beispiel #2
0
/* GLTexture::loadImagePortion
 * Loads a portion of a SImage to the texture. Only used internally,
 * the portion must be 128x128 in size
 *******************************************************************/
bool GLTexture::loadImagePortion(SImage* image, rect_t rect, Palette8bit* pal, bool add)
{
	// Check image was given
	if (!image)
		return false;

	// Check image is valid
	if (!image->isValid())
		return false;

	// Check portion rect is valid
	if (rect.width() <= 0 || rect.height() <= 0)
		return false;

	// Get RGBA image data
	MemChunk rgba;
	image->getRGBAData(rgba, pal);

	// Init texture data
	MemChunk portion;
	portion.reSize(rect.width() * rect.height() * 4, false);
	portion.fillData(0);

	// Read portion of image if rect isn't completely outside the image
	if (!(rect.left() >= image->getWidth() || rect.right() < 0 || rect.top() >= image->getHeight() || rect.bottom() < 0))
	{
		// Determine start of each row to read
		uint32_t row_start = 0;
		if (rect.left() > 0)
			row_start = rect.left();

		// Determine width of each row to read
		uint32_t row_width = rect.right() - row_start;
		if (rect.right() >= image->getWidth())
			row_width = image->getWidth() - row_start;

		// Determine difference between the left of the portion and the left of the image
		uint32_t skip = 0;
		if (rect.left() < 0)
			skip = (0 - rect.left()) * 4;

		// Create temp row buffer
		uint8_t* buf = new uint8_t[rect.width() * 4];

		// Go through each row
		for (int32_t row = rect.top(); row < rect.bottom(); row++)
		{
			// Clear row buffer
			memset(buf, 0, rect.width() * 4);

			// Check that the current row is within the image
			if (row >= 0 && row < image->getHeight())
			{
				// Seek to current row in image data
				rgba.seek((row * image->getWidth() + row_start) * 4, SEEK_SET);

				// Copy the row data
				rgba.read(buf + skip, row_width * 4);
			}

			// Write the row
			portion.write(buf, rect.width() * 4);
		}

		// Free buffer
		delete[] buf;
	}
	scale_x = scale_y = 1.0;

	// Generate texture from rgba data
	return loadData(portion.getData(), rect.width(), rect.height(), add);
}