//----------------------------------------------------------------------------------- GLuint Renderer::GenerateVAOHandle() { GLuint vaoID; glGenVertexArrays(1, &vaoID); ASSERT_OR_DIE(vaoID != NULL, "VAO was null"); return vaoID; }
//----------------------------------------------------------------------------------- SceneImport* FbxLoadSceneFromFile(const char* fbxFilename, const Matrix4x4& engineBasis, bool isEngineBasisRightHanded, const Matrix4x4& transform) { FbxScene* scene = nullptr; FbxManager* fbxManager = FbxManager::Create(); if (nullptr == fbxManager) { Console::instance->PrintLine("Could not create fbx manager."); DebuggerPrintf("Could not create fbx manager."); return nullptr; } FbxIOSettings* ioSettings = FbxIOSettings::Create(fbxManager, IOSROOT); //Name of object is blank, we don't care fbxManager->SetIOSettings(ioSettings); //Create an importer FbxImporter* importer = FbxImporter::Create(fbxManager, ""); bool loadSuccessful = importer->Initialize(fbxFilename, -1, fbxManager->GetIOSettings()); if (loadSuccessful) { //We have imported the FBX scene = FbxScene::Create(fbxManager, ""); bool importSuccessful = importer->Import(scene); ASSERT_OR_DIE(importSuccessful, "Scene import failed!"); } else { Console::instance->PrintLine(Stringf("Could not import scene: %s", fbxFilename)); DebuggerPrintf("Could not import scene: %s", fbxFilename); } SceneImport* import = new SceneImport(); MatrixStack4x4 matrixStack; matrixStack.Push(transform); //Set up our initial transforms Matrix4x4 sceneBasis = GetSceneBasis(scene); Matrix4x4::MatrixTranspose(&sceneBasis); if (!isEngineBasisRightHanded) { Vector3 forward = Matrix4x4::MatrixGetForward(&sceneBasis); Matrix4x4::MatrixSetForward(&sceneBasis, -forward); //3rd row or column } matrixStack.Push(sceneBasis); ImportScene(import, scene, matrixStack); FBX_SAFE_DESTROY(importer); FBX_SAFE_DESTROY(ioSettings); FBX_SAFE_DESTROY(scene); FBX_SAFE_DESTROY(fbxManager); return import; }
//----------------------------------------------------------------------------------- void AnimationMotion::ReadFromFile(const char* filename) { BinaryFileReader reader; ASSERT_OR_DIE(reader.Open(filename), "File Open failed!"); { ReadFromStream(reader); } reader.Close(); }
//----------------------------------------------------------------------------------- void AnimationMotion::WriteToFile(const char* filename) { BinaryFileWriter writer; ASSERT_OR_DIE(writer.Open(filename), "File Open failed!"); { WriteToStream(writer); } writer.Close(); }
void PathFinder::WalkClosedListAndConstructPath() { ASSERT_OR_DIE(!m_closedList.empty(), "ERROR: CAN'T CONSTRUCT PATH BECAUSE CLOSED LIST IS EMPTY"); PathNode* currNode = m_closedList.back(); while (nullptr != currNode) { m_currBestPath.push_back(currNode->m_position); currNode = currNode->m_parent; } }
//----------------------------------------------------------------------------------- void Skeleton::ReadFromStream(IBinaryReader& reader) { //FILE VERSION //Number of joints //Joint Names //Joint Heirarchy //Initial Model Space uint32_t fileVersion = 0; ASSERT_OR_DIE(reader.Read<uint32_t>(fileVersion), "Failed to read file version"); ASSERT_OR_DIE(fileVersion == FILE_VERSION, "File version didn't match!"); uint32_t numberOfJoints = 0; ASSERT_OR_DIE(reader.Read<uint32_t>(numberOfJoints), "Failed to read number of joints"); for (unsigned int i = 0; i < numberOfJoints; ++i) { const char* jointName = nullptr; reader.ReadString(jointName, 64); m_names.push_back(jointName); } for (unsigned int i = 0; i < numberOfJoints; ++i) { int index = 0; reader.Read<int>(index); m_parentIndices.push_back(index); } for (unsigned int i = 0; i < numberOfJoints; ++i) { Matrix4x4 matrix = Matrix4x4::IDENTITY; for (int j = 0; j < 16; ++j) { reader.Read<float>(matrix.data[j]); } m_boneToModelSpace.push_back(matrix); //m_boneToModelSpace.push_back(Matrix4x4((float*)reader.ReadBytes(16))); //Matrix4x4 invertedMatrix = m_boneToModelSpace[i]; //Matrix4x4::MatrixInvert(&invertedMatrix); //m_modelToBoneSpace.push_back(invertedMatrix); } }
//----------------------------------------------------------------------------------- void AnimationMotion::ReadFromStream(IBinaryReader& reader) { //FILE VERSION //Frame Count //Total Length Seconds //Framerate //Frametime //Motion name //Joint count //Keyframes uint32_t fileVersion = 0; ASSERT_OR_DIE(reader.Read<uint32_t>(fileVersion), "Failed to read file version"); ASSERT_OR_DIE(fileVersion == FILE_VERSION, "File version didn't match!"); ASSERT_OR_DIE(reader.Read<uint32_t>(m_frameCount), "Failed to read frame count"); ASSERT_OR_DIE(reader.Read<float>(m_totalLengthSeconds), "Failed to read frame count"); ASSERT_OR_DIE(reader.Read<float>(m_frameRate), "Failed to read frame count"); ASSERT_OR_DIE(reader.Read<float>(m_frameTime), "Failed to read frame count"); const char* motionName = nullptr; reader.ReadString(motionName, 64); m_motionName = std::string(motionName); ASSERT_OR_DIE(reader.Read<int>(m_jointCount), "Failed to read frame count"); ASSERT_OR_DIE(reader.Read<PLAYBACK_MODE>(m_playbackMode), "Failed to read playback mode"); ASSERT_OR_DIE(reader.Read<float>(m_lastTime), "Failed to read last time"); unsigned int numKeyframes = m_frameCount * m_jointCount; m_keyframes = new Matrix4x4[numKeyframes]; for (unsigned int index = 0; index < numKeyframes; ++index) { Matrix4x4 matrix = Matrix4x4::IDENTITY; for (int i = 0; i < 16; ++i) { reader.Read<float>(matrix.data[i]); } m_keyframes[index] = matrix; } }
//----------------------------------------------------------------------------------- Generator* GeneratorRegistration::CreateGeneratorByName(const std::string& name) { GeneratorRegistration* generatorRegistration = nullptr; ASSERT_OR_DIE(s_generatorRegistrationMap, "s_GenerationRegistrationMap doesn't exist"); GeneratorRegistrationMap::iterator gRegIter = s_generatorRegistrationMap->find(name); if (gRegIter != s_generatorRegistrationMap->end()) { generatorRegistration = gRegIter->second; Generator* generator = nullptr; generator = (*generatorRegistration->m_creationFunction)(generatorRegistration->m_name); return generator; } else { ERROR_AND_DIE("Generator didn't exist!"); return nullptr; } }
//------------------------------------------------------------------------ bool CallstackSystemInit() { gDebugHelp = LoadLibraryA("dbghelp.dll"); ASSERT_OR_DIE(gDebugHelp != nullptr, "Unable to load dbghelp.dll"); LSymInitialize = (sym_initialize_t)GetProcAddress(gDebugHelp, "SymInitialize"); LSymCleanup = (sym_cleanup_t)GetProcAddress(gDebugHelp, "SymCleanup"); LSymFromAddr = (sym_from_addr_t)GetProcAddress(gDebugHelp, "SymFromAddr"); LSymGetLineFromAddr64 = (sym_get_line_t)GetProcAddress(gDebugHelp, "SymGetLineFromAddr64"); gProcess = GetCurrentProcess(); LSymInitialize(gProcess, NULL, TRUE); gSymbol = (SYMBOL_INFO*)malloc(sizeof(SYMBOL_INFO) + (MAX_FILENAME_LENGTH * sizeof(char))); gSymbol->MaxNameLen = MAX_FILENAME_LENGTH; gSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); return true; }
PathNode* PathFinder::FindLowestFNodeOnOpenListAndRemoveIt() { ASSERT_OR_DIE(!m_openList.empty(), "ERROR: OPEN LIST IS EMPTY"); PathNode* currNode = m_openList.front(); for (std::list<PathNode*>::iterator it = m_openList.begin(); it != m_openList.end(); ++it) { if (it == m_openList.begin()) { continue; } PathNode* node = *it; if (node->f < currNode->f) { currNode = node; } } m_openList.remove(currNode); return currNode; }
//----------------------------------------------------------------------------------- static Skeleton* ImportSkeleton(SceneImport* import, MatrixStack4x4& matrixStack, Skeleton* skeleton, int parentJointIndex, FbxSkeleton* fbxSkeleton, std::map<int, FbxNode*>& nodeToJointIndex) { Skeleton* returnSkeleton = nullptr; if (fbxSkeleton->IsSkeletonRoot()) { //THIS IS NEW SKELETON returnSkeleton = new Skeleton(); import->skeletons.push_back(returnSkeleton); } else { returnSkeleton = skeleton; ASSERT_OR_DIE(returnSkeleton != nullptr, "Return skeleton was null! (This should never happen lol)"); } Matrix4x4 geotransform = GetGeometricTransform(fbxSkeleton->GetNode()); matrixStack.Push(geotransform); Matrix4x4 modelSpace = matrixStack.GetTop(); nodeToJointIndex[returnSkeleton->GetJointCount()] = fbxSkeleton->GetNode(); returnSkeleton->AddJoint(fbxSkeleton->GetNode()->GetName(), parentJointIndex, modelSpace); matrixStack.Pop(); return returnSkeleton; }
//----------------------------------------------------------------------------------- static void ImportMotions(SceneImport* import, FbxScene* scene, Matrix4x4& matrixStackTop, std::map<int, FbxNode*>& map, float framerate) { int animationCount = scene->GetSrcObjectCount<FbxAnimStack>(); if (animationCount == 0) { return; } if (import->skeletons.size() == 0) { return; } //Timing information for animation in this scene. How fast is the framerate in this file? FbxGlobalSettings& settings = scene->GetGlobalSettings(); FbxTime::EMode timeMode = settings.GetTimeMode(); double sceneFramerate; if (timeMode == FbxTime::eCustom) { sceneFramerate = settings.GetCustomFrameRate(); } else { sceneFramerate = FbxTime::GetFrameRate(timeMode); } //Only supporting one skeleton for now, update when needed. uint32_t skeletonCount = import->skeletons.size(); Skeleton* skeleton= import->skeletons.at(0); ASSERT_OR_DIE(skeletonCount == 1, "Had multiple skeletons, we only support 1!"); //Time between frames FbxTime advance; advance.SetSecondDouble((double)(1.0f / framerate)); for (int animIndex = 0; animIndex < animationCount; ++animIndex) { //Import Motions FbxAnimStack* anim = scene->GetSrcObject<FbxAnimStack>(); if (nullptr == anim) { continue; } FbxTime startTime = anim->LocalStart; FbxTime endTime = anim->LocalStop; FbxTime duration = endTime - startTime; scene->SetCurrentAnimationStack(anim); const char* motionName = anim->GetName(); float timeSpan = duration.GetSecondDouble(); AnimationMotion* motion = new AnimationMotion(motionName, timeSpan, framerate, skeleton); int jointCount = skeleton->GetJointCount(); for (int jointIndex = 0; jointIndex < jointCount; ++jointIndex) { FbxNode* node = map[jointIndex]; //Extracting world position //local, you would need to grab parent as well Matrix4x4* boneKeyframes = motion->GetJointKeyframes(jointIndex); FbxTime evalTime = FbxTime(0); for (uint32_t frameIndex = 0; frameIndex < motion->m_frameCount; ++frameIndex) { Matrix4x4* boneKeyframe = boneKeyframes + frameIndex; Matrix4x4 boneTransform = GetNodeWorldTransformAtTime(node, evalTime, matrixStackTop); double seconds = evalTime.GetSecondDouble(); seconds = seconds; *boneKeyframe = boneTransform; evalTime += advance; } } import->motions.push_back(motion); } }
//THIS MUST HAPPEN AFTER IMPORTING SKELETONS. //----------------------------------------------------------------------------------- static void ImportMesh(SceneImport* import, FbxMesh* mesh, MatrixStack4x4& matrixStack, std::map<int, FbxNode*>& nodeToJointIndex) { MeshBuilder builder = MeshBuilder(); ASSERT_OR_DIE(mesh->IsTriangleMesh(), "Was unable to load the mesh, it's not a triangle mesh!"); Matrix4x4 geoTransform = GetGeometricTransform(mesh); matrixStack.Push(geoTransform); int controlPointCount = mesh->GetControlPointsCount(); //Figure out our weighs for all verts before importing any of them std::vector<SkinWeight> skinWeights; if (HasSkinWeights(mesh)) { skinWeights.resize(controlPointCount); GetSkinWeights(import, skinWeights, mesh, nodeToJointIndex); } else { FbxNode* node = mesh->GetNode(); //Walk tree up till you reach the node associated with that joint. //Find the first parent node that has a joint associated with it //All vertices (fully weighted) //All Skin Weights = indices{jointINdex, 0, 0, 0 } weights{1.0f, 0.0f, 0.0f, 0.0f}; int jointIndex = Skeleton::INVALID_JOINT_INDEX; for (auto iter = nodeToJointIndex.begin(); iter != nodeToJointIndex.end(); ++iter) { if (iter->second == node) { jointIndex = iter->first; break; } } if (jointIndex == Skeleton::INVALID_JOINT_INDEX) { for (unsigned int i = 0; i < skinWeights.size(); ++i) { skinWeights[i].indices = Vector4Int::ZERO; skinWeights[i].weights = Vector4::UNIT_X; } } else { for (unsigned int i = 0; i < skinWeights.size(); ++i) { skinWeights[i].indices = Vector4Int(jointIndex, 0, 0, 0); skinWeights[i].weights = Vector4::UNIT_X; } } } builder.Begin(); { Matrix4x4 transform = matrixStack.GetTop(); int polyCount = mesh->GetPolygonCount(); for (int polyIndex = 0; polyIndex < polyCount; ++polyIndex) { int vertCount = mesh->GetPolygonSize(polyIndex); ASSERT_OR_DIE(vertCount == 3, "Vertex count was not 3"); for (int vertIndex = 0; vertIndex < vertCount; ++vertIndex) { ImportVertex(builder, transform, mesh, polyIndex, vertIndex, skinWeights); } } } builder.End(); FbxSurfaceMaterial* material = mesh->GetNode()->GetMaterial(0); builder.SetMaterialName(material->GetName()); matrixStack.Pop(); import->meshes.push_back(builder); }
//----------------------------------------------------------------------------------- static void GetSkinWeights(SceneImport* import, std::vector<SkinWeight>& skinWeights, const FbxMesh* mesh, std::map<int, FbxNode*>& nodeToJointIndex) { int controlPointCount = mesh->GetControlPointsCount(); skinWeights.resize(controlPointCount); for (size_t i = 0; i < skinWeights.size(); ++i) { skinWeights[i].indices = Vector4Int(0, 0, 0, 0); skinWeights[i].weights = Vector4(0.0f, 0.0f, 0.0f, 0.0f); } int deformerCount = mesh->GetDeformerCount((FbxDeformer::eSkin)); ASSERT_OR_DIE(deformerCount == 1, "Deformer count wasn't 1"); for (int deformerIndex = 0; deformerIndex < deformerCount; ++deformerIndex) { FbxSkin* skin = (FbxSkin*)mesh->GetDeformer(deformerIndex, FbxDeformer::eSkin); if (skin == nullptr) { continue; } //Clusters are a link between this skin object, bones, and the verts that bone affects. int clusterCount = skin->GetClusterCount(); for (int clusterIndex = 0; clusterIndex < clusterCount; ++clusterIndex) { FbxCluster* cluster = skin->GetCluster(clusterIndex); const FbxNode* linkNode = cluster->GetLink(); //Not associated with a bone? Ignore it, we don't care about it if (linkNode == nullptr) { continue; } int jointIndex = Skeleton::INVALID_JOINT_INDEX; for (auto iter = nodeToJointIndex.begin(); iter != nodeToJointIndex.end(); ++iter) { if (iter->second == linkNode) { jointIndex = iter->first; break; } } if (jointIndex == Skeleton::INVALID_JOINT_INDEX) { continue; } int* controlPointIndices = cluster->GetControlPointIndices(); int indexCount = cluster->GetControlPointIndicesCount(); double* weights = cluster->GetControlPointWeights(); for (int i = 0; i < indexCount; ++i) { int controlIndex = controlPointIndices[i]; double weight = weights[i]; SkinWeight* skinWeight = &skinWeights[controlIndex]; AddHighestWeightWhileKickingTheLowestWeightOut(skinWeight, jointIndex, (float)weight); } } } for (SkinWeight& sw : skinWeights) { //Renormalize all the skin weights //Be sure to set weights such that all weights add up to 1 //All weights should add up to 1, so things that were all zeroes add up to 1 //If skin-weights were never added, make sure you set it to 1, 0, 0, 0 float totalWeight = sw.weights.x + sw.weights.y + sw.weights.z + sw.weights.w; if(totalWeight > 0.0f) { sw.weights /= totalWeight; } else { sw.weights = { 1.0f, 0.0f, 0.0f, 0.0f }; } } }