#include #include #include #include //dynamically link tomlcpp if it becomes common in repositories #include #define BUFFER_SIZE_MODEL_DESC 8192 // 8 KiB #define BUFFER_SIZE_TEXTURE 16777220 // 16 MiB void textureFromArchive(zip_t* archive, const char* path, ModelPart* part, size_t slot, std::string triggerName) { zip_file_t* textureFile = zip_fopen(archive, path, 0); if (textureFile != NULL) { unsigned char* textureBuffer = new unsigned char[BUFFER_SIZE_TEXTURE]; size_t textureLength = zip_fread(textureFile, textureBuffer, BUFFER_SIZE_TEXTURE-1); part->addTexture(textureBuffer, textureLength, slot, triggerName); delete [] textureBuffer; } else { std::cerr << path << " does not exist in archive!" << std::endl; } } Model::Model(const char* path) { int zipError; zip_t* archive = zip_open(path, ZIP_RDONLY, &zipError); if (!archive) { std::cerr << "Model file " << path << " does not exist!" << std::endl; return; } // get model description file (model.toml) zip_file_t* modelDescFile = zip_fopen(archive, "model.toml", 0); char modelDescBuffer[BUFFER_SIZE_MODEL_DESC]; size_t descLength = zip_fread(modelDescFile, modelDescBuffer, BUFFER_SIZE_MODEL_DESC-1); modelDescBuffer[descLength] = 0; //null-terminate // parse model.toml auto modelDesc = toml::parse(std::string(modelDescBuffer)); if (!modelDesc.table) { std::cerr << "cannot parse model.toml! " << std::endl << modelDesc.errmsg << std::endl; } auto partsDescArray = modelDesc.table->getArray("part"); auto partsVec = *partsDescArray->getTableVector(); for (int i = 0; i < partsVec.size(); i++) { ModelPart newPart; // position auto bindResult = partsVec[i].getString("bind"); if (!bindResult.first) { std::cerr << "Part " << i << " does not define a bind!" << std::endl; } else { newPart.setBind(bindResult.second); } auto parentResult = partsVec[i].getString("follow"); auto factorResult = partsVec[i].getDouble("factor"); if (parentResult.first) { newPart.setFollowTarget(parentResult.second); if (factorResult.first) { newPart.setFollowFactor((float)factorResult.second); } else { newPart.setFollowFactor(1.0f); } } // texture auto textureSingle = partsVec[i].getString("texture"); if (textureSingle.first) { // only a single texture was defined textureFromArchive(archive, textureSingle.second.c_str(), &newPart, 0, "null"); } else { auto textureArray = partsVec[i].getArray("textures"); auto textureVec = *textureArray->getTableVector().get(); if (textureVec.size() < 1) { std::cerr << "Part " << i << " does not define any textures!" << std::endl; } else { // a list of textures with triggers were defined for (int j = 0; j < textureVec.size(); j++) { auto fileResult = textureVec[j].getString("file"); auto triggerResult = textureVec[j].getString("trigger"); if (fileResult.first) { std::string trigger = triggerResult.first ? triggerResult.second : "null"; textureFromArchive(archive, fileResult.second.c_str(), &newPart, j, trigger); } } } } parts.push_back(newPart); } } void Model::draw() { for (size_t i = 0; i < parts.size(); i++) { parts[i].bindAndDraw(); } } void Model::updateTransforms(struct FaceData faceData) { for (size_t i = 0; i < parts.size(); i++) { parts[i].processFaceData(faceData); } }