refactor: image and obj data loading

This commit is contained in:
Jan
2024-09-24 12:01:42 +01:00
parent 5fee875495
commit 5cc52c42cd
97 changed files with 1784 additions and 1878 deletions

View File

@ -2,6 +2,7 @@
#include "IZoneAssetDumperState.h"
#include "Obj/Gdt/GdtStream.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/ClassUtils.h"
#include "Zone/Zone.h"
@ -18,6 +19,7 @@ public:
Zone* m_zone;
std::string m_base_path;
std::unique_ptr<GdtOutputStream> m_gdt;
ISearchPath* m_obj_search_path;
AssetDumpingContext();

View File

@ -1,13 +1,63 @@
#include "AssetDumperGfxImage.h"
#include "Image/DdsWriter.h"
#include "Image/Dx9TextureLoader.h"
#include "Image/IwiLoader.h"
#include "Image/IwiTypes.h"
#include "Image/IwiWriter6.h"
#include "Image/Texture.h"
#include "ObjWriting.h"
#include "SearchPath/ISearchPath.h"
#include <algorithm>
#include <cassert>
#include <format>
using namespace IW3;
namespace
{
std::unique_ptr<Texture> LoadImageFromLoadDef(const GfxImage* image)
{
Dx9TextureLoader textureLoader;
const auto& loadDef = *image->texture.loadDef;
textureLoader.Width(loadDef.dimensions[0]).Height(loadDef.dimensions[1]).Depth(loadDef.dimensions[2]);
if (loadDef.flags & iwi6::IMG_FLAG_VOLMAP)
textureLoader.Type(TextureType::T_3D);
else if (loadDef.flags & iwi6::IMG_FLAG_CUBEMAP)
textureLoader.Type(TextureType::T_CUBE);
else
textureLoader.Type(TextureType::T_2D);
textureLoader.Format(static_cast<oat::D3DFORMAT>(loadDef.format));
textureLoader.HasMipMaps(!(loadDef.flags & iwi6::IMG_FLAG_NOMIPMAPS));
return textureLoader.LoadTexture(loadDef.data);
}
std::unique_ptr<Texture> LoadImageFromIwi(const GfxImage* image, ISearchPath* searchPath)
{
const auto imageFileName = std::format("images/{}.iwi", image->name);
const auto filePathImage = searchPath->Open(imageFileName);
if (!filePathImage.IsOpen())
{
std::cerr << std::format("Could not find data for image \"{}\"\n", image->name);
return nullptr;
}
return iwi::LoadIwi(*filePathImage.m_stream);
}
std::unique_ptr<Texture> LoadImageData(ISearchPath* searchPath, const GfxImage* image)
{
if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0)
return LoadImageFromLoadDef(image);
return LoadImageFromIwi(image, searchPath);
}
} // namespace
AssetDumperGfxImage::AssetDumperGfxImage()
{
switch (ObjWriting::Configuration.ImageOutputFormat)
@ -27,37 +77,29 @@ AssetDumperGfxImage::AssetDumperGfxImage()
bool AssetDumperGfxImage::ShouldDump(XAssetInfo<GfxImage>* asset)
{
const auto* image = asset->Asset();
return image->cardMemory.platform[0] > 0;
return true;
}
std::string AssetDumperGfxImage::GetAssetFileName(XAssetInfo<GfxImage>* asset) const
std::string AssetDumperGfxImage::GetAssetFileName(const XAssetInfo<GfxImage>& asset) const
{
std::string cleanAssetName = asset->m_name;
for (auto& c : cleanAssetName)
{
switch (c)
{
case '*':
c = '_';
break;
auto cleanAssetName = asset.m_name;
std::ranges::replace(cleanAssetName, '*', '_');
default:
break;
}
}
return "images/" + cleanAssetName + m_writer->GetFileExtension();
return std::format("images/{}{}", cleanAssetName, m_writer->GetFileExtension());
}
void AssetDumperGfxImage::DumpAsset(AssetDumpingContext& context, XAssetInfo<GfxImage>* asset)
{
const auto* image = asset->Asset();
const auto assetFile = context.OpenAssetFile(GetAssetFileName(asset));
const auto texture = LoadImageData(context.m_obj_search_path, image);
if (!texture)
return;
const auto assetFile = context.OpenAssetFile(GetAssetFileName(*asset));
if (!assetFile)
return;
auto& stream = *assetFile;
m_writer->DumpImage(stream, image->texture.texture);
m_writer->DumpImage(stream, texture.get());
}

View File

@ -12,7 +12,7 @@ namespace IW3
{
std::unique_ptr<IImageWriter> m_writer;
std::string GetAssetFileName(XAssetInfo<GfxImage>* asset) const;
[[nodiscard]] std::string GetAssetFileName(const XAssetInfo<GfxImage>& asset) const;
protected:
bool ShouldDump(XAssetInfo<GfxImage>* asset) override;

View File

@ -1,13 +1,60 @@
#include "AssetDumperGfxImage.h"
#include "Image/DdsWriter.h"
#include "Image/Dx9TextureLoader.h"
#include "Image/IwiLoader.h"
#include "Image/IwiWriter8.h"
#include "ObjWriting.h"
#include <algorithm>
#include <cassert>
#include <format>
using namespace IW4;
namespace
{
std::unique_ptr<Texture> LoadImageFromLoadDef(const GfxImage* image)
{
Dx9TextureLoader textureLoader;
const auto& loadDef = *image->texture.loadDef;
textureLoader.Width(image->width).Height(image->height).Depth(image->depth);
if ((loadDef.flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == iwi8::IMG_FLAG_MAPTYPE_3D)
textureLoader.Type(TextureType::T_3D);
else if ((loadDef.flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == iwi8::IMG_FLAG_MAPTYPE_CUBE)
textureLoader.Type(TextureType::T_CUBE);
else
textureLoader.Type(TextureType::T_2D);
textureLoader.Format(static_cast<oat::D3DFORMAT>(loadDef.format));
textureLoader.HasMipMaps(!(loadDef.flags & iwi8::IMG_FLAG_NOMIPMAPS));
return textureLoader.LoadTexture(loadDef.data);
}
std::unique_ptr<Texture> LoadImageFromIwi(const GfxImage* image, ISearchPath* searchPath)
{
const auto imageFileName = std::format("images/{}.iwi", image->name);
const auto filePathImage = searchPath->Open(imageFileName);
if (!filePathImage.IsOpen())
{
std::cerr << std::format("Could not find data for image \"{}\"\n", image->name);
return nullptr;
}
return iwi::LoadIwi(*filePathImage.m_stream);
}
std::unique_ptr<Texture> LoadImageData(ISearchPath* searchPath, const GfxImage* image)
{
if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0)
return LoadImageFromLoadDef(image);
return LoadImageFromIwi(image, searchPath);
}
} // namespace
AssetDumperGfxImage::AssetDumperGfxImage()
{
switch (ObjWriting::Configuration.ImageOutputFormat)
@ -27,37 +74,29 @@ AssetDumperGfxImage::AssetDumperGfxImage()
bool AssetDumperGfxImage::ShouldDump(XAssetInfo<GfxImage>* asset)
{
const auto* image = asset->Asset();
return image->cardMemory.platform[0] > 0;
return true;
}
std::string AssetDumperGfxImage::GetAssetFileName(XAssetInfo<GfxImage>* asset) const
std::string AssetDumperGfxImage::GetAssetFileName(const XAssetInfo<GfxImage>& asset) const
{
std::string cleanAssetName = asset->m_name;
for (auto& c : cleanAssetName)
{
switch (c)
{
case '*':
c = '_';
break;
auto cleanAssetName = asset.m_name;
std::ranges::replace(cleanAssetName, '*', '_');
default:
break;
}
}
return "images/" + cleanAssetName + m_writer->GetFileExtension();
return std::format("images/{}{}", cleanAssetName, m_writer->GetFileExtension());
}
void AssetDumperGfxImage::DumpAsset(AssetDumpingContext& context, XAssetInfo<GfxImage>* asset)
{
const auto* image = asset->Asset();
const auto assetFile = context.OpenAssetFile(GetAssetFileName(asset));
const auto texture = LoadImageData(context.m_obj_search_path, image);
if (!texture)
return;
const auto assetFile = context.OpenAssetFile(GetAssetFileName(*asset));
if (!assetFile)
return;
auto& stream = *assetFile;
m_writer->DumpImage(stream, image->texture.texture);
m_writer->DumpImage(stream, texture.get());
}

View File

@ -12,7 +12,7 @@ namespace IW4
{
std::unique_ptr<IImageWriter> m_writer;
std::string GetAssetFileName(XAssetInfo<GfxImage>* asset) const;
[[nodiscard]] std::string GetAssetFileName(const XAssetInfo<GfxImage>& asset) const;
protected:
bool ShouldDump(XAssetInfo<GfxImage>* asset) override;

View File

@ -1,13 +1,61 @@
#include "AssetDumperGfxImage.h"
#include "Image/DdsWriter.h"
#include "Image/Dx9TextureLoader.h"
#include "Image/IwiLoader.h"
#include "Image/IwiWriter8.h"
#include "ObjWriting.h"
#include <algorithm>
#include <cassert>
#include <format>
using namespace IW5;
namespace
{
std::unique_ptr<Texture> LoadImageFromLoadDef(const GfxImage* image)
{
Dx9TextureLoader textureLoader;
const auto& loadDef = *image->texture.loadDef;
textureLoader.Width(image->width).Height(image->height).Depth(image->depth);
if ((loadDef.flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == iwi8::IMG_FLAG_MAPTYPE_3D)
textureLoader.Type(TextureType::T_3D);
else if ((loadDef.flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == iwi8::IMG_FLAG_MAPTYPE_CUBE)
textureLoader.Type(TextureType::T_CUBE);
else
textureLoader.Type(TextureType::T_2D);
textureLoader.Format(static_cast<oat::D3DFORMAT>(loadDef.format));
textureLoader.HasMipMaps(!(loadDef.flags & iwi8::IMG_FLAG_NOMIPMAPS));
return textureLoader.LoadTexture(loadDef.data);
}
std::unique_ptr<Texture> LoadImageFromIwi(const GfxImage* image, ISearchPath* searchPath)
{
const auto imageFileName = std::format("images/{}.iwi", image->name);
const auto filePathImage = searchPath->Open(imageFileName);
if (!filePathImage.IsOpen())
{
std::cerr << std::format("Could not find data for image \"{}\"\n", image->name);
return nullptr;
}
return iwi::LoadIwi(*filePathImage.m_stream);
}
std::unique_ptr<Texture> LoadImageData(ISearchPath* searchPath, const GfxImage* image)
{
if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0)
return LoadImageFromLoadDef(image);
return LoadImageFromIwi(image, searchPath);
}
} // namespace
AssetDumperGfxImage::AssetDumperGfxImage()
{
switch (ObjWriting::Configuration.ImageOutputFormat)
@ -27,37 +75,29 @@ AssetDumperGfxImage::AssetDumperGfxImage()
bool AssetDumperGfxImage::ShouldDump(XAssetInfo<GfxImage>* asset)
{
const auto* image = asset->Asset();
return image->cardMemory.platform[0] > 0;
return true;
}
std::string AssetDumperGfxImage::GetAssetFileName(XAssetInfo<GfxImage>* asset) const
std::string AssetDumperGfxImage::GetAssetFileName(const XAssetInfo<GfxImage>& asset) const
{
std::string cleanAssetName = asset->m_name;
for (auto& c : cleanAssetName)
{
switch (c)
{
case '*':
c = '_';
break;
auto cleanAssetName = asset.m_name;
std::ranges::replace(cleanAssetName, '*', '_');
default:
break;
}
}
return "images/" + cleanAssetName + m_writer->GetFileExtension();
return std::format("images/{}{}", cleanAssetName, m_writer->GetFileExtension());
}
void AssetDumperGfxImage::DumpAsset(AssetDumpingContext& context, XAssetInfo<GfxImage>* asset)
{
const auto* image = asset->Asset();
const auto assetFile = context.OpenAssetFile(GetAssetFileName(asset));
const auto texture = LoadImageData(context.m_obj_search_path, image);
if (!texture)
return;
const auto assetFile = context.OpenAssetFile(GetAssetFileName(*asset));
if (!assetFile)
return;
auto& stream = *assetFile;
m_writer->DumpImage(stream, image->texture.texture);
m_writer->DumpImage(stream, texture.get());
}

View File

@ -12,7 +12,7 @@ namespace IW5
{
std::unique_ptr<IImageWriter> m_writer;
std::string GetAssetFileName(XAssetInfo<GfxImage>* asset) const;
[[nodiscard]] std::string GetAssetFileName(const XAssetInfo<GfxImage>& asset) const;
protected:
bool ShouldDump(XAssetInfo<GfxImage>* asset) override;

View File

@ -1,13 +1,60 @@
#include "AssetDumperGfxImage.h"
#include "Image/DdsWriter.h"
#include "Image/IwiWriter27.h"
#include "Image/Dx9TextureLoader.h"
#include "Image/IwiLoader.h"
#include "Image/IwiWriter13.h"
#include "ObjWriting.h"
#include <algorithm>
#include <cassert>
#include <format>
using namespace T5;
namespace
{
std::unique_ptr<Texture> LoadImageFromLoadDef(const GfxImage* image)
{
Dx9TextureLoader textureLoader;
const auto& loadDef = *image->texture.loadDef;
textureLoader.Width(image->width).Height(image->height).Depth(image->depth);
if (loadDef.flags & iwi13::IMG_FLAG_VOLMAP)
textureLoader.Type(TextureType::T_3D);
else if (loadDef.flags & iwi13::IMG_FLAG_CUBEMAP)
textureLoader.Type(TextureType::T_CUBE);
else
textureLoader.Type(TextureType::T_2D);
textureLoader.Format(static_cast<oat::D3DFORMAT>(loadDef.format));
textureLoader.HasMipMaps(!(loadDef.flags & iwi13::IMG_FLAG_NOMIPMAPS));
return textureLoader.LoadTexture(loadDef.data);
}
std::unique_ptr<Texture> LoadImageFromIwi(const GfxImage* image, ISearchPath* searchPath)
{
const auto imageFileName = std::format("images/{}.iwi", image->name);
const auto filePathImage = searchPath->Open(imageFileName);
if (!filePathImage.IsOpen())
{
std::cerr << std::format("Could not find data for image \"{}\"\n", image->name);
return nullptr;
}
return iwi::LoadIwi(*filePathImage.m_stream);
}
std::unique_ptr<Texture> LoadImageData(ISearchPath* searchPath, const GfxImage* image)
{
if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0)
return LoadImageFromLoadDef(image);
return LoadImageFromIwi(image, searchPath);
}
} // namespace
AssetDumperGfxImage::AssetDumperGfxImage()
{
switch (ObjWriting::Configuration.ImageOutputFormat)
@ -16,7 +63,7 @@ AssetDumperGfxImage::AssetDumperGfxImage()
m_writer = std::make_unique<DdsWriter>();
break;
case ObjWriting::Configuration_t::ImageOutputFormat_e::IWI:
m_writer = std::make_unique<iwi27::IwiWriter>();
m_writer = std::make_unique<iwi13::IwiWriter>();
break;
default:
assert(false);
@ -27,37 +74,29 @@ AssetDumperGfxImage::AssetDumperGfxImage()
bool AssetDumperGfxImage::ShouldDump(XAssetInfo<GfxImage>* asset)
{
const auto* image = asset->Asset();
return image->loadedSize > 0;
return true;
}
std::string AssetDumperGfxImage::GetAssetFileName(XAssetInfo<GfxImage>* asset) const
std::string AssetDumperGfxImage::GetAssetFileName(const XAssetInfo<GfxImage>& asset) const
{
std::string cleanAssetName = asset->m_name;
for (auto& c : cleanAssetName)
{
switch (c)
{
case '*':
c = '_';
break;
auto cleanAssetName = asset.m_name;
std::ranges::replace(cleanAssetName, '*', '_');
default:
break;
}
}
return "images/" + cleanAssetName + m_writer->GetFileExtension();
return std::format("images/{}{}", cleanAssetName, m_writer->GetFileExtension());
}
void AssetDumperGfxImage::DumpAsset(AssetDumpingContext& context, XAssetInfo<GfxImage>* asset)
{
const auto* image = asset->Asset();
const auto assetFile = context.OpenAssetFile(GetAssetFileName(asset));
const auto texture = LoadImageData(context.m_obj_search_path, image);
if (!texture)
return;
const auto assetFile = context.OpenAssetFile(GetAssetFileName(*asset));
if (!assetFile)
return;
auto& stream = *assetFile;
m_writer->DumpImage(stream, image->texture.texture);
m_writer->DumpImage(stream, texture.get());
}

View File

@ -12,7 +12,7 @@ namespace T5
{
std::unique_ptr<IImageWriter> m_writer;
std::string GetAssetFileName(XAssetInfo<GfxImage>* asset) const;
[[nodiscard]] std::string GetAssetFileName(const XAssetInfo<GfxImage>& asset) const;
protected:
bool ShouldDump(XAssetInfo<GfxImage>* asset) override;

View File

@ -1,13 +1,78 @@
#include "AssetDumperGfxImage.h"
#include "Image/DdsWriter.h"
#include "Image/Dx12TextureLoader.h"
#include "Image/IwiLoader.h"
#include "Image/IwiWriter27.h"
#include "ObjContainer/IPak/IPak.h"
#include "ObjWriting.h"
#include <algorithm>
#include <cassert>
#include <format>
using namespace T6;
namespace
{
std::unique_ptr<Texture> LoadImageFromLoadDef(const GfxImage* image)
{
Dx12TextureLoader textureLoader;
const auto& loadDef = *image->texture.loadDef;
textureLoader.Width(image->width).Height(image->height).Depth(image->depth);
if (loadDef.flags & iwi27::IMG_FLAG_VOLMAP)
textureLoader.Type(TextureType::T_3D);
else if (loadDef.flags & iwi27::IMG_FLAG_CUBEMAP)
textureLoader.Type(TextureType::T_CUBE);
else
textureLoader.Type(TextureType::T_2D);
textureLoader.Format(static_cast<oat::DXGI_FORMAT>(loadDef.format));
textureLoader.HasMipMaps(!(loadDef.flags & iwi27::IMG_FLAG_NOMIPMAPS));
return textureLoader.LoadTexture(loadDef.data);
}
std::unique_ptr<Texture> LoadImageFromIwi(const GfxImage* image, ISearchPath* searchPath)
{
if (image->streamedPartCount > 0)
{
for (auto* ipak : IPak::Repository)
{
auto ipakStream = ipak->GetEntryStream(image->hash, image->streamedParts[0].hash);
if (ipakStream)
{
auto loadedTexture = iwi::LoadIwi(*ipakStream);
ipakStream->close();
if (loadedTexture != nullptr)
return loadedTexture;
}
}
}
const auto imageFileName = std::format("images/{}.iwi", image->name);
const auto filePathImage = searchPath->Open(imageFileName);
if (!filePathImage.IsOpen())
{
std::cerr << std::format("Could not find data for image \"{}\"\n", image->name);
return nullptr;
}
return iwi::LoadIwi(*filePathImage.m_stream);
}
std::unique_ptr<Texture> LoadImageData(ISearchPath* searchPath, const GfxImage* image)
{
if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0)
return LoadImageFromLoadDef(image);
return LoadImageFromIwi(image, searchPath);
}
} // namespace
AssetDumperGfxImage::AssetDumperGfxImage()
{
switch (ObjWriting::Configuration.ImageOutputFormat)
@ -27,37 +92,29 @@ AssetDumperGfxImage::AssetDumperGfxImage()
bool AssetDumperGfxImage::ShouldDump(XAssetInfo<GfxImage>* asset)
{
const auto* image = asset->Asset();
return image->loadedSize > 0;
return true;
}
std::string AssetDumperGfxImage::GetAssetFileName(XAssetInfo<GfxImage>* asset) const
std::string AssetDumperGfxImage::GetAssetFileName(const XAssetInfo<GfxImage>& asset) const
{
std::string cleanAssetName = asset->m_name;
for (auto& c : cleanAssetName)
{
switch (c)
{
case '*':
c = '_';
break;
auto cleanAssetName = asset.m_name;
std::ranges::replace(cleanAssetName, '*', '_');
default:
break;
}
}
return "images/" + cleanAssetName + m_writer->GetFileExtension();
return std::format("images/{}{}", cleanAssetName, m_writer->GetFileExtension());
}
void AssetDumperGfxImage::DumpAsset(AssetDumpingContext& context, XAssetInfo<GfxImage>* asset)
{
const auto* image = asset->Asset();
const auto assetFile = context.OpenAssetFile(GetAssetFileName(asset));
const auto texture = LoadImageData(context.m_obj_search_path, image);
if (!texture)
return;
const auto assetFile = context.OpenAssetFile(GetAssetFileName(*asset));
if (!assetFile)
return;
auto& stream = *assetFile;
m_writer->DumpImage(stream, image->texture.texture);
m_writer->DumpImage(stream, texture.get());
}

View File

@ -12,7 +12,7 @@ namespace T6
{
std::unique_ptr<IImageWriter> m_writer;
std::string GetAssetFileName(XAssetInfo<GfxImage>* asset) const;
std::string GetAssetFileName(const XAssetInfo<GfxImage>& asset) const;
protected:
bool ShouldDump(XAssetInfo<GfxImage>* asset) override;

View File

@ -13,10 +13,51 @@ const std::map<ImageFormatId, ImageFormatId> DDS_CONVERSION_TABLE{
class DdsWriterInternal
{
std::ostream& m_stream;
Texture* m_texture;
std::unique_ptr<Texture> m_converted_texture;
bool m_use_dx10_extension;
public:
static bool SupportsImageFormat(const ImageFormat* imageFormat)
{
return true;
}
static std::string GetFileExtension()
{
return ".dds";
}
DdsWriterInternal(std::ostream& stream, const Texture* texture)
: m_stream(stream),
m_texture(texture),
m_use_dx10_extension(false)
{
}
void DumpImage()
{
ConvertTextureIfNecessary();
DDS_HEADER header{};
PopulateDdsHeader(header);
constexpr auto magic = MakeFourCc('D', 'D', 'S', ' ');
m_stream.write(reinterpret_cast<const char*>(&magic), sizeof(magic));
m_stream.write(reinterpret_cast<const char*>(&header), sizeof(header));
if (m_use_dx10_extension)
{
DDS_HEADER_DXT10 dxt10{};
PopulateDxt10Header(dxt10);
m_stream.write(reinterpret_cast<const char*>(&dxt10), sizeof(dxt10));
}
const auto mipCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1;
for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++)
{
const auto* buffer = m_texture->GetBufferForMipLevel(mipLevel);
const auto mipLevelSize = m_texture->GetSizeOfMipLevel(mipLevel) * m_texture->GetFaceCount();
m_stream.write(reinterpret_cast<const char*>(buffer), mipLevelSize);
}
}
static constexpr unsigned Mask1(const unsigned length)
{
@ -164,61 +205,20 @@ class DdsWriterInternal
void ConvertTextureIfNecessary()
{
auto entry = DDS_CONVERSION_TABLE.find(m_texture->GetFormat()->GetId());
const auto entry = DDS_CONVERSION_TABLE.find(m_texture->GetFormat()->GetId());
if (entry != DDS_CONVERSION_TABLE.end())
{
TextureConverter converter(m_texture, ImageFormat::ALL_FORMATS[static_cast<unsigned>(entry->second)]);
m_converted_texture = std::unique_ptr<Texture>(converter.Convert());
m_converted_texture = converter.Convert();
m_texture = m_converted_texture.get();
}
}
public:
static bool SupportsImageFormat(const ImageFormat* imageFormat)
{
return true;
}
static std::string GetFileExtension()
{
return ".dds";
}
DdsWriterInternal(std::ostream& stream, Texture* texture)
: m_stream(stream),
m_texture(texture),
m_use_dx10_extension(false)
{
}
void DumpImage()
{
ConvertTextureIfNecessary();
DDS_HEADER header{};
PopulateDdsHeader(header);
constexpr auto magic = MakeFourCc('D', 'D', 'S', ' ');
m_stream.write(reinterpret_cast<const char*>(&magic), sizeof(magic));
m_stream.write(reinterpret_cast<const char*>(&header), sizeof(header));
if (m_use_dx10_extension)
{
DDS_HEADER_DXT10 dxt10{};
PopulateDxt10Header(dxt10);
m_stream.write(reinterpret_cast<const char*>(&dxt10), sizeof(dxt10));
}
const auto mipCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1;
for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++)
{
const auto* buffer = m_texture->GetBufferForMipLevel(mipLevel);
const auto mipLevelSize = m_texture->GetSizeOfMipLevel(mipLevel) * m_texture->GetFaceCount();
m_stream.write(reinterpret_cast<const char*>(buffer), mipLevelSize);
}
}
std::ostream& m_stream;
const Texture* m_texture;
std::unique_ptr<Texture> m_converted_texture;
bool m_use_dx10_extension;
};
DdsWriter::~DdsWriter() = default;
@ -233,7 +233,7 @@ std::string DdsWriter::GetFileExtension()
return DdsWriterInternal::GetFileExtension();
}
void DdsWriter::DumpImage(std::ostream& stream, Texture* texture)
void DdsWriter::DumpImage(std::ostream& stream, const Texture* texture)
{
DdsWriterInternal internal(stream, texture);
internal.DumpImage();

View File

@ -8,5 +8,5 @@ public:
bool SupportsImageFormat(const ImageFormat* imageFormat) override;
std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, Texture* texture) override;
void DumpImage(std::ostream& stream, const Texture* texture) override;
};

View File

@ -8,9 +8,14 @@
class IImageWriter
{
public:
IImageWriter() = default;
virtual ~IImageWriter() = default;
IImageWriter(const IImageWriter& other) = default;
IImageWriter(IImageWriter&& other) noexcept = default;
IImageWriter& operator=(const IImageWriter& other) = default;
IImageWriter& operator=(IImageWriter&& other) noexcept = default;
virtual bool SupportsImageFormat(const ImageFormat* imageFormat) = 0;
virtual std::string GetFileExtension() = 0;
virtual void DumpImage(std::ostream& stream, Texture* texture) = 0;
virtual void DumpImage(std::ostream& stream, const Texture* texture) = 0;
};

View File

@ -0,0 +1,141 @@
#include "IwiWriter13.h"
#include <cassert>
#include <ostream>
using namespace iwi13;
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::R16_G16_B16_A16_FLOAT:
return IwiFormat::IMG_FORMAT_A16B16G16R16F;
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;
}
}
bool IwiWriter::SupportsImageFormat(const ImageFormat* imageFormat)
{
return GetIwiFormatForImageFormat(imageFormat) != IwiFormat::IMG_FORMAT_INVALID;
}
std::string IwiWriter::GetFileExtension()
{
return ".iwi";
}
void IwiWriter::WriteVersion(std::ostream& stream)
{
IwiVersion version{};
version.tag[0] = 'I';
version.tag[1] = 'W';
version.tag[2] = 'i';
version.version = 13;
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
}
void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
{
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header.dimensions[2] = 1;
}
void IwiWriter::FillHeaderCube(IwiHeader& header, const TextureCube& texture)
{
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header.dimensions[2] = 1;
header.flags |= IMG_FLAG_CUBEMAP;
}
void IwiWriter::FillHeader3D(IwiHeader& header, const 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;
}
void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture)
{
assert(texture != nullptr);
WriteVersion(stream);
IwiHeader header{};
header.flags = 0;
header.gamma = 0.0f;
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_v<decltype(IwiHeader::fileSizeForPicmip)>))
header.fileSizeForPicmip[currentMipLevel] = currentFileSize;
}
if (const auto* texture2D = dynamic_cast<const Texture2D*>(texture))
{
FillHeader2D(header, *texture2D);
}
else if (const auto* textureCube = dynamic_cast<const TextureCube*>(texture))
{
FillHeaderCube(header, *textureCube);
}
else if (const auto* texture3D = dynamic_cast<const 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<const char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
}
}

View File

@ -0,0 +1,30 @@
#pragma once
#include "IImageWriter.h"
#include "Image/IwiTypes.h"
namespace iwi13
{
class IwiWriter final : public IImageWriter
{
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
static void WriteVersion(std::ostream& stream);
static void FillHeader2D(IwiHeader& header, const Texture2D& texture);
static void FillHeaderCube(IwiHeader& header, const TextureCube& texture);
static void FillHeader3D(IwiHeader& header, const 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, const Texture* texture) override;
};
} // namespace iwi13

View File

@ -63,30 +63,30 @@ void IwiWriter::WriteVersion(std::ostream& stream)
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
}
void IwiWriter::FillHeader2D(IwiHeader* header, Texture2D* texture)
void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
{
header->dimensions[0] = static_cast<uint16_t>(texture->GetWidth());
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight());
header->dimensions[2] = 1;
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header.dimensions[2] = 1;
}
void IwiWriter::FillHeaderCube(IwiHeader* header, TextureCube* texture)
void IwiWriter::FillHeaderCube(IwiHeader& header, const TextureCube& texture)
{
header->dimensions[0] = static_cast<uint16_t>(texture->GetWidth());
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight());
header->dimensions[2] = 1;
header->flags |= IMG_FLAG_CUBEMAP;
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header.dimensions[2] = 1;
header.flags |= IMG_FLAG_CUBEMAP;
}
void IwiWriter::FillHeader3D(IwiHeader* header, Texture3D* texture)
void IwiWriter::FillHeader3D(IwiHeader& header, const 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;
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;
}
void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture)
{
assert(texture != nullptr);
@ -116,17 +116,17 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
header.fileSizeForPicmip[currentMipLevel] = currentFileSize;
}
if (auto* texture2D = dynamic_cast<Texture2D*>(texture))
if (const auto* texture2D = dynamic_cast<const Texture2D*>(texture))
{
FillHeader2D(&header, texture2D);
FillHeader2D(header, *texture2D);
}
else if (auto* textureCube = dynamic_cast<TextureCube*>(texture))
else if (const auto* textureCube = dynamic_cast<const TextureCube*>(texture))
{
FillHeaderCube(&header, textureCube);
FillHeaderCube(header, *textureCube);
}
else if (auto* texture3D = dynamic_cast<Texture3D*>(texture))
else if (const auto* texture3D = dynamic_cast<const Texture3D*>(texture))
{
FillHeader3D(&header, texture3D);
FillHeader3D(header, *texture3D);
}
else
{
@ -139,6 +139,6 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
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);
stream.write(reinterpret_cast<const char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
}
}

