finish CKTexture reading

This commit is contained in:
2023-09-12 17:03:06 +08:00
parent 9c1fcd172d
commit 42feff734d
12 changed files with 257 additions and 106 deletions

View File

@ -137,7 +137,7 @@ namespace LibCmo::CK2 {
#pragma region Core Read / Write
bool CKBitmapData::ReadFromChunk(CKStateChunk* chunk, CKFileVisitor* file, const CKBitmapDataReadIdentifiers& identifiers) {
XContainer::XBitArray notReadSlot;
XContainer::XBitArray hasReadSlot;
// check 3 types enbedded image
// MARK: i think there is a potential vulnerable issue.
@ -152,7 +152,7 @@ namespace LibCmo::CK2 {
chunk->ReadStruct(bpp);
SetSlotCount(slotcount);
notReadSlot.resize(slotcount, false);
hasReadSlot.resize(slotcount, false);
// the height and width is written outside of specific format
// so we create image first for it.
@ -162,7 +162,7 @@ namespace LibCmo::CK2 {
for (CKDWORD i = 0; i < slotcount; ++i) {
CreateImage(width, height, i);
if (ReadSpecificFormatBitmap(chunk, GetImageDesc(i))) {
notReadSlot[i] = true;
hasReadSlot[i] = true;
} else {
ReleaseImage(i);
}
@ -175,7 +175,7 @@ namespace LibCmo::CK2 {
chunk->ReadStruct(slotcount);
SetSlotCount(slotcount);
notReadSlot.resize(slotcount, false);
hasReadSlot.resize(slotcount, false);
// the height and width is read by raw data function self.
// so we pass a cache variable to reader and do some modification
@ -183,7 +183,7 @@ namespace LibCmo::CK2 {
for (CKDWORD i = 0; i < slotcount; ++i) {
VxMath::VxImageDescEx rawcache;
if (ReadRawBitmap(chunk, &rawcache)) {
notReadSlot[i] = true;
hasReadSlot[i] = true;
// do upside down blit
CreateImage(rawcache.GetWidth(), rawcache.GetHeight(), i);
@ -197,12 +197,12 @@ namespace LibCmo::CK2 {
chunk->ReadStruct(slotcount);
SetSlotCount(slotcount);
notReadSlot.resize(slotcount, false);
hasReadSlot.resize(slotcount, false);
// MARK: a rough implement because we do not support this identifier
for (CKDWORD i = 0; i < slotcount; ++i) {
if (ReadOldRawBitmap(chunk, GetImageDesc(i))) {
notReadSlot[i] = true;
hasReadSlot[i] = true;
} else {
ReleaseImage(i);
}
@ -224,7 +224,7 @@ namespace LibCmo::CK2 {
chunk->ReadString(filename);
if (filename.empty()) continue;
bool isNotLoaded = i >= notReadSlot.size() || notReadSlot[i];
bool isNotLoaded = i >= hasReadSlot.size() || (!hasReadSlot[i]);
if (isNotLoaded) {
// if this image is not loaded.
// try resolve its file name and load it.
@ -399,6 +399,14 @@ namespace LibCmo::CK2 {
CKDWORD CKBitmapData::GetTransparentColor() {
return m_TransColor;
}
void CKBitmapData::SetPickThreshold(CKDWORD threshold) {
m_PickThreshold = threshold;
}
CKDWORD CKBitmapData::GetPickThreshold() {
return m_PickThreshold;
}
#pragma endregion

View File

@ -114,12 +114,32 @@ namespace LibCmo::CK2 {
See also: SetTranparentColor,SetTransparent
*/
CKDWORD GetTransparentColor();
/**
Summary: Sets pick threshold value.
Arguments:
pt: Pick threshold value to be set.
Remarks:
+ The pick threshold is used when picking object with
transparent textures.
+ It is the minimum value for alpha component
below which picking is not valid.So this value is supposed to be in the range 0..255
and the default value 0 means the picking is always valid.
+ But if a value >0 is used and the texture use transparency (some pixels of the bitmap will have
alpha component of 0) an object will not be picked on its transparent part.
See Also: CKRenderContext::Pick
*/
void SetPickThreshold(CKDWORD threshold);
/**
Summary: Gets pick threshold value.
*/
CKDWORD GetPickThreshold();
protected:
CKContext* m_Context;
XContainer::XArray<CKBitmapSlot> m_Slots;
CKDWORD m_CurrentSlot;
CKINT m_PickThreshold;
CKDWORD m_PickThreshold;
CK_BITMAPDATA_FLAGS m_BitmapFlags;
CKDWORD m_TransColor;

View File

@ -17,6 +17,7 @@
#include "ObjImpls/CKRenderObject.hpp"
#include "ObjImpls/CK3dEntity.hpp"
#include "ObjImpls/CK3dObject.hpp"
#include "ObjImpls/CKTexture.hpp"
namespace LibCmo::CK2 {
@ -270,6 +271,7 @@ CKClassRegister(cid, parentCid, \
EasyClassReg(ObjImpls::CKRenderObject, CK_CLASSID::CKCID_RENDEROBJECT, CK_CLASSID::CKCID_BEOBJECT, "Render Object");
EasyClassReg(ObjImpls::CK3dEntity, CK_CLASSID::CKCID_3DENTITY, CK_CLASSID::CKCID_RENDEROBJECT, "3D Entity");
EasyClassReg(ObjImpls::CK3dObject, CK_CLASSID::CKCID_3DOBJECT, CK_CLASSID::CKCID_3DENTITY, "3D Object");
EasyClassReg(ObjImpls::CKTexture, CK_CLASSID::CKCID_TEXTURE, CK_CLASSID::CKCID_BEOBJECT, "Texture");
#undef EasyClassReg

View File

@ -282,7 +282,7 @@ namespace LibCmo::CK2::DataHandlers {
}
std::unique_ptr<CKBitmapHandler, CKBitmapHandlerDeleter> CKBitmapHandler::GetBitmapHandlerWrapper(const CKFileExtension& ext, const CKGUID& guid) {
return std::unique_ptr<CKBitmapHandler, std::function<void(CKBitmapHandler*)>>(GetBitmapHandler(ext, guid));
return std::unique_ptr<CKBitmapHandler, CKBitmapHandlerDeleter>(GetBitmapHandler(ext, guid));
}
void CKBitmapHandlerDeleter::operator()(CKBitmapHandler* handler) {

View File

@ -3,7 +3,63 @@
namespace LibCmo::CK2::ObjImpls {
CKTexture::CKTexture(CKContext* ctx, CK_ID ckid, CKSTRING name) {}
/**
* @brief A fake struct define.
* This define is served for a buffer read / write in CKTexture.
* Because Virtools directly write a raw struct into file,
* and our defines are different with Virtools.
* So we need create a fake struct.
*/
struct FakeBitmapProperties {
CKINT m_Size;
struct {
// fake CKGUID
CKDWORD d1, d2;
}m_ReaderGuid;
struct {
// fake CKFileExtension
CKCHAR m_Data[4];
}m_Ext;
struct {
// fake VxImageDescEx
CK2::CKINT Size; ///< Size of the structure
CK2::CKDWORD Flags; ///< Reserved for special formats (such as compressed ) 0 otherwise
CK2::CKINT Width; ///< Width in pixel of the image
CK2::CKINT Height; ///< Height in pixel of the image
union {
CK2::CKINT BytesPerLine; ///< Pitch (width in bytes) of the image
CK2::CKINT TotalImageSize; ///< For compressed image (DXT1...) the total size of the image
};
CK2::CKINT BitsPerPixel; ///< Number of bits per pixel
union {
CK2::CKDWORD RedMask; ///< Mask for Red component
CK2::CKDWORD BumpDuMask; ///< Mask for Bump Du component
};
union {
CK2::CKDWORD GreenMask; ///< Mask for Green component
CK2::CKDWORD BumpDvMask; ///< Mask for Bump Dv component
};
union {
CK2::CKDWORD BlueMask; ///< Mask for Blue component
CK2::CKDWORD BumpLumMask; ///< Mask for Luminance component
};
CK2::CKDWORD AlphaMask; ///< Mask for Alpha component
CK2::CKWORD BytesPerColorEntry; ///< ColorMap Stride
CK2::CKWORD ColorMapEntries; ///< If other than 0 image is palletized
CK2::CKBYTE* ColorMap; ///< Palette colors
CK2::CKBYTE* Image; ///< Image
}m_Format;
void* m_Data;
};
CKTexture::CKTexture(CKContext* ctx, CK_ID ckid, CKSTRING name) :
CKBeObject(ctx, ckid, name),
m_ImageHost(ctx),
m_VideoFormat(VxMath::VX_PIXELFORMAT::_16_ARGB1555), m_UseMipMap(false), m_MipmapImages() {}
CKTexture::~CKTexture() {}
@ -18,6 +74,118 @@ namespace LibCmo::CK2::ObjImpls {
bool suc = CKBeObject::Load(chunk, file);
if (!suc) return false;
// read base image
suc = m_ImageHost.ReadFromChunk(chunk, file, CKBitmapDataReadIdentifiers {
.m_SpecificFormat = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXREADER),
.m_RawData = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXCOMPRESSED),
.m_OldRawData = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXBITMAPS),
.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;
if (chunk->GetDataVersion() < CK_STATECHUNK_DATAVERSION::CHUNK_MAJORCHANGE_VERSION) {
// MARK: old data process. i don't want to process it anymore.
// thus return false directly.
return false;
} else {
CKDWORD fmtbytesize;
if (chunk->SeekIdentifierAndReturnSize(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_OLDTEXONLY, &fmtbytesize)) {
// 0xFF (blank) 0xFF (save options) 0xFF (transparent + movie info + video fmt) 0xFF (mip map)
CKDWORD mixdata;
chunk->ReadStruct(mixdata);
m_UseMipMap = (mixdata & 0xFF);
m_ImageHost.SetSaveOptions(static_cast<CK_TEXTURE_SAVEOPTIONS>((mixdata & 0xFF0000) >> 16));
mixdata = mixdata & 0xFF00 >> 8;
m_ImageHost.SetTransparent(mixdata & 0x1);
bool hasVideoFmt = mixdata & 0x2;
// MARK: I ignore 0x4 in there because it involve video.
// set current slot, transparent color, and video format.
CKDWORD currentSlot, transColor, videoFmt;
fmtbytesize -= CKSizeof(CKDWORD);
switch (fmtbytesize) {
case (3 * sizeof(CKDWORD)):
chunk->ReadStruct(transColor);
m_ImageHost.SetTransparentColor(transColor);
chunk->ReadStruct(currentSlot);
m_ImageHost.SetCurrentSlot(currentSlot);
chunk->ReadStruct(m_VideoFormat);
break;
case (2 * sizeof(CKDWORD)):
if (m_ImageHost.GetSlotCount() <= 1 || !hasVideoFmt) {
chunk->ReadStruct(transColor);
m_ImageHost.SetTransparentColor(transColor);
}
if (m_ImageHost.GetSlotCount() > 1) {
chunk->ReadStruct(currentSlot);
m_ImageHost.SetCurrentSlot(currentSlot);
}
if (hasVideoFmt) {
chunk->ReadStruct(m_VideoFormat);
}
break;
case (sizeof(CKDWORD)):
if (hasVideoFmt) {
chunk->ReadStruct(m_VideoFormat);
} else if (m_ImageHost.GetSlotCount() <= 1) {
chunk->ReadStruct(transColor);
m_ImageHost.SetTransparentColor(transColor);
} else {
chunk->ReadStruct(currentSlot);
m_ImageHost.SetCurrentSlot(currentSlot);
}
break;
}
}
// read mipmap
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_USERMIPMAP)) {
CKDWORD mipmapCount;
chunk->ReadStruct(mipmapCount);
m_MipmapImages.resize(mipmapCount);
for (CKDWORD i = 0; i < mipmapCount; ++i) {
VxMath::VxImageDescEx cache;
if (CKBitmapData::ReadRawBitmap(chunk, &cache)) {
VxMath::VxDoBlitUpsideDown(&cache, &m_MipmapImages[i]);
}
}
}
// pick threshold
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_PICKTHRESHOLD)) {
CKDWORD threshold;
chunk->ReadStruct(threshold);
m_ImageHost.SetPickThreshold(threshold);
}
// save properties
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXSAVEFORMAT)) {
CKDWORD bufsize;
CKStateChunk::TBuffer buf;
chunk->ReadBufferWrapper(&buf, &bufsize);
if (buf != nullptr) {
FakeBitmapProperties* props = reinterpret_cast<FakeBitmapProperties*>(buf.get());
CKBitmapProperties myprops(
CKGUID(props->m_ReaderGuid.d1, props->m_ReaderGuid.d2),
props->m_Ext.m_Data
);
m_ImageHost.SetSaveFormat(myprops);
}
}
}
// correct video format
if (m_VideoFormat > VxMath::VX_PIXELFORMAT::_32_X8L8V8U8) {
m_VideoFormat = VxMath::VX_PIXELFORMAT::_16_ARGB1555;
}
return true;
}

View File

@ -25,6 +25,7 @@ namespace LibCmo::CK2::ObjImpls {
CKBitmapData m_ImageHost;
VxMath::VX_PIXELFORMAT m_VideoFormat;
bool m_UseMipMap;
XContainer::XArray<VxMath::VxImageDescEx> m_MipmapImages;
};
//class CKRenderObject : public CKBeObject {