int MFString::Enumerate(const MFArray<MFString> keys, bool bCaseSensitive) { if(IsEmpty()) return -1; for(size_t i=0; i<keys.size(); ++i) { if(bCaseSensitive ? Equals(keys[i]) : EqualsInsensitive(keys[i])) return (int)i; } return -1; }
void Game_Draw() { if(!bShowModel) { MFView_SetOrtho(); // draw model list if(models.size() > 0) { for(int a=0; a<(int)models.size(); ++a) { MFFont_DrawText2(MFFont_GetDebugFont(), 100.f, 100.f + (-menuIndex*20 + a*20), 20.f, a == menuIndex ? MFVector::yellow : MFVector::white, models[a].CStr()); } } else { MFFont_DrawText2(MFFont_GetDebugFont(), 100.f, 100.f, 20.f, MFVector::red, "No models found!"); } } else { if(pModel) { // set projection MFView_ConfigureProjection(MFDEGREES(60.f), 0.1f, 10000.f); MFView_SetAspectRatio(MFDisplay_GetNativeAspectRatio()); MFView_SetProjection(); // render the mesh MFRenderer_AddModel(pModel, NULL, MFView_GetViewState()); } else { MFView_SetOrtho(); MFFont_DrawText2(MFFont_GetDebugFont(), 100.f, 100.f, 20.f, MFVector::red, "Failed to load model!"); } } }
void Scan(MFString path) { MFFindData fd; MFFind *pFind = MFFileSystem_FindFirst(MFStr("%s*", path.CStr()), &fd); if(pFind) { do { if(fd.attributes & MFFA_Directory) { Scan(MFString::Format("%s%s/", path.CStr(), fd.pFilename).CStr()); } else { MFString ext = MFString(fd.pFilename).GetExtension(); if(ext.Enumerate(ppFormats, sizeof(ppFormats) / sizeof(ppFormats[0])) > -1) models.push(MFString::Format("%s%s", path.CStr(), fd.pFilename)); } } while(MFFileSystem_FindNext(pFind, &fd)); MFFileSystem_FindClose(pFind); } }
void ParseOBJFile(const char *pFilePtr) { const char *pToken = GetNextToken(pFilePtr); while(*pToken != 0) { if(!MFString_CaseCmp(pToken, "o")) { const char *pName = GetRestOfLine(pFilePtr); pModel->name = pName; } else if(!MFString_CaseCmp(pToken, "g")) { const char *pName = GetRestOfLine(pFilePtr); if(!vertsInGroup) { // we'll just rename the current subobject, since theres nothing in it.. F3DSubObject &sub = pModel->GetMeshChunk()->subObjects[subObject]; sub.name = pName; } else { // probably wanna copy vertex data in at this point.. // and subtract the min from each of the components indices.. CopyDataIntoSubobject(subObject); ++subObject; matSub = 0; minVertIndex = -1; minUVIndex = -1; minNormIndex = -1; maxVertIndex = -1; maxUVIndex = -1; maxNormIndex = -1; vertsInGroup = false; vertsInMatSub = false; F3DSubObject &sub = pModel->GetMeshChunk()->subObjects[subObject]; sub.name = pName; } } else if(!MFString_CaseCmp(pToken, "v")) { const char *pX = GetNextToken(pFilePtr); const char *pY = GetNextToken(pFilePtr); const char *pZ = GetNextToken(pFilePtr); pFilePtr = MFSeekNewline(pFilePtr); MFVector v; v.x = (float)atof(pX); v.y = (float)atof(pY); v.z = (float)atof(pZ); v.w = 1.0f; verts.push(v); } else if(!MFString_CaseCmp(pToken, "vt")) { const char *pU = GetNextToken(pFilePtr); const char *pV = GetNextToken(pFilePtr); pFilePtr = MFSeekNewline(pFilePtr); MFVector v; v.x = (float)atof(pU); v.y = (float)atof(pV); v.z = 0.0f; v.w = 1.0f; uvs.push(v); } else if(!MFString_CaseCmp(pToken, "vn")) { const char *pX = GetNextToken(pFilePtr); const char *pY = GetNextToken(pFilePtr); const char *pZ = GetNextToken(pFilePtr); pFilePtr = MFSeekNewline(pFilePtr); MFVector v; v.x = (float)atof(pX); v.y = (float)atof(pY); v.z = (float)atof(pZ); v.w = 1.0f; normals.push(v); } else if(!MFString_CaseCmp(pToken, "f")) { vertsInGroup = true; vertsInMatSub = true; F3DSubObject &sub = pModel->GetMeshChunk()->subObjects[subObject]; const char *pRestOfLine = GetRestOfLine(pFilePtr); int firstVert = (int)sub.matSubobjects[matSub].vertices.size(); pToken = GetNextToken(pRestOfLine); while(*pToken) { const char *pPos = GetNextIndex(pToken); const char *pUV = GetNextIndex(pToken); const char *pNorm = GetNextIndex(pToken); int posid = atoi(pPos); int texid = atoi(pUV); int normid = atoi(pNorm); if(posid < 0) posid = (int)verts.size() - posid; else posid = posid - 1; if(texid < 0) texid = (int)uvs.size() - texid; else texid = texid - 1; if(normid < 0) normid = (int)normals.size() - normid; else normid = normid - 1; minVertIndex = minVertIndex == -1 ? posid : MFMin(minVertIndex, posid); minUVIndex = minUVIndex == -1 ? texid : MFMin(minUVIndex, texid); minNormIndex = minNormIndex == -1 ? normid : MFMin(minNormIndex, normid); maxVertIndex = minVertIndex == -1 ? posid : MFMax(maxVertIndex, posid); maxUVIndex = maxUVIndex == -1 ? texid : MFMax(maxUVIndex, texid); maxNormIndex = maxNormIndex == -1 ? normid : MFMax(maxNormIndex, normid); int vi = (int)sub.matSubobjects[matSub].vertices.size(); int f = vi - firstVert; F3DVertex &vert = sub.matSubobjects[matSub].vertices[firstVert + f]; vert.position = posid; vert.uv[0] = texid; vert.normal = normid; // add a triangle if we are up to the third vert or beyond if(f >= 2) { F3DTriangle &tri = sub.matSubobjects[matSub].triangles.push(); tri.v[0] = firstVert; tri.v[1] = vi-1; tri.v[2] = vi; } pToken = GetNextToken(pRestOfLine); } } else if(!MFString_CaseCmp(pToken, "usemtl")) { F3DSubObject &sub = pModel->GetMeshChunk()->subObjects[subObject]; if(vertsInGroup && vertsInMatSub) { ++matSub; vertsInMatSub = false; } const char *pName = GetRestOfLine(pFilePtr); sub.matSubobjects[matSub].materialIndex = GetMaterialID(pName); } else if(!MFString_CaseCmp(pToken, "mtllib")) { // load material info? //.. pFilePtr = MFSeekNewline(pFilePtr); } else if(pToken[0] == '#') { pFilePtr = MFSeekNewline(pFilePtr); } else { MFDebug_Warn(2, MFStr("Unknown token encountered in obj file '%s'!", pToken)); pFilePtr = MFSeekNewline(pFilePtr); } pToken = GetNextToken(pFilePtr); } // want to copy vertex data into the last subobject at this point... if(vertsInGroup) { CopyDataIntoSubobject(subObject); } }
void Game_Update() { if(!bShowModel) { if(MFInput_WasPressed(Key_Up, IDD_Keyboard) && menuIndex > 0) --menuIndex; else if(MFInput_WasPressed(Key_Down, IDD_Keyboard) && menuIndex < (int)models.size()-1) ++menuIndex; else if(MFInput_WasPressed(Key_Return, IDD_Keyboard) && models.size() > 0) { bShowModel = true; // load model pModel = MFModel_CreateWithAnimation(models[menuIndex].CStr()); } } else { if(MFInput_WasPressed(Key_Escape, IDD_Keyboard)) { if(pModel) { MFModel_Destroy(pModel); pModel = NULL; } models.clear(); Scan("data:"); if(models.size() <= (size_t)menuIndex) menuIndex = models.size() ? (int)models.size() - 1 : 0; bShowModel = false; return; } if(pModel) { if(MFInput_Read(Mouse_LeftButton, IDD_Mouse) > 0.f) { yaw += -MFInput_Read(Mouse_XDelta, IDD_Mouse) * 0.02f; pitch += -MFInput_Read(Mouse_YDelta, IDD_Mouse) * 0.015f; } if(MFInput_Read(Mouse_MiddleButton, IDD_Mouse) > 0.f) { zoom *= 1.f + -MFInput_Read(Mouse_YDelta, IDD_Mouse) * 0.02f; } // calculate a spinning world matrix MFMatrix world; world.SetTranslation(MakeVector(0, -0.25f, 1) * zoom); world.RotateY(yaw); world.RotateX(pitch); // set world matrix to the model MFModel_SetWorldMatrix(pModel, world); // advance the animation MFAnimation *pAnim = MFModel_GetAnimation(pModel); if(pAnim) { float start, end; MFAnimation_GetFrameRange(pAnim, &start, &end); static float time = 0.f; time += MFSystem_TimeDelta();// * 500; while(time >= end) time -= end; MFAnimation_SetFrame(pAnim, time); } } } }
void LoadTextXFile(const char *pText) { const char *pTok = GetNextToken(pText, &pText); while(pTok) { if(!MFString_Compare(pTok, "Header")) { SkipToken(pText, "{"); int maj = GetInt(pText, &pText); int min = GetInt(pText, &pText); int flag = GetInt(pText, &pText); // printf("XFile V%d.%d, 0x%X\n", maj, min, flag); pTok = GetNextToken(pText, &pText); while(MFString_Compare(pTok, "}")) { pTok = GetNextToken(pText, &pText); } } else if(!MFString_Compare(pTok, "Frame")) { pText = ParseFrame(pText, MFMatrix::identity, -1); } else if(!MFString_Compare(pTok, "Mesh")) { gMeshChunks.push(XMeshChunk::Create(MFMatrix::identity, pText, "")); SkipSection(pText); } else if(!MFString_Compare(pTok, "AnimationSet")) { gAnimSets.push(pText); SkipSection(pText); } else if(!MFString_Compare(pTok, "template")) { // const char *pName = GetNextToken(pText, &pText); SkipSection(pText); } else { MFDebug_Warn(4, MFStr("Unknown token '%s'\n", pTok)); SkipSection(pText); } pTok = GetNextToken(pText, &pText); } int a; for(a=0; a<gMeshChunks.size(); a++) { ParseMesh(gMeshChunks[a].pMesh, gMeshChunks[a].mat, gMeshChunks[a].frameName); } for(a=0; a<gAnimSets.size(); a++) { ParseAnimationSet(gAnimSets[a]); } gMeshChunks.clear(); }
const char *ParseFrame(const char *pText, const MFMatrix &mat, int parentID) { char frameName[64]; const char *pName = GetNextToken(pText, &pText, frameName); MFMatrix worldMatrix = mat; F3DBone *pBone = NULL; if(!MFString_CaseCmpN(pName, "bn_", 3) || !MFString_CaseCmpN(pName, "z_", 2)) { int boneID = pModel->GetSkeletonChunk()->bones.size(); pBone = &pModel->GetSkeletonChunk()->bones[boneID]; F3DBone *pParent = parentID == -1 ? NULL : &pModel->GetSkeletonChunk()->bones[parentID]; parentID = boneID; MFString_Copy(pBone->name, pName); MFString_Copy(pBone->parentName, pParent ? pParent->name : ""); pBone->worldMatrix = mat; } if(MFString_Compare(pName, "{")) SkipToken(pText, "{"); const char *pTok = GetNextToken(pText, &pText); while(MFString_Compare(pTok, "}")) { if(!MFString_Compare(pTok, "Frame")) { pText = ParseFrame(pText, worldMatrix, parentID); } else if(!MFString_Compare(pTok, "FrameTransformMatrix")) { SkipToken(pText, "{"); MFMatrix localMatrix; GetFloatArray(pText, (float*)&localMatrix, 16, &pText); worldMatrix.Multiply(localMatrix, worldMatrix); if(pBone) { pBone->boneMatrix = localMatrix; pBone->worldMatrix = worldMatrix; } SkipToken(pText, ";"); SkipToken(pText, "}"); } else if(!MFString_Compare(pTok, "Mesh")) { gMeshChunks.push(XMeshChunk::Create(worldMatrix, pText, pName)); SkipSection(pText); } else { MFDebug_Warn(4, MFStr("Unexpected token '%s'\n", pTok)); SkipSection(pText); } pTok = GetNextToken(pText, &pText); } return pText; }