void RageTexture::GetFrameDimensionsFromFileName( CString sPath, int* piFramesWide, int* piFramesHigh ) { *piFramesWide = *piFramesHigh = 1; // set default values in case we don't find the dimension in the file name sPath.MakeLower(); const CString sFName = SetExtension( sPath, "" ); CStringArray arrayBits; split( sFName, " ", arrayBits, false ); /* XXX: allow dims to be in parens */ for( unsigned i=0; i<arrayBits.size(); i++ ) { CString &sBit = arrayBits[ i ]; // Test to see if it looks like "%ux%u" (e.g. 16x8) CStringArray arrayDimensionsBits; split( sBit, "x", arrayDimensionsBits, false ); if( arrayDimensionsBits.size() != 2 ) continue; else if( !IsAnInt(arrayDimensionsBits[0]) || !IsAnInt(arrayDimensionsBits[1]) ) continue; *piFramesWide = atoi(arrayDimensionsBits[0]); *piFramesHigh = atoi(arrayDimensionsBits[1]); return; } }
void ActorFrame::LoadChildrenFromNode( const XNode* pNode ) { // Shouldn't be calling this unless we're going to delete our children. ASSERT( m_bDeleteChildren ); // Load children const XNode* pChildren = pNode->GetChild("children"); bool bArrayOnly = false; if( pChildren == NULL ) { bArrayOnly = true; pChildren = pNode; } FOREACH_CONST_Child( pChildren, pChild ) { if( bArrayOnly && !IsAnInt(pChild->GetName()) ) continue; Actor* pChildActor = ActorUtil::LoadFromNode( pChild, this ); if( pChildActor ) AddChild( pChildActor ); } SortByDrawOrder(); }
static void ReadTimeSigs( const NameToData_t &mapNameToData, MeasureToTimeSig_t &out ) { NameToData_t::const_iterator it; for( it = mapNameToData.lower_bound("#00000"); it != mapNameToData.end(); ++it ) { const RString &sName = it->first; if( sName.size() != 6 || sName[0] != '#' || !IsAnInt(sName.substr(1, 5)) ) continue; // this is step or offset data. Looks like "#00705" const RString &sData = it->second; int iMeasureNo = atoi( sName.substr(1, 3).c_str() ); int iBMSTrackNo = atoi( sName.substr(4, 2).c_str() ); if( iBMSTrackNo == BMS_TRACK_TIME_SIG ) out[iMeasureNo] = StringToFloat( sData ); } }
void Font::LoadFontPageSettings( FontPageSettings &cfg, IniFile &ini, const RString &sTexturePath, const RString &sPageName, RString sChars ) { cfg.m_sTexturePath = sTexturePath; /* If we have any characters to map, add them. */ for( unsigned n=0; n<sChars.size(); n++ ) { char c = sChars[n]; cfg.CharToGlyphNo[c] = n; } int iNumFramesWide, iNumFramesHigh; RageTexture::GetFrameDimensionsFromFileName( sTexturePath, &iNumFramesWide, &iNumFramesHigh ); int iNumFrames = iNumFramesWide * iNumFramesHigh; ini.RenameKey("Char Widths", "main"); // LOG->Trace("Loading font page '%s' settings from page name '%s'", // TexturePath.c_str(), sPageName.c_str()); ini.GetValue( sPageName, "DrawExtraPixelsLeft", cfg.m_iDrawExtraPixelsLeft ); ini.GetValue( sPageName, "DrawExtraPixelsRight", cfg.m_iDrawExtraPixelsRight ); ini.GetValue( sPageName, "AddToAllWidths", cfg.m_iAddToAllWidths ); ini.GetValue( sPageName, "ScaleAllWidthsBy", cfg.m_fScaleAllWidthsBy ); ini.GetValue( sPageName, "LineSpacing", cfg.m_iLineSpacing ); ini.GetValue( sPageName, "Top", cfg.m_iTop ); ini.GetValue( sPageName, "Baseline", cfg.m_iBaseline ); ini.GetValue( sPageName, "DefaultWidth", cfg.m_iDefaultWidth ); ini.GetValue( sPageName, "AdvanceExtraPixels", cfg.m_iAdvanceExtraPixels ); ini.GetValue( sPageName, "TextureHints", cfg.m_sTextureHints ); /* Iterate over all keys. */ const XNode* pNode = ini.GetChild( sPageName ); if( pNode ) { FOREACH_CONST_Attr( pNode, pAttr ) { RString sName = pAttr->first; const XNodeValue *pValue = pAttr->second; sName.MakeUpper(); /* If val is an integer, it's a width, eg. "10=27". */ if( IsAnInt(sName) ) { cfg.m_mapGlyphWidths[atoi(sName)] = pValue->GetValue<int>(); continue; } /* "map codepoint=frame" maps a char to a frame. */ if( sName.substr(0, 4) == "MAP " ) { /* * map CODEPOINT=frame. CODEPOINT can be * 1. U+hexval * 2. an alias ("oq") * 3. a character in quotes ("X") * * map 1=2 is the same as * range unicode #1-1=2 */ RString sCodepoint = sName.substr(4); /* "CODEPOINT" */ wchar_t c; if( sCodepoint.substr(0, 2) == "U+" && IsHexVal(sCodepoint.substr(2)) ) sscanf( sCodepoint.substr(2).c_str(), "%x", &c ); else if( sCodepoint.size() > 0 && utf8_get_char_len(sCodepoint[0]) == int(sCodepoint.size()) ) { c = utf8_get_char( sCodepoint.c_str() ); if(c == wchar_t(-1)) LOG->Warn("Font definition '%s' has an invalid value '%s'.", ini.GetPath().c_str(), sName.c_str() ); } else if( !FontCharAliases::GetChar(sCodepoint, c) ) { LOG->Warn("Font definition '%s' has an invalid value '%s'.", ini.GetPath().c_str(), sName.c_str() ); continue; } cfg.CharToGlyphNo[c] = pValue->GetValue<int>(); continue; } if( sName.substr(0, 6) == "RANGE " ) { /* * range CODESET=first_frame or * range CODESET #start-end=first_frame * eg * range CP1252=0 (default for 256-frame fonts) * range ASCII=0 (default for 128-frame fonts) * * (Start and end are in hex.) * * Map two high-bit portions of ISO-8859- to one font: * range ISO-8859-2 #80-FF=0 * range ISO-8859-3 #80-FF=128 * * Map hiragana to 0-84: * range Unicode #3041-3094=0 */ vector<RString> asMatches; static Regex parse("^RANGE ([A-Z0-9\\-]+)( ?#([0-9A-F]+)-([0-9A-F]+))?$"); bool bMatch = parse.Compare( sName, asMatches ); ASSERT( asMatches.size() == 4 ); /* 4 parens */ if( !bMatch || asMatches[0].empty() ) RageException::Throw( "Font definition \"%s\" has an invalid range \"%s\": parse error.", ini.GetPath().c_str(), sName.c_str() ); /* We must have either 1 match (just the codeset) or 4 (the whole thing). */ int iCount = -1; int iFirst = 0; if( !asMatches[2].empty() ) { sscanf( asMatches[2].c_str(), "%x", &iFirst ); int iLast; sscanf( asMatches[3].c_str(), "%x", &iLast ); if( iLast < iFirst ) RageException::Throw( "Font definition \"%s\" has an invalid range \"%s\": %i < %i.", ini.GetPath().c_str(), sName.c_str(), iLast, iFirst ); iCount = iLast - iFirst + 1; } RString sRet = cfg.MapRange( asMatches[0], iFirst, pValue->GetValue<int>(), iCount ); if( !sRet.empty() ) RageException::Throw( "Font definition \"%s\" has an invalid range \"%s\": %s.", ini.GetPath().c_str(), sName.c_str(), sRet.c_str() ); continue; } if( sName.substr(0, 5) == "LINE " ) { /* line ROW=CHAR1CHAR2CHAR3CHAR4 * eg. * line 0=ABCDEFGH * * This lets us assign characters very compactly and readably. */ RString sRowStr = sName.substr(5); TrimLeft( sRowStr ); ASSERT( IsAnInt(sRowStr) ); const int iRow = atoi( sRowStr.c_str() ); const int iFirstFrame = iRow * iNumFramesWide; if( iRow > iNumFramesHigh ) RageException::Throw( "The font definition \"%s\" tries to assign line %i, but the font is only %i characters high.", ini.GetPath().c_str(), iFirstFrame, iNumFramesHigh ); /* Decode the string. */ const wstring wdata( RStringToWstring(pValue->GetValue<RString>()) ); if( int(wdata.size()) > iNumFramesWide ) RageException::Throw( "The font definition \"%s\" assigns %i characters to row %i (\"%ls\"), but the font is only %i characters wide.", ini.GetPath().c_str(), (int)wdata.size(), iRow, wdata.c_str(), iNumFramesWide ); for( unsigned i = 0; i < wdata.size(); ++i ) cfg.CharToGlyphNo[wdata[i]] = iFirstFrame+i; } } }
static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameToData, Steps &out, const MeasureToTimeSig_t &sigAdjustments, const map<RString,int> &idToKeySoundIndex ) { LOG->Trace( "Steps::LoadFromBMSFile( '%s' )", sPath.c_str() ); out.m_StepsType = StepsType_Invalid; // BMS player code. Fill in below and use to determine StepsType. int iPlayer = -1; RString sData; if( GetTagFromMap( mapNameToData, "#player", sData ) ) iPlayer = atoi(sData); if( GetTagFromMap( mapNameToData, "#playlevel", sData ) ) out.SetMeter( atoi(sData) ); NoteData ndNotes; ndNotes.SetNumTracks( NUM_BMS_TRACKS ); /* Read time signatures. Note that these can differ across files in the same * song. */ MeasureToTimeSig_t mapMeasureToTimeSig; ReadTimeSigs( mapNameToData, mapMeasureToTimeSig ); int iHoldStarts[NUM_BMS_TRACKS]; int iHoldPrevs[NUM_BMS_TRACKS]; for( int i = 0; i < NUM_BMS_TRACKS; ++i ) { iHoldStarts[i] = -1; iHoldPrevs[i] = -1; } NameToData_t::const_iterator it; for( it = mapNameToData.lower_bound("#00000"); it != mapNameToData.end(); ++it ) { const RString &sName = it->first; if( sName.size() != 6 || sName[0] != '#' || !IsAnInt( sName.substr(1, 5) ) ) continue; // this is step or offset data. Looks like "#00705" int iMeasureNo = atoi( sName.substr(1,3).c_str() ); int iRawTrackNum = atoi( sName.substr(4,2).c_str() ); int iRowNo = GetMeasureStartRow( mapMeasureToTimeSig, iMeasureNo, sigAdjustments ); float fBeatsPerMeasure = GetBeatsPerMeasure( mapMeasureToTimeSig, iMeasureNo, sigAdjustments ); const RString &sNoteData = it->second; vector<TapNote> vTapNotes; for( size_t i=0; i+1<sNoteData.size(); i+=2 ) { RString sNoteId = sNoteData.substr( i, 2 ); if( sNoteId != "00" ) { vTapNotes.push_back( TAP_ORIGINAL_TAP ); map<RString,int>::const_iterator it = idToKeySoundIndex.find( sNoteId ); if( it != idToKeySoundIndex.end() ) vTapNotes.back().iKeysoundIndex = it->second; } else { vTapNotes.push_back( TAP_EMPTY ); } } const unsigned iNumNotesInThisMeasure = vTapNotes.size(); for( unsigned j=0; j<iNumNotesInThisMeasure; j++ ) { float fPercentThroughMeasure = (float)j/(float)iNumNotesInThisMeasure; int row = iRowNo + lrintf( fPercentThroughMeasure * fBeatsPerMeasure * ROWS_PER_BEAT ); // some BMS files seem to have funky alignment, causing us to write gigantic cache files. // Try to correct for this by quantizing. row = Quantize( row, ROWS_PER_MEASURE/64 ); BmsTrack bmsTrack; bool bIsHold; if( ConvertRawTrackToTapNote(iRawTrackNum, bmsTrack, bIsHold) ) { TapNote &tn = vTapNotes[j]; if( tn.type != TapNote::empty ) { if( bmsTrack == BMS_AUTO_KEYSOUND_1 ) { // shift the auto keysound as far right as possible int iLastEmptyTrack = -1; if( ndNotes.GetTapLastEmptyTrack(row, iLastEmptyTrack) && iLastEmptyTrack >= BMS_AUTO_KEYSOUND_1 ) { tn.type = TapNote::autoKeysound; bmsTrack = (BmsTrack)iLastEmptyTrack; } else { // no room for this note. Drop it. continue; } } else if( bIsHold ) { if( iHoldStarts[bmsTrack] == -1 ) { // Start of a hold. iHoldStarts[bmsTrack] = row; iHoldPrevs[bmsTrack] = row; } else { // We're continuing a hold. iHoldPrevs[bmsTrack] = row; } continue; } } if( iHoldStarts[bmsTrack] != -1 ) { // This is ending a hold. const int iBegin = iHoldStarts[bmsTrack]; const int iEnd = iHoldPrevs[bmsTrack]; if( iBegin < iEnd ) ndNotes.AddHoldNote( bmsTrack, iBegin, iEnd, TAP_ORIGINAL_HOLD_HEAD ); else ndNotes.SetTapNote( bmsTrack, iBegin, TAP_ORIGINAL_TAP ); iHoldStarts[bmsTrack] = -1; iHoldPrevs[bmsTrack] = -1; } // Don't bother inserting empty taps. if( tn.type != TapNote::empty ) ndNotes.SetTapNote( bmsTrack, row, tn ); } } } // We're done reading in all of the BMS values. Time to check for any unfinished holds. for( int iTrack = 0; iTrack < NUM_BMS_TRACKS; ++iTrack ) { const int iBegin = iHoldStarts[iTrack]; const int iEnd = iHoldPrevs[iTrack]; if( iBegin == -1 ) continue; if( iBegin < iEnd ) ndNotes.AddHoldNote( iTrack, iBegin, iEnd, TAP_ORIGINAL_HOLD_HEAD ); else ndNotes.SetTapNote( iTrack, iBegin, TAP_ORIGINAL_TAP ); } out.m_StepsType = DetermineStepsType( iPlayer, ndNotes, sPath ); if( out.m_StepsType == StepsType_beat_single5 && GetTagFromMap( mapNameToData, "#title", sData ) ) { /* Hack: guess at 6-panel. */ // extract the Steps description (looks like 'Music <BASIC>') const size_t iOpenBracket = sData.find_first_of( "<(" ); const size_t iCloseBracket = sData.find_first_of( ">)", iOpenBracket ); // if there's a 6 in the description, it's probably part of "6panel" or "6-panel" if( sData.find('6', iOpenBracket) < iCloseBracket ) out.m_StepsType = StepsType_dance_solo; } if( out.m_StepsType == StepsType_Invalid ) { LOG->UserLog( "Song file", sPath, "has an unknown steps type" ); return false; } // shift all of the autokeysound tracks onto the main tracks for( int t=BMS_AUTO_KEYSOUND_1; t<BMS_AUTO_KEYSOUND_1+NUM_AUTO_KEYSOUND_TRACKS; t++ ) { FOREACH_NONEMPTY_ROW_IN_TRACK( ndNotes, t, row ) { TapNote tn = ndNotes.GetTapNote( t, row ); int iEmptyTrack; if( ndNotes.GetTapFirstEmptyTrack(row, iEmptyTrack) ) { ndNotes.SetTapNote( iEmptyTrack, row, tn ); ndNotes.SetTapNote( t, row, TAP_EMPTY ); } else { LOG->UserLog( "Song file", sPath, "has no room to shift the autokeysound tracks." ); } } }
// function that tokenizes the input, using a structure of conscell's, where each conscell has a car and a cdr, // each car has two values, the type and the actual value. ConsCell* tokenize(char *expression) { ConsCell *current =malloc(sizeof(ConsCell)); ConsCell *Head = current; int i = 0; for (int i = 0; expression[i]; i++) { if (expression[i]==' ') continue; else if (expression[i] == '\n'){ continue; } if (expression[i]== '\t'){ continue; } Value *carVar = malloc(sizeof(Value)); Value *cdrVar = malloc(sizeof(Value)); if (expression[i]=='(') { carVar->type = 6; carVar->openValue = '('; } else if (expression[i]==')') { carVar->type=7; carVar->closeValue = ')'; } else { if (IsAnInt(expression, i)) { carVar->type=2; carVar->intValue=GiveInt(expression, i); i = getNextTerminal(expression, i); i -=1; } else if(IsSymbol(expression, i)) { int symbolLength=returnSymbolLength(expression, i); carVar->type=5; carVar->symbolValue=returnSymbol(expression, i, symbolLength); if (IsId(carVar->symbolValue)){ carVar->type = 9; carVar->idValue = carVar->symbolValue; } else if (IsPrimitive(carVar->symbolValue)) { carVar->type = 13; carVar->primValue = carVar->symbolValue; } i+=symbolLength; } else if(IsString(expression, i)) { carVar->type=4; carVar->stringValue=returnString(expression, i); int lengthOfString = findLengthOfString(carVar->stringValue); i+=lengthOfString; } else if(IsBoolean(expression,i)){ carVar->type = 1; carVar->boolValue=returnBoolean(expression,i); i +=1; } else if(IsFloat(expression, i)) { carVar->type=3; carVar->floatValue=GiveFloat(expression, i); i = getNextTerminal(expression, i); i -=1; } else if(expression[i] == ';') { free(carVar); free(cdrVar); break; } else { free(carVar); free(cdrVar); printf("Error: Bad syntax.\n"); ConsCell *emptyCons =malloc(sizeof(ConsCell)); Value *Val = malloc(sizeof(Value)); Val->type = 0; Val->intValue= 1; emptyCons->car = Val; Value *cdrVal = malloc(sizeof(Value)); cdrVal->type = 0; cdrVal->intValue = 0; current->car = cdrVal; cleanupCCLL(Head); return emptyCons; break; } } ConsCell *newCell = malloc(sizeof(ConsCell)); cdrVar->type = 8; cdrVar->cons = newCell; current = insertCC(current, carVar, cdrVar); current = newCell; } Value *cdrVal = malloc(sizeof(Value)); cdrVal->type = 0; cdrVal->intValue = 0; current->car = cdrVal; return Head; }