View File

@ -10,9 +10,9 @@ namespace iwi27
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);
static void FillHeader2D(IwiHeader& header, const Texture2D& texture);
static void FillHeaderCube(IwiHeader& header, const TextureCube& texture);
static void FillHeader3D(IwiHeader& header, const Texture3D& texture);
public:
IwiWriter();
@ -25,6 +25,6 @@ namespace iwi27
bool SupportsImageFormat(const ImageFormat* imageFormat) override;
std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, Texture* texture) override;
void DumpImage(std::ostream& stream, const Texture* texture) override;
};
} // namespace iwi27

View File

@ -49,27 +49,27 @@ void IwiWriter::WriteVersion(std::ostream& stream)
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
}
void IwiWriter::FillHeader2D(IwiHeader* header, Texture2D* texture)
void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
{
header->dimensions[0] = static_cast<uint16_t>(texture->GetWidth());
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight());
header->dimensions[2] = 1u;
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)
void IwiWriter::FillHeaderCube(IwiHeader& header, const 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;
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)
void IwiWriter::FillHeader3D(IwiHeader& header, const 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;
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)
@ -82,7 +82,7 @@ std::string IwiWriter::GetFileExtension()
return ".iwi";
}
void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture)
{
assert(texture != nullptr);
@ -108,17 +108,17 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
header.fileSizeForPicmip[currentMipLevel] = currentFileSize;
}
if (auto* texture2D = dynamic_cast<Texture2D*>(texture))
if (const auto* texture2D = dynamic_cast<const Texture2D*>(texture))
{
FillHeader2D(&header, texture2D);
FillHeader2D(header, *texture2D);
}
else if (auto* textureCube = dynamic_cast<TextureCube*>(texture))
else if (const auto* textureCube = dynamic_cast<const TextureCube*>(texture))
{
FillHeaderCube(&header, textureCube);
FillHeaderCube(header, *textureCube);
}
else if (auto* texture3D = dynamic_cast<Texture3D*>(texture))
else if (const auto* texture3D = dynamic_cast<const Texture3D*>(texture))
{
FillHeader3D(&header, texture3D);
FillHeader3D(header, *texture3D);
}
else
{
@ -131,6 +131,6 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
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);
stream.write(reinterpret_cast<const char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
}
}

