#include #include #include #include //dynamically link tomlcpp if it becomes common in repositories #include #include #define BUFFER_SIZE_MODEL_DESC 8192 // 8 KiB #define BUFFER_SIZE_TEXTURE 16777220 // 16 MiB #define SUPPORTED_MODEL_MAJOR 0 #define SUPPORTED_MODEL_MINOR 2 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; } // get format table auto format = modelDesc.table->getTable("format"); if (!format) { std::cerr << "Model does not have a format table!" << std::endl; } else { // get format version auto formatMajResult = format->getInt("version_major"); auto formatMinResult = format->getInt("version_minor"); if (formatMajResult.first && formatMinResult.first) { // check format version if (formatMajResult.second != SUPPORTED_MODEL_MAJOR || formatMinResult.second > SUPPORTED_MODEL_MINOR ) { std::cerr << "Model format version " << formatMajResult.second << "." << formatMinResult.second << " is unsupported! This version of " << PROJECT_NAME << " supports model file version " << SUPPORTED_MODEL_MAJOR << ".0 to version " << SUPPORTED_MODEL_MAJOR << "." << SUPPORTED_MODEL_MINOR << std::endl; } } else { std::cerr << "Model does not define a format version!" << std::endl; } } // get model info table auto modelInfo = modelDesc.table->getTable("model_info"); if (!modelInfo) { std::cerr << "Model does not have a model_info table!" << std::endl; } else { // get name auto nameResult = modelInfo->getString("name"); if (!nameResult.first) { std::cerr << "Model does not have a name!" << std::endl; } else { name = nameResult.second; } } // parse parts 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); } } // rotation and scale factor auto rotFacResult = partsVec[i].getDouble("rot_factor"); auto scaleFacResult = partsVec[i].getDouble("scale_factor"); if (rotFacResult.first) { newPart.setRotationFactor((float)rotFacResult.second); } if (scaleFacResult.first) { newPart.setScaleFactor((float)scaleFacResult.second); } // 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); } } std::string Model::getName() { return name; }