Changed up how resources import/export files. Added Model codecs.
This commit is contained in:
parent
54012df3a1
commit
93f881cf03
@ -144,14 +144,14 @@ set(EHS_SOURCES
|
|||||||
src/io/img/PNG_Chunk.cpp include/ehs/io/img/PNG_Chunk.h
|
src/io/img/PNG_Chunk.cpp include/ehs/io/img/PNG_Chunk.h
|
||||||
src/io/img/ImgCodec.cpp include/ehs/io/img/ImgCodec.h
|
src/io/img/ImgCodec.cpp include/ehs/io/img/ImgCodec.h
|
||||||
|
|
||||||
include/ehs/io/model/Vertex.h
|
include/ehs/io/mdl/Vertex.h
|
||||||
src/io/model/Mesh.cpp include/ehs/io/model/Mesh.h
|
src/io/model/Mesh.cpp include/ehs/io/mdl/Mesh.h
|
||||||
src/io/model/Bone.cpp include/ehs/io/model/Bone.h
|
src/io/model/Bone.cpp include/ehs/io/mdl/Bone.h
|
||||||
src/io/model/Model.cpp include/ehs/io/model/Model.h
|
src/io/model/Mdl.cpp include/ehs/io/mdl/Mdl.h
|
||||||
src/io/model/Animation.cpp include/ehs/io/model/Animation.h
|
src/io/model/Animation.cpp include/ehs/io/mdl/Animation.h
|
||||||
src/io/model/AnimBone.cpp include/ehs/io/model/AnimBone.h
|
src/io/model/AnimBone.cpp include/ehs/io/mdl/AnimBone.h
|
||||||
src/io/model/KeyFrame.cpp include/ehs/io/model/KeyFrame.h
|
src/io/model/KeyFrame.cpp include/ehs/io/mdl/KeyFrame.h
|
||||||
src/io/model/PropertyChange.cpp include/ehs/io/model/PropertyChange.h
|
src/io/model/PropertyChange.cpp include/ehs/io/mdl/PropertyChange.h
|
||||||
|
|
||||||
src/io/hid/ButtonState.cpp include/ehs/io/hid/ButtonState.h
|
src/io/hid/ButtonState.cpp include/ehs/io/hid/ButtonState.h
|
||||||
src/io/hid/Button.cpp include/ehs/io/hid/Button.h
|
src/io/hid/Button.cpp include/ehs/io/hid/Button.h
|
||||||
@ -160,6 +160,8 @@ set(EHS_SOURCES
|
|||||||
src/io/hid/HID.cpp include/ehs/io/hid/HID.h
|
src/io/hid/HID.cpp include/ehs/io/hid/HID.h
|
||||||
src/io/hid/InputHandler.cpp include/ehs/io/hid/InputHandler.h
|
src/io/hid/InputHandler.cpp include/ehs/io/hid/InputHandler.h
|
||||||
src/io/hid/Input.cpp include/ehs/io/hid/Input.h
|
src/io/hid/Input.cpp include/ehs/io/hid/Input.h
|
||||||
|
src/io/model/MdlCodec.cpp
|
||||||
|
include/ehs/io/mdl/MdlCodec.h
|
||||||
)
|
)
|
||||||
|
|
||||||
if (IS_OS_WINDOWS)
|
if (IS_OS_WINDOWS)
|
||||||
|
@ -39,7 +39,7 @@ namespace ehs
|
|||||||
|
|
||||||
Audio();
|
Audio();
|
||||||
|
|
||||||
Audio(Str_8 id);
|
Audio(const Str_8& filePath);
|
||||||
|
|
||||||
Audio(Str_8 id, UInt_64 sampleRate, DataType dataType, UInt_8 channels, UInt_64 frames, const Byte* data);
|
Audio(Str_8 id, UInt_64 sampleRate, DataType dataType, UInt_8 channels, UInt_64 frames, const Byte* data);
|
||||||
|
|
||||||
@ -123,17 +123,7 @@ namespace ehs
|
|||||||
|
|
||||||
Audio GetAsChannels(UInt_8 newChannels) const;
|
Audio GetAsChannels(UInt_8 newChannels) const;
|
||||||
|
|
||||||
bool ToFile(const Str_8& filePath) const;
|
bool Export(const Str_8& filePath) const;
|
||||||
|
|
||||||
static Audio FromFile(const Str_8& filePath);
|
|
||||||
|
|
||||||
static Audio* FromFile_Heap(const Str_8& filePath);
|
|
||||||
|
|
||||||
static Audio FromFile(const Str_8& filePath, DataType required);
|
|
||||||
|
|
||||||
static Audio* FromFile_Heap(const Str_8& filePath, DataType required);
|
|
||||||
|
|
||||||
static Audio FromData(Str_8 id, const Str_8& ext, Serializer<UInt_64>& data);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ToMono(UInt_64 newFrameCount, Byte* newData, UInt_64 frameOffset) const;
|
void ToMono(UInt_64 newFrameCount, Byte* newData, UInt_64 frameOffset) const;
|
||||||
@ -201,4 +191,10 @@ namespace ehs
|
|||||||
|
|
||||||
void SInt_32_to_SInt_64(Byte* newData, Byte* newPeak) const;
|
void SInt_32_to_SInt_64(Byte* newData, Byte* newPeak) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool EncodeEHA(const ehs::AudioCodec* codec, ehs::Serializer<ehs::UInt_64>& out, const ehs::Audio* in);
|
||||||
|
|
||||||
|
bool DecodeEHA(const ehs::AudioCodec* codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Audio* out);
|
||||||
|
|
||||||
|
bool DecodeWAV(const ehs::AudioCodec* codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Audio* out);
|
||||||
}
|
}
|
@ -42,7 +42,7 @@ namespace ehs
|
|||||||
|
|
||||||
Img();
|
Img();
|
||||||
|
|
||||||
Img(Str_8 id);
|
Img(const Str_8& filePath);
|
||||||
|
|
||||||
Img(Str_8 id, UInt_8 byteDepth, UInt_8 channels, const Vec2_u64& resolution, const Byte* data);
|
Img(Str_8 id, UInt_8 byteDepth, UInt_8 channels, const Vec2_u64& resolution, const Byte* data);
|
||||||
|
|
||||||
@ -124,13 +124,7 @@ namespace ehs
|
|||||||
|
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
bool ToFile(const Str_8& filePath) const;
|
bool Export(const Str_8& filePath) const;
|
||||||
|
|
||||||
static Img FromFile(const Str_8& filePath);
|
|
||||||
|
|
||||||
static Img* FromFile_Heap(const Str_8& filePath);
|
|
||||||
|
|
||||||
static Img FromData(Str_8 id, const Str_8& ext, Serializer<UInt_64>& data);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Img GetNearestNeighbor(const Vec2_u64& newResolution) const;
|
Img GetNearestNeighbor(const Vec2_u64& newResolution) const;
|
||||||
@ -185,4 +179,10 @@ namespace ehs
|
|||||||
|
|
||||||
void BD16_to_BD8(UInt_64 newSize, Byte* buffer) const;
|
void BD16_to_BD8(UInt_64 newSize, Byte* buffer) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool EncodeQOI(const ehs::ImgCodec* codec, ehs::Serializer<ehs::UInt_64>& out, const ehs::Img* in);
|
||||||
|
|
||||||
|
bool DecodeQOI(const ehs::ImgCodec* codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Img* out);
|
||||||
|
|
||||||
|
bool DecodePNG(const ehs::ImgCodec* codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Img* out);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,10 @@
|
|||||||
namespace ehs
|
namespace ehs
|
||||||
{
|
{
|
||||||
class Img;
|
class Img;
|
||||||
|
class ImgCodec;
|
||||||
|
|
||||||
|
typedef bool (*EncodeImgCb)(const ImgCodec* const, Serializer<UInt_64>&, const Img*);
|
||||||
|
typedef bool (*DecodeImgCb)(const ImgCodec* const, Serializer<UInt_64>&, Img*);
|
||||||
|
|
||||||
class ImgCodec
|
class ImgCodec
|
||||||
{
|
{
|
||||||
@ -15,15 +19,13 @@ namespace ehs
|
|||||||
UInt_64 hashExt;
|
UInt_64 hashExt;
|
||||||
Str_8 ext;
|
Str_8 ext;
|
||||||
Endianness endianness;
|
Endianness endianness;
|
||||||
bool (*encodeCb)(const ImgCodec* const, Serializer<UInt_64>&, const Img*);
|
EncodeImgCb encoder;
|
||||||
bool (*decodeCb)(const ImgCodec* const, Serializer<UInt_64>&, Img*);
|
DecodeImgCb decoder;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ImgCodec();
|
ImgCodec();
|
||||||
|
|
||||||
ImgCodec(Str_8 id, Str_8 ext, const Endianness end,
|
ImgCodec(Str_8 id, Str_8 ext, Endianness end, EncodeImgCb encoder, DecodeImgCb decoder);
|
||||||
bool (*encodeCb)(const ImgCodec* const, Serializer<UInt_64>&, const Img*),
|
|
||||||
bool (*decodeCb)(const ImgCodec* const, Serializer<UInt_64>&, Img*));
|
|
||||||
|
|
||||||
ImgCodec(ImgCodec&& codec) noexcept;
|
ImgCodec(ImgCodec&& codec) noexcept;
|
||||||
|
|
||||||
|
93
include/ehs/io/mdl/Mdl.h
Normal file
93
include/ehs/io/mdl/Mdl.h
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ehs/EHS.h"
|
||||||
|
#include "ehs/Array.h"
|
||||||
|
#include "ehs/io/File.h"
|
||||||
|
#include "MdlCodec.h"
|
||||||
|
#include "Mesh.h"
|
||||||
|
#include "Bone.h"
|
||||||
|
#include "Animation.h"
|
||||||
|
|
||||||
|
namespace ehs
|
||||||
|
{
|
||||||
|
enum class ModelEncoding : UInt_8
|
||||||
|
{
|
||||||
|
EHM
|
||||||
|
};
|
||||||
|
|
||||||
|
class Mdl : public BaseObj
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static Array<MdlCodec> codecs;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
UInt_64 hashId;
|
||||||
|
Str_8 id;
|
||||||
|
Array<Mesh> meshes;
|
||||||
|
Bone skeleton;
|
||||||
|
Array<Animation> animations;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static bool HasCodec(UInt_64 hashExt);
|
||||||
|
|
||||||
|
static bool HasCodec(const Str_8& ext);
|
||||||
|
|
||||||
|
static bool AddCodec(MdlCodec codec);
|
||||||
|
|
||||||
|
static const MdlCodec* GetCodec(UInt_64 hashExt);
|
||||||
|
|
||||||
|
static const MdlCodec* GetCodec(const Str_8& ext);
|
||||||
|
|
||||||
|
Mdl();
|
||||||
|
|
||||||
|
Mdl(const Str_8& filePath);
|
||||||
|
|
||||||
|
Mdl(Str_8 id, Array<Mesh> meshes, Bone skeleton, Array<Animation> animations);
|
||||||
|
|
||||||
|
Mdl(Str_8 id, Array<Mesh> meshes, Bone skeleton);
|
||||||
|
|
||||||
|
Mdl(Str_8 id, Array<Mesh> meshes);
|
||||||
|
|
||||||
|
Mdl(Mdl&& model) noexcept;
|
||||||
|
|
||||||
|
Mdl(const Mdl& model) = default;
|
||||||
|
|
||||||
|
Mdl& operator=(Mdl&& model) noexcept;
|
||||||
|
|
||||||
|
Mdl& operator=(const Mdl& model) = default;
|
||||||
|
|
||||||
|
void Release();
|
||||||
|
|
||||||
|
UInt_64 GetHashId() const;
|
||||||
|
|
||||||
|
void SetId(Str_8 newId);
|
||||||
|
|
||||||
|
Str_8 GetId() const;
|
||||||
|
|
||||||
|
const Array<Mesh>& GetMeshes() const;
|
||||||
|
|
||||||
|
Array<Mesh>& GetMeshes();
|
||||||
|
|
||||||
|
Mesh* GetMesh(UInt_64 inHashId);
|
||||||
|
|
||||||
|
Mesh* GetMesh(const Str_8& inId);
|
||||||
|
|
||||||
|
const Bone& GetSkeleton() const;
|
||||||
|
|
||||||
|
Bone& GetSkeleton();
|
||||||
|
|
||||||
|
Animation* GetAnimation(UInt_64 inHashId);
|
||||||
|
|
||||||
|
const Array<Animation>& GetAnimations() const;
|
||||||
|
|
||||||
|
Array<Animation>& GetAnimations();
|
||||||
|
|
||||||
|
void Calculate();
|
||||||
|
|
||||||
|
bool Export(const Str_8& filePath) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool EncodeEHM(const MdlCodec* codec, Serializer<UInt_64>& data, const Mdl* mdl);
|
||||||
|
|
||||||
|
bool DecodeEHM(const MdlCodec* codec, Serializer<UInt_64>& data, Mdl* mdl);
|
||||||
|
}
|
50
include/ehs/io/mdl/MdlCodec.h
Normal file
50
include/ehs/io/mdl/MdlCodec.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ehs/Str.h"
|
||||||
|
#include "ehs/Serializer.h"
|
||||||
|
#include "ehs/system/CPU.h"
|
||||||
|
|
||||||
|
namespace ehs
|
||||||
|
{
|
||||||
|
class Mdl;
|
||||||
|
class MdlCodec;
|
||||||
|
|
||||||
|
typedef bool (*EnocdeMdlCb)(const MdlCodec*, Serializer<UInt_64>&, const Mdl*);
|
||||||
|
typedef bool (*DecodeMdlCb)(const MdlCodec*, Serializer<UInt_64>&, Mdl*);
|
||||||
|
|
||||||
|
class MdlCodec
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Str_8 id;
|
||||||
|
UInt_64 hashExt;
|
||||||
|
Str_8 ext;
|
||||||
|
Endianness endianness;
|
||||||
|
EnocdeMdlCb encoder;
|
||||||
|
DecodeMdlCb decoder;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MdlCodec();
|
||||||
|
|
||||||
|
MdlCodec(Str_8 id, Str_8 ext, Endianness end, EnocdeMdlCb encoder, DecodeMdlCb decoder);
|
||||||
|
|
||||||
|
MdlCodec(MdlCodec&& codec) noexcept;
|
||||||
|
|
||||||
|
MdlCodec(const MdlCodec& codec);
|
||||||
|
|
||||||
|
MdlCodec& operator=(MdlCodec&& codec) noexcept;
|
||||||
|
|
||||||
|
MdlCodec& operator=(const MdlCodec& codec);
|
||||||
|
|
||||||
|
Str_8 GetId() const;
|
||||||
|
|
||||||
|
UInt_64 GetHashExt() const;
|
||||||
|
|
||||||
|
Str_8 GetExt() const;
|
||||||
|
|
||||||
|
Endianness GetEndianness() const;
|
||||||
|
|
||||||
|
bool Encode(Serializer<UInt_64>& out, const Mdl* in) const;
|
||||||
|
|
||||||
|
bool Decode(Serializer<UInt_64>& in, Mdl* out) const;
|
||||||
|
};
|
||||||
|
}
|
@ -1,80 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "ehs/EHS.h"
|
|
||||||
#include "ehs/Array.h"
|
|
||||||
#include "ehs/io/File.h"
|
|
||||||
#include "Mesh.h"
|
|
||||||
#include "Bone.h"
|
|
||||||
#include "Animation.h"
|
|
||||||
|
|
||||||
namespace ehs
|
|
||||||
{
|
|
||||||
enum class ModelEncoding : UInt_8
|
|
||||||
{
|
|
||||||
EHM
|
|
||||||
};
|
|
||||||
|
|
||||||
class Model : public BaseObj
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
UInt_64 hashId;
|
|
||||||
Str_8 id;
|
|
||||||
Array<Mesh> meshes;
|
|
||||||
Bone skeleton;
|
|
||||||
Array<Animation> animations;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Model();
|
|
||||||
|
|
||||||
Model(const Str_8& filePath);
|
|
||||||
|
|
||||||
Model(Str_8 id, Array<Mesh> meshes, Bone skeleton, Array<Animation> animations);
|
|
||||||
|
|
||||||
Model(Str_8 id, Array<Mesh> meshes, Bone skeleton);
|
|
||||||
|
|
||||||
Model(Str_8 id, Array<Mesh> meshes);
|
|
||||||
|
|
||||||
Model(Model&& model) noexcept;
|
|
||||||
|
|
||||||
Model(const Model& model) = default;
|
|
||||||
|
|
||||||
Model& operator=(Model&& model) noexcept;
|
|
||||||
|
|
||||||
Model& operator=(const Model& model) = default;
|
|
||||||
|
|
||||||
void Release();
|
|
||||||
|
|
||||||
UInt_64 GetHashId() const;
|
|
||||||
|
|
||||||
void SetId(Str_8 newId);
|
|
||||||
|
|
||||||
Str_8 GetId() const;
|
|
||||||
|
|
||||||
const Array<Mesh>& GetMeshes() const;
|
|
||||||
|
|
||||||
Array<Mesh>& GetMeshes();
|
|
||||||
|
|
||||||
Mesh* GetMesh(UInt_64 inHashId);
|
|
||||||
|
|
||||||
Mesh* GetMesh(const Str_8& inId);
|
|
||||||
|
|
||||||
const Bone& GetSkeleton() const;
|
|
||||||
|
|
||||||
Bone& GetSkeleton();
|
|
||||||
|
|
||||||
Animation* GetAnimation(UInt_64 inHashId);
|
|
||||||
|
|
||||||
const Array<Animation>& GetAnimations() const;
|
|
||||||
|
|
||||||
Array<Animation>& GetAnimations();
|
|
||||||
|
|
||||||
void Calculate();
|
|
||||||
|
|
||||||
void Export(const Str_8& filePath, ModelEncoding encoding);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void ToEHM(File& file);
|
|
||||||
|
|
||||||
void FromEHM(File& file);
|
|
||||||
};
|
|
||||||
}
|
|
534
src/EHS.cpp
534
src/EHS.cpp
@ -7,6 +7,7 @@
|
|||||||
#include "ehs/io/img/Img.h"
|
#include "ehs/io/img/Img.h"
|
||||||
#include "ehs/io/img/PNG.h"
|
#include "ehs/io/img/PNG.h"
|
||||||
#include "ehs/io/RIFF.h"
|
#include "ehs/io/RIFF.h"
|
||||||
|
#include "ehs/io/mdl/Mdl.h"
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
@ -94,531 +95,6 @@ namespace ehs
|
|||||||
{
|
{
|
||||||
return appVer;
|
return appVer;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DecodeWAV(const ehs::AudioCodec* const codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Audio* out)
|
|
||||||
{
|
|
||||||
RIFF riff(in);
|
|
||||||
|
|
||||||
if (riff.GetType() != "WAVE")
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 0, "Data is not in WAVE format.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RIFF_Chunk fmt = riff.GetChunk("fmt ");
|
|
||||||
if (!fmt.IsValid())
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 1, "Wave does not have a format chunk.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Serializer<> fmtSer = fmt.GetData();
|
|
||||||
|
|
||||||
RIFF_Chunk dChunk = riff.GetChunk("data");
|
|
||||||
if (!dChunk.IsValid())
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 2, "Wave does not have a data chunk.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt_16 compression = fmtSer.Read<UInt_16>();
|
|
||||||
if (compression == 0x2)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 3, "Microsoft ADPCM compression unsupported.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (compression == 0x6)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 4, "ITU G.711 a-law compression unsupported.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (compression == 0x7)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 5, "ITU G.711 µ-law compression unsupported.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (compression == 0x11)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 6, "IMA ADPCM compression unsupported.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (compression == 0x16)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 7, "TU G.723 ADPCM (Yamaha) compression unsupported.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (compression == 0x31)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 8, "GSM 6.10 compression unsupported.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (compression == 0x40)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 9, "ITU G.721 ADPCM compression unsupported.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (compression == 0x50)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 10, "MPEG compression unsupported.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (compression == 0xFFFF)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 11, "Experimental compression unsupported.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (compression != 0x1 && compression != 0x3)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 12, "Wave has unknown compression of " + Str_8::FromNum(compression) + ".");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt_16 channels = fmtSer.Read<UInt_16>();
|
|
||||||
UInt_32 sampleRate = fmtSer.Read<UInt_32>();
|
|
||||||
fmtSer.SetOffset(fmtSer.GetOffset() + 6);
|
|
||||||
UInt_8 byteDepth = (UInt_8)(fmtSer.Read<UInt_16>() / 8);
|
|
||||||
|
|
||||||
DataType dataType;
|
|
||||||
if (byteDepth == 1)
|
|
||||||
dataType = DataType::SINT_8;
|
|
||||||
else if (byteDepth == 2)
|
|
||||||
dataType = DataType::SINT_16;
|
|
||||||
else if (byteDepth == 3)
|
|
||||||
dataType = DataType::SINT_24;
|
|
||||||
else if (byteDepth == 4 && compression == 0x3)
|
|
||||||
dataType = DataType::FLOAT;
|
|
||||||
else if (byteDepth == 4)
|
|
||||||
dataType = DataType::SINT_32;
|
|
||||||
else if (byteDepth == 8)
|
|
||||||
dataType = DataType::SINT_64;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
|
|
||||||
UInt_64 size = dChunk.GetData().Size();
|
|
||||||
UInt_64 frames = size / byteDepth / channels;
|
|
||||||
|
|
||||||
*out = std::move(Audio(out->GetId(), sampleRate, dataType, channels, frames));
|
|
||||||
|
|
||||||
Serializer<> dataSer = dChunk.GetData();
|
|
||||||
|
|
||||||
for (UInt_32 i = 0; i < dataSer.Size(); i += byteDepth)
|
|
||||||
{
|
|
||||||
if (byteDepth == 1)
|
|
||||||
{
|
|
||||||
*(SInt_8*)&(*out)[i] = dataSer.Read<SInt_8>();
|
|
||||||
if ((*out)[i] > *(SInt_8*)out->GetPeak())
|
|
||||||
out->SetPeak(sizeof(SInt_8), &(*out)[i]);
|
|
||||||
}
|
|
||||||
else if (byteDepth == 2)
|
|
||||||
{
|
|
||||||
*(SInt_16*)&(*out)[i] = dataSer.Read<SInt_16>();
|
|
||||||
if (*(SInt_16*)&(*out)[i] > *(SInt_16*)out->GetPeak())
|
|
||||||
out->SetPeak(sizeof(SInt_16), &(*out)[i]);
|
|
||||||
}
|
|
||||||
else if (byteDepth == 3)
|
|
||||||
{
|
|
||||||
*(SInt_16*)&(*out)[i + 1] = dataSer.Read<SInt_16>();
|
|
||||||
(*out)[i] = dataSer.Read<Byte>();
|
|
||||||
|
|
||||||
SInt_32 signal = 0;
|
|
||||||
signal |= (*out)[i];
|
|
||||||
signal |= (*out)[i + 1] << 8;
|
|
||||||
signal |= (*out)[i + 2] << 16;
|
|
||||||
|
|
||||||
SInt_32 peak = 0;
|
|
||||||
peak |= out->GetPeak()[0];
|
|
||||||
peak |= out->GetPeak()[1] << 8;
|
|
||||||
peak |= out->GetPeak()[2] << 16;
|
|
||||||
|
|
||||||
if (signal > peak)
|
|
||||||
out->SetPeak(3, &(*out)[i]);
|
|
||||||
}
|
|
||||||
else if (byteDepth == 4 && compression == 0x3)
|
|
||||||
{
|
|
||||||
*(float*)&(*out)[i] = dataSer.Read<float>();
|
|
||||||
if (*(float*)&(*out)[i] > *(float*)out->GetPeak())
|
|
||||||
out->SetPeak(sizeof(float), &(*out)[i]);
|
|
||||||
}
|
|
||||||
else if (byteDepth == 4)
|
|
||||||
{
|
|
||||||
*(SInt_32*)&(*out)[i] = dataSer.Read<SInt_32>();
|
|
||||||
if (*(SInt_32*)&(*out)[i] > *(SInt_32*)out->GetPeak())
|
|
||||||
out->SetPeak(sizeof(SInt_32), &(*out)[i]);
|
|
||||||
}
|
|
||||||
else if (byteDepth == 8)
|
|
||||||
{
|
|
||||||
*(SInt_64*)&(*out)[i] = dataSer.Read<SInt_64>();
|
|
||||||
if (*(SInt_64*)&(*out)[i] > *(SInt_64*)out->GetPeak())
|
|
||||||
out->SetPeak(sizeof(SInt_64), &(*out)[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EncodeEHA(const ehs::AudioCodec* const codec, ehs::Serializer<ehs::UInt_64>& out, const ehs::Audio* in)
|
|
||||||
{
|
|
||||||
Serializer<UInt_64> result(codec->GetEndianness());
|
|
||||||
result.WriteVersion({1, 0, 0});
|
|
||||||
result.Write(in->GetSampleRate());
|
|
||||||
result.Write(in->GetDataType());
|
|
||||||
result.Write(in->GetByteDepth());
|
|
||||||
result.Write(in->GetChannels());
|
|
||||||
result.Write(in->GetFrameCount());
|
|
||||||
|
|
||||||
UInt_64 size = in->GetSize();
|
|
||||||
UInt_8 byteDepth = in->GetByteDepth();
|
|
||||||
|
|
||||||
result.Resize(result.Size() + size + byteDepth);
|
|
||||||
Util::Copy(&result[result.GetOffset()], &in[0], size);
|
|
||||||
result.SetOffset(result.GetOffset() + size);
|
|
||||||
|
|
||||||
Util::Copy(&result[result.GetOffset()], in->GetPeak(), byteDepth);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DecodeEHA(const ehs::AudioCodec* const codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Audio* out)
|
|
||||||
{
|
|
||||||
Version version = in.ReadVersion();
|
|
||||||
if (version != Version(1, 0, 0))
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 0, "Incompatible audio file version.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt_64 sampleRate = in.Read<UInt_64>();
|
|
||||||
DataType dataType = in.Read<DataType>();
|
|
||||||
UInt_8 byteDepth = in.Read<UInt_8>();
|
|
||||||
UInt_8 channels = in.Read<UInt_8>();
|
|
||||||
UInt_64 frames = in.Read<UInt_64>();
|
|
||||||
|
|
||||||
*out = Audio(out->GetId(), sampleRate, dataType, channels, frames);
|
|
||||||
|
|
||||||
UInt_64 size = out->GetSize();
|
|
||||||
Util::Copy(&(*out)[0], &in[in.GetOffset()], size);
|
|
||||||
in.SetOffset(in.GetOffset() + size);
|
|
||||||
|
|
||||||
out->SetPeak(byteDepth, &in[in.GetOffset()]);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DecodePNG(const ehs::ImgCodec* const codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Img* out)
|
|
||||||
{
|
|
||||||
PNG png(out->GetId(), in);
|
|
||||||
|
|
||||||
PNG_Chunk* ihdr = png.GetChunk("IHDR");
|
|
||||||
Serializer<UInt_64>* ihdrData = ihdr->GetData();
|
|
||||||
|
|
||||||
UInt_32 width = ihdrData->Read<UInt_32>();
|
|
||||||
UInt_32 height = ihdrData->Read<UInt_32>();
|
|
||||||
UInt_8 bitDepth = ihdrData->Read<UInt_8>();
|
|
||||||
|
|
||||||
UInt_8 colorType = ihdrData->Read<UInt_8>();
|
|
||||||
if (colorType == 3)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 1, "Color type of " + Str_8::FromNum(colorType) + " is unsupported.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt_8 channels = 1;
|
|
||||||
if (colorType == 2)
|
|
||||||
channels = 3;
|
|
||||||
else if (colorType == 4)
|
|
||||||
channels = 2;
|
|
||||||
else if (colorType == 6)
|
|
||||||
channels = 4;
|
|
||||||
|
|
||||||
*out = Img(out->GetId(), bitDepth / 8, channels, {width, height});
|
|
||||||
|
|
||||||
UInt_8 compression = ihdrData->Read<UInt_8>();
|
|
||||||
if (compression)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 2, "Compression method of " + Str_8::FromNum(compression) + " is unsupported.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt_8 filter = ihdrData->Read<UInt_8>();
|
|
||||||
if (filter)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 3, "Filter method of " + Str_8::FromNum(filter) + " is unsupported.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt_8 interlaced = ihdrData->Read<UInt_8>();
|
|
||||||
if (interlaced)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 4, "Interlacing method of " + Str_8::FromNum(interlaced) + " is unsupported.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt_32 scanline = width * (bitDepth / 8) * channels;
|
|
||||||
UInt_32 scanLineF = scanline + 1;
|
|
||||||
UInt_32 bufferSize = scanline * height + height;
|
|
||||||
|
|
||||||
Byte* buffer = new Byte[bufferSize];
|
|
||||||
|
|
||||||
PNG_Chunk* idat = png.GetChunk("IDAT");
|
|
||||||
Serializer<UInt_64>* idatData = idat->GetData();
|
|
||||||
|
|
||||||
z_stream strm = {};
|
|
||||||
strm.zalloc = Z_NULL;
|
|
||||||
strm.zfree = Z_NULL;
|
|
||||||
strm.opaque = Z_NULL;
|
|
||||||
strm.avail_in = idatData->Size();
|
|
||||||
strm.next_in = *idatData;
|
|
||||||
strm.avail_out = bufferSize;
|
|
||||||
strm.next_out = buffer;
|
|
||||||
|
|
||||||
int code = inflateInit(&strm);
|
|
||||||
if (code != Z_OK)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 5, "Failed to initialize zlib inflate with error #" + Str_8::FromNum(code) + ".");
|
|
||||||
delete[] buffer;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
code = inflate(&strm, Z_NO_FLUSH);
|
|
||||||
if (code != Z_STREAM_END && code != Z_OK)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 6, "Failed to zlib inflate with error #" + Str_8::FromNum(code) + ".");
|
|
||||||
delete[] buffer;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} while (strm.avail_out);
|
|
||||||
|
|
||||||
code = inflateEnd(&strm);
|
|
||||||
if (code != Z_OK)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 7, "Failed to uninitialize zlib inflate with error #" + Str_8::FromNum(code) + ".");
|
|
||||||
delete[] buffer;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (UInt_32 i = 0, o = 0; i < bufferSize; i += scanLineF, o += scanline)
|
|
||||||
{
|
|
||||||
UInt_8 fCode = buffer[i];
|
|
||||||
if (fCode == 0)
|
|
||||||
PNG::FilterNone(&buffer[i + 1], &(*out)[o], bitDepth, channels, scanline);
|
|
||||||
else if (fCode == 1)
|
|
||||||
PNG::FilterSub(&buffer[i + 1], &(*out)[o], bitDepth, channels, scanline);
|
|
||||||
else if (fCode == 2)
|
|
||||||
PNG::FilterUp(&buffer[i + 1], &(*out)[o - scanline], bitDepth, channels, scanline);
|
|
||||||
else if (fCode == 3)
|
|
||||||
PNG::FilterAverage(&buffer[i + 1], &(*out)[o - scanline], bitDepth, channels, scanline);
|
|
||||||
else if (fCode == 4)
|
|
||||||
PNG::FilterPaeth(&buffer[i + 1], &(*out)[o - scanline], bitDepth, channels, scanline);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] buffer;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EncodeQOI(const ehs::ImgCodec* const codec, ehs::Serializer<ehs::UInt_64>& out, const ehs::Img* in)
|
|
||||||
{
|
|
||||||
UInt_8 channels = in->GetChannels();
|
|
||||||
Vec2_u64 resolution = in->GetResolution();
|
|
||||||
|
|
||||||
UInt_32 px_len = resolution.x * resolution.y * channels;
|
|
||||||
UInt_32 px_end = px_len - channels;
|
|
||||||
|
|
||||||
Byte index[256];
|
|
||||||
for (UInt_64 i = 0; i < 64; ++i)
|
|
||||||
*(UInt_32*)&index[i * 4] = 0;
|
|
||||||
|
|
||||||
Byte prevPixel[4] = {0, 0, 0, 255};
|
|
||||||
Byte pixel[4] = {0, 0, 0, 255};
|
|
||||||
|
|
||||||
Serializer<UInt_32> result(Endianness::BE, resolution.x * resolution.y * (channels + 1) + 22);
|
|
||||||
|
|
||||||
result.Write('q');
|
|
||||||
result.Write('o');
|
|
||||||
result.Write('i');
|
|
||||||
result.Write('f');
|
|
||||||
result.Write<UInt_32>(resolution.x);
|
|
||||||
result.Write<UInt_32>(resolution.y);
|
|
||||||
result.Write(in->GetChannels());
|
|
||||||
result.Write(1);
|
|
||||||
|
|
||||||
for (UInt_32 px_pos = 0, run = 0; px_pos < px_len; px_pos += channels)
|
|
||||||
{
|
|
||||||
if (channels == 4)
|
|
||||||
{
|
|
||||||
*(UInt_32*)pixel = *(UInt_32*)&(*in)[px_pos];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pixel[0] = (*in)[px_pos];
|
|
||||||
pixel[1] = (*in)[px_pos + 1];
|
|
||||||
pixel[2] = (*in)[px_pos + 2];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*(UInt_32*)pixel == *(UInt_32*)prevPixel)
|
|
||||||
{
|
|
||||||
run++;
|
|
||||||
if (run == 62 || px_pos == px_end)
|
|
||||||
{
|
|
||||||
result.Write<UInt_8>(0xc0 | (run - 1));
|
|
||||||
run = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (run > 0)
|
|
||||||
{
|
|
||||||
result.Write<UInt_8>(0xc0 | (run - 1));
|
|
||||||
run = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt_32 index_pos = (prevPixel[0] * 3 + prevPixel[1] * 5 + prevPixel[2] * 7 + prevPixel[3] * 11) % 64 * channels;
|
|
||||||
|
|
||||||
if (*(UInt_32*)&index[index_pos] == *(UInt_32*)pixel)
|
|
||||||
{
|
|
||||||
result.Write<UInt_8>(0x00 | (index_pos / channels));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*(UInt_32*)&index[index_pos] = *(UInt_32*)pixel;
|
|
||||||
|
|
||||||
if (pixel[3] == prevPixel[3])
|
|
||||||
{
|
|
||||||
SInt_8 vr = pixel[0] - prevPixel[0];
|
|
||||||
SInt_8 vg = pixel[1] - prevPixel[1];
|
|
||||||
SInt_8 vb = pixel[2] - prevPixel[2];
|
|
||||||
|
|
||||||
SInt_8 vg_r = vr - vg;
|
|
||||||
SInt_8 vg_b = vb - vg;
|
|
||||||
|
|
||||||
if (
|
|
||||||
vr > -3 && vr < 2 &&
|
|
||||||
vg > -3 && vg < 2 &&
|
|
||||||
vb > -3 && vb < 2
|
|
||||||
)
|
|
||||||
{
|
|
||||||
result.Write<UInt_8>(0x40 | (vr + 2) << 4 | (vg + 2) << 2 | (vb + 2));
|
|
||||||
}
|
|
||||||
else if (
|
|
||||||
vg_r > -9 && vg_r < 8 &&
|
|
||||||
vg > -33 && vg < 32 &&
|
|
||||||
vg_b > -9 && vg_b < 8
|
|
||||||
)
|
|
||||||
{
|
|
||||||
result.Write<UInt_8>(0x80 | (vg + 32));
|
|
||||||
result.Write<UInt_8>((vg_r + 8) << 4 | (vg_b + 8));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result.Write<UInt_8>(0xfe);
|
|
||||||
result.Write(pixel[0]);
|
|
||||||
result.Write(pixel[1]);
|
|
||||||
result.Write(pixel[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result.Write<UInt_8>(0xff);
|
|
||||||
result.SetEndianness(CPU::GetEndianness());
|
|
||||||
result.Write(*(UInt_32*)pixel);
|
|
||||||
result.SetEndianness(Endianness::BE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*(UInt_32*)prevPixel = *(UInt_32*)pixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Write(0x100000000000000);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DecodeQOI(const ehs::ImgCodec* const codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Img* out)
|
|
||||||
{
|
|
||||||
Str_8 imgType = in.ReadStr<Char_8, UInt_64>(4);
|
|
||||||
if (imgType != "qoif")
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 0, "Given data is not in the qoif format.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt_64 width = in.Read<UInt_32>();
|
|
||||||
UInt_64 height = in.Read<UInt_32>();
|
|
||||||
|
|
||||||
UInt_8 channels = in.Read<UInt_8>();
|
|
||||||
channels = 4;
|
|
||||||
UInt_8 space = in.Read<UInt_8>();
|
|
||||||
UInt_8 bitDepth = 8;
|
|
||||||
|
|
||||||
UInt_64 size = width * channels * height;
|
|
||||||
|
|
||||||
*out = Img(out->GetId(), bitDepth / 8, channels, {width, height});
|
|
||||||
|
|
||||||
Byte prevPixel[4] = {0, 0, 0, 255};
|
|
||||||
|
|
||||||
Byte index[256];
|
|
||||||
for (UInt_64 i = 0; i < 64; ++i)
|
|
||||||
*(UInt_32*)&index[i * 4] = 0;
|
|
||||||
|
|
||||||
UInt_32 chunksLen = in.Size() - 8;
|
|
||||||
for (UInt_32 pos = 0, run = 0; pos < size; pos += channels)
|
|
||||||
{
|
|
||||||
if (run > 0)
|
|
||||||
--run;
|
|
||||||
else if (in.GetOffset() < chunksLen)
|
|
||||||
{
|
|
||||||
UInt_32 chunkType = (UInt_32)in.Read<UInt_8>();
|
|
||||||
if (chunkType == 0xfe) // RGB
|
|
||||||
{
|
|
||||||
prevPixel[0] = in.Read<UInt_8>(); // R-value
|
|
||||||
prevPixel[1] = in.Read<UInt_8>(); // G-value
|
|
||||||
prevPixel[2] = in.Read<UInt_8>(); // B-value
|
|
||||||
}
|
|
||||||
else if (chunkType == 0xff) // RGBA
|
|
||||||
{
|
|
||||||
*(UInt_32*)prevPixel = in.Read<UInt_32>();
|
|
||||||
}
|
|
||||||
else if ((chunkType & 0xc0) == 0x00) // Index
|
|
||||||
{
|
|
||||||
*(UInt_32*)prevPixel = *(UInt_32*)&index[chunkType * channels];
|
|
||||||
}
|
|
||||||
else if ((chunkType & 0xc0) == 0x40) // Diff
|
|
||||||
{
|
|
||||||
prevPixel[0] += ((chunkType >> 4) & 0x03) - 2; // R-value
|
|
||||||
prevPixel[1] += ((chunkType >> 2) & 0x03) - 2; // G-value
|
|
||||||
prevPixel[2] += (chunkType & 0x03) - 2; // B-value
|
|
||||||
}
|
|
||||||
else if ((chunkType & 0xc0) == 0x80) // Luma
|
|
||||||
{
|
|
||||||
UInt_32 mod = (UInt_32)in.Read<UInt_8>();
|
|
||||||
UInt_32 vg = (chunkType & 0x3f) - 32;
|
|
||||||
prevPixel[0] += vg - 8 + ((mod >> 4) & 0x0f); // R-value
|
|
||||||
prevPixel[1] += vg; // G-value
|
|
||||||
prevPixel[2] += vg - 8 + (mod & 0x0f); // B-value
|
|
||||||
}
|
|
||||||
else if ((chunkType & 0xc0) == 0xc0) // Run
|
|
||||||
run = (chunkType & 0x3f);
|
|
||||||
|
|
||||||
*(UInt_32*)&index[(prevPixel[0] * 3 + prevPixel[1] * 5 + prevPixel[2] * 7 + prevPixel[3] * 11) % 64 * channels] = *(UInt_32*)prevPixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (channels == 4)
|
|
||||||
{
|
|
||||||
*((UInt_32*)&(*out)[pos]) = *(UInt_32*)prevPixel;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
(*out)[pos] = prevPixel[0];
|
|
||||||
(*out)[pos + 1] = prevPixel[1];
|
|
||||||
(*out)[pos + 2] = prevPixel[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogRaised(const ehs::Log& log)
|
void LogRaised(const ehs::Log& log)
|
||||||
@ -677,6 +153,14 @@ int main()
|
|||||||
ehs::DecodeQOI
|
ehs::DecodeQOI
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ehs::Mdl::AddCodec({
|
||||||
|
"Event Horizon Model",
|
||||||
|
"ehm",
|
||||||
|
ehs::Endianness::LE,
|
||||||
|
ehs::EncodeEHM,
|
||||||
|
ehs::DecodeEHM
|
||||||
|
});
|
||||||
|
|
||||||
ehs::GarbageCollector::Start();
|
ehs::GarbageCollector::Start();
|
||||||
|
|
||||||
const ehs::SInt_32 code = Main(&ehs::appName, &ehs::appVerId, &ehs::appVer);
|
const ehs::SInt_32 code = Main(&ehs::appName, &ehs::appVerId, &ehs::appVer);
|
||||||
|
@ -57,6 +57,29 @@ namespace ehs
|
|||||||
AddType("Audio");
|
AddType("Audio");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Audio::Audio(const Str_8& filePath)
|
||||||
|
: Resource(File::ParseName_8(filePath)), sampleRate(0), dataType(DataType::FLOAT), byteDepth(0), channels(0),
|
||||||
|
frames(0), length(0.0f), data(nullptr), peak(nullptr)
|
||||||
|
{
|
||||||
|
AddType("Audio");
|
||||||
|
|
||||||
|
File file(filePath, Mode::READ, Disposition::OPEN);
|
||||||
|
Str_8 ext = file.GetExtension();
|
||||||
|
|
||||||
|
const AudioCodec* codec = GetCodec(ext);
|
||||||
|
if (!codec)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 0, "Codec not found for file extension, \"" + ext + "\".");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serializer<UInt_64> data = file.ReadSerializer_64(codec->GetEndianness(), file.Size());
|
||||||
|
|
||||||
|
file.Release();
|
||||||
|
|
||||||
|
codec->Decode(data, this);
|
||||||
|
}
|
||||||
|
|
||||||
Audio::Audio(Str_8 id, const UInt_64 sampleRate, const DataType dataType, const UInt_8 channels, const UInt_64 frames, const Byte* const data)
|
Audio::Audio(Str_8 id, const UInt_64 sampleRate, const DataType dataType, const UInt_8 channels, const UInt_64 frames, const Byte* const data)
|
||||||
: Resource((Str_8&&)id), dataType(dataType), byteDepth(ToByteDepth(dataType)), sampleRate(sampleRate),
|
: Resource((Str_8&&)id), dataType(dataType), byteDepth(ToByteDepth(dataType)), sampleRate(sampleRate),
|
||||||
channels(channels), frames(frames), length((float)frames / (float)sampleRate),
|
channels(channels), frames(frames), length((float)frames / (float)sampleRate),
|
||||||
@ -105,13 +128,6 @@ namespace ehs
|
|||||||
AddType("Audio");
|
AddType("Audio");
|
||||||
}
|
}
|
||||||
|
|
||||||
Audio::Audio(Str_8 id)
|
|
||||||
: Resource((Str_8&&)id), sampleRate(0), dataType(DataType::FLOAT), byteDepth(0), channels(0),
|
|
||||||
frames(0), length(0.0f), data(nullptr), peak(nullptr)
|
|
||||||
{
|
|
||||||
AddType("Audio");
|
|
||||||
}
|
|
||||||
|
|
||||||
Audio::Audio(Audio&& audio) noexcept
|
Audio::Audio(Audio&& audio) noexcept
|
||||||
: Resource((Resource&&)audio), sampleRate(audio.sampleRate), dataType(audio.dataType),
|
: Resource((Resource&&)audio), sampleRate(audio.sampleRate), dataType(audio.dataType),
|
||||||
byteDepth(audio.byteDepth), channels(audio.channels), frames(audio.frames), length(audio.length),
|
byteDepth(audio.byteDepth), channels(audio.channels), frames(audio.frames), length(audio.length),
|
||||||
@ -853,7 +869,7 @@ namespace ehs
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Audio::ToFile(const Str_8& filePath) const
|
bool Audio::Export(const Str_8& filePath) const
|
||||||
{
|
{
|
||||||
Str_8 ext = File::ParseExt_8(filePath);
|
Str_8 ext = File::ParseExt_8(filePath);
|
||||||
|
|
||||||
@ -874,96 +890,6 @@ namespace ehs
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Audio Audio::FromFile(const Str_8& filePath)
|
|
||||||
{
|
|
||||||
File file(filePath, Mode::READ, Disposition::OPEN);
|
|
||||||
Str_8 ext = file.GetExtension();
|
|
||||||
|
|
||||||
Audio result(file.GetName());
|
|
||||||
|
|
||||||
const AudioCodec* codec = GetCodec(ext);
|
|
||||||
if (!codec)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 0, "Codec not found for file extension, \"" + ext + "\".");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Serializer<UInt_64> data = file.ReadSerializer_64(codec->GetEndianness(), file.Size());
|
|
||||||
|
|
||||||
file.Release();
|
|
||||||
|
|
||||||
if (!codec->Decode(data, &result))
|
|
||||||
return {};
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Audio* Audio::FromFile_Heap(const Str_8& filePath)
|
|
||||||
{
|
|
||||||
File file(filePath, Mode::READ, Disposition::OPEN);
|
|
||||||
Str_8 ext = file.GetExtension();
|
|
||||||
|
|
||||||
Audio* result = nullptr;
|
|
||||||
|
|
||||||
const AudioCodec* codec = GetCodec(ext);
|
|
||||||
if (!codec)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 0, "Codec not found for file extension, \"" + ext + "\".");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = new Audio(file.GetName());
|
|
||||||
|
|
||||||
Serializer<UInt_64> data = file.ReadSerializer_64(codec->GetEndianness(), file.Size());
|
|
||||||
|
|
||||||
file.Release();
|
|
||||||
|
|
||||||
if (!codec->Decode(data, result))
|
|
||||||
{
|
|
||||||
delete result;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Audio Audio::FromFile(const Str_8& filePath, const DataType required)
|
|
||||||
{
|
|
||||||
Audio result = std::move(FromFile(filePath));
|
|
||||||
if (!result.data)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
result.ToDataType(required);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Audio* Audio::FromFile_Heap(const Str_8& filePath, const DataType required)
|
|
||||||
{
|
|
||||||
Audio* result = FromFile_Heap(filePath);
|
|
||||||
if (!result)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
result->ToDataType(required);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Audio Audio::FromData(Str_8 id, const Str_8& ext, Serializer<UInt_64>& data)
|
|
||||||
{
|
|
||||||
Audio result((Str_8&&)id);
|
|
||||||
|
|
||||||
const AudioCodec* codec = GetCodec(ext);
|
|
||||||
if (!codec)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 0, "Codec not found for file extension, \"" + ext + "\".");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!codec->Decode(data, &result))
|
|
||||||
return {};
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Audio::ToMono(const UInt_64 newFrameCount, Byte* newData, const UInt_64 frameOffset) const
|
void Audio::ToMono(const UInt_64 newFrameCount, Byte* newData, const UInt_64 frameOffset) const
|
||||||
{
|
{
|
||||||
switch (dataType)
|
switch (dataType)
|
||||||
@ -1948,4 +1874,213 @@ namespace ehs
|
|||||||
|
|
||||||
*(SInt_64*)newPeak = (SInt_64)((float)*(SInt_32*)peak / (float)EHS_SINT_32_MAX * (float)EHS_SINT_64_MAX);
|
*(SInt_64*)newPeak = (SInt_64)((float)*(SInt_32*)peak / (float)EHS_SINT_32_MAX * (float)EHS_SINT_64_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EncodeEHA(const ehs::AudioCodec* const codec, ehs::Serializer<ehs::UInt_64>& out, const ehs::Audio* const in)
|
||||||
|
{
|
||||||
|
Serializer<UInt_64> result(codec->GetEndianness());
|
||||||
|
result.WriteVersion({1, 0, 0});
|
||||||
|
result.Write(in->GetSampleRate());
|
||||||
|
result.Write(in->GetDataType());
|
||||||
|
result.Write(in->GetByteDepth());
|
||||||
|
result.Write(in->GetChannels());
|
||||||
|
result.Write(in->GetFrameCount());
|
||||||
|
|
||||||
|
UInt_64 size = in->GetSize();
|
||||||
|
UInt_8 byteDepth = in->GetByteDepth();
|
||||||
|
|
||||||
|
result.Resize(result.Size() + size + byteDepth);
|
||||||
|
Util::Copy(&result[result.GetOffset()], &in[0], size);
|
||||||
|
result.SetOffset(result.GetOffset() + size);
|
||||||
|
|
||||||
|
Util::Copy(&result[result.GetOffset()], in->GetPeak(), byteDepth);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DecodeEHA(const ehs::AudioCodec* const codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Audio* const out)
|
||||||
|
{
|
||||||
|
Version version = in.ReadVersion();
|
||||||
|
if (version != Version(1, 0, 0))
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 0, "Incompatible audio file version.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt_64 sampleRate = in.Read<UInt_64>();
|
||||||
|
DataType dataType = in.Read<DataType>();
|
||||||
|
UInt_8 byteDepth = in.Read<UInt_8>();
|
||||||
|
UInt_8 channels = in.Read<UInt_8>();
|
||||||
|
UInt_64 frames = in.Read<UInt_64>();
|
||||||
|
|
||||||
|
*out = Audio(out->GetId(), sampleRate, dataType, channels, frames);
|
||||||
|
|
||||||
|
UInt_64 size = out->GetSize();
|
||||||
|
Util::Copy(&(*out)[0], &in[in.GetOffset()], size);
|
||||||
|
in.SetOffset(in.GetOffset() + size);
|
||||||
|
|
||||||
|
out->SetPeak(byteDepth, &in[in.GetOffset()]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DecodeWAV(const ehs::AudioCodec* const codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Audio* out)
|
||||||
|
{
|
||||||
|
RIFF riff(in);
|
||||||
|
|
||||||
|
if (riff.GetType() != "WAVE")
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 0, "Data is not in WAVE format.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RIFF_Chunk fmt = riff.GetChunk("fmt ");
|
||||||
|
if (!fmt.IsValid())
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 1, "Wave does not have a format chunk.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serializer<> fmtSer = fmt.GetData();
|
||||||
|
|
||||||
|
RIFF_Chunk dChunk = riff.GetChunk("data");
|
||||||
|
if (!dChunk.IsValid())
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 2, "Wave does not have a data chunk.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt_16 compression = fmtSer.Read<UInt_16>();
|
||||||
|
if (compression == 0x2)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 3, "Microsoft ADPCM compression unsupported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (compression == 0x6)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 4, "ITU G.711 a-law compression unsupported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (compression == 0x7)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 5, "ITU G.711 µ-law compression unsupported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (compression == 0x11)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 6, "IMA ADPCM compression unsupported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (compression == 0x16)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 7, "TU G.723 ADPCM (Yamaha) compression unsupported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (compression == 0x31)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 8, "GSM 6.10 compression unsupported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (compression == 0x40)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 9, "ITU G.721 ADPCM compression unsupported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (compression == 0x50)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 10, "MPEG compression unsupported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (compression == 0xFFFF)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 11, "Experimental compression unsupported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (compression != 0x1 && compression != 0x3)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 12, "Wave has unknown compression of " + Str_8::FromNum(compression) + ".");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt_16 channels = fmtSer.Read<UInt_16>();
|
||||||
|
UInt_32 sampleRate = fmtSer.Read<UInt_32>();
|
||||||
|
fmtSer.SetOffset(fmtSer.GetOffset() + 6);
|
||||||
|
UInt_8 byteDepth = (UInt_8)(fmtSer.Read<UInt_16>() / 8);
|
||||||
|
|
||||||
|
DataType dataType;
|
||||||
|
if (byteDepth == 1)
|
||||||
|
dataType = DataType::SINT_8;
|
||||||
|
else if (byteDepth == 2)
|
||||||
|
dataType = DataType::SINT_16;
|
||||||
|
else if (byteDepth == 3)
|
||||||
|
dataType = DataType::SINT_24;
|
||||||
|
else if (byteDepth == 4 && compression == 0x3)
|
||||||
|
dataType = DataType::FLOAT;
|
||||||
|
else if (byteDepth == 4)
|
||||||
|
dataType = DataType::SINT_32;
|
||||||
|
else if (byteDepth == 8)
|
||||||
|
dataType = DataType::SINT_64;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
UInt_64 size = dChunk.GetData().Size();
|
||||||
|
UInt_64 frames = size / byteDepth / channels;
|
||||||
|
|
||||||
|
*out = std::move(Audio(out->GetId(), sampleRate, dataType, channels, frames));
|
||||||
|
|
||||||
|
Serializer<> dataSer = dChunk.GetData();
|
||||||
|
|
||||||
|
for (UInt_32 i = 0; i < dataSer.Size(); i += byteDepth)
|
||||||
|
{
|
||||||
|
if (byteDepth == 1)
|
||||||
|
{
|
||||||
|
*(SInt_8*)&(*out)[i] = dataSer.Read<SInt_8>();
|
||||||
|
if ((*out)[i] > *(SInt_8*)out->GetPeak())
|
||||||
|
out->SetPeak(sizeof(SInt_8), &(*out)[i]);
|
||||||
|
}
|
||||||
|
else if (byteDepth == 2)
|
||||||
|
{
|
||||||
|
*(SInt_16*)&(*out)[i] = dataSer.Read<SInt_16>();
|
||||||
|
if (*(SInt_16*)&(*out)[i] > *(SInt_16*)out->GetPeak())
|
||||||
|
out->SetPeak(sizeof(SInt_16), &(*out)[i]);
|
||||||
|
}
|
||||||
|
else if (byteDepth == 3)
|
||||||
|
{
|
||||||
|
*(SInt_16*)&(*out)[i + 1] = dataSer.Read<SInt_16>();
|
||||||
|
(*out)[i] = dataSer.Read<Byte>();
|
||||||
|
|
||||||
|
SInt_32 signal = 0;
|
||||||
|
signal |= (*out)[i];
|
||||||
|
signal |= (*out)[i + 1] << 8;
|
||||||
|
signal |= (*out)[i + 2] << 16;
|
||||||
|
|
||||||
|
SInt_32 peak = 0;
|
||||||
|
peak |= out->GetPeak()[0];
|
||||||
|
peak |= out->GetPeak()[1] << 8;
|
||||||
|
peak |= out->GetPeak()[2] << 16;
|
||||||
|
|
||||||
|
if (signal > peak)
|
||||||
|
out->SetPeak(3, &(*out)[i]);
|
||||||
|
}
|
||||||
|
else if (byteDepth == 4 && compression == 0x3)
|
||||||
|
{
|
||||||
|
*(float*)&(*out)[i] = dataSer.Read<float>();
|
||||||
|
if (*(float*)&(*out)[i] > *(float*)out->GetPeak())
|
||||||
|
out->SetPeak(sizeof(float), &(*out)[i]);
|
||||||
|
}
|
||||||
|
else if (byteDepth == 4)
|
||||||
|
{
|
||||||
|
*(SInt_32*)&(*out)[i] = dataSer.Read<SInt_32>();
|
||||||
|
if (*(SInt_32*)&(*out)[i] > *(SInt_32*)out->GetPeak())
|
||||||
|
out->SetPeak(sizeof(SInt_32), &(*out)[i]);
|
||||||
|
}
|
||||||
|
else if (byteDepth == 8)
|
||||||
|
{
|
||||||
|
*(SInt_64*)&(*out)[i] = dataSer.Read<SInt_64>();
|
||||||
|
if (*(SInt_64*)&(*out)[i] > *(SInt_64*)out->GetPeak())
|
||||||
|
out->SetPeak(sizeof(SInt_64), &(*out)[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,4 +1,7 @@
|
|||||||
#include "ehs/io/img/Img.h"
|
#include "ehs/io/img/Img.h"
|
||||||
|
#include "ehs/io/img/PNG.h"
|
||||||
|
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
namespace ehs
|
namespace ehs
|
||||||
{
|
{
|
||||||
@ -53,6 +56,30 @@ namespace ehs
|
|||||||
AddType("Img");
|
AddType("Img");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Img::Img(const Str_8& filePath)
|
||||||
|
: byteDepth(0), channels(0), size(0), data(nullptr)
|
||||||
|
{
|
||||||
|
AddType("Img");
|
||||||
|
|
||||||
|
File file(filePath, Mode::READ, Disposition::OPEN);
|
||||||
|
Str_8 ext = file.GetExtension();
|
||||||
|
hashId = file.GetName().Hash_64();
|
||||||
|
id = file.GetName();
|
||||||
|
|
||||||
|
const ImgCodec* codec = GetCodec(ext);
|
||||||
|
if (!codec)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 0, "Codec not found for file extension, \"" + ext + "\".");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serializer<UInt_64> inData = file.ReadSerializer_64(codec->GetEndianness(), file.Size());
|
||||||
|
|
||||||
|
file.Release();
|
||||||
|
|
||||||
|
codec->Decode(inData, this);
|
||||||
|
}
|
||||||
|
|
||||||
Img::Img(Str_8 id, const UInt_8 byteDepth, const UInt_8 channels, const Vec2_u64& resolution, const Byte* const data)
|
Img::Img(Str_8 id, const UInt_8 byteDepth, const UInt_8 channels, const Vec2_u64& resolution, const Byte* const data)
|
||||||
: hashId(id.Hash_64()), id((Str_8&&)id), byteDepth(byteDepth), channels(channels), resolution(resolution),
|
: hashId(id.Hash_64()), id((Str_8&&)id), byteDepth(byteDepth), channels(channels), resolution(resolution),
|
||||||
size(resolution.x * byteDepth * channels * resolution.y), data(new Byte[size])
|
size(resolution.x * byteDepth * channels * resolution.y), data(new Byte[size])
|
||||||
@ -69,12 +96,6 @@ namespace ehs
|
|||||||
AddType("Img");
|
AddType("Img");
|
||||||
}
|
}
|
||||||
|
|
||||||
Img::Img(Str_8 id)
|
|
||||||
: hashId(id.Hash_64()), id((Str_8&&)id), byteDepth(0), channels(0), size(0), data(nullptr)
|
|
||||||
{
|
|
||||||
AddType("Img");
|
|
||||||
}
|
|
||||||
|
|
||||||
Img::Img(Img&& img) noexcept
|
Img::Img(Img&& img) noexcept
|
||||||
: BaseObj((BaseObj&&)img), hashId(img.hashId), id((Str_8&&)img.id), byteDepth(img.byteDepth),
|
: BaseObj((BaseObj&&)img), hashId(img.hashId), id((Str_8&&)img.id), byteDepth(img.byteDepth),
|
||||||
channels(img.channels), resolution(img.resolution), size(img.size), data(img.data)
|
channels(img.channels), resolution(img.resolution), size(img.size), data(img.data)
|
||||||
@ -849,7 +870,7 @@ namespace ehs
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Img::ToFile(const Str_8& filePath) const
|
bool Img::Export(const Str_8& filePath) const
|
||||||
{
|
{
|
||||||
Str_8 ext = File::ParseExt_8(filePath);
|
Str_8 ext = File::ParseExt_8(filePath);
|
||||||
|
|
||||||
@ -870,76 +891,6 @@ namespace ehs
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Img Img::FromFile(const Str_8& filePath)
|
|
||||||
{
|
|
||||||
File file(filePath, Mode::READ, Disposition::OPEN);
|
|
||||||
Str_8 ext = file.GetExtension();
|
|
||||||
|
|
||||||
Img result(file.GetName());
|
|
||||||
|
|
||||||
const ImgCodec* codec = GetCodec(ext);
|
|
||||||
if (!codec)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 0, "Codec not found for file extension, \"" + ext + "\".");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Serializer<UInt_64> data = file.ReadSerializer_64(codec->GetEndianness(), file.Size());
|
|
||||||
|
|
||||||
file.Release();
|
|
||||||
|
|
||||||
if (!codec->Decode(data, &result))
|
|
||||||
return {};
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Img* Img::FromFile_Heap(const Str_8& filePath)
|
|
||||||
{
|
|
||||||
File file(filePath, Mode::READ, Disposition::OPEN);
|
|
||||||
Str_8 ext = file.GetExtension();
|
|
||||||
|
|
||||||
Img* result = nullptr;
|
|
||||||
|
|
||||||
const ImgCodec* codec = GetCodec(ext);
|
|
||||||
if (!codec)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 0, "Codec not found for file extension, \"" + ext + "\".");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = new Img(file.GetName());
|
|
||||||
|
|
||||||
Serializer<UInt_64> data = file.ReadSerializer_64(codec->GetEndianness(), file.Size());
|
|
||||||
|
|
||||||
file.Release();
|
|
||||||
|
|
||||||
if (!codec->Decode(data, result))
|
|
||||||
{
|
|
||||||
delete result;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Img Img::FromData(Str_8 id, const Str_8& ext, Serializer<UInt_64>& data)
|
|
||||||
{
|
|
||||||
Img result((Str_8&&)id);
|
|
||||||
|
|
||||||
const ImgCodec* codec = GetCodec(ext);
|
|
||||||
if (!codec)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT("Error", 0, "Codec not found for file extension, \"" + ext + "\".");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!codec->Decode(data, &result))
|
|
||||||
return {};
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Img Img::GetNearestNeighbor(const Vec2_u64& newResolution) const
|
Img Img::GetNearestNeighbor(const Vec2_u64& newResolution) const
|
||||||
{
|
{
|
||||||
Img result(id, byteDepth, channels, newResolution);
|
Img result(id, byteDepth, channels, newResolution);
|
||||||
@ -1485,4 +1436,320 @@ namespace ehs
|
|||||||
for (UInt_64 i = 0, n = 0; i < newSize; ++i, n += 2)
|
for (UInt_64 i = 0, n = 0; i < newSize; ++i, n += 2)
|
||||||
buffer[i] = (Byte)((float)*(UInt_16*)&data[n] / (float)EHS_UINT_16_MAX * (float)EHS_UINT_8_MAX);
|
buffer[i] = (Byte)((float)*(UInt_16*)&data[n] / (float)EHS_UINT_16_MAX * (float)EHS_UINT_8_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EncodeQOI(const ehs::ImgCodec* const codec, ehs::Serializer<ehs::UInt_64>& out, const ehs::Img* in)
|
||||||
|
{
|
||||||
|
UInt_8 channels = in->GetChannels();
|
||||||
|
Vec2_u64 resolution = in->GetResolution();
|
||||||
|
|
||||||
|
UInt_32 px_len = resolution.x * resolution.y * channels;
|
||||||
|
UInt_32 px_end = px_len - channels;
|
||||||
|
|
||||||
|
Byte index[256];
|
||||||
|
for (UInt_64 i = 0; i < 64; ++i)
|
||||||
|
*(UInt_32*)&index[i * 4] = 0;
|
||||||
|
|
||||||
|
Byte prevPixel[4] = {0, 0, 0, 255};
|
||||||
|
Byte pixel[4] = {0, 0, 0, 255};
|
||||||
|
|
||||||
|
Serializer<UInt_32> result(Endianness::BE, resolution.x * resolution.y * (channels + 1) + 22);
|
||||||
|
|
||||||
|
result.Write('q');
|
||||||
|
result.Write('o');
|
||||||
|
result.Write('i');
|
||||||
|
result.Write('f');
|
||||||
|
result.Write<UInt_32>(resolution.x);
|
||||||
|
result.Write<UInt_32>(resolution.y);
|
||||||
|
result.Write(in->GetChannels());
|
||||||
|
result.Write(1);
|
||||||
|
|
||||||
|
for (UInt_32 px_pos = 0, run = 0; px_pos < px_len; px_pos += channels)
|
||||||
|
{
|
||||||
|
if (channels == 4)
|
||||||
|
{
|
||||||
|
*(UInt_32*)pixel = *(UInt_32*)&(*in)[px_pos];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pixel[0] = (*in)[px_pos];
|
||||||
|
pixel[1] = (*in)[px_pos + 1];
|
||||||
|
pixel[2] = (*in)[px_pos + 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(UInt_32*)pixel == *(UInt_32*)prevPixel)
|
||||||
|
{
|
||||||
|
run++;
|
||||||
|
if (run == 62 || px_pos == px_end)
|
||||||
|
{
|
||||||
|
result.Write<UInt_8>(0xc0 | (run - 1));
|
||||||
|
run = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (run > 0)
|
||||||
|
{
|
||||||
|
result.Write<UInt_8>(0xc0 | (run - 1));
|
||||||
|
run = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt_32 index_pos = (prevPixel[0] * 3 + prevPixel[1] * 5 + prevPixel[2] * 7 + prevPixel[3] * 11) % 64 * channels;
|
||||||
|
|
||||||
|
if (*(UInt_32*)&index[index_pos] == *(UInt_32*)pixel)
|
||||||
|
{
|
||||||
|
result.Write<UInt_8>(0x00 | (index_pos / channels));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*(UInt_32*)&index[index_pos] = *(UInt_32*)pixel;
|
||||||
|
|
||||||
|
if (pixel[3] == prevPixel[3])
|
||||||
|
{
|
||||||
|
SInt_8 vr = pixel[0] - prevPixel[0];
|
||||||
|
SInt_8 vg = pixel[1] - prevPixel[1];
|
||||||
|
SInt_8 vb = pixel[2] - prevPixel[2];
|
||||||
|
|
||||||
|
SInt_8 vg_r = vr - vg;
|
||||||
|
SInt_8 vg_b = vb - vg;
|
||||||
|
|
||||||
|
if (
|
||||||
|
vr > -3 && vr < 2 &&
|
||||||
|
vg > -3 && vg < 2 &&
|
||||||
|
vb > -3 && vb < 2
|
||||||
|
)
|
||||||
|
{
|
||||||
|
result.Write<UInt_8>(0x40 | (vr + 2) << 4 | (vg + 2) << 2 | (vb + 2));
|
||||||
|
}
|
||||||
|
else if (
|
||||||
|
vg_r > -9 && vg_r < 8 &&
|
||||||
|
vg > -33 && vg < 32 &&
|
||||||
|
vg_b > -9 && vg_b < 8
|
||||||
|
)
|
||||||
|
{
|
||||||
|
result.Write<UInt_8>(0x80 | (vg + 32));
|
||||||
|
result.Write<UInt_8>((vg_r + 8) << 4 | (vg_b + 8));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Write<UInt_8>(0xfe);
|
||||||
|
result.Write(pixel[0]);
|
||||||
|
result.Write(pixel[1]);
|
||||||
|
result.Write(pixel[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Write<UInt_8>(0xff);
|
||||||
|
result.SetEndianness(CPU::GetEndianness());
|
||||||
|
result.Write(*(UInt_32*)pixel);
|
||||||
|
result.SetEndianness(Endianness::BE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*(UInt_32*)prevPixel = *(UInt_32*)pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Write(0x100000000000000);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DecodeQOI(const ehs::ImgCodec* const codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Img* out)
|
||||||
|
{
|
||||||
|
Str_8 imgType = in.ReadStr<Char_8, UInt_64>(4);
|
||||||
|
if (imgType != "qoif")
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 0, "Given data is not in the qoif format.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt_64 width = in.Read<UInt_32>();
|
||||||
|
UInt_64 height = in.Read<UInt_32>();
|
||||||
|
|
||||||
|
UInt_8 channels = in.Read<UInt_8>();
|
||||||
|
channels = 4;
|
||||||
|
UInt_8 space = in.Read<UInt_8>();
|
||||||
|
UInt_8 bitDepth = 8;
|
||||||
|
|
||||||
|
UInt_64 size = width * channels * height;
|
||||||
|
|
||||||
|
*out = Img(out->GetId(), bitDepth / 8, channels, {width, height});
|
||||||
|
|
||||||
|
Byte prevPixel[4] = {0, 0, 0, 255};
|
||||||
|
|
||||||
|
Byte index[256];
|
||||||
|
for (UInt_64 i = 0; i < 64; ++i)
|
||||||
|
*(UInt_32*)&index[i * 4] = 0;
|
||||||
|
|
||||||
|
UInt_32 chunksLen = in.Size() - 8;
|
||||||
|
for (UInt_32 pos = 0, run = 0; pos < size; pos += channels)
|
||||||
|
{
|
||||||
|
if (run > 0)
|
||||||
|
--run;
|
||||||
|
else if (in.GetOffset() < chunksLen)
|
||||||
|
{
|
||||||
|
UInt_32 chunkType = (UInt_32)in.Read<UInt_8>();
|
||||||
|
if (chunkType == 0xfe) // RGB
|
||||||
|
{
|
||||||
|
prevPixel[0] = in.Read<UInt_8>(); // R-value
|
||||||
|
prevPixel[1] = in.Read<UInt_8>(); // G-value
|
||||||
|
prevPixel[2] = in.Read<UInt_8>(); // B-value
|
||||||
|
}
|
||||||
|
else if (chunkType == 0xff) // RGBA
|
||||||
|
{
|
||||||
|
*(UInt_32*)prevPixel = in.Read<UInt_32>();
|
||||||
|
}
|
||||||
|
else if ((chunkType & 0xc0) == 0x00) // Index
|
||||||
|
{
|
||||||
|
*(UInt_32*)prevPixel = *(UInt_32*)&index[chunkType * channels];
|
||||||
|
}
|
||||||
|
else if ((chunkType & 0xc0) == 0x40) // Diff
|
||||||
|
{
|
||||||
|
prevPixel[0] += ((chunkType >> 4) & 0x03) - 2; // R-value
|
||||||
|
prevPixel[1] += ((chunkType >> 2) & 0x03) - 2; // G-value
|
||||||
|
prevPixel[2] += (chunkType & 0x03) - 2; // B-value
|
||||||
|
}
|
||||||
|
else if ((chunkType & 0xc0) == 0x80) // Luma
|
||||||
|
{
|
||||||
|
UInt_32 mod = (UInt_32)in.Read<UInt_8>();
|
||||||
|
UInt_32 vg = (chunkType & 0x3f) - 32;
|
||||||
|
prevPixel[0] += vg - 8 + ((mod >> 4) & 0x0f); // R-value
|
||||||
|
prevPixel[1] += vg; // G-value
|
||||||
|
prevPixel[2] += vg - 8 + (mod & 0x0f); // B-value
|
||||||
|
}
|
||||||
|
else if ((chunkType & 0xc0) == 0xc0) // Run
|
||||||
|
run = (chunkType & 0x3f);
|
||||||
|
|
||||||
|
*(UInt_32*)&index[(prevPixel[0] * 3 + prevPixel[1] * 5 + prevPixel[2] * 7 + prevPixel[3] * 11) % 64 * channels] = *(UInt_32*)prevPixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channels == 4)
|
||||||
|
{
|
||||||
|
*((UInt_32*)&(*out)[pos]) = *(UInt_32*)prevPixel;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*out)[pos] = prevPixel[0];
|
||||||
|
(*out)[pos + 1] = prevPixel[1];
|
||||||
|
(*out)[pos + 2] = prevPixel[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DecodePNG(const ehs::ImgCodec* const codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Img* out)
|
||||||
|
{
|
||||||
|
PNG png(out->GetId(), in);
|
||||||
|
|
||||||
|
PNG_Chunk* ihdr = png.GetChunk("IHDR");
|
||||||
|
Serializer<UInt_64>* ihdrData = ihdr->GetData();
|
||||||
|
|
||||||
|
UInt_32 width = ihdrData->Read<UInt_32>();
|
||||||
|
UInt_32 height = ihdrData->Read<UInt_32>();
|
||||||
|
UInt_8 bitDepth = ihdrData->Read<UInt_8>();
|
||||||
|
|
||||||
|
UInt_8 colorType = ihdrData->Read<UInt_8>();
|
||||||
|
if (colorType == 3)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 1, "Color type of " + Str_8::FromNum(colorType) + " is unsupported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt_8 channels = 1;
|
||||||
|
if (colorType == 2)
|
||||||
|
channels = 3;
|
||||||
|
else if (colorType == 4)
|
||||||
|
channels = 2;
|
||||||
|
else if (colorType == 6)
|
||||||
|
channels = 4;
|
||||||
|
|
||||||
|
*out = Img(out->GetId(), bitDepth / 8, channels, {width, height});
|
||||||
|
|
||||||
|
UInt_8 compression = ihdrData->Read<UInt_8>();
|
||||||
|
if (compression)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 2, "Compression method of " + Str_8::FromNum(compression) + " is unsupported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt_8 filter = ihdrData->Read<UInt_8>();
|
||||||
|
if (filter)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 3, "Filter method of " + Str_8::FromNum(filter) + " is unsupported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt_8 interlaced = ihdrData->Read<UInt_8>();
|
||||||
|
if (interlaced)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 4, "Interlacing method of " + Str_8::FromNum(interlaced) + " is unsupported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt_32 scanline = width * (bitDepth / 8) * channels;
|
||||||
|
UInt_32 scanLineF = scanline + 1;
|
||||||
|
UInt_32 bufferSize = scanline * height + height;
|
||||||
|
|
||||||
|
Byte* buffer = new Byte[bufferSize];
|
||||||
|
|
||||||
|
PNG_Chunk* idat = png.GetChunk("IDAT");
|
||||||
|
Serializer<UInt_64>* idatData = idat->GetData();
|
||||||
|
|
||||||
|
z_stream strm = {};
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
strm.zfree = Z_NULL;
|
||||||
|
strm.opaque = Z_NULL;
|
||||||
|
strm.avail_in = idatData->Size();
|
||||||
|
strm.next_in = *idatData;
|
||||||
|
strm.avail_out = bufferSize;
|
||||||
|
strm.next_out = buffer;
|
||||||
|
|
||||||
|
int code = inflateInit(&strm);
|
||||||
|
if (code != Z_OK)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 5, "Failed to initialize zlib inflate with error #" + Str_8::FromNum(code) + ".");
|
||||||
|
delete[] buffer;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
code = inflate(&strm, Z_NO_FLUSH);
|
||||||
|
if (code != Z_STREAM_END && code != Z_OK)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 6, "Failed to zlib inflate with error #" + Str_8::FromNum(code) + ".");
|
||||||
|
delete[] buffer;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} while (strm.avail_out);
|
||||||
|
|
||||||
|
code = inflateEnd(&strm);
|
||||||
|
if (code != Z_OK)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 7, "Failed to uninitialize zlib inflate with error #" + Str_8::FromNum(code) + ".");
|
||||||
|
delete[] buffer;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UInt_32 i = 0, o = 0; i < bufferSize; i += scanLineF, o += scanline)
|
||||||
|
{
|
||||||
|
UInt_8 fCode = buffer[i];
|
||||||
|
if (fCode == 0)
|
||||||
|
PNG::FilterNone(&buffer[i + 1], &(*out)[o], bitDepth, channels, scanline);
|
||||||
|
else if (fCode == 1)
|
||||||
|
PNG::FilterSub(&buffer[i + 1], &(*out)[o], bitDepth, channels, scanline);
|
||||||
|
else if (fCode == 2)
|
||||||
|
PNG::FilterUp(&buffer[i + 1], &(*out)[o - scanline], bitDepth, channels, scanline);
|
||||||
|
else if (fCode == 3)
|
||||||
|
PNG::FilterAverage(&buffer[i + 1], &(*out)[o - scanline], bitDepth, channels, scanline);
|
||||||
|
else if (fCode == 4)
|
||||||
|
PNG::FilterPaeth(&buffer[i + 1], &(*out)[o - scanline], bitDepth, channels, scanline);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] buffer;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
@ -4,30 +4,29 @@
|
|||||||
namespace ehs
|
namespace ehs
|
||||||
{
|
{
|
||||||
ImgCodec::ImgCodec()
|
ImgCodec::ImgCodec()
|
||||||
: hashExt(0), endianness(Endianness::LE), encodeCb(nullptr), decodeCb(nullptr)
|
: hashExt(0), endianness(Endianness::LE), encoder(nullptr), decoder(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ImgCodec::ImgCodec(Str_8 id, Str_8 ext, const Endianness end,
|
ImgCodec::ImgCodec(Str_8 id, Str_8 ext, const Endianness end, EncodeImgCb encoder, DecodeImgCb decoder)
|
||||||
bool (* encodeCb)(const ImgCodec* const, Serializer<UInt_64>&, const Img*),
|
: id(std::move(id)), hashExt(ext.Hash_64()), ext(std::move(ext)), endianness(end), encoder(encoder),
|
||||||
bool (* decodeCb)(const ImgCodec* const, Serializer<UInt_64>&, Img*))
|
decoder(decoder)
|
||||||
: id(std::move(id)), hashExt(ext.Hash_64()), ext(std::move(ext)), endianness(end), encodeCb(encodeCb), decodeCb(decodeCb)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ImgCodec::ImgCodec(ImgCodec&& codec) noexcept
|
ImgCodec::ImgCodec(ImgCodec&& codec) noexcept
|
||||||
: id(std::move(codec.id)), hashExt(codec.hashExt), ext(std::move(codec.ext)), endianness(codec.endianness),
|
: id(std::move(codec.id)), hashExt(codec.hashExt), ext(std::move(codec.ext)), endianness(codec.endianness),
|
||||||
encodeCb(codec.encodeCb), decodeCb(codec.decodeCb)
|
encoder(codec.encoder), decoder(codec.decoder)
|
||||||
{
|
{
|
||||||
codec.hashExt = 0;
|
codec.hashExt = 0;
|
||||||
codec.endianness = Endianness::LE;
|
codec.endianness = Endianness::LE;
|
||||||
codec.encodeCb = nullptr;
|
codec.encoder = nullptr;
|
||||||
codec.decodeCb = nullptr;
|
codec.decoder = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImgCodec::ImgCodec(const ImgCodec& codec)
|
ImgCodec::ImgCodec(const ImgCodec& codec)
|
||||||
: id(codec.id), hashExt(codec.hashExt), ext(codec.ext), endianness(codec.endianness), encodeCb(codec.encodeCb),
|
: id(codec.id), hashExt(codec.hashExt), ext(codec.ext), endianness(codec.endianness), encoder(codec.encoder),
|
||||||
decodeCb(codec.decodeCb)
|
decoder(codec.decoder)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,13 +39,13 @@ namespace ehs
|
|||||||
hashExt = codec.hashExt;
|
hashExt = codec.hashExt;
|
||||||
ext = std::move(codec.ext);
|
ext = std::move(codec.ext);
|
||||||
endianness = codec.endianness;
|
endianness = codec.endianness;
|
||||||
encodeCb = codec.encodeCb;
|
encoder = codec.encoder;
|
||||||
decodeCb = codec.decodeCb;
|
decoder = codec.decoder;
|
||||||
|
|
||||||
codec.hashExt = 0;
|
codec.hashExt = 0;
|
||||||
codec.endianness = Endianness::LE;
|
codec.endianness = Endianness::LE;
|
||||||
codec.encodeCb = nullptr;
|
codec.encoder = nullptr;
|
||||||
codec.decodeCb = nullptr;
|
codec.decoder = nullptr;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -60,8 +59,8 @@ namespace ehs
|
|||||||
hashExt = codec.hashExt;
|
hashExt = codec.hashExt;
|
||||||
ext = codec.ext;
|
ext = codec.ext;
|
||||||
endianness = codec.endianness;
|
endianness = codec.endianness;
|
||||||
encodeCb = codec.encodeCb;
|
encoder = codec.encoder;
|
||||||
decodeCb = codec.decodeCb;
|
decoder = codec.decoder;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -88,23 +87,23 @@ namespace ehs
|
|||||||
|
|
||||||
bool ImgCodec::Encode(Serializer<UInt_64>& out, const Img* in) const
|
bool ImgCodec::Encode(Serializer<UInt_64>& out, const Img* in) const
|
||||||
{
|
{
|
||||||
if (!encodeCb)
|
if (!encoder)
|
||||||
{
|
{
|
||||||
EHS_LOG_INT("Error", 0, "Encoding is not supported for the " + id + " format.");
|
EHS_LOG_INT("Error", 0, "Encoding is not supported for the " + id + " format.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return encodeCb(this, out, in);
|
return encoder(this, out, in);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImgCodec::Decode(Serializer<UInt_64>& in, Img* out) const
|
bool ImgCodec::Decode(Serializer<UInt_64>& in, Img* out) const
|
||||||
{
|
{
|
||||||
if (!decodeCb)
|
if (!decoder)
|
||||||
{
|
{
|
||||||
EHS_LOG_INT("Error", 0, "Decoding is not supported for the " + id + " format.");
|
EHS_LOG_INT("Error", 0, "Decoding is not supported for the " + id + " format.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return decodeCb(this, in, out);
|
return decoder(this, in, out);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,54 +1,102 @@
|
|||||||
#include "ehs/io/model/Model.h"
|
#include "ehs/io/mdl/Mdl.h"
|
||||||
|
|
||||||
namespace ehs
|
namespace ehs
|
||||||
{
|
{
|
||||||
Model::Model()
|
Array<MdlCodec> Mdl::codecs;
|
||||||
: hashId(0)
|
|
||||||
|
bool Mdl::HasCodec(const UInt_64 hashExt)
|
||||||
{
|
{
|
||||||
AddType("Model");
|
for (UInt_64 i = 0; i < codecs.Size(); ++i)
|
||||||
|
if (codecs[i].GetHashExt() == hashExt)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Model::Model(const Str_8& filePath)
|
bool Mdl::HasCodec(const Str_8& ext)
|
||||||
{
|
{
|
||||||
AddType("Model");
|
return HasCodec(ext.Hash_64());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mdl::AddCodec(MdlCodec codec)
|
||||||
|
{
|
||||||
|
if (HasCodec(codec.GetHashExt()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
codecs.Push(std::move(codec));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MdlCodec* Mdl::GetCodec(const UInt_64 hashExt)
|
||||||
|
{
|
||||||
|
for (UInt_64 i = 0; i < codecs.Size(); ++i)
|
||||||
|
if (codecs[i].GetHashExt() == hashExt)
|
||||||
|
return &codecs[i];
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MdlCodec* Mdl::GetCodec(const Str_8& ext)
|
||||||
|
{
|
||||||
|
return GetCodec(ext.Hash_64());
|
||||||
|
}
|
||||||
|
|
||||||
|
Mdl::Mdl()
|
||||||
|
: hashId(0)
|
||||||
|
{
|
||||||
|
AddType("Mdl");
|
||||||
|
}
|
||||||
|
|
||||||
|
Mdl::Mdl(const Str_8& filePath)
|
||||||
|
{
|
||||||
|
AddType("Mdl");
|
||||||
|
|
||||||
File file(filePath, Mode::READ, Disposition::OPEN);
|
File file(filePath, Mode::READ, Disposition::OPEN);
|
||||||
|
Str_8 ext = file.GetExtension();
|
||||||
hashId = file.GetName().Hash_64();
|
hashId = file.GetName().Hash_64();
|
||||||
id = file.GetName();
|
id = file.GetName();
|
||||||
|
|
||||||
if (file.GetExtension() == "ehm")
|
const MdlCodec* codec = GetCodec(ext);
|
||||||
|
if (!codec)
|
||||||
{
|
{
|
||||||
FromEHM(file);
|
EHS_LOG_INT("Error", 0, "Codec not found for file extension, \"" + ext + "\".");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Serializer<UInt_64> data = file.ReadSerializer_64(codec->GetEndianness(), file.Size());
|
||||||
|
|
||||||
|
file.Release();
|
||||||
|
|
||||||
|
codec->Decode(data, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Model::Model(Str_8 id, Array<Mesh> meshes, Bone skeleton, Array<Animation> animations)
|
Mdl::Mdl(Str_8 id, Array<Mesh> meshes, Bone skeleton, Array<Animation> animations)
|
||||||
: hashId(id.Hash_64()), id((Str_8&&)id), meshes((Array<Mesh>&&)meshes), skeleton((Bone&&)skeleton),
|
: hashId(id.Hash_64()), id((Str_8&&)id), meshes((Array<Mesh>&&)meshes), skeleton((Bone&&)skeleton),
|
||||||
animations((Array<Animation>&&)animations)
|
animations((Array<Animation>&&)animations)
|
||||||
{
|
{
|
||||||
AddType("Model");
|
AddType("Mdl");
|
||||||
}
|
}
|
||||||
|
|
||||||
Model::Model(Str_8 id, Array<Mesh> meshes, Bone skeleton)
|
Mdl::Mdl(Str_8 id, Array<Mesh> meshes, Bone skeleton)
|
||||||
: hashId(id.Hash_64()), id((Str_8&&)id), meshes((Array<Mesh>&&)meshes), skeleton((Bone&&)skeleton)
|
: hashId(id.Hash_64()), id((Str_8&&)id), meshes((Array<Mesh>&&)meshes), skeleton((Bone&&)skeleton)
|
||||||
{
|
{
|
||||||
AddType("Model");
|
AddType("Mdl");
|
||||||
}
|
}
|
||||||
|
|
||||||
Model::Model(Str_8 id, Array<Mesh> meshes)
|
Mdl::Mdl(Str_8 id, Array<Mesh> meshes)
|
||||||
: hashId(id.Hash_64()), id((Str_8&&)id), meshes((Array<Mesh>&&)meshes)
|
: hashId(id.Hash_64()), id((Str_8&&)id), meshes((Array<Mesh>&&)meshes)
|
||||||
{
|
{
|
||||||
AddType("Model");
|
AddType("Mdl");
|
||||||
}
|
}
|
||||||
|
|
||||||
Model::Model(Model&& model) noexcept
|
Mdl::Mdl(Mdl&& model) noexcept
|
||||||
: BaseObj((BaseObj&&)model), hashId(model.hashId), id((Str_8&&)model.id), meshes((Array<Mesh>&&)model.meshes),
|
: BaseObj((BaseObj&&)model), hashId(model.hashId), id((Str_8&&)model.id), meshes((Array<Mesh>&&)model.meshes),
|
||||||
skeleton((Bone&&)model.skeleton), animations((Array<Animation>&&)model.animations)
|
skeleton((Bone&&)model.skeleton), animations((Array<Animation>&&)model.animations)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Model& Model::operator=(Model&& model) noexcept
|
Mdl& Mdl::operator=(Mdl&& model) noexcept
|
||||||
{
|
{
|
||||||
if (this == &model)
|
if (this == &model)
|
||||||
return *this;
|
return *this;
|
||||||
@ -66,40 +114,40 @@ namespace ehs
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::Release()
|
void Mdl::Release()
|
||||||
{
|
{
|
||||||
meshes.Clear();
|
meshes.Clear();
|
||||||
skeleton = {};
|
skeleton = {};
|
||||||
animations.Clear();
|
animations.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt_64 Model::GetHashId() const
|
UInt_64 Mdl::GetHashId() const
|
||||||
{
|
{
|
||||||
return hashId;
|
return hashId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::SetId(Str_8 newId)
|
void Mdl::SetId(Str_8 newId)
|
||||||
{
|
{
|
||||||
hashId = newId.Hash_64();
|
hashId = newId.Hash_64();
|
||||||
id = (Str_8&&)newId;
|
id = (Str_8&&)newId;
|
||||||
}
|
}
|
||||||
|
|
||||||
Str_8 Model::GetId() const
|
Str_8 Mdl::GetId() const
|
||||||
{
|
{
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Array<Mesh>& Model::GetMeshes() const
|
const Array<Mesh>& Mdl::GetMeshes() const
|
||||||
{
|
{
|
||||||
return meshes;
|
return meshes;
|
||||||
}
|
}
|
||||||
|
|
||||||
Array<Mesh>& Model::GetMeshes()
|
Array<Mesh>& Mdl::GetMeshes()
|
||||||
{
|
{
|
||||||
return meshes;
|
return meshes;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh* Model::GetMesh(const UInt_64 inHashId)
|
Mesh* Mdl::GetMesh(const UInt_64 inHashId)
|
||||||
{
|
{
|
||||||
for (UInt_64 i = 0; i < meshes.Size(); ++i)
|
for (UInt_64 i = 0; i < meshes.Size(); ++i)
|
||||||
if (meshes[i].GetHashId() == inHashId)
|
if (meshes[i].GetHashId() == inHashId)
|
||||||
@ -108,22 +156,22 @@ namespace ehs
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh* Model::GetMesh(const Str_8& inId)
|
Mesh* Mdl::GetMesh(const Str_8& inId)
|
||||||
{
|
{
|
||||||
return GetMesh(inId.Hash_64());
|
return GetMesh(inId.Hash_64());
|
||||||
}
|
}
|
||||||
|
|
||||||
const Bone& Model::GetSkeleton() const
|
const Bone& Mdl::GetSkeleton() const
|
||||||
{
|
{
|
||||||
return skeleton;
|
return skeleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bone& Model::GetSkeleton()
|
Bone& Mdl::GetSkeleton()
|
||||||
{
|
{
|
||||||
return skeleton;
|
return skeleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
Animation* Model::GetAnimation(const UInt_64 inHashId)
|
Animation* Mdl::GetAnimation(const UInt_64 inHashId)
|
||||||
{
|
{
|
||||||
for (UInt_64 i = 0; i < animations.Size(); ++i)
|
for (UInt_64 i = 0; i < animations.Size(); ++i)
|
||||||
if (animations[i].GetHashId() == inHashId)
|
if (animations[i].GetHashId() == inHashId)
|
||||||
@ -132,39 +180,47 @@ namespace ehs
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Array<Animation>& Model::GetAnimations() const
|
const Array<Animation>& Mdl::GetAnimations() const
|
||||||
{
|
{
|
||||||
return animations;
|
return animations;
|
||||||
}
|
}
|
||||||
|
|
||||||
Array<Animation>& Model::GetAnimations()
|
Array<Animation>& Mdl::GetAnimations()
|
||||||
{
|
{
|
||||||
return animations;
|
return animations;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::Calculate()
|
void Mdl::Calculate()
|
||||||
{
|
{
|
||||||
for (UInt_64 i = 0; i < meshes.Size(); ++i)
|
for (UInt_64 i = 0; i < meshes.Size(); ++i)
|
||||||
meshes[i].Calculate();
|
meshes[i].Calculate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::Export(const Str_8& filePath, const ModelEncoding encoding)
|
bool Mdl::Export(const Str_8& filePath) const
|
||||||
{
|
{
|
||||||
File file(filePath, Mode::WRITE, Disposition::OPEN_PERSISTENT);
|
Str_8 ext = File::ParseExt_8(filePath);
|
||||||
|
|
||||||
switch (encoding)
|
const MdlCodec* codec = GetCodec(ext);
|
||||||
|
if (!codec)
|
||||||
{
|
{
|
||||||
case ModelEncoding::EHM:
|
EHS_LOG_INT("Error", 0, "Codec not found for file extension, \"" + ext + "\".");
|
||||||
{
|
return false;
|
||||||
ToEHM(file);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Serializer<UInt_64> result;
|
||||||
|
if (!codec->Encode(result, this))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
File file(filePath, Mode::WRITE, Disposition::CREATE_PERSISTENT);
|
||||||
|
file.WriteSerializer_64(result);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::ToEHM(File& file)
|
bool EncodeEHM(const MdlCodec* const codec, Serializer<UInt_64>& data, const Mdl* const mdl)
|
||||||
{
|
{
|
||||||
Serializer<UInt_64> data(Endianness::LE);
|
const Array<Mesh>& meshes = mdl->GetMeshes();
|
||||||
|
|
||||||
data.WriteVersion({1, 0, 0});
|
data.WriteVersion({1, 0, 0});
|
||||||
data.Write<UInt_64>(meshes.Size());
|
data.Write<UInt_64>(meshes.Size());
|
||||||
|
|
||||||
@ -184,24 +240,23 @@ namespace ehs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
file.WriteSerializer_64(data);
|
return true;
|
||||||
file.Truncate(data.Size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::FromEHM(File& file)
|
bool DecodeEHM(const MdlCodec* const codec, Serializer<UInt_64>& data, Mdl* const mdl)
|
||||||
{
|
{
|
||||||
Serializer<UInt_64> data = file.ReadSerializer_64(Endianness::LE, file.Size());
|
|
||||||
|
|
||||||
Version ver = data.ReadVersion();
|
Version ver = data.ReadVersion();
|
||||||
if (ver != Version(1, 0, 0))
|
if (ver != Version(1, 0, 0))
|
||||||
{
|
{
|
||||||
EHS_LOG_INT("Error", 0, "Cannot decode EHM file version " + Str_8::FromNum(ver.major) + "." +
|
EHS_LOG_INT("Error", 0, "Cannot decode EHM file version " + Str_8::FromNum(ver.major) + "." +
|
||||||
Str_8::FromNum(ver.minor) + "." + Str_8::FromNum(ver.patch) +
|
Str_8::FromNum(ver.minor) + "." + Str_8::FromNum(ver.patch) +
|
||||||
", must be version 0.0.0.");
|
", must be version 0.0.0.");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Array<Mesh>& meshes = mdl->GetMeshes();
|
||||||
meshes.Resize(data.Read<UInt_64>());
|
meshes.Resize(data.Read<UInt_64>());
|
||||||
|
|
||||||
for (UInt_64 i = 0; i < meshes.Size(); ++i)
|
for (UInt_64 i = 0; i < meshes.Size(); ++i)
|
||||||
{
|
{
|
||||||
meshes[i].SetId(data.ReadStr<Char_8, UInt_64>());
|
meshes[i].SetId(data.ReadStr<Char_8, UInt_64>());
|
||||||
@ -220,6 +275,7 @@ namespace ehs
|
|||||||
|
|
||||||
meshes[i].SetIndices(data.ReadArray<UInt_32, UInt_64>());
|
meshes[i].SetIndices(data.ReadArray<UInt_32, UInt_64>());
|
||||||
|
|
||||||
|
Bone& skeleton = mdl->GetSkeleton();
|
||||||
UInt_8 boneCount = data.Read<UInt_8>();
|
UInt_8 boneCount = data.Read<UInt_8>();
|
||||||
for (UInt_8 b = 0; b < boneCount; ++b)
|
for (UInt_8 b = 0; b < boneCount; ++b)
|
||||||
{
|
{
|
||||||
@ -237,14 +293,16 @@ namespace ehs
|
|||||||
if (!parent)
|
if (!parent)
|
||||||
{
|
{
|
||||||
EHS_LOG_INT("Error", 0, "Invalid bone order.");
|
EHS_LOG_INT("Error", 0, "Invalid bone order.");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
parent->AddBone({name, b, localBindTrans, invBindTrans});
|
parent->AddBone({name, b, localBindTrans, invBindTrans});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
animations = Array<Animation>(data.Read<UInt_64>());
|
Array<Animation>& animations = mdl->GetAnimations();
|
||||||
|
animations.Resize(data.Read<UInt_64>());
|
||||||
|
|
||||||
for (UInt_64 a = 0; a < animations.Size(); ++a)
|
for (UInt_64 a = 0; a < animations.Size(); ++a)
|
||||||
{
|
{
|
||||||
Str_8 animId = data.ReadStr<Char_8, UInt_64>();
|
Str_8 animId = data.ReadStr<Char_8, UInt_64>();
|
||||||
@ -271,5 +329,7 @@ namespace ehs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
108
src/io/model/MdlCodec.cpp
Normal file
108
src/io/model/MdlCodec.cpp
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#include "ehs/io/mdl/MdlCodec.h"
|
||||||
|
|
||||||
|
namespace ehs
|
||||||
|
{
|
||||||
|
MdlCodec::MdlCodec()
|
||||||
|
: hashExt(0), endianness(Endianness::LE), encoder(nullptr), decoder(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MdlCodec::MdlCodec(Str_8 id, Str_8 ext, const Endianness end, EnocdeMdlCb encoder, DecodeMdlCb decoder)
|
||||||
|
: id(std::move(id)), hashExt(ext.Hash_64()), ext(std::move(ext)), endianness(end), encoder(encoder),
|
||||||
|
decoder(decoder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MdlCodec::MdlCodec(MdlCodec&& codec) noexcept
|
||||||
|
: id(std::move(codec.id)), hashExt(codec.hashExt), ext(std::move(codec.ext)), endianness(codec.endianness),
|
||||||
|
encoder(codec.encoder), decoder(codec.decoder)
|
||||||
|
{
|
||||||
|
codec.hashExt = 0;
|
||||||
|
codec.endianness = Endianness::LE;
|
||||||
|
codec.encoder = nullptr;
|
||||||
|
codec.decoder = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MdlCodec::MdlCodec(const MdlCodec& codec)
|
||||||
|
: id(codec.id), hashExt(codec.hashExt), ext(codec.ext), endianness(codec.endianness), encoder(codec.encoder),
|
||||||
|
decoder(codec.decoder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MdlCodec& MdlCodec::operator=(MdlCodec&& codec) noexcept
|
||||||
|
{
|
||||||
|
if (this == &codec)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
id = std::move(codec.id);
|
||||||
|
hashExt = codec.hashExt;
|
||||||
|
ext = std::move(codec.ext);
|
||||||
|
endianness = codec.endianness;
|
||||||
|
encoder = codec.encoder;
|
||||||
|
decoder = codec.decoder;
|
||||||
|
|
||||||
|
codec.hashExt = 0;
|
||||||
|
codec.endianness = Endianness::LE;
|
||||||
|
codec.encoder = nullptr;
|
||||||
|
codec.decoder = nullptr;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MdlCodec& MdlCodec::operator=(const MdlCodec& codec)
|
||||||
|
{
|
||||||
|
if (this == &codec)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
id = codec.id;
|
||||||
|
hashExt = codec.hashExt;
|
||||||
|
ext = codec.ext;
|
||||||
|
endianness = codec.endianness;
|
||||||
|
encoder = codec.encoder;
|
||||||
|
decoder = codec.decoder;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Str_8 MdlCodec::GetId() const
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt_64 MdlCodec::GetHashExt() const
|
||||||
|
{
|
||||||
|
return hashExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
Str_8 MdlCodec::GetExt() const
|
||||||
|
{
|
||||||
|
return ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
Endianness MdlCodec::GetEndianness() const
|
||||||
|
{
|
||||||
|
return endianness;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MdlCodec::Encode(Serializer<UInt_64>& out, const Mdl* in) const
|
||||||
|
{
|
||||||
|
if (!encoder)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 0, "Encoding is not supported for the " + id + " format.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder(this, out, in);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MdlCodec::Decode(Serializer<UInt_64>& in, Mdl* out) const
|
||||||
|
{
|
||||||
|
if (!decoder)
|
||||||
|
{
|
||||||
|
EHS_LOG_INT("Error", 0, "Decoding is not supported for the " + id + " format.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return decoder(this, in, out);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user