예제 #1
0
파일: world.cpp 프로젝트: cornytrace/opendf
void World::loadPakList(std::string&& fname, std::vector<PakArray> &paklist)
{
    VFS::IStreamPtr stream = VFS::Manager::get().open(fname.c_str());
    if(!stream) throw std::runtime_error("Failed to open "+fname);

    size_t rownum = 0;
    std::map<size_t,size_t> offsets_rows;
    offsets_rows[VFS::read_le32(*stream)] = rownum++;
    while((size_t)stream->tellg() < offsets_rows.begin()->first)
        offsets_rows[VFS::read_le32(*stream)] = rownum++;

    auto iter = offsets_rows.begin();
    while(iter != offsets_rows.end())
    {
        auto next = std::next(iter);

        PakArray pak;
        while((next != offsets_rows.end() && (size_t)stream->tellg() < next->first) ||
              (next == offsets_rows.end() && stream->peek() != std::istream::traits_type::eof()))
        {
            uint16_t count = VFS::read_le16(*stream);
            uint8_t val = stream->get();
            pak.push_back(std::make_pair(count, val));
        }

        if(iter->second >= paklist.size())
            paklist.resize(iter->second+1);
        paklist[iter->second] = std::move(pak);

        iter = next;
    }
}
예제 #2
0
void TextureManager::initialize()
{
    VFS::IStreamPtr stream = VFS::Manager::get().open("PAL.PAL");

    std::streamsize len = 0;
    if(stream && stream->seekg(0, std::ios_base::end))
    {
        len = stream->tellg();
        stream->seekg(0);
    }

    if(len == 776)
    {
        len -= 8;
        stream->ignore(8);
    }

    if(len != sizeof(mCurrentPalette))
        throw std::runtime_error("Invalid palette size (expected 768 or 776 bytes)");

    stream->read(reinterpret_cast<char*>(mCurrentPalette.data()), sizeof(mCurrentPalette));
}
예제 #3
0
DFAFile::DFAFile(const std::string &filename, const Palette &palette)
	: pixels()
{
	VFS::IStreamPtr stream = VFS::Manager::get().open(filename.c_str());
	Debug::check(stream != nullptr, "DFAFile", "Could not open \"" + filename + "\".");

	stream->seekg(0, std::ios::end);
	const auto fileSize = stream->tellg();
	stream->seekg(0, std::ios::beg);

	std::vector<uint8_t> srcData(fileSize);
	stream->read(reinterpret_cast<char*>(srcData.data()), srcData.size());

	// Read DFA header data.
	const uint16_t imageCount = Bytes::getLE16(srcData.data());
	const uint16_t unknown1 = Bytes::getLE16(srcData.data() + 2);
	const uint16_t unknown2 = Bytes::getLE16(srcData.data() + 4);
	const uint16_t width = Bytes::getLE16(srcData.data() + 6);
	const uint16_t height = Bytes::getLE16(srcData.data() + 8);
	const uint16_t compressedLength = Bytes::getLE16(srcData.data() + 10); // First frame.

	// Frame data with palette indices.
	std::vector<std::vector<uint8_t>> frames;

	// Uncompress the initial frame.
	frames.push_back(std::vector<uint8_t>(width * height));
	Compression::decodeRLE(srcData.data() + 12, width * height, frames.at(0));

	// Make copies of the original frame for each update chunk.
	for (int i = 1; i < imageCount; ++i)
	{
		frames.push_back(frames.at(0));
	}

	// Offset to the beginning of the chunk data; advances as the chunk data is read.
	uint32_t offset = 12 + compressedLength;

	// Start reading chunks for each update group. Skip the first frame because 
	// that's the full image.
	for (uint32_t frameIndex = 1; frameIndex < imageCount; ++frameIndex)
	{
		// Select the frame buffer at the current frame index.
		std::vector<uint8_t> &frame = frames.at(frameIndex);

		// Pointer to the beginning of the chunk data. Each update chunk
		// changes a group of pixels in a copy of the original image.
		const uint8_t *chunkData = srcData.data() + offset;
		const uint16_t chunkSize = Bytes::getLE16(chunkData);
		const uint16_t chunkCount = Bytes::getLE16(chunkData + 2);

		// Move the offset past the chunk header.
		offset += 4;

		for (uint32_t chunkIndex = 0; chunkIndex < chunkCount; ++chunkIndex)
		{
			const uint8_t *updateData = srcData.data() + offset;
			const uint16_t updateOffset = Bytes::getLE16(updateData);
			const uint16_t updateCount = Bytes::getLE16(updateData + 2);

			// Move the offset past the update header.
			offset += 4;

			for (uint32_t i = 0; i < updateCount; ++i)
			{
				frame.at(updateOffset + i) = *(srcData.begin() + offset);
				offset++;
			}
		}
	}

	this->width = width;
	this->height = height;

	// Finally, create 32-bit images using each frame's palette indices.
	for (const auto &frame : frames)
	{
		this->pixels.push_back(std::unique_ptr<uint32_t>(
			new uint32_t[this->width * this->height]));

		uint32_t *dstPixels = this->pixels.at(this->pixels.size() - 1).get();

		std::transform(frame.begin(), frame.begin() + frame.size(), dstPixels,
			[&palette](uint8_t col) -> uint32_t
		{
			return palette[col].toARGB();
		});
	}
}
예제 #4
0
파일: world.cpp 프로젝트: cornytrace/opendf
void World::initialize(osgViewer::Viewer *viewer, osg::Group *sceneroot)
{
    std::set<std::string> names = VFS::Manager::get().list("MAPNAMES.[0-9]*");
    if(names.empty()) throw std::runtime_error("Failed to find any regions");

    VFS::IStreamPtr stream;
    for(const std::string &name : names)
    {
        size_t pos = name.rfind('.');
        if(pos == std::string::npos)
            continue;
        std::string regstr = name.substr(pos+1);
        unsigned long regnum = std::stoul(regstr, nullptr, 10);

        /* Get names */
        stream = VFS::Manager::get().open(name.c_str());
        if(!stream) throw std::runtime_error("Failed to open "+name);

        uint32_t mapcount = VFS::read_le32(*stream);
        if(mapcount == 0) continue;

        MapRegion region;
        region.mNames.resize(mapcount);
        for(std::string &mapname : region.mNames)
        {
            char mname[32];
            if(!stream->read(mname, sizeof(mname)) || stream->gcount() != sizeof(mname))
                throw std::runtime_error("Failed to read map names from "+name);
            mapname.assign(mname, sizeof(mname));
            size_t end = mapname.find('\0');
            if(end != std::string::npos)
                mapname.resize(end);
        }
        stream = nullptr;

        /* Get table data */
        std::string fname = "MAPTABLE."+regstr;
        stream = VFS::Manager::get().open(fname.c_str());
        if(!stream) throw std::runtime_error("Failed to open "+fname);

        region.mTable.resize(region.mNames.size());
        for(MapTable &maptable : region.mTable)
        {
            maptable.mMapId = VFS::read_le32(*stream);
            maptable.mUnknown1 = stream->get();
            maptable.mLongitudeType = VFS::read_le32(*stream);
            maptable.mLatitude = VFS::read_le16(*stream);
            maptable.mUnknown2 = VFS::read_le16(*stream);
            maptable.mUnknown3 = VFS::read_le32(*stream);
        }
        stream = nullptr;

        /* Get exterior data */
        fname = "MAPPITEM."+regstr;
        stream = VFS::Manager::get().open(fname.c_str());
        if(!stream) throw std::runtime_error("Failed to open "+fname);

        std::vector<uint32_t> extoffsets(region.mNames.size());
        for(uint32_t &offset : extoffsets)
            offset = VFS::read_le32(*stream);
        std::streamoff extbase_offset = stream->tellg();

        uint32_t *extoffset = extoffsets.data();
        region.mExteriors.resize(extoffsets.size());
        for(ExteriorLocation &extinfo : region.mExteriors)
        {
            stream->seekg(extbase_offset + *extoffset);
            extinfo.load(*stream);
            ++extoffset;
        }
        stream = nullptr;

        /* Get dungeon data */
        fname = "MAPDITEM."+regstr;
        stream = VFS::Manager::get().open(fname.c_str());
        if(!stream) throw std::runtime_error("Failed to open "+fname);

        DungeonHeader dheader;
        dheader.load(*stream);
        std::streamoff dbase_offset = stream->tellg();

        DungeonHeader::Offset *doffset = dheader.mOffsets.data();
        region.mDungeons.resize(dheader.mDungeonCount);
        for(DungeonInterior &dinfo : region.mDungeons)
        {
            stream->seekg(dbase_offset + doffset->mOffset);
            dinfo.load(*stream);
            if(dinfo.mExteriorLocationId != doffset->mExteriorLocationId)
                throw std::runtime_error("Dungeon exterior location id mismatch for "+std::string(dinfo.mLocationName)+": "+
                    std::to_string(dinfo.mExteriorLocationId)+" / "+std::to_string(doffset->mExteriorLocationId));
            ++doffset;
        }
        stream = nullptr;

        if(regnum >= mRegions.size()) mRegions.resize(regnum+1);
        mRegions[regnum] = std::move(region);
    }

    loadPakList("CLIMATE.PAK", mClimates);
    loadPakList("POLITIC.PAK", mPolitics);

    mViewer = viewer;
    mSceneRoot = sceneroot;
}