#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 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& 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(); 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(); } } data.num_vertices = rs.Read(); 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(); 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& 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(); 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(); bone.transform = rs.Read(); } } void TSR::ParseSKAN(const std::string& str, std::vector& 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(); tps = rs.Read(); auto num_channels = rs.Read(); 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(); frame.rot = rs.Read(); frame.scl = rs.Read(); } } }