mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-20 00:02:55 +00:00
add iw3 asset dumping basics
This commit is contained in:
parent
dbcbb4a4b3
commit
07fb470466
@ -0,0 +1,48 @@
|
|||||||
|
#include "AssetDumperGfxImage.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "ObjWriting.h"
|
||||||
|
#include "Image/IwiWriter6.h"
|
||||||
|
#include "Image/DdsWriter.h"
|
||||||
|
|
||||||
|
using namespace IW3;
|
||||||
|
|
||||||
|
AssetDumperGfxImage::AssetDumperGfxImage()
|
||||||
|
{
|
||||||
|
switch (ObjWriting::Configuration.ImageOutputFormat)
|
||||||
|
{
|
||||||
|
case ObjWriting::Configuration_t::ImageOutputFormat_e::DDS:
|
||||||
|
m_writer = std::make_unique<DdsWriter>();
|
||||||
|
break;
|
||||||
|
case ObjWriting::Configuration_t::ImageOutputFormat_e::IWI:
|
||||||
|
m_writer = std::make_unique<iwi6::IwiWriter>();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
m_writer = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssetDumperGfxImage::ShouldDump(XAssetInfo<GfxImage>* asset)
|
||||||
|
{
|
||||||
|
const auto* image = asset->Asset();
|
||||||
|
return image->cardMemory.platform[0] > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssetDumperGfxImage::CanDumpAsRaw()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AssetDumperGfxImage::GetFileNameForAsset(Zone* zone, XAssetInfo<GfxImage>* asset)
|
||||||
|
{
|
||||||
|
return "images/" + asset->m_name + m_writer->GetFileExtension();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetDumperGfxImage::DumpRaw(AssetDumpingContext& context, XAssetInfo<GfxImage>* asset, std::ostream& stream)
|
||||||
|
{
|
||||||
|
const auto* image = asset->Asset();
|
||||||
|
m_writer->DumpImage(stream, image->texture.texture);
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Dumping/AbstractAssetDumper.h"
|
||||||
|
#include "Game/IW3/IW3.h"
|
||||||
|
#include "Image/IImageWriter.h"
|
||||||
|
|
||||||
|
namespace IW3
|
||||||
|
{
|
||||||
|
class AssetDumperGfxImage final : public AbstractAssetDumper<GfxImage>
|
||||||
|
{
|
||||||
|
std::unique_ptr<IImageWriter> m_writer;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool ShouldDump(XAssetInfo<GfxImage>* asset) override;
|
||||||
|
bool CanDumpAsRaw() override;
|
||||||
|
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<GfxImage>* asset) override;
|
||||||
|
void DumpRaw(AssetDumpingContext& context, XAssetInfo<GfxImage>* asset, std::ostream& stream) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AssetDumperGfxImage();
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
#include "AssetDumperLoadedSound.h"
|
||||||
|
|
||||||
|
#include "Sound/WavTypes.h"
|
||||||
|
|
||||||
|
using namespace IW3;
|
||||||
|
|
||||||
|
bool AssetDumperLoadedSound::ShouldDump(XAssetInfo<LoadedSound>* asset)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssetDumperLoadedSound::CanDumpAsRaw()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AssetDumperLoadedSound::GetFileNameForAsset(Zone* zone, XAssetInfo<LoadedSound>* asset)
|
||||||
|
{
|
||||||
|
return "sound/" + asset->m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetDumperLoadedSound::DumpWavPcm(AssetDumpingContext& context, const LoadedSound* asset, std::ostream& stream)
|
||||||
|
{
|
||||||
|
const auto riffMasterChunkSize = sizeof(WAV_CHUNK_ID_RIFF)
|
||||||
|
+ sizeof(uint32_t)
|
||||||
|
+ sizeof(WAV_WAVE_ID)
|
||||||
|
+ sizeof(WavChunkHeader)
|
||||||
|
+ sizeof(WavFormatChunkPcm)
|
||||||
|
+ sizeof(WavChunkHeader)
|
||||||
|
+ sizeof(asset->sound.info.data_len);
|
||||||
|
|
||||||
|
stream.write(reinterpret_cast<const char*>(&WAV_CHUNK_ID_RIFF), sizeof(WAV_CHUNK_ID_RIFF));
|
||||||
|
stream.write(reinterpret_cast<const char*>(&riffMasterChunkSize), sizeof(riffMasterChunkSize));
|
||||||
|
stream.write(reinterpret_cast<const char*>(&WAV_WAVE_ID), sizeof(WAV_WAVE_ID));
|
||||||
|
|
||||||
|
const WavChunkHeader formatChunkHeader
|
||||||
|
{
|
||||||
|
WAV_CHUNK_ID_FMT,
|
||||||
|
sizeof(WavFormatChunkPcm)
|
||||||
|
};
|
||||||
|
stream.write(reinterpret_cast<const char*>(&formatChunkHeader), sizeof(formatChunkHeader));
|
||||||
|
|
||||||
|
WavFormatChunkPcm formatChunk
|
||||||
|
{
|
||||||
|
WavFormat::PCM,
|
||||||
|
static_cast<uint16_t>(asset->sound.info.channels),
|
||||||
|
asset->sound.info.rate,
|
||||||
|
asset->sound.info.rate * asset->sound.info.channels * asset->sound.info.bits / 8,
|
||||||
|
static_cast<uint16_t>(asset->sound.info.block_size),
|
||||||
|
static_cast<uint16_t>(asset->sound.info.bits)
|
||||||
|
};
|
||||||
|
stream.write(reinterpret_cast<const char*>(&formatChunk), sizeof(formatChunk));
|
||||||
|
|
||||||
|
const WavChunkHeader dataChunkHeader
|
||||||
|
{
|
||||||
|
WAV_CHUNK_ID_DATA,
|
||||||
|
asset->sound.info.data_len
|
||||||
|
};
|
||||||
|
stream.write(reinterpret_cast<const char*>(&dataChunkHeader), sizeof(dataChunkHeader));
|
||||||
|
stream.write(asset->sound.data, asset->sound.info.data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetDumperLoadedSound::DumpRaw(AssetDumpingContext& context, XAssetInfo<LoadedSound>* asset, std::ostream& stream)
|
||||||
|
{
|
||||||
|
const auto* loadedSound = asset->Asset();
|
||||||
|
switch (static_cast<WavFormat>(loadedSound->sound.info.format))
|
||||||
|
{
|
||||||
|
case WavFormat::PCM:
|
||||||
|
DumpWavPcm(context, loadedSound, stream);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf("Unknown format %i for loaded sound: %s\n", loadedSound->sound.info.format, loadedSound->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Dumping/AbstractAssetDumper.h"
|
||||||
|
#include "Game/IW3/IW3.h"
|
||||||
|
|
||||||
|
namespace IW3
|
||||||
|
{
|
||||||
|
class AssetDumperLoadedSound final : public AbstractAssetDumper<LoadedSound>
|
||||||
|
{
|
||||||
|
static void DumpWavPcm(AssetDumpingContext& context, const LoadedSound* asset, std::ostream& stream);
|
||||||
|
protected:
|
||||||
|
bool ShouldDump(XAssetInfo<LoadedSound>* asset) override;
|
||||||
|
bool CanDumpAsRaw() override;
|
||||||
|
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<LoadedSound>* asset) override;
|
||||||
|
void DumpRaw(AssetDumpingContext& context, XAssetInfo<LoadedSound>* asset, std::ostream& stream) override;
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
#include "AssetDumperLocalizeEntry.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include "Localize/LocalizeCommon.h"
|
||||||
|
#include "Dumping/Localize/StringFileDumper.h"
|
||||||
|
|
||||||
|
using namespace IW3;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
void AssetDumperLocalizeEntry::DumpPool(AssetDumpingContext& context, AssetPool<LocalizeEntry>* pool)
|
||||||
|
{
|
||||||
|
if (pool->m_asset_lookup.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto language = LocalizeCommon::GetNameOfLanguage(context.m_zone->m_language);
|
||||||
|
fs::path stringsPath(context.m_base_path);
|
||||||
|
stringsPath.append(language);
|
||||||
|
stringsPath.append("localizedstrings");
|
||||||
|
|
||||||
|
create_directories(stringsPath);
|
||||||
|
|
||||||
|
auto stringFilePath(stringsPath);
|
||||||
|
stringFilePath.append(context.m_zone->m_name + ".str");
|
||||||
|
|
||||||
|
std::ofstream stringFile(stringFilePath, std::fstream::out | std::ofstream::binary);
|
||||||
|
|
||||||
|
if (stringFile.is_open())
|
||||||
|
{
|
||||||
|
StringFileDumper stringFileDumper(context.m_zone, stringFile);
|
||||||
|
|
||||||
|
stringFileDumper.SetLanguageName(language);
|
||||||
|
|
||||||
|
// Magic string. Original string files do have this config file. The purpose of the config file is unknown though.
|
||||||
|
stringFileDumper.SetConfigFile(R"(C:\trees\cod3\cod3\bin\StringEd.cfg)");
|
||||||
|
|
||||||
|
stringFileDumper.SetNotes("");
|
||||||
|
|
||||||
|
for (auto* localizeEntry : *pool)
|
||||||
|
{
|
||||||
|
stringFileDumper.WriteLocalizeEntry(localizeEntry->m_name, localizeEntry->Asset()->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
stringFileDumper.Finalize();
|
||||||
|
|
||||||
|
stringFile.close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Could not create string file for dumping localized strings of zone '%s'\n", context.m_zone->m_name.c_str());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Dumping/AbstractAssetDumper.h"
|
||||||
|
#include "Game/IW3/IW3.h"
|
||||||
|
|
||||||
|
namespace IW3
|
||||||
|
{
|
||||||
|
class AssetDumperLocalizeEntry final : public IAssetDumper<LocalizeEntry>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void DumpPool(AssetDumpingContext& context, AssetPool<LocalizeEntry>* pool) override;
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
#include "AssetDumperRawFile.h"
|
||||||
|
|
||||||
|
using namespace IW3;
|
||||||
|
|
||||||
|
bool AssetDumperRawFile::ShouldDump(XAssetInfo<RawFile>* asset)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssetDumperRawFile::CanDumpAsRaw()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AssetDumperRawFile::GetFileNameForAsset(Zone* zone, XAssetInfo<RawFile>* asset)
|
||||||
|
{
|
||||||
|
return asset->m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetDumperRawFile::DumpRaw(AssetDumpingContext& context, XAssetInfo<RawFile>* asset, std::ostream& stream)
|
||||||
|
{
|
||||||
|
const auto* rawFile = asset->Asset();
|
||||||
|
stream.write(rawFile->buffer, rawFile->len);
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Dumping/AbstractAssetDumper.h"
|
||||||
|
#include "Game/IW3/IW3.h"
|
||||||
|
|
||||||
|
namespace IW3
|
||||||
|
{
|
||||||
|
class AssetDumperRawFile final : public AbstractAssetDumper<RawFile>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
bool ShouldDump(XAssetInfo<RawFile>* asset) override;
|
||||||
|
bool CanDumpAsRaw() override;
|
||||||
|
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<RawFile>* asset) override;
|
||||||
|
void DumpRaw(AssetDumpingContext& context, XAssetInfo<RawFile>* asset, std::ostream& stream) override;
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
#include "AssetDumperStringTable.h"
|
||||||
|
|
||||||
|
#include "Csv/CsvStream.h"
|
||||||
|
|
||||||
|
using namespace IW3;
|
||||||
|
|
||||||
|
bool AssetDumperStringTable::ShouldDump(XAssetInfo<StringTable>* asset)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssetDumperStringTable::CanDumpAsRaw()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AssetDumperStringTable::GetFileNameForAsset(Zone* zone, XAssetInfo<StringTable>* asset)
|
||||||
|
{
|
||||||
|
return asset->m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetDumperStringTable::DumpRaw(AssetDumpingContext& context, XAssetInfo<StringTable>* asset, std::ostream& stream)
|
||||||
|
{
|
||||||
|
const auto* stringTable = asset->Asset();
|
||||||
|
CsvOutputStream csv(stream);
|
||||||
|
|
||||||
|
for (auto row = 0; row < stringTable->rowCount; row++)
|
||||||
|
{
|
||||||
|
for (auto column = 0; column < stringTable->columnCount; column++)
|
||||||
|
{
|
||||||
|
csv.WriteColumn(stringTable->values[column + row * stringTable->columnCount]);
|
||||||
|
}
|
||||||
|
|
||||||
|
csv.NextRow();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Dumping/AbstractAssetDumper.h"
|
||||||
|
#include "Game/IW3/IW3.h"
|
||||||
|
|
||||||
|
namespace IW3
|
||||||
|
{
|
||||||
|
class AssetDumperStringTable final : public AbstractAssetDumper<StringTable>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
bool ShouldDump(XAssetInfo<StringTable>* asset) override;
|
||||||
|
bool CanDumpAsRaw() override;
|
||||||
|
|
||||||
|
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<StringTable>* asset) override;
|
||||||
|
void DumpRaw(AssetDumpingContext& context, XAssetInfo<StringTable>* asset, std::ostream& stream) override;
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
#include "ZoneDumperIW3.h"
|
||||||
|
|
||||||
|
#include "Game/IW3/GameIW3.h"
|
||||||
|
#include "Game/IW3/GameAssetPoolIW3.h"
|
||||||
|
|
||||||
|
#include "AssetDumpers/AssetDumperGfxImage.h"
|
||||||
|
#include "AssetDumpers/AssetDumperLoadedSound.h"
|
||||||
|
#include "AssetDumpers/AssetDumperLocalizeEntry.h"
|
||||||
|
#include "AssetDumpers/AssetDumperRawFile.h"
|
||||||
|
#include "AssetDumpers/AssetDumperStringTable.h"
|
||||||
|
#include "AssetDumpers/AssetDumperWeapon.h"
|
||||||
|
|
||||||
|
using namespace IW3;
|
||||||
|
|
||||||
|
bool ZoneDumper::CanHandleZone(AssetDumpingContext& context) const
|
||||||
|
{
|
||||||
|
return context.m_zone->m_game == &g_GameIW3;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZoneDumper::DumpZone(AssetDumpingContext& context) const
|
||||||
|
{
|
||||||
|
#define DUMP_ASSET_POOL(dumperType, poolName) \
|
||||||
|
if(assetPools->poolName) \
|
||||||
|
{ \
|
||||||
|
dumperType dumper; \
|
||||||
|
dumper.DumpPool(context, assetPools->poolName.get()); \
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* assetPools = dynamic_cast<GameAssetPoolIW3*>(context.m_zone->m_pools.get());
|
||||||
|
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperPhysPreset, m_phys_preset)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperPhysCollmap, m_phys_collmap)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperXAnimParts, m_xanim_parts)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperXModel, m_xmodel)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperMaterial, m_material)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperMaterialPixelShader, m_material_pixel_shader)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperMaterialVertexShader, m_material_vertex_shader)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperMaterialVertexDeclaration, m_material_vertex_decl)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperMaterialTechniqueSet, m_technique_set)
|
||||||
|
DUMP_ASSET_POOL(AssetDumperGfxImage, m_image)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumpersnd_alias_list_t, m_sound)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperSndCurve, m_sound_curve)
|
||||||
|
DUMP_ASSET_POOL(AssetDumperLoadedSound, m_loaded_sound)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperclipMap_t, m_clip_map)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperComWorld, m_com_world)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperGameWorldSp, m_game_world_sp)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperGameWorldMp, m_game_world_mp)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperMapEnts, m_map_ents)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperFxWorld, m_fx_world)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperGfxWorld, m_gfx_world)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperGfxLightDef, m_gfx_light_def)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperFont_s, m_font)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperMenuList, m_menu_list)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumpermenuDef_t, m_menu_def)
|
||||||
|
DUMP_ASSET_POOL(AssetDumperLocalizeEntry, m_localize)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperWeapon, m_weapon)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperSndDriverGlobals, m_snd_driver_globals)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperFxEffectDef, m_fx)
|
||||||
|
// DUMP_ASSET_POOL(AssetDumperFxImpactTable, m_fx_impact_table)
|
||||||
|
DUMP_ASSET_POOL(AssetDumperRawFile, m_raw_file)
|
||||||
|
DUMP_ASSET_POOL(AssetDumperStringTable, m_string_table)
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#undef DUMP_ASSET_POOL
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Dumping/IZoneDumper.h"
|
||||||
|
|
||||||
|
namespace IW3
|
||||||
|
{
|
||||||
|
class ZoneDumper final : public IZoneDumper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool CanHandleZone(AssetDumpingContext& context) const override;
|
||||||
|
bool DumpZone(AssetDumpingContext& context) const override;
|
||||||
|
};
|
||||||
|
}
|
138
src/ObjWriting/Image/IwiWriter6.cpp
Normal file
138
src/ObjWriting/Image/IwiWriter6.cpp
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
#include "IwiWriter6.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
using namespace iwi6;
|
||||||
|
|
||||||
|
IwiWriter::IwiWriter()
|
||||||
|
= default;
|
||||||
|
|
||||||
|
IwiWriter::~IwiWriter()
|
||||||
|
= default;
|
||||||
|
|
||||||
|
IwiFormat IwiWriter::GetIwiFormatForImageFormat(const ImageFormat * imageFormat)
|
||||||
|
{
|
||||||
|
switch (imageFormat->GetId())
|
||||||
|
{
|
||||||
|
case ImageFormatId::R8_G8_B8:
|
||||||
|
return IwiFormat::IMG_FORMAT_BITMAP_RGB;
|
||||||
|
|
||||||
|
case ImageFormatId::R8_G8_B8_A8:
|
||||||
|
return IwiFormat::IMG_FORMAT_BITMAP_RGBA;
|
||||||
|
|
||||||
|
case ImageFormatId::A8:
|
||||||
|
return IwiFormat::IMG_FORMAT_BITMAP_ALPHA;
|
||||||
|
|
||||||
|
case ImageFormatId::BC1:
|
||||||
|
return IwiFormat::IMG_FORMAT_DXT1;
|
||||||
|
|
||||||
|
case ImageFormatId::BC2:
|
||||||
|
return IwiFormat::IMG_FORMAT_DXT3;
|
||||||
|
|
||||||
|
case ImageFormatId::BC3:
|
||||||
|
return IwiFormat::IMG_FORMAT_DXT5;
|
||||||
|
|
||||||
|
case ImageFormatId::BC5:
|
||||||
|
return IwiFormat::IMG_FORMAT_DXN;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return IwiFormat::IMG_FORMAT_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IwiWriter::WriteVersion(std::ostream & stream)
|
||||||
|
{
|
||||||
|
IwiVersion version{};
|
||||||
|
version.tag[0] = 'I';
|
||||||
|
version.tag[1] = 'W';
|
||||||
|
version.tag[2] = 'i';
|
||||||
|
version.version = 6;
|
||||||
|
|
||||||
|
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
|
||||||
|
}
|
||||||
|
|
||||||
|
void IwiWriter::FillHeader2D(IwiHeader * header, Texture2D * texture)
|
||||||
|
{
|
||||||
|
header->dimensions[0] = static_cast<uint16_t>(texture->GetWidth());
|
||||||
|
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight());
|
||||||
|
header->dimensions[2] = 1u;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IwiWriter::FillHeaderCube(IwiHeader * header, TextureCube * texture)
|
||||||
|
{
|
||||||
|
header->dimensions[0] = static_cast<uint16_t>(texture->GetWidth());
|
||||||
|
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight());
|
||||||
|
header->dimensions[2] = 1u;
|
||||||
|
header->flags |= IMG_FLAG_CUBEMAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IwiWriter::FillHeader3D(IwiHeader * header, Texture3D * texture)
|
||||||
|
{
|
||||||
|
header->dimensions[0] = static_cast<uint16_t>(texture->GetWidth());
|
||||||
|
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight());
|
||||||
|
header->dimensions[2] = static_cast<uint16_t>(texture->GetDepth());
|
||||||
|
header->flags |= IMG_FLAG_VOLMAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IwiWriter::SupportsImageFormat(const ImageFormat * imageFormat)
|
||||||
|
{
|
||||||
|
return GetIwiFormatForImageFormat(imageFormat) != IwiFormat::IMG_FORMAT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IwiWriter::GetFileExtension()
|
||||||
|
{
|
||||||
|
return ".iwi";
|
||||||
|
}
|
||||||
|
|
||||||
|
void IwiWriter::DumpImage(std::ostream & stream, Texture * texture)
|
||||||
|
{
|
||||||
|
assert(texture != nullptr);
|
||||||
|
|
||||||
|
WriteVersion(stream);
|
||||||
|
|
||||||
|
IwiHeader header{};
|
||||||
|
header.flags = 0;
|
||||||
|
|
||||||
|
header.format = static_cast<int8_t>(GetIwiFormatForImageFormat(texture->GetFormat()));
|
||||||
|
|
||||||
|
if (!texture->HasMipMaps())
|
||||||
|
header.flags |= IMG_FLAG_NOMIPMAPS;
|
||||||
|
|
||||||
|
auto currentFileSize = sizeof(IwiVersion) + sizeof(IwiHeader);
|
||||||
|
|
||||||
|
const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1;
|
||||||
|
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
|
||||||
|
{
|
||||||
|
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
|
||||||
|
currentFileSize += mipLevelSize;
|
||||||
|
|
||||||
|
if (currentMipLevel < static_cast<int>(std::extent<decltype(IwiHeader::fileSizeForPicmip)>::value))
|
||||||
|
header.fileSizeForPicmip[currentMipLevel] = currentFileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto* texture2D = dynamic_cast<Texture2D*>(texture))
|
||||||
|
{
|
||||||
|
FillHeader2D(&header, texture2D);
|
||||||
|
}
|
||||||
|
else if (auto* textureCube = dynamic_cast<TextureCube*>(texture))
|
||||||
|
{
|
||||||
|
FillHeaderCube(&header, textureCube);
|
||||||
|
}
|
||||||
|
else if (auto* texture3D = dynamic_cast<Texture3D*>(texture))
|
||||||
|
{
|
||||||
|
FillHeader3D(&header, texture3D);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.write(reinterpret_cast<char*>(&header), sizeof(IwiHeader));
|
||||||
|
|
||||||
|
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
|
||||||
|
{
|
||||||
|
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
|
||||||
|
stream.write(reinterpret_cast<char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
|
||||||
|
}
|
||||||
|
}
|
30
src/ObjWriting/Image/IwiWriter6.h
Normal file
30
src/ObjWriting/Image/IwiWriter6.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IImageWriter.h"
|
||||||
|
#include "Image/IwiTypes.h"
|
||||||
|
|
||||||
|
namespace iwi6
|
||||||
|
{
|
||||||
|
class IwiWriter final : public IImageWriter
|
||||||
|
{
|
||||||
|
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
|
||||||
|
|
||||||
|
static void WriteVersion(std::ostream& stream);
|
||||||
|
static void FillHeader2D(IwiHeader* header, Texture2D* texture);
|
||||||
|
static void FillHeaderCube(IwiHeader* header, TextureCube* texture);
|
||||||
|
static void FillHeader3D(IwiHeader* header, Texture3D* texture);
|
||||||
|
|
||||||
|
public:
|
||||||
|
IwiWriter();
|
||||||
|
IwiWriter(const IwiWriter& other) = delete;
|
||||||
|
IwiWriter(IwiWriter&& other) noexcept = delete;
|
||||||
|
~IwiWriter() override;
|
||||||
|
|
||||||
|
IwiWriter& operator=(const IwiWriter& other) = delete;
|
||||||
|
IwiWriter& operator=(IwiWriter&& other) noexcept = delete;
|
||||||
|
|
||||||
|
bool SupportsImageFormat(const ImageFormat* imageFormat) override;
|
||||||
|
std::string GetFileExtension() override;
|
||||||
|
void DumpImage(std::ostream& stream, Texture* texture) override;
|
||||||
|
};
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
#include "ObjWriting.h"
|
#include "ObjWriting.h"
|
||||||
#include "Dumping/IZoneDumper.h"
|
#include "Dumping/IZoneDumper.h"
|
||||||
|
#include "Game/IW3/ZoneDumperIW3.h"
|
||||||
#include "Game/IW4/ZoneDumperIW4.h"
|
#include "Game/IW4/ZoneDumperIW4.h"
|
||||||
#include "Game/T6/ZoneDumperT6.h"
|
#include "Game/T6/ZoneDumperT6.h"
|
||||||
|
|
||||||
@ -7,6 +8,7 @@ ObjWriting::Configuration_t ObjWriting::Configuration;
|
|||||||
|
|
||||||
const IZoneDumper* const ZONE_DUMPER[]
|
const IZoneDumper* const ZONE_DUMPER[]
|
||||||
{
|
{
|
||||||
|
new IW3::ZoneDumper(),
|
||||||
new IW4::ZoneDumper(),
|
new IW4::ZoneDumper(),
|
||||||
new T6::ZoneDumper()
|
new T6::ZoneDumper()
|
||||||
};
|
};
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "ContentLister/ZoneDefWriter.h"
|
#include "ContentLister/ZoneDefWriter.h"
|
||||||
#include "ObjContainer/IWD/IWD.h"
|
#include "ObjContainer/IWD/IWD.h"
|
||||||
#include "UnlinkerArgs.h"
|
#include "UnlinkerArgs.h"
|
||||||
|
#include "Game/IW3/ZoneDefWriterIW3.h"
|
||||||
|
|
||||||
#include "Game/IW4/ZoneDefWriterIW4.h"
|
#include "Game/IW4/ZoneDefWriterIW4.h"
|
||||||
#include "Game/T6/ZoneDefWriterT6.h"
|
#include "Game/T6/ZoneDefWriterT6.h"
|
||||||
@ -25,6 +26,7 @@ namespace fs = std::filesystem;
|
|||||||
|
|
||||||
const IZoneDefWriter* const ZONE_DEF_WRITERS[]
|
const IZoneDefWriter* const ZONE_DEF_WRITERS[]
|
||||||
{
|
{
|
||||||
|
new IW3::ZoneDefWriter(),
|
||||||
new IW4::ZoneDefWriter(),
|
new IW4::ZoneDefWriter(),
|
||||||
new T6::ZoneDefWriter()
|
new T6::ZoneDefWriter()
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user