View File

@ -10,9 +10,9 @@ namespace iwi6
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);
static void FillHeader2D(IwiHeader& header, const Texture2D& texture);
static void FillHeaderCube(IwiHeader& header, const TextureCube& texture);
static void FillHeader3D(IwiHeader& header, const Texture3D& texture);
public:
IwiWriter();
@ -25,6 +25,6 @@ namespace iwi6
bool SupportsImageFormat(const ImageFormat* imageFormat) override;
std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, Texture* texture) override;
void DumpImage(std::ostream& stream, const Texture* texture) override;
};
} // namespace iwi6

View File

@ -49,27 +49,27 @@ void IwiWriter::WriteVersion(std::ostream& stream)
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
}
void IwiWriter::FillHeader2D(IwiHeader* header, Texture2D* texture)
void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
{
header->dimensions[0] = static_cast<uint16_t>(texture->GetWidth());
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight());
header->dimensions[2] = 1u;
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)
void IwiWriter::FillHeaderCube(IwiHeader& header, const 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_MAPTYPE_CUBE;
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_MAPTYPE_CUBE;
}
void IwiWriter::FillHeader3D(IwiHeader* header, Texture3D* texture)
void IwiWriter::FillHeader3D(IwiHeader& header, const 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_MAPTYPE_3D;
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_MAPTYPE_3D;
}
bool IwiWriter::SupportsImageFormat(const ImageFormat* imageFormat)
@ -82,7 +82,7 @@ std::string IwiWriter::GetFileExtension()
return ".iwi";
}
void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture)
{
assert(texture != nullptr);
@ -108,17 +108,17 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
header.fileSizeForPicmip[currentMipLevel] = currentFileSize;
}
if (auto* texture2D = dynamic_cast<Texture2D*>(texture))
if (const auto* texture2D = dynamic_cast<const Texture2D*>(texture))
{
FillHeader2D(&header, texture2D);
FillHeader2D(header, *texture2D);
}
else if (auto* textureCube = dynamic_cast<TextureCube*>(texture))
else if (const auto* textureCube = dynamic_cast<const TextureCube*>(texture))
{
FillHeaderCube(&header, textureCube);
FillHeaderCube(header, *textureCube);
}
else if (auto* texture3D = dynamic_cast<Texture3D*>(texture))
else if (const auto* texture3D = dynamic_cast<const Texture3D*>(texture))
{
FillHeader3D(&header, texture3D);
FillHeader3D(header, *texture3D);
}
else
{
@ -131,6 +131,6 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
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);
stream.write(reinterpret_cast<const char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
}
}

View File

@ -10,9 +10,9 @@ namespace iwi8
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);
static void FillHeader2D(IwiHeader& header, const Texture2D& texture);
static void FillHeaderCube(IwiHeader& header, const TextureCube& texture);
static void FillHeader3D(IwiHeader& header, const Texture3D& texture);
public:
IwiWriter();
@ -25,6 +25,6 @@ namespace iwi8
bool SupportsImageFormat(const ImageFormat* imageFormat) override;
std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, Texture* texture) override;
void DumpImage(std::ostream& stream, const Texture* texture) override;
};
} // namespace iwi8