RepoRole RepoBSONFactory::_makeRepoRole( const std::string &roleName, const std::string &database, const std::vector<RepoPrivilege> &privileges, const std::vector<std::pair<std::string, std::string> > &inheritedRoles ) { RepoBSONBuilder builder; builder << REPO_LABEL_ID << database + "." + roleName; builder << REPO_ROLE_LABEL_ROLE << roleName; builder << REPO_ROLE_LABEL_DATABASE << database; //====== Add Privileges ======== if (privileges.size() > 0) { RepoBSONBuilder privilegesBuilder; for (size_t i = 0; i < privileges.size(); ++i) { const auto &p = privileges[i]; RepoBSONBuilder innerBsonBuilder, actionBuilder; RepoBSON resource = BSON(REPO_ROLE_LABEL_DATABASE << p.database << REPO_ROLE_LABEL_COLLECTION << p.collection); innerBsonBuilder << REPO_ROLE_LABEL_RESOURCE << resource; for (size_t aCount = 0; aCount < p.actions.size(); ++aCount) { actionBuilder << std::to_string(aCount) << RepoRole::dbActionToString(p.actions[aCount]); } innerBsonBuilder.appendArray(REPO_ROLE_LABEL_ACTIONS, actionBuilder.obj()); privilegesBuilder << std::to_string(i) << innerBsonBuilder.obj(); } builder.appendArray(REPO_ROLE_LABEL_PRIVILEGES, privilegesBuilder.obj()); } else { repoDebug << "Creating a role with no privileges!"; } //====== Add Inherited Roles ======== if (inheritedRoles.size() > 0) { RepoBSONBuilder inheritedRolesBuilder; for (size_t i = 0; i < inheritedRoles.size(); ++i) { RepoBSON parentRole = BSON( REPO_ROLE_LABEL_ROLE << inheritedRoles[i].second << REPO_ROLE_LABEL_DATABASE << inheritedRoles[i].first ); inheritedRolesBuilder << std::to_string(i) << parentRole; } builder.appendArray(REPO_ROLE_LABEL_INHERITED_ROLES, inheritedRolesBuilder.obj()); } return RepoRole(builder.obj()); }
TransformationNode RepoBSONFactory::makeTransformationNode( const std::vector<std::vector<float>> &transMatrix, const std::string &name, const std::vector<repoUUID> &parents, const int &apiLevel) { RepoBSONBuilder builder; auto defaults = appendDefaults(REPO_NODE_TYPE_TRANSFORMATION, apiLevel, generateUUID(), name, parents); builder.appendElements(defaults); //-------------------------------------------------------------------------- // Store matrix as array of arrays uint32_t matrixSize = 4; RepoBSONBuilder rows; for (uint32_t i = 0; i < transMatrix.size(); ++i) { RepoBSONBuilder columns; for (uint32_t j = 0; j < transMatrix[i].size(); ++j){ columns << std::to_string(j) << transMatrix[i][j]; } rows.appendArray(std::to_string(i), columns.obj()); } builder.appendArray(REPO_NODE_LABEL_MATRIX, rows.obj()); return TransformationNode(builder.obj()); }
RepoProjectSettings RepoBSONFactory::makeRepoProjectSettings( const std::string &uniqueProjectName, const std::string &owner, const std::string &type, const std::string &description, const double pinSize, const double avatarHeight, const double visibilityLimit, const double speed, const double zNear, const double zFar) { RepoBSONBuilder builder; //-------------------------------------------------------------------------- // Project name if (!uniqueProjectName.empty()) builder << REPO_LABEL_ID << uniqueProjectName; //-------------------------------------------------------------------------- // Owner if (!owner.empty()) builder << REPO_LABEL_OWNER << owner; //-------------------------------------------------------------------------- // Description if (!description.empty()) builder << REPO_LABEL_DESCRIPTION << description; //-------------------------------------------------------------------------- // Type if (!type.empty()) builder << REPO_LABEL_TYPE << type; //-------------------------------------------------------------------------- // Properties (embedded sub-bson) RepoBSONBuilder propertiesBuilder; if (pinSize != REPO_DEFAULT_PROJECT_PIN_SIZE) propertiesBuilder << REPO_LABEL_PIN_SIZE << pinSize; if (avatarHeight != REPO_DEFAULT_PROJECT_AVATAR_HEIGHT) propertiesBuilder << REPO_LABEL_AVATAR_HEIGHT << avatarHeight; if (visibilityLimit != REPO_DEFAULT_PROJECT_VISIBILITY_LIMIT) propertiesBuilder << REPO_LABEL_VISIBILITY_LIMIT << visibilityLimit; if (speed != REPO_DEFAULT_PROJECT_SPEED) propertiesBuilder << REPO_LABEL_SPEED << speed; if (zNear != REPO_DEFAULT_PROJECT_ZNEAR) propertiesBuilder << REPO_LABEL_ZNEAR << zNear; if (zFar != REPO_DEFAULT_PROJECT_ZFAR) propertiesBuilder << REPO_LABEL_ZFAR << zFar; RepoBSON propertiesBSON = propertiesBuilder.obj(); if (propertiesBSON.isValid() && !propertiesBSON.isEmpty()) builder << REPO_LABEL_PROPERTIES << propertiesBSON; //-------------------------------------------------------------------------- // Add to the parent object return RepoProjectSettings(builder.obj()); }
RepoUser RepoBSONFactory::makeRepoUser( const std::string &userName, const std::string &password, const std::string &firstName, const std::string &lastName, const std::string &email, const std::list<std::pair<std::string, std::string>> &roles, const std::list<std::pair<std::string, std::string>> &apiKeys, const std::vector<char> &avatar) { RepoBSONBuilder builder; RepoBSONBuilder customDataBuilder; builder.append(REPO_LABEL_ID, generateUUID()); if (!userName.empty()) builder << REPO_USER_LABEL_USER << userName; if (!password.empty()) { RepoBSONBuilder credentialsBuilder; credentialsBuilder << REPO_USER_LABEL_CLEARTEXT << password; builder << REPO_USER_LABEL_CREDENTIALS << credentialsBuilder.obj(); } if (!firstName.empty()) customDataBuilder << REPO_USER_LABEL_FIRST_NAME << firstName; if (!lastName.empty()) customDataBuilder << REPO_USER_LABEL_LAST_NAME << lastName; if (!email.empty()) customDataBuilder << REPO_USER_LABEL_EMAIL << email; if (!apiKeys.empty()) customDataBuilder.appendArrayPair(REPO_USER_LABEL_API_KEYS, apiKeys, REPO_USER_LABEL_LABEL, REPO_USER_LABEL_KEY); if (avatar.size()) { RepoBSONBuilder avatarBuilder; avatarBuilder.appendBinary(REPO_LABEL_DATA, &avatar.at(0), sizeof(avatar.at(0))*avatar.size()); customDataBuilder << REPO_LABEL_AVATAR << avatarBuilder.obj(); } builder << REPO_USER_LABEL_CUSTOM_DATA << customDataBuilder.obj(); if (roles.size()) builder.appendArrayPair(REPO_USER_LABEL_ROLES, roles, REPO_USER_LABEL_DB, REPO_USER_LABEL_ROLE); return RepoUser(builder.obj()); }
TEST(RepoBSONTest, AppendDefaultsTest) { RepoBSONBuilder builder; RepoBSONFactory::appendDefaults( builder, "test"); RepoNode n = builder.obj(); EXPECT_FALSE(n.isEmpty()); EXPECT_EQ(4, n.nFields()); EXPECT_TRUE(n.hasField(REPO_NODE_LABEL_ID)); EXPECT_TRUE(n.hasField(REPO_NODE_LABEL_SHARED_ID)); EXPECT_TRUE(n.hasField(REPO_NODE_LABEL_API)); EXPECT_TRUE(n.hasField(REPO_NODE_LABEL_TYPE)); //Ensure existing fields doesnt' disappear RepoBSONBuilder builderWithFields; builderWithFields << "Number" << 1023; builderWithFields << "doll" << "Kitty"; RepoBSONFactory::appendDefaults( builderWithFields, "test"); }
MetadataNode RepoBSONFactory::makeMetaDataNode( RepoBSON &metadata, const std::string &mimeType, const std::string &name, const std::vector<repoUUID> &parents, const int &apiLevel) { RepoBSONBuilder builder; // Compulsory fields such as _id, type, api as well as path // and optional name auto defaults = appendDefaults(REPO_NODE_TYPE_METADATA, apiLevel, generateUUID(), name, parents); builder.appendElements(defaults); //-------------------------------------------------------------------------- // Media type if (!mimeType.empty()) builder << REPO_LABEL_MEDIA_TYPE << mimeType; //-------------------------------------------------------------------------- // Add metadata subobject if (!metadata.isEmpty()) builder << REPO_NODE_LABEL_METADATA << metadata; return MetadataNode(builder.obj()); }
RepoNode RepoNode::cloneAndRemoveParent( const repoUUID &parentID, const bool &newUniqueID) const { RepoBSONBuilder builder; RepoBSONBuilder arrayBuilder; std::vector<repoUUID> currentParents = getParentIDs(); auto parentIdx = std::find(currentParents.begin(), currentParents.end(), parentID); if (parentIdx != currentParents.end()) { currentParents.erase(parentIdx); if (newUniqueID) { builder.append(REPO_NODE_LABEL_ID, generateUUID()); } } else { repoWarning << "Trying to remove a parent that isn't really a parent!"; } if (currentParents.size() > 0) { builder.appendArray(REPO_NODE_LABEL_PARENTS, currentParents); builder.appendElementsUnique(*this); } else { builder.appendElementsUnique(removeField(REPO_NODE_LABEL_PARENTS)); } return RepoNode(builder.obj(), bigFiles); }
RepoRoleSettings RepoBSONFactory::makeRepoRoleSettings( const std::string &uniqueRoleName, const std::string &color, const std::string &description, const std::vector<std::string> &modules) { RepoBSONBuilder builder; //-------------------------------------------------------------------------- // Project name if (!uniqueRoleName.empty()) builder << REPO_LABEL_ID << uniqueRoleName; // Color if (!color.empty()) builder << REPO_LABEL_COLOR << color; // Description if (!description.empty()) builder << REPO_LABEL_DESCRIPTION << description; // Modules if (modules.size() > 0) builder.appendArray(REPO_LABEL_MODULES, modules); return RepoRoleSettings(builder.obj()); }
RepoNode RepoNode::cloneAndAddParent( const repoUUID &parentID, const bool &newUniqueID, const bool &newSharedID, const bool &overwrite) const { RepoBSONBuilder builder; RepoBSONBuilder arrayBuilder; std::vector<repoUUID> currentParents; if (!overwrite) { currentParents = getParentIDs(); } if (std::find(currentParents.begin(), currentParents.end(), parentID) == currentParents.end()) currentParents.push_back(parentID); builder.appendArray(REPO_NODE_LABEL_PARENTS, currentParents); if (newUniqueID) builder.append(REPO_NODE_LABEL_ID, generateUUID()); if (newSharedID) builder.append(REPO_NODE_LABEL_SHARED_ID, generateUUID()); builder.appendElementsUnique(*this); return RepoNode(builder.obj(), bigFiles); }
RepoBSON MeshNode::meshMappingAsBSON(const repo_mesh_mapping_t &mapping) { RepoBSONBuilder builder; builder.append(REPO_NODE_MESH_LABEL_MAP_ID, mapping.mesh_id); builder.append(REPO_NODE_MESH_LABEL_MATERIAL_ID, mapping.material_id); builder << REPO_NODE_MESH_LABEL_VERTEX_FROM << mapping.vertFrom; builder << REPO_NODE_MESH_LABEL_VERTEX_TO << mapping.vertTo; builder << REPO_NODE_MESH_LABEL_TRIANGLE_FROM << mapping.triFrom; builder << REPO_NODE_MESH_LABEL_TRIANGLE_TO << mapping.triTo; RepoBSONBuilder bbBuilder; bbBuilder.append("0", mapping.min); bbBuilder.append("1", mapping.max); builder.appendArray(REPO_NODE_MESH_LABEL_BOUNDING_BOX, bbBuilder.obj()); return builder.obj(); }
TEST(RepoBSONFactoryTest, AppendDefaultsTest) { RepoBSONBuilder builder; auto defaults = RepoBSONFactory::appendDefaults("test"); builder.appendElements(defaults); RepoNode n = builder.obj(); EXPECT_FALSE(n.isEmpty()); EXPECT_EQ(4, n.nFields()); EXPECT_TRUE(n.hasField(REPO_NODE_LABEL_ID)); EXPECT_TRUE(n.hasField(REPO_NODE_LABEL_SHARED_ID)); EXPECT_TRUE(n.hasField(REPO_NODE_LABEL_API)); EXPECT_TRUE(n.hasField(REPO_NODE_LABEL_TYPE)); //Ensure existing fields doesnt' disappear RepoBSONBuilder builderWithFields; builderWithFields << "Number" << 1023; builderWithFields << "doll" << "Kitty"; auto defaults2 = RepoBSONFactory::appendDefaults("test"); builderWithFields.appendElements(defaults2); RepoNode nWithExists = builderWithFields.obj(); EXPECT_FALSE(nWithExists.isEmpty()); EXPECT_EQ(6, nWithExists.nFields()); EXPECT_TRUE(nWithExists.hasField(REPO_NODE_LABEL_ID)); EXPECT_TRUE(nWithExists.hasField(REPO_NODE_LABEL_SHARED_ID)); EXPECT_TRUE(nWithExists.hasField(REPO_NODE_LABEL_API)); EXPECT_TRUE(nWithExists.hasField(REPO_NODE_LABEL_TYPE)); EXPECT_TRUE(nWithExists.hasField("doll")); EXPECT_EQ("Kitty", std::string(nWithExists.getStringField("doll"))); EXPECT_TRUE(nWithExists.hasField("Number")); EXPECT_EQ(nWithExists.getField("Number").Int(), 1023); }
bool RepoScene::commitStash( repo::core::handler::AbstractDatabaseHandler *handler, std::string &errMsg) { /* * Don't bother if: * 1. root node is null (not instantiated) * 2. revnode is null (unoptimised scene graph needs to be commited first */ repoUUID rev; if (!handler) { errMsg += "Cannot commit stash graph - nullptr to database handler."; return false; } if (!revNode) { errMsg += "Revision node not found, make sure the default scene graph is commited"; return false; } else { rev = revNode->getUniqueID(); } if (stashGraph.rootNode) { updateRevisionStatus(handler, repo::core::model::RevisionNode::UploadStatus::GEN_REPO_STASH); //Add rev id onto the stash nodes before committing. std::vector<repoUUID> nodes; RepoBSONBuilder builder; builder.append(REPO_NODE_STASH_REF, rev); RepoBSON revID = builder.obj(); // this should be RepoBSON? for (auto &pair : stashGraph.nodesByUniqueID) { nodes.push_back(pair.first); *pair.second = pair.second->cloneAndAddFields(&revID, false); } auto success = commitNodes(handler, nodes, GraphType::OPTIMIZED, errMsg); if (success) updateRevisionStatus(handler, repo::core::model::RevisionNode::UploadStatus::COMPLETE); return success; } else { //Not neccessarily an error. Make it visible for debugging purposes repoDebug << "Stash graph not commited. Root node is nullptr!"; return true; } }
CameraNode RepoBSONFactory::makeCameraNode( const float &aspectRatio, const float &farClippingPlane, const float &nearClippingPlane, const float &fieldOfView, const repo_vector_t &lookAt, const repo_vector_t &position, const repo_vector_t &up, const std::string &name, const int &apiLevel) { RepoBSONBuilder builder; //-------------------------------------------------------------------------- // Compulsory fields such as _id, type, api as well as path // and optional name auto defaults = appendDefaults(REPO_NODE_TYPE_CAMERA, apiLevel, generateUUID(), name); builder.appendElements(defaults); //-------------------------------------------------------------------------- // Aspect ratio builder << REPO_NODE_LABEL_ASPECT_RATIO << aspectRatio; //-------------------------------------------------------------------------- // Far clipping plane builder << REPO_NODE_LABEL_FAR << farClippingPlane; //-------------------------------------------------------------------------- // Near clipping plane builder << REPO_NODE_LABEL_NEAR << nearClippingPlane; //-------------------------------------------------------------------------- // Field of view builder << REPO_NODE_LABEL_FOV << fieldOfView; //-------------------------------------------------------------------------- // Look at vector builder.append(REPO_NODE_LABEL_LOOK_AT, lookAt); //-------------------------------------------------------------------------- // Position vector builder.append(REPO_NODE_LABEL_POSITION, position); //-------------------------------------------------------------------------- // Up vector builder.append(REPO_NODE_LABEL_UP, up); return CameraNode(builder.obj()); }
TransformationNode RepoBSONFactory::makeTransformationNode( const repo::lib::RepoMatrix &transMatrix, const std::string &name, const std::vector<repo::lib::RepoUUID> &parents, const int &apiLevel) { RepoBSONBuilder builder; auto defaults = appendDefaults(REPO_NODE_TYPE_TRANSFORMATION, apiLevel, repo::lib::RepoUUID::createUUID(), name, parents); builder.appendElements(defaults); builder.append(REPO_NODE_LABEL_MATRIX, transMatrix); return TransformationNode(builder.obj()); }
RepoBSON RepoBSONFactory::appendDefaults( const std::string &type, const unsigned int api, const repoUUID &sharedId, const std::string &name, const std::vector<repoUUID> &parents, const repoUUID &uniqueID) { RepoBSONBuilder builder; uint64_t bytesize = 0; //-------------------------------------------------------------------------- // ID field (UUID) builder.append(REPO_NODE_LABEL_ID, uniqueID); //-------------------------------------------------------------------------- // Shared ID (UUID) builder.append(REPO_NODE_LABEL_SHARED_ID, sharedId); bytesize += 2 * sizeof(repoUUID); //-------------------------------------------------------------------------- // Type if (!type.empty()) { builder << REPO_NODE_LABEL_TYPE << type; } //-------------------------------------------------------------------------- // API level builder << REPO_NODE_LABEL_API << api; //-------------------------------------------------------------------------- // Parents if (parents.size() > 0) { builder.appendArray(REPO_NODE_LABEL_PARENTS, parents); } //-------------------------------------------------------------------------- // Name if (!name.empty()) { builder << REPO_NODE_LABEL_NAME << name; } return builder.obj(); }
RepoNode RepoNode::cloneAndAddFields( const RepoBSON *changes, const bool &newUniqueID) const { RepoBSONBuilder builder; if (newUniqueID) { builder.append(REPO_NODE_LABEL_ID, generateUUID()); } builder.appendElementsUnique(*changes); builder.appendElementsUnique(*this); return RepoNode(builder.obj(), bigFiles); }
TextureNode RepoBSONFactory::makeTextureNode( const std::string &name, const char *data, const uint32_t &byteCount, const uint32_t &width, const uint32_t &height, const int &apiLevel) { RepoBSONBuilder builder; auto defaults = appendDefaults(REPO_NODE_TYPE_TEXTURE, apiLevel, generateUUID(), name); builder.appendElements(defaults); // // Width // builder << REPO_LABEL_WIDTH << width; // // Height // builder << REPO_LABEL_HEIGHT << height; // // Format TODO: replace format with MIME Type? // if (!name.empty()) { boost::filesystem::path file{ name }; std::string ext = file.extension().string(); if (!ext.empty()) builder << REPO_NODE_LABEL_EXTENSION << ext.substr(1, ext.size()); } // // Data // if (data && byteCount) builder.appendBinary( REPO_LABEL_DATA, data, byteCount); else { repoWarning << " Creating a texture node with no texture!"; } return TextureNode(builder.obj()); }
RepoNode RepoNode::cloneAndAddParent( const std::vector<repoUUID> &parentIDs) const { RepoBSONBuilder builder; RepoBSONBuilder arrayBuilder; std::vector<repoUUID> currentParents = getParentIDs(); currentParents.insert(currentParents.end(), parentIDs.begin(), parentIDs.end()); std::sort(currentParents.begin(), currentParents.end()); auto last = std::unique(currentParents.begin(), currentParents.end()); if (last != currentParents.end()) currentParents.erase(last, currentParents.end()); builder.appendArray(REPO_NODE_LABEL_PARENTS, currentParents); builder.appendElementsUnique(*this); return RepoNode(builder.obj(), bigFiles); }
bool RepoScene::loadRevision( repo::core::handler::AbstractDatabaseHandler *handler, std::string &errMsg){ bool success = true; if (!handler) { errMsg = "Cannot load revision with an empty database handler"; return false; } RepoBSON bson; repoTrace << "loading revision : " << databaseName << "." << projectName << " head Revision: " << headRevision; if (headRevision){ RepoBSONBuilder critBuilder; critBuilder.append(REPO_NODE_LABEL_SHARED_ID, branch); critBuilder << REPO_NODE_REVISION_LABEL_INCOMPLETE << BSON("$exists" << false); bson = handler->findOneByCriteria(databaseName, projectName + "." + revExt, critBuilder.obj(), REPO_NODE_REVISION_LABEL_TIMESTAMP); repoTrace << "Fetching head of revision from branch " << UUIDtoString(branch); } else{ bson = handler->findOneByUniqueID(databaseName, projectName + "." + revExt, revision); repoTrace << "Fetching revision using unique ID: " << UUIDtoString(revision); } if (bson.isEmpty()){ errMsg = "Failed: cannot find revision document from " + databaseName + "." + projectName + "." + revExt; success = false; } else{ revNode = new RevisionNode(bson); worldOffset = revNode->getCoordOffset(); } return success; }
ReferenceNode RepoBSONFactory::makeReferenceNode( const std::string &database, const std::string &project, const repoUUID &revisionID, const bool &isUniqueID, const std::string &name, const int &apiLevel) { RepoBSONBuilder builder; std::string nodeName = name.empty() ? database + "." + project : name; auto defaults = appendDefaults(REPO_NODE_TYPE_REFERENCE, apiLevel, generateUUID(), nodeName); builder.appendElements(defaults); //-------------------------------------------------------------------------- // Project owner (company or individual) if (!database.empty()) builder << REPO_NODE_REFERENCE_LABEL_OWNER << database; //-------------------------------------------------------------------------- // Project name if (!project.empty()) builder << REPO_NODE_REFERENCE_LABEL_PROJECT << project; //-------------------------------------------------------------------------- // Revision ID (specific revision if UID, branch if SID) builder.append( REPO_NODE_REFERENCE_LABEL_REVISION_ID, revisionID); //-------------------------------------------------------------------------- // Unique set if the revisionID is UID, not set if SID (branch) if (isUniqueID) builder << REPO_NODE_REFERENCE_LABEL_UNIQUE << isUniqueID; return ReferenceNode(builder.obj()); }
MaterialNode RepoBSONFactory::makeMaterialNode( const repo_material_t &material, const std::string &name, const int &apiLevel) { RepoBSONBuilder builder; // Compulsory fields such as _id, type, api as well as path // and optional name auto defaults = appendDefaults(REPO_NODE_TYPE_MATERIAL, apiLevel, generateUUID(), name); builder.appendElements(defaults); if (material.ambient.size() > 0) builder.appendArray(REPO_NODE_MATERIAL_LABEL_AMBIENT, material.ambient); if (material.diffuse.size() > 0) builder.appendArray(REPO_NODE_MATERIAL_LABEL_DIFFUSE, material.diffuse); if (material.specular.size() > 0) builder.appendArray(REPO_NODE_MATERIAL_LABEL_SPECULAR, material.specular); if (material.emissive.size() > 0) builder.appendArray(REPO_NODE_MATERIAL_LABEL_EMISSIVE, material.emissive); if (material.isWireframe) builder << REPO_NODE_MATERIAL_LABEL_WIREFRAME << material.isWireframe; if (material.isTwoSided) builder << REPO_NODE_MATERIAL_LABEL_TWO_SIDED << material.isTwoSided; if (material.opacity == material.opacity) builder << REPO_NODE_MATERIAL_LABEL_OPACITY << material.opacity; if (material.shininess == material.shininess) builder << REPO_NODE_MATERIAL_LABEL_SHININESS << material.shininess; if (material.shininessStrength == material.shininessStrength) builder << REPO_NODE_MATERIAL_LABEL_SHININESS_STRENGTH << material.shininessStrength; return MaterialNode(builder.obj()); }
RevisionNode RepoBSONFactory::makeRevisionNode( const std::string &user, const repoUUID &branch, const std::vector<repoUUID> ¤tNodes, //const std::vector<repoUUID> &added, //const std::vector<repoUUID> &removed, //const std::vector<repoUUID> &modified, const std::vector<std::string> &files, const std::vector<repoUUID> &parent, const std::vector<double> &worldOffset, const std::string &message, const std::string &tag, const int &apiLevel ) { RepoBSONBuilder builder; repoUUID uniqueID = generateUUID(); //-------------------------------------------------------------------------- // Compulsory fields such as _id, type, api as well as path auto defaults = appendDefaults(REPO_NODE_TYPE_REVISION, apiLevel, branch, "", parent, uniqueID); builder.appendElements(defaults); //-------------------------------------------------------------------------- // Author if (!user.empty()) builder << REPO_NODE_REVISION_LABEL_AUTHOR << user; //-------------------------------------------------------------------------- // Message if (!message.empty()) builder << REPO_NODE_REVISION_LABEL_MESSAGE << message; //-------------------------------------------------------------------------- // Tag if (!tag.empty()) builder << REPO_NODE_REVISION_LABEL_TAG << tag; //-------------------------------------------------------------------------- // Timestamp builder.appendTimeStamp(REPO_NODE_REVISION_LABEL_TIMESTAMP); //-------------------------------------------------------------------------- // Current Unique IDs if (currentNodes.size() > 0) builder.appendArray(REPO_NODE_REVISION_LABEL_CURRENT_UNIQUE_IDS, currentNodes); //-------------------------------------------------------------------------- // Shift for world coordinates if (worldOffset.size() > 0) builder.appendArray(REPO_NODE_REVISION_LABEL_WORLD_COORD_SHIFT, worldOffset); ////-------------------------------------------------------------------------- //// Added Shared IDs //if (added.size() > 0) // builder.appendArray(REPO_NODE_REVISION_LABEL_ADDED_SHARED_IDS, builder.createArrayBSON(added)); ////-------------------------------------------------------------------------- //// Deleted Shared IDs //if (removed.size() > 0) // builder.appendArray(REPO_NODE_REVISION_LABEL_DELETED_SHARED_IDS, builder.createArrayBSON(removed)); ////-------------------------------------------------------------------------- //// Modified Shared IDs //if (modified.size() > 0) // builder.appendArray(REPO_NODE_REVISION_LABEL_MODIFIED_SHARED_IDS, builder.createArrayBSON(modified)); //-------------------------------------------------------------------------- //-------------------------------------------------------------------------- // original files references if (files.size() > 0) { std::string uniqueIDStr = UUIDtoString(uniqueID); mongo::BSONObjBuilder arrbuilder; for (int i = 0; i < files.size(); ++i) { arrbuilder << std::to_string(i) << uniqueIDStr + files[i]; } builder.appendArray(REPO_NODE_REVISION_LABEL_REF_FILE, arrbuilder.obj()); } return RevisionNode(builder.obj()); }
bool RepoScene::loadStash( repo::core::handler::AbstractDatabaseHandler *handler, std::string &errMsg){ bool success = true; if (!handler) { errMsg += "Trying to load stash graph without a database handler!"; return false; } if (!revNode){ if (!loadRevision(handler, errMsg)) return false; } //Get the relevant nodes from the scene graph using the unique IDs stored in this revision node RepoBSONBuilder builder; builder.append(REPO_NODE_STASH_REF, revNode->getUniqueID()); std::vector<RepoBSON> nodes = handler->findAllByCriteria(databaseName, projectName + "." + stashExt, builder.obj()); if (success = nodes.size()) { repoInfo << "# of nodes in this stash scene = " << nodes.size(); success = populate(GraphType::OPTIMIZED, handler, nodes, errMsg); } else { errMsg += "stash is empty"; } return success; }
MeshNode RepoBSONFactory::makeMeshNode( const std::vector<repo_vector_t> &vertices, const std::vector<repo_face_t> &faces, const std::vector<repo_vector_t> &normals, const std::vector<std::vector<float>> &boundingBox, const std::vector<std::vector<repo_vector2d_t>> &uvChannels, const std::vector<repo_color4d_t> &colors, const std::vector<std::vector<float>> &outline, const std::string &name, const int &apiLevel) { RepoBSONBuilder builder; uint64_t bytesize = 0; //track the (approximate) size to know when we need to offload to gridFS repoUUID uniqueID = generateUUID(); auto defaults = appendDefaults(REPO_NODE_TYPE_MESH, apiLevel, generateUUID(), name, std::vector<repoUUID>(), uniqueID); bytesize += defaults.objsize(); builder.appendElements(defaults); if (!vertices.size() || !faces.size()) { repoWarning << "Creating a mesh (" << defaults.getUUIDField(REPO_NODE_LABEL_ID) << ") with no vertices/faces!"; } std::unordered_map<std::string, std::pair<std::string, std::vector<uint8_t>>> binMapping; if (boundingBox.size() > 0) { RepoBSONBuilder arrayBuilder; for (int i = 0; i < boundingBox.size(); i++) { arrayBuilder.appendArray(std::to_string(i), boundingBox[i]); bytesize += boundingBox[i].size() * sizeof(boundingBox[i][0]); } builder.appendArray(REPO_NODE_MESH_LABEL_BOUNDING_BOX, arrayBuilder.obj()); } if (outline.size() > 0) { RepoBSONBuilder arrayBuilder; for (int i = 0; i < outline.size(); i++) { arrayBuilder.appendArray(boost::lexical_cast<std::string>(i), outline[i]); bytesize += outline[i].size() * sizeof(outline[i][0]); } builder.appendArray(REPO_NODE_MESH_LABEL_OUTLINE, arrayBuilder.obj()); } /* * TODO: because mongo has a stupid internal limit of 64MB, we can't store everything in a BSON * There are 2 options * 1. store binaries in memory outside of the bson and put it into GRIDFS at the point of commit * 2. leave mongo's bson, use our own/exteral library that doesn't have this limit and database handle this at the point of commit * below uses option 1, but ideally we should be doing option 2. */ if (vertices.size() > 0) { uint64_t verticesByteCount = vertices.size() * sizeof(vertices[0]); if (verticesByteCount + bytesize >= REPO_BSON_MAX_BYTE_SIZE) { std::string bName = UUIDtoString(uniqueID) + "_vertices"; //inclusion of this binary exceeds the maximum, store separately binMapping[REPO_NODE_MESH_LABEL_VERTICES] = std::pair<std::string, std::vector<uint8_t>>(bName, std::vector<uint8_t>()); binMapping[REPO_NODE_MESH_LABEL_VERTICES].second.resize(verticesByteCount); //uint8_t will ensure it is a byte addrressing memcpy(binMapping[REPO_NODE_MESH_LABEL_VERTICES].second.data(), &vertices[0], verticesByteCount); bytesize += sizeof(bName); } else { builder.appendBinary( REPO_NODE_MESH_LABEL_VERTICES, &vertices[0], vertices.size() * sizeof(vertices[0]) ); bytesize += verticesByteCount; } } if (faces.size() > 0) { builder << REPO_NODE_MESH_LABEL_FACES_COUNT << (uint32_t)(faces.size()); // In API LEVEL 1, faces are stored as // [n1, v1, v2, ..., n2, v1, v2...] std::vector<repo_face_t>::iterator faceIt; std::vector<uint32_t> facesLevel1; for (auto &face : faces){ auto nIndices = face.size(); if (!nIndices) { repoWarning << "number of indices in this face is 0!"; } facesLevel1.push_back(nIndices); for (uint32_t ind = 0; ind < nIndices; ind++) { facesLevel1.push_back(face[ind]); } } uint64_t facesByteCount = facesLevel1.size() * sizeof(facesLevel1[0]); if (facesByteCount + bytesize >= REPO_BSON_MAX_BYTE_SIZE) { std::string bName = UUIDtoString(uniqueID) + "_faces"; //inclusion of this binary exceeds the maximum, store separately binMapping[REPO_NODE_MESH_LABEL_FACES] = std::pair<std::string, std::vector<uint8_t>>(bName, std::vector<uint8_t>()); binMapping[REPO_NODE_MESH_LABEL_FACES].second.resize(facesByteCount); //uint8_t will ensure it is a byte addrressing memcpy(binMapping[REPO_NODE_MESH_LABEL_FACES].second.data(), &facesLevel1[0], facesByteCount); bytesize += sizeof(bName); } else { builder.appendBinary( REPO_NODE_MESH_LABEL_FACES, &facesLevel1[0], facesLevel1.size() * sizeof(facesLevel1[0]) ); bytesize += facesByteCount; } } if (normals.size() > 0) { uint64_t normalsByteCount = normals.size() * sizeof(normals[0]); if (normalsByteCount + bytesize >= REPO_BSON_MAX_BYTE_SIZE) { std::string bName = UUIDtoString(uniqueID) + "_normals"; //inclusion of this binary exceeds the maximum, store separately binMapping[REPO_NODE_MESH_LABEL_NORMALS] = std::pair<std::string, std::vector<uint8_t>>(bName, std::vector<uint8_t>()); binMapping[REPO_NODE_MESH_LABEL_NORMALS].second.resize(normalsByteCount); //uint8_t will ensure it is a byte addrressing memcpy(binMapping[REPO_NODE_MESH_LABEL_NORMALS].second.data(), &normals[0], normalsByteCount); bytesize += sizeof(bName); } else { builder.appendBinary( REPO_NODE_MESH_LABEL_NORMALS, &normals[0], normals.size() * sizeof(normals[0])); bytesize += normalsByteCount; } } //if (!vertexHash.empty()) //{ // // TODO: Fix this call - needs to be fixed as int conversion is overloaded // //builder << REPO_NODE_LABEL_SHA256 << (long unsigned int)(vertexHash); //} //-------------------------------------------------------------------------- // Vertex colors if (colors.size()) { uint64_t colorsByteCount = colors.size() * sizeof(colors[0]); if (colorsByteCount + bytesize >= REPO_BSON_MAX_BYTE_SIZE) { std::string bName = UUIDtoString(uniqueID) + "_colors"; //inclusion of this binary exceeds the maximum, store separately binMapping[REPO_NODE_MESH_LABEL_COLORS] = std::pair<std::string, std::vector<uint8_t>>(bName, std::vector<uint8_t>()); binMapping[REPO_NODE_MESH_LABEL_COLORS].second.resize(colorsByteCount); //uint8_t will ensure it is a byte addrressing memcpy(binMapping[REPO_NODE_MESH_LABEL_COLORS].second.data(), &colors[0], colorsByteCount); bytesize += sizeof(bName); } else { builder.appendBinary( REPO_NODE_MESH_LABEL_COLORS, &colors[0], colors.size() * sizeof(colors[0])); bytesize += colorsByteCount; } } //-------------------------------------------------------------------------- // UV channels if (uvChannels.size() > 0) { // Could be unsigned __int64 if BSON had such construct (the closest is only __int64) builder << REPO_NODE_MESH_LABEL_UV_CHANNELS_COUNT << (uint32_t)(uvChannels.size()); std::vector<repo_vector2d_t> concatenated; for (auto it = uvChannels.begin(); it != uvChannels.end(); ++it) { std::vector<repo_vector2d_t> channel = *it; std::vector<repo_vector2d_t>::iterator cit; for (cit = channel.begin(); cit != channel.end(); ++cit) { concatenated.push_back(*cit); } } uint64_t uvByteCount = concatenated.size() * sizeof(concatenated[0]); if (uvByteCount + bytesize >= REPO_BSON_MAX_BYTE_SIZE) { std::string bName = UUIDtoString(uniqueID) + "_uv"; //inclusion of this binary exceeds the maximum, store separately binMapping[REPO_NODE_MESH_LABEL_UV_CHANNELS] = std::pair<std::string, std::vector<uint8_t>>(bName, std::vector<uint8_t>()); binMapping[REPO_NODE_MESH_LABEL_UV_CHANNELS].second.resize(uvByteCount); //uint8_t will ensure it is a byte addrressing memcpy(binMapping[REPO_NODE_MESH_LABEL_UV_CHANNELS].second.data(), &concatenated[0], uvByteCount); bytesize += sizeof(bName); } else { builder.appendBinary( REPO_NODE_MESH_LABEL_UV_CHANNELS, &concatenated[0], concatenated.size() * sizeof(concatenated[0])); bytesize += uvByteCount; } } return MeshNode(builder.obj(), binMapping); }