finish CKtexture writer

- finish CKTexture writer
- add std::enable_if for CKStateChunk::ReadIdent&WriteIdent to limit it in enum type.
- fix error function calling in CKBitmapData writer.
- let CKTexture reader mor formal for mipmap.
- fix CKStateChunk ReadBuffer redirect guideline.
- add a stupid height and width getter for CKBitmapData to serve CKTexture using.
This commit is contained in:
yyc12345 2023-09-30 11:51:04 +08:00
parent 3195a9682f
commit eedd9bdb55
6 changed files with 189 additions and 100 deletions

View File

@ -458,40 +458,35 @@ namespace LibCmo::CK2 {
// save data
if (saveopt == CK_TEXTURE_SAVEOPTIONS::CKTEXTURE_RAWDATA) {
// save as raw data
chunk->WriteIdentifier(identifiers.m_RawData);
chunk->WriteIdentifierDword(identifiers.m_RawData);
chunk->WriteStruct(slotcount);
VxMath::VxImageDescEx invalidDesc;
for (CKDWORD i = 0; i < slotcount; ++i) {
if (XContainer::NSXBitArray::IsSet(validExternalSavingSlot, i)) {
VxMath::VxImageDescEx* thisimg = GetImageDesc(i);
if (XContainer::NSXBitArray::IsSet(validExternalSavingSlot, i) || !thisimg->IsValid()) {
// if this slot can save as external, pass a invalid desc to writer
// or image is invalid, simply write it as invalid one.
WriteRawBitmap(chunk, &invalidDesc);
} else {
// otherwise, pass the real slot data
WriteRawBitmap(chunk, GetImageDesc(i));
// do upside down first as reader done
VxMath::VxImageDescEx upsidedown(thisimg->GetWidth(), thisimg->GetHeight());
VxMath::VxDoBlitUpsideDown(thisimg, &upsidedown);
WriteRawBitmap(chunk, &upsidedown);
}
}
}
if (saveopt == CK_TEXTURE_SAVEOPTIONS::CKTEXTURE_IMAGEFORMAT) {
// save as special format
chunk->WriteIdentifier(identifiers.m_SpecificFormat);
chunk->WriteIdentifierDword(identifiers.m_SpecificFormat);
chunk->WriteStruct(slotcount);
// prepare height, width, bpp data
CKDWORD height = 0, width = 0, bpp = 32;
for (CKDWORD i = 0; i < slotcount; ++i) {
VxMath::VxImageDescEx* desc = GetImageDesc(i);
if (desc->IsValid()) {
height = desc->GetHeight();
width = desc->GetWidth();
break;
}
}
// write it
chunk->WriteStruct(width);
chunk->WriteStruct(height);
chunk->WriteStruct(bpp);
// write width, height and bpp
chunk->WriteStruct(GetWidth());
chunk->WriteStruct(GetHeight());
chunk->WriteStruct(32);
// write slot one by one
for (CKDWORD i = 0; i < slotcount; ++i) {
@ -502,7 +497,7 @@ namespace LibCmo::CK2 {
// write filename
{
chunk->WriteIdentifier(identifiers.m_FileNames);
chunk->WriteIdentifierDword(identifiers.m_FileNames);
chunk->WriteStruct(slotcount);
XContainer::XString filename;
@ -629,6 +624,24 @@ namespace LibCmo::CK2 {
else return m_Slots[slot].m_FileName.c_str();
}
CKDWORD CKBitmapData::GetWidth() const {
for (auto& slot : m_Slots) {
if (slot.m_ImageData.IsValid()) {
return slot.m_ImageData.GetWidth();
}
}
return 0;
}
CKDWORD CKBitmapData::GetHeight() const {
for (auto& slot : m_Slots) {
if (slot.m_ImageData.IsValid()) {
return slot.m_ImageData.GetHeight();
}
}
return 0;
}
#pragma endregion
#pragma region Not important variable visitor

View File

@ -106,6 +106,17 @@ namespace LibCmo::CK2 {
*/
CKSTRING GetSlotFileName(CKDWORD slot) const;
/**
* @brief Get first valid image's width.
* @return 0 if no valid image.
*/
CKDWORD GetWidth() const;
/**
* @brief Get first valid image's height.
* @return 0 if no valid image
*/
CKDWORD GetHeight() const;
#pragma endregion
#pragma region Not important funcs

View File

@ -3,6 +3,7 @@
#include "../VTAll.hpp"
#include <memory>
#include <functional>
#include <type_traits>
namespace LibCmo::CK2 {
@ -268,11 +269,11 @@ namespace LibCmo::CK2 {
public:
bool SeekIdentifierDword(CKDWORD identifier);
bool SeekIdentifierDwordAndReturnSize(CKDWORD identifier, CKDWORD* out_size);
template<typename TEnum>
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline bool SeekIdentifier(TEnum enum_v) {
return SeekIdentifierDword(static_cast<CKDWORD>(enum_v));
}
template<typename TEnum>
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline bool SeekIdentifierAndReturnSize(TEnum enum_v, CKDWORD* out_size) {
return SeekIdentifierDwordAndReturnSize(static_cast<CKDWORD>(enum_v), out_size);
}
@ -403,18 +404,21 @@ namespace LibCmo::CK2 {
/*
Buffer related function implements:
ReadBuffer(void**) Read Byte based size. -> ReadAndCopyBuffer(void**, CKDWORD*)
ReadAndFillBuffer(int, void*) User give Byte based size. -> ReadBuffer(const void**, CKDWORD)
ReadAndFillBuffer(void*) Read Byte based size. -> ReadBuffer(const void**, CKDWORD*)
ReadAndFillBuffer_LEndian(int, void*) User give Byte based size. -> ReadBuffer(const void**, CKDWORD)
ReadAndFillBuffer_LEndian(void*) Read Byte based size. -> ReadBuffer(const void**, CKDWORD*)
ReadAndFillBuffer_LEndian16(int, void*) User give Byte based size. -> ReadBuffer(const void**, CKDWORD)
ReadAndFillBuffer_LEndian16(void*) Read Byte based size. -> ReadBuffer(const void**, CKDWORD*)
ReadBuffer(void**) Read Byte based size. -> ReadBuffer(void**, CKDWORD*)
ReadAndFillBuffer(int, void*) User give Byte based size. -> ReadAndFillBuffer(const void*, CKDWORD)
ReadAndFillBuffer(void*) Read Byte based size. -> ReadAndFillBuffer(const void*)
ReadAndFillBuffer_LEndian(int, void*) User give Byte based size. -> ReadAndFillBuffer(const void*, CKDWORD)
ReadAndFillBuffer_LEndian(void*) Read Byte based size. -> ReadAndFillBuffer(const void*)
ReadAndFillBuffer_LEndian16(int, void*) User give Byte based size. -> ReadAndFillBuffer(const void*, CKDWORD)
ReadAndFillBuffer_LEndian16(void*) Read Byte based size. -> ReadAndFillBuffer(const void*)
*/
/**
* @brief Read buffer and copy it.
*
* The size of buffer will be read from CKStateChunk internally.
* It mean the read buffer must be written by WriteBuffer().
*
* The copied buffer and the size of buffer will be returned to caller.
* Caller should free the buffer by calling CKStateChunk::DeleteBuffer(void*).
*
@ -454,6 +458,7 @@ namespace LibCmo::CK2 {
* @brief Read buffer and fill user struct.
*
* The size of buffer will be read from CKStateChunk internally and return to caller.
* It mean the read buffer must be written by WriteBuffer().
*
* @param pData[out] The pointer holding the data.
* @return True if success.
@ -467,6 +472,7 @@ namespace LibCmo::CK2 {
* @brief Read buffer and fill user struct.
*
* The size of buffer is provided by user.
* It mean the read buffer must be written by WriteBufferNoSize().
*
* @param pData[out] The pointer holding the data.
* @param size_in_byte[in] The size of data which you want to read in byte unit
@ -553,7 +559,7 @@ namespace LibCmo::CK2 {
public:
bool WriteIdentifierDword(CKDWORD identifier);
template<typename TEnum>
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline bool WriteIdentifier(TEnum enum_v) {
return WriteIdentifierDword(static_cast<CKDWORD>(enum_v));
}

View File

@ -22,6 +22,11 @@ namespace LibCmo::CK2 {
// force chunk version
this->m_ChunkVersion = CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION4;
// set data version
// MARK: in virtools impl, this statement is written in CKObject::Save
// and data version is delivered by merging CKStateChunk.
// but we do not use that saving strategy, so we init data version in here.
this->m_DataVersion = CK_STATECHUNK_DATAVERSION::CHUNK_DEV_2_1;
// switch status
this->m_Parser.m_Status = CKStateChunkStatus::WRITE;

View File

@ -70,6 +70,129 @@ namespace LibCmo::CK2::ObjImpls {
bool suc = CKBeObject::Save(chunk, file, flags);
if (!suc) return false;
// save base image
suc = m_ImageHost.DumpToChunk(chunk, file, CKBitmapDataWriteIdentifiers {
.m_SpecificFormat = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXREADER),
.m_RawData = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXCOMPRESSED),
.m_FileNames = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXFILENAMES),
.m_MovieFileName = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXAVIFILENAME)
});
if (!suc) return false;
// write main properties
{
// write ident
chunk->WriteIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_OLDTEXONLY);
// prepare mix data. see Read for more info about the struct of this mix data
CKDWORD mixdata = 0;
// save options
mixdata &= static_cast<CKDWORD>(m_ImageHost.GetSaveOptions()) & 0xFF;
mixdata <<= 8;
// mix flags
CKDWORD mixflags = 0;
if (m_ImageHost.IsTransparent()) {
mixflags &= 0x1;
}
if (m_VideoFormat != VxMath::VX_PIXELFORMAT::UNKNOWN_PF) {
mixflags &= 0x2;
}
if (m_ImageHost.IsCubeMap()) {
mixflags &= 0x4;
}
mixdata &= mixflags & 0xFF;
mixdata <<= 8;
// mipmap
mixdata &= (IsUseMipmap() ? 0xFF : 0);
// write mix data
chunk->WriteStruct(mixdata);
// transparent color
chunk->WriteStruct(m_ImageHost.GetTransparentColor());
// current slot
if (m_ImageHost.GetSlotCount() > 1) {
chunk->WriteStruct(m_ImageHost.GetCurrentSlot());
}
// video fmt
if (m_VideoFormat != VxMath::VX_PIXELFORMAT::UNKNOWN_PF) {
chunk->WriteStruct(m_VideoFormat);
}
}
// mipmap
if (GetMipmapLevel() != 0) {
chunk->WriteIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_USERMIPMAP);
// write mipmap level
chunk->WriteStruct(GetMipmapLevel());
// write data
for (auto& level : m_MipmapImages) {
if (level.IsValid()) {
// do upside down and write
VxMath::VxImageDescEx upsidedown(level.GetWidth(), level.GetHeight());
VxMath::VxDoBlitUpsideDown(&level, &upsidedown);
CKBitmapData::WriteRawBitmap(chunk, &upsidedown);
} else {
// write it directly
CKBitmapData::WriteRawBitmap(chunk, &level);
}
}
}
// pick threshold
if (m_ImageHost.GetPickThreshold() != 0) {
chunk->WriteIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_PICKTHRESHOLD);
chunk->WriteStruct(m_ImageHost.GetPickThreshold());
}
// bitmap properties
{
chunk->WriteIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXSAVEFORMAT);
// prepare a fake one
FakeBitmapProperties props;
const CKBitmapProperties& realprops = m_ImageHost.GetSaveFormat();
// setup fake self
props.m_Size = CKSizeof(props);
props.m_Data = 6172;
// setup fake VxImageDescEx
props.m_Format.Size = CKSizeof(props.m_Format);
props.m_Format.Flags = static_cast<CKDWORD>(VxMath::VX_PIXELFORMAT::_32_ARGB8888);
props.m_Format.Width = m_ImageHost.GetWidth();
props.m_Format.Height = m_ImageHost.GetHeight();
props.m_Format.BytesPerLine = VxMath::VxImageDescEx::PixelSize * props.m_Format.Height * props.m_Format.Width;
props.m_Format.BitsPerPixel = 32;
props.m_Format.RedMask = 0x00FF0000;
props.m_Format.GreenMask = 0x0000FF00;
props.m_Format.BlueMask = 0x000000FF;
props.m_Format.AlphaMask = 0xFF000000;
props.m_Format.BytesPerColorEntry = 0;
props.m_Format.ColorMapEntries = 0;
props.m_Format.ColorMap = 0;
props.m_Format.Image = 0;
// setup ext and guid
props.m_ReaderGuid.d1 = realprops.m_ReaderGuid.d1;
props.m_ReaderGuid.d2 = realprops.m_ReaderGuid.d2;
std::memcpy(
props.m_Ext.m_Data,
realprops.m_Ext.GetExt(),
std::min(CKSizeof(props.m_Ext.m_Data), realprops.m_Ext.GetSize())
);
// write fake one
chunk->WriteBuffer(&props, CKSizeof(props));
}
chunk->SetClassId(CK_CLASSID::CKCID_TEXTURE);
return true;
}
@ -104,7 +227,7 @@ namespace LibCmo::CK2::ObjImpls {
CKDWORD mixdata;
chunk->ReadStruct(mixdata);
// set mipmap
m_UseMipMap = (mixdata & 0xFF);
UseMipmap(mixdata & 0xFF);
mixdata >>= 8;
// mix flags
CKDWORD mixflags = mixdata & 0xFF;
@ -159,7 +282,7 @@ namespace LibCmo::CK2::ObjImpls {
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_USERMIPMAP)) {
CKDWORD mipmapCount;
chunk->ReadStruct(mipmapCount);
m_MipmapImages.resize(mipmapCount);
SetMipmapLevel(mipmapCount);
for (CKDWORD i = 0; i < mipmapCount; ++i) {
VxMath::VxImageDescEx cache;

View File

@ -1,69 +0,0 @@
# Visual Studio 生成了具有 C++ 设置的 .editorconfig 文件。
root = true
[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]
# Visual C++ 代码样式设置
cpp_generate_documentation_comments = doxygen_slash_star
# Visual C++ 格式设置
cpp_indent_braces = false
cpp_indent_multi_line_relative_to = statement_begin
cpp_indent_within_parentheses = indent
cpp_indent_preserve_within_parentheses = true
cpp_indent_case_contents = true
cpp_indent_case_labels = true
cpp_indent_case_contents_when_block = false
cpp_indent_lambda_braces_when_parameter = true
cpp_indent_goto_labels = one_left
cpp_indent_preprocessor = leftmost_column
cpp_indent_access_specifiers = false
cpp_indent_namespace_contents = true
cpp_indent_preserve_comments = false
cpp_new_line_before_open_brace_namespace = same_line
cpp_new_line_before_open_brace_type = same_line
cpp_new_line_before_open_brace_function = same_line
cpp_new_line_before_open_brace_block = same_line
cpp_new_line_before_open_brace_lambda = same_line
cpp_new_line_scope_braces_on_separate_lines = true
cpp_new_line_close_brace_same_line_empty_type = true
cpp_new_line_close_brace_same_line_empty_function = true
cpp_new_line_before_catch = false
cpp_new_line_before_else = false
cpp_new_line_before_while_in_do_while = false
cpp_space_before_function_open_parenthesis = remove
cpp_space_within_parameter_list_parentheses = false
cpp_space_between_empty_parameter_list_parentheses = false
cpp_space_after_keywords_in_control_flow_statements = true
cpp_space_within_control_flow_statement_parentheses = false
cpp_space_before_lambda_open_parenthesis = false
cpp_space_within_cast_parentheses = false
cpp_space_after_cast_close_parenthesis = false
cpp_space_within_expression_parentheses = false
cpp_space_before_block_open_brace = true
cpp_space_between_empty_braces = false
cpp_space_before_initializer_list_open_brace = true
cpp_space_within_initializer_list_braces = true
cpp_space_preserve_in_initializer_list = true
cpp_space_before_open_square_bracket = false
cpp_space_within_square_brackets = false
cpp_space_before_empty_square_brackets = false
cpp_space_between_empty_square_brackets = false
cpp_space_group_square_brackets = true
cpp_space_within_lambda_brackets = false
cpp_space_between_empty_lambda_brackets = false
cpp_space_before_comma = false
cpp_space_after_comma = true
cpp_space_remove_around_member_operators = true
cpp_space_before_inheritance_colon = true
cpp_space_before_constructor_colon = true
cpp_space_remove_before_semicolon = true
cpp_space_after_semicolon = true
cpp_space_remove_around_unary_operator = true
cpp_space_around_binary_operator = insert
cpp_space_around_assignment_operator = insert
cpp_space_pointer_reference_alignment = left
cpp_space_around_ternary_operator = insert
cpp_wrap_preserve_blocks = one_liners