160 lines
3.9 KiB
C++
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>();
|
|
}
|
|
}
|
|
}
|
|
|