// Filename:- anims.cpp // // Module to read basic animation-description files... // // Currently reads either ".frames" and/or "animtion.cfg" files... // #include "stdafx.h" #include "includes.h" // #include "sequence.h" // #include "anims.h" bool Anims_ReadFile_FRAMES(ModelContainer_t *pContainer, LPCSTR psLocalFilename_GLA) { LPCSTR psFilename = va("%s%s.frames",gamedir,Filename_WithoutExt(psLocalFilename_GLA)); FILE *fHandle = fopen(psFilename,"rt"); if (fHandle) { // file format is like this per XSI... // // models/test/m4/m44keith.xsi // { // startframe "0" // duration "2" // } // // so... Sequence_t Sequence; bool bStartFrameRead = false; bool bDurationRead = false; bool bFPSRead = false; char sLine[1024]; while (fgets(sLine,sizeof(sLine)-1,fHandle)!=NULL) { if (bStartFrameRead && bDurationRead && bFPSRead) { pContainer->SequenceList.push_back(Sequence); bStartFrameRead = false; bDurationRead = false; bFPSRead = false; } sLine[sizeof(sLine)-1]='\0'; strlwr(sLine); // :-) CString str(sLine); str.TrimLeft(); str.TrimRight(); str.Replace("\"",""); strcpy(sLine,str); if (strstr(sLine,".xsi")) { Sequence_Clear(&Sequence); strcpy(Sequence.sName,Filename_WithoutPath(Filename_WithoutExt(sLine))); // these can be really long... strncpy(Sequence.sNameWithPath,Filename_WithoutExt(sLine),sizeof(Sequence.sNameWithPath)); Sequence.sNameWithPath[sizeof(Sequence.sNameWithPath)-1]='\0'; } else if (strnicmp(sLine,"startframe",strlen("startframe"))==0) { CString str(&sLine[strlen("startframe")]); str.Replace("\"",""); Sequence.iStartFrame = atoi(str); bStartFrameRead = true; } else if (strnicmp(sLine,"duration",strlen("duration"))==0) { CString str(&sLine[strlen("duration")]); str.Replace("\"",""); Sequence.iFrameCount = atoi(str); bDurationRead = true; } else if (strnicmp(sLine,"fps",strlen("fps"))==0) { CString str(&sLine[strlen("fps")]); str.Replace("\"",""); Sequence.iFPS = atoi(str); bFPSRead = true; } } fclose(fHandle); } return !!(pContainer->SequenceList.size()); } // Code pasted from MD3View and hacked about a bit.............. // // this has now been re-written to only add to pulldown menus when all menus have been scanned, this way // I can strcat frame info to the seq names while keeping a smooth tabbing line... // // Note that this function can automatically read either ID format or Raven format files transparently... // /* typedef struct { string sName; int iStartFrame; int iFrameCount; int iLoopFrame; int iFrameSpeed; bool bMultiSeq; } Sequence_t; */ /* typedef struct { char sName[MAX_QPATH]; // eg "run1" int iStartFrame; int iFrameCount; int iLoopFrame; // -1 for no wrap, else framenum to add to iStartFrame // int iFrameSpeed; // bool bMultiSeq; bool bIsDefault; // only true if no anim/enum file found } Sequence_t; */ static bool LoadAnimationCFG(LPCSTR psFullPath, ModelContainer_t *pContainer, FILE *handle)//, HDC hDC) // hDC for text metrics { // int iLongestTextMetric = 0; // SIZE Size; bool bOk = false; // FILE *handle = fopen(psFullPath,"rt"); if (handle) { static char sLineBuffer[2048]; int iFirstFrameAfterBoth = -1; // stuff I need to do for ID's non-folded frame numbers int iFirstFrameAfterTorso= -1; while (1) { ZEROMEM(sLineBuffer); if (!fgets(sLineBuffer,sizeof(sLineBuffer),handle)) { if (ferror(handle)) { ErrorBox(va("Error while reading \"%s\"!",psFullPath)); // ClearAnimationCFG(); } break; // whether error or EOF } char sComment[2048] = {0}; // keep comments now because of the way ID cfg files work // zap any comments... // char *p = strstr(sLineBuffer,"//"); if (p) { strcpy(sComment,p+2); *p=0; } // update, to read ID cfg files, we need to skip over some stuff that Raven ones don't have... // // our cfg files don't have "sex" (how depressingly apt...) // if (strnicmp(sLineBuffer,"sex",3)==0) continue; // // or this other crap either... // if (strnicmp(sLineBuffer,"footsteps",9)==0) continue; if (strnicmp(sLineBuffer,"headoffset",10)==0) continue; if (strnicmp(sLineBuffer,"soundpath",9)==0) continue; Sequence_t seq; memset(&seq,0,sizeof(seq)); char sLine[2048]; int iElementsDone = sscanf( sLineBuffer, "%s %d %d %d %d", &sLine, &seq.iStartFrame, &seq.iFrameCount, &seq.iLoopFrame, &seq.iFPS ); if (iElementsDone == EOF) continue; // probably skipping over a comment line bool bElementsScannedOk = false; if (iElementsDone == 5) { // then it must be a Raven line... // bElementsScannedOk = true; // mdview.bAnimIsMultiPlayerFormat = false; } else { // try scanning it as an ID line... // iElementsDone = sscanf( sLineBuffer, "%d %d %d %d", &seq.iStartFrame, &seq.iFrameCount, &seq.iLoopFrame, &seq.iFPS ); if (iElementsDone == 4) { // mdview.bAnimIsMultiPlayerFormat = true; // scanned an ID line in ok, now convert it to Raven format... // iElementsDone = sscanf( sComment, "%s", &sLine ); // grab anim name from original saved comment if (iElementsDone == 1) { // ... and convert their loop format to ours... // if (seq.iLoopFrame == 0) { seq.iLoopFrame = -1; } else { seq.iLoopFrame = seq.iFrameCount - seq.iLoopFrame; } // now do the folding number stuff since ID don't do it in their files... // if ( !strnicmp(sLine,"TORSO_",6) && iFirstFrameAfterBoth == -1) { iFirstFrameAfterBoth = seq.iStartFrame; } if ( !strnicmp(sLine,"LEGS_",5)) { if (iFirstFrameAfterTorso == -1) { iFirstFrameAfterTorso = seq.iStartFrame; } // now correct the leg framenumber... // if (iFirstFrameAfterBoth != -1) // if it did, then there'd be no torso frames, so no adj nec. { seq.iStartFrame -= (iFirstFrameAfterTorso - iFirstFrameAfterBoth); } } bElementsScannedOk = true; } } } if (bElementsScannedOk) { strcpy(seq.sName,sLine);//seq.sName = sLine; pContainer->SequenceList.push_back(seq); // // this line seems to be ok... // // OutputDebugString(va("%s %d %d %d %d\n",seq.sName.c_str(), seq.iStartFrame, seq.iFrameCount, seq.iLoopFrame, seq.iFrameSpeed )); // "both" or "torso" get added to 'upper' menu... // /* if ( (!strnicmp(seq.sName.c_str(),"BOTH_",5)) || (!strnicmp(seq.sName.c_str(),"TORSO_",6)) ) { Sequences_UpperAnims.push_back(seq); if (iAnimLockLongestString < strlen(seq.sName.c_str())) iAnimLockLongestString = strlen(seq.sName.c_str()); if (GetTextExtentPoint( hDC, // HDC hdc, // handle to device context seq.sName.c_str(), // LPCTSTR lpString, // pointer to text string strlen(seq.sName.c_str()), // int cbString, // number of characters in string &Size // LPSIZE lpSize // pointer to structure for string size ) ) { if (iLongestTextMetric < Size.cx) iLongestTextMetric = Size.cx; } // Menu_UpperAnims_AddItem(seq.sName.c_str()); } // "both" or "legs" get added to 'lower' menu... // if ( (!strnicmp(seq.sName.c_str(),"BOTH_",5)) || (!strnicmp(seq.sName.c_str(),"LEGS_",5)) ) { Sequences_LowerAnims.push_back(seq); if (iAnimLockLongestString < strlen(seq.sName.c_str())) iAnimLockLongestString = strlen(seq.sName.c_str()); if (GetTextExtentPoint( hDC, // HDC hdc, // handle to device context seq.sName.c_str(), // LPCTSTR lpString, // pointer to text string strlen(seq.sName.c_str()), // int cbString, // number of characters in string &Size // LPSIZE lpSize // pointer to structure for string size ) ) { if (iLongestTextMetric < Size.cx) iLongestTextMetric = Size.cx; } // Menu_LowerAnims_AddItem(seq.sName.c_str()); } */ } else { // so do we report this as an error or what? // ErrorBox(sLineBuffer); } } fclose(handle); /* // now add to menus... (this code is awful, it was simple at first then mutated with feature-add) // char sLine[2048]; vector< Sequence_t >::iterator it; for (it=Sequences_UpperAnims.begin(); it!=Sequences_UpperAnims.end(); it++) { sprintf(sLine,(*it).sName.c_str()); while (1) { GetTextExtentPoint( hDC, // HDC hdc, // handle to device context sLine, // LPCTSTR lpString, // pointer to text string strlen(sLine), // int cbString, // number of characters in string &Size // LPSIZE lpSize // pointer to structure for string size ); if (Size.cx >= iLongestTextMetric) break; strcat(sLine," "); } Menu_UpperAnims_AddItem(va("%s (%d...%d)%s",sLine,(*it).iStartFrame,((*it).iStartFrame+(*it).iFrameCount)-1,((*it).iLoopFrame==-1)?"":va(" Loop %d",(*it).iStartFrame+(*it).iLoopFrame))); } for (it=Sequences_LowerAnims.begin(); it!=Sequences_LowerAnims.end(); it++) { sprintf(sLine,(*it).sName.c_str()); while (1) { GetTextExtentPoint( hDC, // HDC hdc, // handle to device context sLine, // LPCTSTR lpString, // pointer to text string strlen(sLine), // int cbString, // number of characters in string &Size // LPSIZE lpSize // pointer to structure for string size ); if (Size.cx >= iLongestTextMetric) break; strcat(sLine," "); } Menu_LowerAnims_AddItem(va("%s (%d...%d)%s",sLine,(*it).iStartFrame,((*it).iStartFrame+(*it).iFrameCount)-1,((*it).iLoopFrame==-1)?"":va(" Loop %d",(*it).iStartFrame+(*it).iLoopFrame))); } */ /* // a bit of sanity checking, to cope with something Bob tried to do... :-) // Sequence_t* pSeq = NULL; gl_model* pModel; if ((pModel = pModel_Lower)!=0) { pSeq = Animation_GetLowerSequence(Animation_GetNumLowerSequences()-1); ReportFrameMismatches(pSeq,pModel); } if ((pModel = pModel_Upper)!=0) { pSeq = Animation_GetUpperSequence(Animation_GetNumUpperSequences()-1); ReportFrameMismatches(pSeq,pModel); } */ } //return bOk; return !!(pContainer->SequenceList.size()); } bool Anims_ReadFile_ANIMATION_CFG(ModelContainer_t *pContainer, LPCSTR psLocalFilename_GLA) { LPCSTR psFilename = va("%s%s/animation.cfg",gamedir,Filename_PathOnly(psLocalFilename_GLA)); FILE *fHandle = fopen(psFilename,"rt"); if (fHandle) { if (LoadAnimationCFG(psFilename, pContainer, fHandle)) { // } fclose(fHandle); } return !!(pContainer->SequenceList.size()); }