TSR_ECS/src/tsr/ia.cpp
2023-12-08 18:28:01 +01:00

160 lines
3.9 KiB
C++

#include "ia.hpp"
using namespace TSR;
class ReadStream {
const char* const m_data;
const char* m_pos;
const char* const m_end;
public:
ReadStream(const char* data, size_t size) : m_data(data), m_pos(data), m_end(m_pos + size) {}
void Seek(size_t pos) {
m_pos = m_data + pos;
if (m_pos > m_end)
throw ParseException("Out of range");
}
template <class T>
const T& Read() {
if (m_pos + sizeof(T) > m_end)
throw ParseException("Out of range");
auto ret_pos = m_pos;
m_pos += sizeof(T);
return *(T*)ret_pos;
}
const void* ReadBlock(size_t size) {
auto start = m_pos;
m_pos += size;
if (m_pos > m_end)
throw ParseException("Out of range");
return start;
}
const char* ReadStr() {
auto start = m_pos;
while (m_pos < m_end) {
if (*(m_pos++) == '\0')
return start;
}
throw ParseException("String not terminated");
}
};
IAData TSR::ParseIA(const std::string& str, std::vector<BoneRef>& bone_list) {
IAData data;
ReadStream rs(str.data(), str.length());
data.is_skeletal = false;
int additional_vertex_size = 0;
auto magic = rs.ReadStr();
if (!strcmp(magic, "IA8"))
data.stride = 8;
else if (!strcmp(magic, "IA2"))
data.stride = 2;
else if (!strcmp(magic, "IA3"))
data.stride = 3;
else if (!strcmp(magic, "SKIA84")) {
data.stride = 8;
data.is_skeletal = true;
additional_vertex_size = 20;
}
else
throw ParseException("Unsupported IA format");
// skip reserved header
rs.Seek(16);
if (data.is_skeletal) {
auto num_bones = rs.Read<uint32_t>();
if (num_bones >= TSR_MAX_BONES)
throw ParseException("Max bones exceeded");
bone_list.resize(num_bones);
for (auto& bone : bone_list) {
bone.name = rs.ReadStr();
bone.offset = rs.Read<glm::mat4>();
}
}
data.num_vertices = rs.Read<uint32_t>();
data.vertices_size = data.num_vertices * (sizeof(float) * data.stride + additional_vertex_size);
data.vertices_ptr = rs.ReadBlock(data.vertices_size);
data.num_indices = rs.Read<uint32_t>();
data.indices_size = data.num_indices * sizeof(uint32_t);
data.indices_ptr = rs.ReadBlock(data.indices_size);
return data;
}
void TSR::ParseSK(const std::string& str, std::vector<BoneInfo>& bone_list) {
ReadStream rs(str.data(), str.length());
auto magic = rs.ReadStr();
if (strcmp(magic, "SK") != 0)
throw ParseException("Unsupported SK format");
// header
rs.Seek(16);
auto num_bones = rs.Read<uint32_t>();
if (num_bones >= TSR_MAX_BONES)
throw ParseException("Max bones exceeded");
bone_list.resize(num_bones);
for (auto& bone : bone_list) {
bone.name = rs.ReadStr();
bone.parent_idx = rs.Read<uint8_t>();
bone.transform = rs.Read<glm::mat4>();
}
}
void TSR::ParseSKAN(const std::string& str, std::vector<SkAnimChannel>& chan_list, size_t& duration, float& tps) {
ReadStream rs(str.data(), str.length());
auto magic = rs.ReadStr();
if (strcmp(magic, "SKAN") != 0)
throw ParseException("Unsupported SKAN format");
// header
rs.Seek(16);
duration = rs.Read<uint32_t>();
tps = rs.Read<float>();
auto num_channels = rs.Read<uint32_t>();
if (num_channels >= TSR_MAX_BONES)
throw ParseException("Max channels exceeded");
chan_list.resize(num_channels);
for (auto& chan : chan_list) {
chan.name = rs.ReadStr();
chan.frames.resize(duration + 1);
for (auto& frame : chan.frames) {
frame.pos = rs.Read<glm::vec3>();
frame.rot = rs.Read<glm::quat>();
frame.scl = rs.Read<glm::vec3>();
}
}
}