#include "xmlModelReader.h" #include "mesh.h" #include "skeleton.h" #include "bone.h" #include "animation.h" #include "vector.h" #include "animationController.h" #include "animatable.h" #include "modelAsset.h" #include #include using namespace std; using namespace tinyxml2; namespace vb01{ XmlModelReader *xmlModelReader = nullptr; XmlModelReader* XmlModelReader::getSingleton(){ if(!xmlModelReader) xmlModelReader = new XmlModelReader(); return xmlModelReader; } Asset* XmlModelReader::readAsset(string path){ XMLDocument *doc = new XMLDocument(); doc->LoadFile(path.c_str()); XMLElement *root = doc->FirstChildElement(); ModelAsset *asset = new ModelAsset(); asset->path = path; asset->rootNode = new Node(); assetRootNode = asset->rootNode; for(XMLElement *ch = root->FirstChildElement(); ch; ch = ch->NextSiblingElement()) assetRootNode->attachChild(processNode(assetRootNode, ch)); vector descendants; assetRootNode->getDescendants(descendants); setupDrivers(descendants); delete doc; return asset; } void XmlModelReader::setupDrivers(vector descendants){ for(pair pair : driversByNodeNames){ for(Node *desc : descendants){ int dotId = pair.first.find_first_of("."); string driverNodeName = (dotId == string::npos ? pair.first : pair.first.substr(dotId + 1)); if(driverNodeName == desc->getName()) desc->addDriver(pair.second); } } } //TODO remove the 4 literal for bone weights and indices Mesh* XmlModelReader::processMesh(XMLElement *meshEl){ int numVertPos = atoi(meshEl->Attribute("num_vertex_pos")); int numVertexGroups = atoi(meshEl->Attribute("num_vertex_groups")); const char *tagName = "vertdata"; Vector3 *vertPos = new Vector3[numVertPos]; float **weights = new float*[numVertPos]; int **boneIndices = new int*[numVertPos], i = 0; for(XMLElement *vertEl = meshEl->FirstChildElement(tagName); vertEl && strcmp(vertEl->Name(), tagName) == 0, i < numVertPos; vertEl = vertEl->NextSiblingElement(), i++){ float posX = atof(vertEl->Attribute("px")); float posY = atof(vertEl->Attribute("py")); float posZ = atof(vertEl->Attribute("pz")); vertPos[i] = Vector3(posX, posY, posZ); weights[i] = new float[4]; boneIndices[i] = new int[4]; for(int j = 0; j < 4; j++){ weights[i][j] = 0; boneIndices[i][j] = -1; } int boneIndex = 0, j = 0; for(XMLElement *weightEl = vertEl->FirstChildElement("weight"); weightEl, j < numVertexGroups; weightEl = weightEl->NextSiblingElement(), j++){ float w = atof(weightEl->Attribute("value")); if(w > 0){ weights[i][boneIndex] = w; boneIndices[i][boneIndex] = j; boneIndex++; } } } string *vertexGroups = new string[numVertexGroups]; tagName = "vertexgroup"; i = 0; if(numVertexGroups > 0) for(XMLElement *vertGroupEl = meshEl->FirstChildElement(tagName); vertGroupEl && strcmp(vertGroupEl->Name(), tagName) == 0 && i < numVertexGroups; vertGroupEl = vertGroupEl->NextSiblingElement(), i++) vertexGroups[i] = vertGroupEl->Attribute("name"); i = 0; int numVertices = 3 * atoi(meshEl->Attribute("num_faces")); MeshData::Vertex *vertices = new MeshData::Vertex[numVertices]; tagName = "vert"; u32 *indices = new u32[numVertices]; Vector3 *normals = new Vector3[numVertices]; vector vertIds; for(XMLElement *vertEl = meshEl->FirstChildElement(tagName); vertEl && strcmp(vertEl->Name(), tagName) == 0; vertEl = vertEl->NextSiblingElement(), i++){ int id = atoi(vertEl->Attribute("id")); vertIds.push_back(id); float uvX = atof(vertEl->Attribute("uvx")); float uvY = atof(vertEl->Attribute("uvy")); Vector2 uv = Vector2(uvX, uvY); float tanX = atof(vertEl->Attribute("tx")); float tanY = atof(vertEl->Attribute("ty")); float tanZ = atof(vertEl->Attribute("tz")); Vector3 tan = Vector3(tanX, tanY, tanZ); float biTanX = atof(vertEl->Attribute("bx")); float biTanY = atof(vertEl->Attribute("by")); float biTanZ = atof(vertEl->Attribute("bz")); Vector3 biTan = Vector3(biTanX, biTanY, biTanZ); normals[i] = biTan.cross(tan); MeshData::Vertex vertex; vertex.pos = &vertPos[id]; vertex.norm = &normals[id]; vertex.uv = uv; vertex.tan = tan; vertex.biTan = biTan; vertex.weights = weights[id]; vertex.boneIndices = boneIndices[id]; indices[i] = i; vertices[i] = vertex; } tagName = "shapekey"; i = 0; int numShapeKeys = atoi(meshEl->Attribute("num_shape_keys")); MeshData::ShapeKey *shapeKeys = nullptr; Vector3 **shapeKeyOffsets = nullptr; if(numShapeKeys > 0){ shapeKeys = new MeshData::ShapeKey[numShapeKeys]; shapeKeyOffsets = new Vector3*[numVertPos]; for(int i = 0; i < numVertPos; i++) shapeKeyOffsets[i] = new Vector3[100]; for(XMLElement *shapeKeyEl = meshEl->FirstChildElement(tagName); shapeKeyEl && strcmp(shapeKeyEl->Name(), tagName) == 0 && i < numShapeKeys; shapeKeyEl = shapeKeyEl->NextSiblingElement(), i++){ string name = shapeKeyEl->Attribute("name"); float minValue = atof(shapeKeyEl->Attribute("min")); float maxValue = atof(shapeKeyEl->Attribute("max")); shapeKeys[i] = MeshData::ShapeKey(name, minValue, minValue, maxValue); XMLElement *driverEl = shapeKeyEl->FirstChildElement("driver"); KeyframeChannel channel = processKeyframeChannells(driverEl)[0]; const char *nodeName = driverEl->Attribute("obj"); const char *boneName = driverEl->Attribute("bone"); Driver::VariableType type = Driver::getDriverVariableType(driverEl->Attribute("type")); driversByNodeNames.push_back(make_pair(string(nodeName) + (boneName ? "." + string(boneName) : ""), new Driver(&shapeKeys[i], channel, type))); int j = 0; for(XMLElement *vertEl = shapeKeyEl->FirstChildElement("vert"); vertEl; vertEl = vertEl->NextSiblingElement(), j++){ float posX = atof(vertEl->Attribute("px")); float posY = atof(vertEl->Attribute("py")); float posZ = atof(vertEl->Attribute("pz")); shapeKeyOffsets[j][i] = Vector3(posX, posY, posZ) - vertPos[j]; } } for(int i = 0; i < numVertices; i++) vertices[i].shapeKeyOffsets = shapeKeyOffsets[vertIds[i]]; } const char *fullSkeletonName = meshEl->Attribute("skeleton"); string name = string(meshEl->Parent()->ToElement()->Attribute("name")) + string(meshEl->Attribute("name")); MeshData meshData = MeshData( vertPos, weights, boneIndices, shapeKeyOffsets, numVertPos, normals, vertices, indices, numVertices / 3, name, vertexGroups, numVertexGroups, (fullSkeletonName ? fullSkeletonName : ""), shapeKeys, numShapeKeys ); Mesh *mesh = new Mesh(meshData); return mesh; } vector XmlModelReader::processKeyframeChannells(XMLElement *containerTag){ vector keyframeChannels; for(XMLElement *channelEl = containerTag->FirstChildElement("channel"); channelEl; channelEl = channelEl->NextSiblingElement()){ vector keyframes; for(XMLElement *keyframeEl = channelEl->FirstChildElement("keyframe"); keyframeEl; keyframeEl = keyframeEl->NextSiblingElement()){ string interpString = keyframeEl->Attribute("interpolation"); Keyframe::Interpolation interpolation = KeyframeChannel::getKeyframeInterpolationType(interpString); float frame = atof(keyframeEl->Attribute("frame")); float value = atof(keyframeEl->Attribute("value")); float leftFrame = atof(keyframeEl->Attribute("lefthandleframe")); float leftValue = atof(keyframeEl->Attribute("lefthandlevalue")); float rightFrame = atof(keyframeEl->Attribute("righthandleframe")); float rightValue = atof(keyframeEl->Attribute("righthandlevalue")); keyframes.push_back(KeyframeChannel::createKeyframe(interpolation, value, frame, leftValue, leftFrame, rightValue, rightFrame)); } string typeStr = channelEl->Attribute("type"); KeyframeChannel::Type type = KeyframeChannel::getKeyframeChannelType(typeStr); string channelName = channelEl->Attribute("name"); keyframeChannels.push_back(KeyframeChannel::createKeyframeChannel(type, channelName, keyframes)); } return keyframeChannels; } void XmlModelReader::processAnimations(XMLElement *animContainer, vector animatables){ AnimationController *animController = AnimationController::getSingleton(); const char *animTag = "animation"; for(XMLElement *animEl = animContainer->FirstChildElement(animTag); animEl && strcmp(animEl->Name(), animTag) == 0; animEl = animEl->NextSiblingElement()){ string name = animEl->Attribute("name"); Animation *animation = new Animation(name); animation->addKeyframeChannels(processKeyframeChannells(animEl)); animController->addAnimation(animation); } } Skeleton* XmlModelReader::processSkeleton(Node *root, XMLElement *skeletonEl){ XMLElement *rootBoneEl = skeletonEl->FirstChildElement("bone"); Bone *rootBone = (Bone*)processNode(root, rootBoneEl, true); root->attachChild(rootBone); Skeleton *skeleton = new Skeleton(skeletonEl->Attribute("name")); vector bones = vector{rootBone}; rootBone->getDescendants(bones); for(Node *bone : bones) skeleton->addBone((Bone*)bone, nullptr); processAnimations(skeletonEl, vector(bones.begin(), bones.end())); return skeleton; } Node* XmlModelReader::processNode(Node *parent, XMLElement *xmlEl, bool bone){ Node *node = nullptr; const char *name = xmlEl->Attribute("name"); if(bone){ float components[]{ atof(xmlEl->Attribute("hx")), atof(xmlEl->Attribute("hy")), atof(xmlEl->Attribute("hz")), atof(xmlEl->Attribute("xaxisx")), atof(xmlEl->Attribute("xaxisy")), atof(xmlEl->Attribute("xaxisz")), atof(xmlEl->Attribute("yaxisx")), atof(xmlEl->Attribute("yaxisy")), atof(xmlEl->Attribute("yaxisz")) }; float eps = pow(10, -2); for(int i = 0; i < 9; i++) if(fabs(components[i]) < eps) components[i] = 0; Vector3 head = Vector3(components[0], components[1], components[2]); Vector3 xAxis = Vector3(components[3], components[4], components[5]); Vector3 yAxis = Vector3(components[6], components[7], components[8]); float length = atof(xmlEl->Attribute("length")); Vector3 zAxis = xAxis.cross(yAxis).norm(); Vector3 pos = head; if(strcmp(xmlEl->Parent()->ToElement()->Name(), "skeleton") == 0){ parent = assetRootNode; swap(pos.y, pos.z); pos.z = -pos.z; swap(yAxis.y, yAxis.z); yAxis.z = -yAxis.z; swap(zAxis.y, zAxis.z); zAxis.z = -zAxis.z; } else pos = pos + Vector3(0, ((Bone*)parent)->getLength(), 0); node = new Bone(name, length, pos, Quaternion::QUAT_W, Vector3::VEC_IJK); node->lookAt(zAxis, yAxis); const char *ikTarget = xmlEl->Attribute("iktarget"); if(ikTarget != nullptr){ ((Bone*)node)->setIkTarget(ikTarget); int ikChainLength = atoi(xmlEl->Attribute("chainlength")); ((Bone*)node)->setIkChainLength(ikChainLength); } } else{ Vector3 pos = Vector3(atof(xmlEl->Attribute("px")), atof(xmlEl->Attribute("py")), atof(xmlEl->Attribute("pz"))); Quaternion rot = Quaternion(atof(xmlEl->Attribute("rw")), atof(xmlEl->Attribute("rx")), atof(xmlEl->Attribute("ry")), atof(xmlEl->Attribute("rz"))); Vector3 scale = Vector3(atof(xmlEl->Attribute("sx")), atof(xmlEl->Attribute("sy")), atof(xmlEl->Attribute("sz"))); node = new Node(pos, rot, scale, name); } XMLElement *skeletonTag = xmlEl->FirstChildElement("skeleton"); if(skeletonTag) node->addSkeleton(processSkeleton(node, skeletonTag)); XMLElement *meshTag = xmlEl->FirstChildElement("mesh"); if(meshTag) node->attachMesh(processMesh(meshTag)); XMLElement *lightTag = xmlEl->FirstChildElement("light"); processAnimations(xmlEl, vector{node}); const char *tagName = (bone ? "bone" : "node"); for(XMLElement *el = xmlEl->FirstChildElement(tagName); el; el = el->NextSiblingElement()) node->attachChild(processNode(node, el, bone)); return node; } }