Last active
April 6, 2016 19:57
-
-
Save shakesoda/d48fba751e1773f33964c88ffe6d49c1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <map> | |
| #include <SDL2/SDL_assert.h> | |
| #include <bx/allocator.h> | |
| #include <iqm.h> | |
| #include "myon.hpp" | |
| #include "mesh.hpp" | |
| #include "fs.hpp" | |
| using namespace myon; | |
| video::mesh::mesh() : | |
| vertices(nullptr), | |
| indices(nullptr) | |
| {} | |
| video::mesh::~mesh() { | |
| if (this->vertices) { | |
| bgfx::destroyVertexBuffer(this->vbo); | |
| bx::free(myon::get_allocator(), this->vertices); | |
| } | |
| if (this->indices) { | |
| bgfx::destroyIndexBuffer(this->ibo); | |
| bx::free(myon::get_allocator(), this->indices); | |
| } | |
| } | |
| #define CHECK_SANITY(field, count, type) SDL_assert_release(header->field + (sizeof(type) * header->count) <= data.size()) | |
| bgfx::AttribType::Enum iqm2bgfxfmt(unsigned int format) { | |
| switch (format) { | |
| case IQM_UBYTE: return bgfx::AttribType::Uint8; | |
| case IQM_FLOAT: return bgfx::AttribType::Float; | |
| default: { | |
| SDL_assert_always(false); | |
| // Note: Unreachable, unless someone continues past the assertion. | |
| return bgfx::AttribType::Float; | |
| } | |
| } | |
| } | |
| bgfx::Attrib::Enum iqm2bgfxtype(unsigned int type) { | |
| switch (type) { | |
| case IQM_POSITION: return bgfx::Attrib::Position; | |
| case IQM_TEXCOORD: return bgfx::Attrib::TexCoord0; | |
| case IQM_NORMAL: return bgfx::Attrib::Normal; | |
| case IQM_TANGENT: return bgfx::Attrib::Tangent; | |
| case IQM_BLENDINDEXES: return bgfx::Attrib::Indices; | |
| case IQM_BLENDWEIGHTS: return bgfx::Attrib::Weight; | |
| case IQM_COLOR: return bgfx::Attrib::Color0; | |
| default: { | |
| SDL_assert_release(false); | |
| return bgfx::Attrib::TexCoord7; | |
| } | |
| } | |
| } | |
| bool video::read_iqm(video::mesh &mesh, const std::string &filename) { | |
| std::vector<uint8_t> data; | |
| fs::read_vector(data, filename); | |
| iqmheader *header = (iqmheader*)&data[0]; | |
| if (strncmp(header->magic, IQM_MAGIC, 16) != 0) { | |
| printf("IQM: Bad magic.\n"); | |
| return false; | |
| } | |
| if (header->version != IQM_VERSION) { | |
| printf("IQM: Unsupported version.\n"); | |
| return false; | |
| } | |
| CHECK_SANITY(ofs_vertexarrays, num_vertexarrays, iqmvertexarray); | |
| /* Read the vertex arrays, so we know what kind of vertex format to expect. | |
| * Most of the work here is just some switches. */ | |
| std::map<bgfx::Attrib::Enum, iqmvertexarray> va_map; | |
| bgfx::VertexDecl vertex_format; | |
| vertex_format.begin(); | |
| iqmvertexarray *vas = (iqmvertexarray*)&data[header->ofs_vertexarrays]; | |
| for (unsigned int i = 0; i < header->num_vertexarrays; i++) { | |
| iqmvertexarray va = vas[i]; | |
| vertex_format.add(iqm2bgfxtype(va.type), va.size, iqm2bgfxfmt(va.format)); | |
| va_map[iqm2bgfxtype(va.type)] = va; | |
| } | |
| vertex_format.end(); | |
| /* Read the vertex list into a vertex buffer. It's a bit of a pain in the | |
| * ass to get right due to the flexible vertex format... oh well. | |
| * | |
| * Almost all the trouble here is just from needing to interleave the | |
| * attributes, because we can't really guarantee anything exists first. */ | |
| size_t stride = vertex_format.getStride(); | |
| size_t size = vertex_format.getSize(header->num_vertexes); | |
| uint8_t *vertices = (uint8_t*)bx::alloc(myon::get_allocator(), size); | |
| for (auto &p : va_map) { | |
| bgfx::Attrib::Enum attr = p.first; | |
| iqmvertexarray va = p.second; | |
| for (unsigned int i = 0; i < header->num_vertexes; i++) { | |
| auto offset = vertex_format.getOffset(attr); | |
| size_t bytes = 0; | |
| switch (va.format) { | |
| case IQM_FLOAT: bytes = sizeof(float); break; | |
| case IQM_UBYTE: bytes = sizeof(uint8_t); break; | |
| default: return false; | |
| } | |
| size_t vtx_offset = (stride * i) + offset; | |
| size_t va_offset = i * (va.size * bytes) + va.offset; | |
| memcpy(&vertices[vtx_offset], &data[va_offset], va.size * bytes); | |
| } | |
| } | |
| /* Read the triangle list into an index buffer (we can't simply memcpy it | |
| * since it involves converting from uint to ushort). */ | |
| iqmtriangle *triangles = (iqmtriangle*)&data[header->ofs_triangles]; | |
| uint16_t indices_size = header->num_triangles * sizeof(uint16_t) * 3; | |
| uint16_t *indices = (uint16_t*)bx::alloc(myon::get_allocator(), indices_size); | |
| for (unsigned int i = 0; i < header->num_triangles; i++) { | |
| indices[i * 3 + 0] = triangles[i].vertex[0]; | |
| indices[i * 3 + 1] = triangles[i].vertex[1]; | |
| indices[i * 3 + 2] = triangles[i].vertex[2]; | |
| } | |
| // We've got everything now, just need to make handles for bgfx. | |
| bgfx::VertexBufferHandle vbo = bgfx::createVertexBuffer( | |
| bgfx::makeRef(vertices, size), | |
| vertex_format | |
| ); | |
| bgfx::IndexBufferHandle ibo = bgfx::createIndexBuffer( | |
| bgfx::makeRef(indices, indices_size) | |
| ); | |
| mesh.vbo = vbo; | |
| mesh.ibo = ibo; | |
| mesh.vertices = vertices; | |
| mesh.indices = indices; | |
| mesh.format = vertex_format; | |
| return true; | |
| } | |
| #undef CHECK_SANITY |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment