static bool ReadBMSFile( const RString &sPath, NameToData_t &mapNameToData ) { RageFile file; if( !file.Open(sPath) ) { LOG->UserLog( "Song file", sPath, "couldn't be opened: %s", file.GetError().c_str() ); return false; } while( !file.AtEOF() ) { RString line; if( file.GetLine(line) == -1 ) { LOG->UserLog( "Song file", sPath, "had a read error: %s", file.GetError().c_str() ); return false; } StripCrnl( line ); // BMS value names can be separated by a space or a colon. size_t iIndexOfSeparator = line.find_first_of( ": " ); RString value_name = line.substr( 0, iIndexOfSeparator ); RString value_data; if( iIndexOfSeparator != line.npos ) value_data = line.substr( iIndexOfSeparator+1 ); value_name.MakeLower(); mapNameToData.insert( make_pair(value_name, value_data) ); } return true; }
bool IniFile::ReadFile( const CString &sPath ) { m_sPath = sPath; CHECKPOINT_M( ssprintf("Reading '%s'",m_sPath.c_str()) ); RageFile f; if( !f.Open( m_sPath ) ) { LOG->Trace( "Reading '%s' failed: %s", m_sPath.c_str(), f.GetError().c_str() ); m_sError = f.GetError(); return 0; } CString keyname; while( 1 ) { CString line; int ret = f.GetLine(line); if( ret == 0 ) /* eof */ return true; if( ret < 0 ) { m_sError = f.GetError(); return false; } if( line.size() >= 3 && line[0] == '\xef' && line[1] == '\xbb' && line[2] == '\xbf' ) { /* Obnoxious NT marker for UTF-8. Remove it. */ line.erase(0, 3); } if( line == "" ) continue; if( line.substr(0, 2) == "//" || line.substr(0) == "#" ) continue; /* comment */ if( line[0] == '[' && line[line.GetLength()-1] == ']' ) { /* New section. */ keyname = line.substr(1, line.size()-2); } else //if a value { int iEqualIndex = line.Find("="); if( iEqualIndex != -1 ) { CString valuename = line.Left(iEqualIndex); CString value = line.Right(line.GetLength()-valuename.GetLength()-1); SetValue(keyname,valuename,value); } } } }
bool msAnimation::LoadMilkshapeAsciiBones( CString sAniName, CString sPath ) { FixSlashesInPlace(sPath); const CString sDir = Dirname( sPath ); RageFile f; if ( !f.Open(sPath) ) RageException::Throw( "Model:: Could not open \"%s\": %s", sPath.c_str(), f.GetError().c_str() ); CString sLine; int iLineNum = 0; msAnimation &Animation = *this; bool bLoaded = false; while( f.GetLine( sLine ) > 0 ) { iLineNum++; if (!strncmp (sLine, "//", 2)) continue; // // bones // int nNumBones = 0; if( sscanf (sLine, "Bones: %d", &nNumBones) != 1 ) continue; char szName[MS_MAX_NAME]; Animation.Bones.resize( nNumBones ); for( int i = 0; i < nNumBones; i++ ) { msBone& Bone = Animation.Bones[i]; // name if( f.GetLine( sLine ) <= 0 ) THROW; if (sscanf (sLine, "\"%[^\"]\"", szName) != 1) THROW; strcpy( Bone.szName, szName ); // parent if( f.GetLine( sLine ) <= 0 ) THROW; strcpy (szName, ""); sscanf (sLine, "\"%[^\"]\"", szName); strcpy( Bone.szParentName, szName ); // flags, position, rotation RageVector3 Position, Rotation; if( f.GetLine( sLine ) <= 0 ) THROW; int nFlags; if (sscanf (sLine, "%d %f %f %f %f %f %f", &nFlags, &Position[0], &Position[1], &Position[2], &Rotation[0], &Rotation[1], &Rotation[2]) != 7) { THROW; } Rotation = RadianToDegree(Rotation); Bone.nFlags = nFlags; memcpy( &Bone.Position, &Position, sizeof(Bone.Position) ); memcpy( &Bone.Rotation, &Rotation, sizeof(Bone.Rotation) ); // position key count if( f.GetLine( sLine ) <= 0 ) THROW; int nNumPositionKeys = 0; if (sscanf (sLine, "%d", &nNumPositionKeys) != 1) THROW; Bone.PositionKeys.resize( nNumPositionKeys ); for( int j = 0; j < nNumPositionKeys; ++j ) { if( f.GetLine( sLine ) <= 0 ) THROW; float fTime; if (sscanf (sLine, "%f %f %f %f", &fTime, &Position[0], &Position[1], &Position[2]) != 4) THROW; msPositionKey key; key.fTime = fTime; key.Position = RageVector3( Position[0], Position[1], Position[2] ); Bone.PositionKeys[j] = key; } // rotation key count if( f.GetLine( sLine ) <= 0 ) THROW; int nNumRotationKeys = 0; if (sscanf (sLine, "%d", &nNumRotationKeys) != 1) THROW; Bone.RotationKeys.resize( nNumRotationKeys ); for( int j = 0; j < nNumRotationKeys; ++j ) { if( f.GetLine( sLine ) <= 0 ) THROW; float fTime; if (sscanf (sLine, "%f %f %f %f", &fTime, &Rotation[0], &Rotation[1], &Rotation[2]) != 4) THROW; Rotation = RadianToDegree(Rotation); msRotationKey key; key.fTime = fTime; key.Rotation = RageVector3( Rotation[0], Rotation[1], Rotation[2] ); Bone.RotationKeys[j] = key; } } // Ignore "Frames:" in file. Calculate it ourself Animation.nTotalFrames = 0; for( int i = 0; i < (int)Animation.Bones.size(); i++ ) { msBone& Bone = Animation.Bones[i]; for( unsigned j = 0; j < Bone.PositionKeys.size(); ++j ) Animation.nTotalFrames = max( Animation.nTotalFrames, (int)Bone.PositionKeys[j].fTime ); for( unsigned j = 0; j < Bone.RotationKeys.size(); ++j ) Animation.nTotalFrames = max( Animation.nTotalFrames, (int)Bone.RotationKeys[j].fTime ); } } return bLoaded; }
void SanityCheck() { /* Read sanity check. */ do { g_TestFile = "hello"; g_TestFilename = "file"; RageFile test; if( !test.Open("/test/file", RageFile::READ ) ) Fail( "Sanity check Open() failed: %s", test.GetError().c_str() ); RString str; int got = test.GetLine( str ); if( got <= 0 ) Fail( "Sanity check GetLine(): got %i", got ); if( str != "hello" ) Fail( "Sanity check Read(): expected \"hello\", got \"%s\"", str.c_str() ); } while(false); /* Read error sanity check. */ do { g_TestFile = "hello world"; g_TestFilename = "file"; g_BytesUntilError = 5; RageFile test; if( !test.Open("/test/file", RageFile::READ ) ) Fail( "Sanity check 2 Open() failed: %s", test.GetError().c_str() ); RString str; int got = test.Read( str, 5 ); if( got != 5 ) Fail( "Sanity check 2 Read(): got %i", got ); if( str != "hello" ) Fail( "Sanity check 2 Read(): expected \"hello\", got \"%s\"", str.c_str() ); got = test.Read( str, 5 ); if( got != -1 ) Fail( "Sanity check 2 GetLine(): expected -1, got %i", got ); if( test.GetError() != "Fake error" ) Fail( "Sanity check 2 GetError(): expected \"Fake error\", got \"%s\"", test.GetError().c_str() ); } while(false); /* Write error sanity check. */ do { g_TestFilename = "file"; g_BytesUntilError = 5; RageFile test; if( !test.Open("/test/file", RageFile::WRITE ) ) Fail( "Write error check Open() failed: %s", test.GetError().c_str() ); int wrote = test.Write( "test", 4 ); if( wrote != 4 ) Fail( "Write error check Write(): wrote %i", wrote ); wrote = test.Write( "ing", 3 ); if( wrote != -1 ) Fail( "Write error check Write(): expected -1, got %i", wrote ); if( test.GetError() != "Fake error" ) Fail( "Write error check GetError(): expected \"Fake error\", got \"%s\"", test.GetError().c_str() ); } while(false); }
void MemoryCardDriverThreaded_Linux::GetUSBStorageDevices( vector<UsbStorageDevice>& vDevicesOut ) { LOG->Trace( "GetUSBStorageDevices" ); vDevicesOut.clear(); { vector<RString> asDevices; RString sBlockDevicePath = "/sys/block/"; GetFileList( sBlockDevicePath, asDevices ); for( unsigned i = 0; i < asDevices.size(); ++i ) { const RString &sDevice = asDevices[i]; if( sDevice == "." || sDevice == ".." ) continue; UsbStorageDevice usbd; RString sPath = sBlockDevicePath + sDevice + "/"; usbd.sSysPath = sPath; /* Ignore non-removable devices. */ RString sBuf; if( !ReadFile( sPath + "removable", sBuf ) ) continue; // already warned if( atoi(sBuf) != 1 ) continue; /* * The kernel isn't exposing all of /sys atomically, so we end up missing * the partition due to it not being shown yet. It won't show up until the * kernel has scanned the partition table, which can take a variable amount * of time, sometimes over a second. Watch for the "queue" sysfs directory, * which is created after this, to tell when partition directories are created. */ RageTimer WaitUntil; WaitUntil += 5; RString sQueueFilePath = usbd.sSysPath + "queue"; while(1) { if( WaitUntil.Ago() >= 0 ) { LOG->Warn( "Timed out waiting for %s", sQueueFilePath.c_str() ); break; } if( access(usbd.sSysPath, F_OK) == -1 ) { LOG->Warn( "Block directory %s went away while we were waiting for %s", usbd.sSysPath.c_str(), sQueueFilePath.c_str() ); break; } if( access(sQueueFilePath, F_OK) != -1 ) break; usleep(10000); } /* Wait for udev to finish handling device node creation */ ExecuteCommand( "udevadm settle" ); /* If the first partition device exists, eg. /sys/block/uba/uba1, use it. */ if( access(usbd.sSysPath + sDevice + "1", F_OK) != -1 ) { LOG->Trace("OK"); usbd.sDevice = "/dev/" + sDevice + "1"; } else { LOG->Trace("error %s", strerror(errno)); usbd.sDevice = "/dev/" + sDevice; } /* * sPath/device should be a symlink to the actual device. For USB * devices, it looks like this: * * device -> ../../devices/pci0000:00/0000:00:02.1/usb2/2-1/2-1:1.0 * * "2-1" is "bus-port". */ char szLink[256]; int iRet = readlink( sPath + "device", szLink, sizeof(szLink) ); if( iRet == -1 ) { LOG->Warn( "readlink(\"%s\"): %s", (sPath + "device").c_str(), strerror(errno) ); } else { /* * The full path looks like * * ../../devices/pci0000:00/0000:00:02.1/usb2/2-2/2-2.1/2-2.1:1.0 * * In newer kernels, it looks like: * * ../../../3-2.1:1.0 * * Each path element refers to a new hop in the chain. * "usb2" = second USB host * 2- second USB host, * -2 port 1 on the host, * .1 port 1 on an attached hub * .2 ... port 2 on the next hub ... * * We want the bus number and the port of the last hop. The level is * the number of hops. */ szLink[iRet] = 0; vector<RString> asBits; split( szLink, "/", asBits ); RString sHostPort = asBits[asBits.size()-1]; if( !sHostPort.empty() ) { /* Strip off the endpoint information after the colon. */ size_t pos = sHostPort.find(':'); if( pos != string::npos ) sHostPort.erase( pos ); /* sHostPort is eg. 2-2.1. */ sHostPort.Replace( "-", "." ); asBits.clear(); split( sHostPort, ".", asBits ); if( asBits.size() > 1 ) { usbd.iBus = atoi( asBits[0] ); usbd.iPort = atoi( asBits[asBits.size()-1] ); usbd.iLevel = asBits.size() - 1; } } } if( ReadFile( sPath + "device/../idVendor", sBuf ) ) sscanf( sBuf, "%x", &usbd.idVendor ); if( ReadFile( sPath + "device/../idProduct", sBuf ) ) sscanf( sBuf, "%x", &usbd.idProduct ); if( ReadFile( sPath + "device/../serial", sBuf ) ) { usbd.sSerial = sBuf; TrimRight( usbd.sSerial ); } if( ReadFile( sPath + "device/../product", sBuf ) ) { usbd.sProduct = sBuf; TrimRight( usbd.sProduct ); } if( ReadFile( sPath + "device/../manufacturer", sBuf ) ) { usbd.sVendor = sBuf; TrimRight( usbd.sVendor ); } vDevicesOut.push_back( usbd ); } } { // Find where each device is mounted. Output looks like: // /dev/sda1 /mnt/flash1 auto noauto,owner 0 0 // /dev/sdb1 /mnt/flash2 auto noauto,owner 0 0 // /dev/sdc1 /mnt/flash3 auto noauto,owner 0 0 RString fn = "/rootfs/etc/fstab"; RageFile f; if( !f.Open(fn) ) { LOG->Warn( "can't open '%s': %s", fn.c_str(), f.GetError().c_str() ); return; } RString sLine; while( !f.AtEOF() ) { switch( f.GetLine(sLine) ) { case 0: continue; /* eof */ case -1: LOG->Warn( "error reading '%s': %s", fn.c_str(), f.GetError().c_str() ); return; } char szScsiDevice[1024]; char szMountPoint[1024]; int iRet = sscanf( sLine, "%s %s", szScsiDevice, szMountPoint ); if( iRet != 2 || szScsiDevice[0] == '#') continue; // don't process this line /* Get the real kernel device name, which should match * the name from /sys/block, by following symlinks in * /dev. This allows us to specify persistent names in * /etc/fstab using things like /dev/device/by-path. */ char szUnderlyingDevice[PATH_MAX]; if( realpath(szScsiDevice, szUnderlyingDevice) == NULL ) { // "No such file or directory" is understandable if (errno != ENOENT) LOG->Warn( "realpath(\"%s\"): %s", szScsiDevice, strerror(errno) ); continue; } RString sMountPoint = szMountPoint; TrimLeft( sMountPoint ); TrimRight( sMountPoint ); // search for the mountpoint corresponding to the device for( unsigned i=0; i<vDevicesOut.size(); i++ ) { UsbStorageDevice& usbd = vDevicesOut[i]; if( usbd.sDevice == szUnderlyingDevice ) // found our match { // Use the device entry from fstab so the mount command works usbd.sDevice = szScsiDevice; usbd.sOsMountDir = sMountPoint; break; // stop looking for a match } } } } for( unsigned i=0; i<vDevicesOut.size(); i++ ) { UsbStorageDevice& usbd = vDevicesOut[i]; LOG->Trace( " sDevice: %s, iBus: %d, iLevel: %d, iPort: %d, id: %04X:%04X, Vendor: '%s', Product: '%s', sSerial: \"%s\", sOsMountDir: %s", usbd.sDevice.c_str(), usbd.iBus, usbd.iLevel, usbd.iPort, usbd.idVendor, usbd.idProduct, usbd.sVendor.c_str(), usbd.sProduct.c_str(), usbd.sSerial.c_str(), usbd.sOsMountDir.c_str() ); } /* Remove any devices that we couldn't find a mountpoint for. */ for( unsigned i=0; i<vDevicesOut.size(); i++ ) { UsbStorageDevice& usbd = vDevicesOut[i]; if( usbd.sOsMountDir.empty() ) { LOG->Trace( "Ignoring %s (couldn't find in /etc/fstab)", usbd.sDevice.c_str() ); vDevicesOut.erase( vDevicesOut.begin()+i ); --i; } } LOG->Trace( "Done with GetUSBStorageDevices" ); }
void TitleSubst::Load(const CString &filename, const CString §ion) { RageFile f; if( !f.Open(filename) ) { LOG->Trace("Error opening %s: %s", filename.c_str(), f.GetError().c_str() ); return; } CString CurrentSection; TitleTrans tr; while (!f.AtEOF()) { CString line; int ret = f.GetLine( line ); if( ret == 0 ) break; if( ret < 0 ) { LOG->Trace("Error reading %s: %s", filename.c_str(), f.GetError().c_str() ); break; } if(line.size() > 0 && utf8_get_char(line.c_str()) == 0xFEFF) { /* Annoying header that Windows puts on UTF-8 plaintext * files; remove it. */ line.erase(0, utf8_get_char_len(line[0])); } TrimLeft(line); TrimRight(line); if(line.size() == 0) continue; /* blank */ if(line[0] == '#') continue; /* comment */ if(!line.CompareNoCase("DontTransliterate")) { tr.translit = false; continue; } size_t pos = line.find_first_of(':'); if(pos != string::npos) { /* x: y */ CString id = line.substr(0, pos); CString txt = line.substr(pos+1); TrimLeft(txt); /* Surround each regex with ^(...)$, to force all comparisons to default * to being a full-line match. (Add ".*" manually if this isn't wanted.) */ if(!id.CompareNoCase("TitleFrom")) tr.TitleFrom = "^(" + txt + ")$"; else if(!id.CompareNoCase("ArtistFrom")) tr.ArtistFrom = "^(" + txt + ")$"; else if(!id.CompareNoCase("SubtitleFrom")) tr.SubFrom = "^(" + txt + ")$"; else if(!id.CompareNoCase("TitleTo")) tr.Dest.Title = txt; else if(!id.CompareNoCase("ArtistTo")) tr.Dest.Artist = txt; else if(!id.CompareNoCase("SubtitleTo")) tr.Dest.Subtitle = txt; else if(!id.CompareNoCase("TitleTransTo")) tr.Dest.TitleTranslit = txt; else if(!id.CompareNoCase("ArtistTransTo")) tr.Dest.ArtistTranslit = txt; else if(!id.CompareNoCase("SubtitleTransTo")) tr.Dest.SubtitleTranslit = txt; else LOG->Warn( "Unknown TitleSubst tag: \"%s\"", id.c_str() ); } /* Add the translation if this is a terminator (*) or section * marker ([foo]). */ if(line[0] == '*' || line[0] == '[') { if(!CurrentSection.CompareNoCase(section)) AddTrans(tr); /* Reset. */ tr = TitleTrans(); } if(line[0] == '[' && line[line.size()-1] == ']') { CurrentSection = line.substr(1, line.size()-2); } } }
bool Model::LoadMaterialsFromMilkshapeAscii(const std::string &_sPath, std::string& load_fail_reason) { #define LOAD_FAIL load_fail_reason= fmt::sprintf("Parse error in \"%s\" at line %d: \"%s\".", sPath.c_str(), iLineNum, sLine.c_str()); return false; std::string sPath = _sPath; FixSlashesInPlace(sPath); const std::string sDir = Rage::dir_name( sPath ); RageFile f; if( !f.Open( sPath ) ) { load_fail_reason= fmt::sprintf("Model::LoadMilkshapeAscii Could not open \"%s\": %s", sPath.c_str(), f.GetError().c_str()); return false; } std::string sLine; int iLineNum = 0; while( f.GetLine( sLine ) > 0 ) { iLineNum++; if( !strncmp (sLine.c_str(), "//", 2) ) { continue; } int nFrame; if( sscanf(sLine.c_str(), "Frames: %d", &nFrame) == 1 ) { // ignore // m_pModel->nTotalFrames = nFrame; } if( sscanf(sLine.c_str(), "Frame: %d", &nFrame) == 1 ) { // ignore // m_pModel->nFrame = nFrame; } // materials int nNumMaterials = 0; if( sscanf(sLine.c_str(), "Materials: %d", &nNumMaterials) == 1 ) { m_Materials.resize( nNumMaterials ); char szName[256]; for( int i = 0; i < nNumMaterials; i++ ) { msMaterial& Material = m_Materials[i]; // name if( f.GetLine( sLine ) <= 0 ) { LOAD_FAIL; } if( sscanf(sLine.c_str(), "\"%255[^\"]\"", szName) != 1 ) { LOAD_FAIL; } Material.sName = szName; // ambient if( f.GetLine( sLine ) <= 0 ) { LOAD_FAIL; } Rage::Vector4 Ambient; if( sscanf(sLine.c_str(), "%f %f %f %f", &Ambient.x, &Ambient.y, &Ambient.z, &Ambient.w) != 4 ) { LOAD_FAIL; } memcpy( &Material.Ambient, &Ambient, sizeof(Material.Ambient) ); // diffuse if( f.GetLine( sLine ) <= 0 ) { LOAD_FAIL; } Rage::Vector4 Diffuse; if( sscanf(sLine.c_str(), "%f %f %f %f", &Diffuse.x, &Diffuse.y, &Diffuse.z, &Diffuse.w) != 4 ) { LOAD_FAIL; } memcpy( &Material.Diffuse, &Diffuse, sizeof(Material.Diffuse) ); // specular if( f.GetLine( sLine ) <= 0 ) { LOAD_FAIL; } Rage::Vector4 Specular; if( sscanf(sLine.c_str(), "%f %f %f %f", &Specular.x, &Specular.y, &Specular.z, &Specular.w) != 4 ) { LOAD_FAIL; } memcpy( &Material.Specular, &Specular, sizeof(Material.Specular) ); // emissive if( f.GetLine( sLine ) <= 0 ) { LOAD_FAIL; } Rage::Vector4 Emissive; if( sscanf (sLine.c_str(), "%f %f %f %f", &Emissive.x, &Emissive.y, &Emissive.z, &Emissive.w) != 4 ) { LOAD_FAIL; } memcpy( &Material.Emissive, &Emissive, sizeof(Material.Emissive) ); // shininess if( f.GetLine( sLine ) <= 0 ) { LOAD_FAIL; } float fShininess; if( !StringConversion::FromString(sLine, fShininess) ) { LOAD_FAIL; } Material.fShininess = fShininess; // transparency if( f.GetLine( sLine ) <= 0 ) { LOAD_FAIL; } float fTransparency; if( !StringConversion::FromString(sLine, fTransparency) ) { LOAD_FAIL; } Material.fTransparency = fTransparency; // diffuse texture if( f.GetLine( sLine ) <= 0 ) { LOAD_FAIL; } strcpy( szName, "" ); sscanf( sLine.c_str(), "\"%255[^\"]\"", szName ); std::string sDiffuseTexture = szName; if( sDiffuseTexture == "" ) { Material.diffuse.LoadBlank(); } else { std::string sTexturePath = sDir + sDiffuseTexture; FixSlashesInPlace( sTexturePath ); CollapsePath( sTexturePath ); if( !IsAFile(sTexturePath) ) { load_fail_reason= fmt::sprintf("\"%s\" references a texture \"%s\" that does not exist.", sPath.c_str(), sTexturePath.c_str()); return false; } Material.diffuse.Load( sTexturePath ); } // alpha texture if( f.GetLine( sLine ) <= 0 ) { LOAD_FAIL; } strcpy( szName, "" ); sscanf( sLine.c_str(), "\"%255[^\"]\"", szName ); std::string sAlphaTexture = szName; if( sAlphaTexture == "" ) { Material.alpha.LoadBlank(); } else { std::string sTexturePath = sDir + sAlphaTexture; FixSlashesInPlace( sTexturePath ); CollapsePath( sTexturePath ); if( !IsAFile(sTexturePath) ) { load_fail_reason= fmt::sprintf("\"%s\" references a texture \"%s\" that does not exist.", sPath.c_str(), sTexturePath.c_str()); return false; } Material.alpha.Load( sTexturePath ); } } } } #undef LOAD_FAIL return true; }
void ConditionalBGA::Load(const CString &szScreenName) { RageFile file; CString szConditionalBGAFile = THEME->GetCurThemeDir() + szScreenName + " ConditionalBGA.ini"; // char filepath[512]; // strcpy(filepath,""); // empty the path first // strcpy(filepath,szConditionalBGAFile.c_str()); LOG->Trace("ConditionalBGA Load:%s",szConditionalBGAFile.c_str()); bool loaded = file.Open(szConditionalBGAFile,RageFile::READ); // FILE* fp = NULL; // fp = fopen(filepath,"r"); if(!loaded) { LOG->Trace("ConditionalBGA File Not Found"); return; } else { CString currentline; int bgano=0; while(!file.AtEOF()) { file.GetLine(currentline); // get the current line // kill any possible comments CStringArray asKillComments; asKillComments.clear(); // get rid of anything in there split(currentline, "#",asKillComments); // A comment starting with # if(!asKillComments.empty()) { currentline = asKillComments[0]; // there was some commentstuff here, take the first bit to be the actual data } asKillComments.clear(); // get rid of anything in there split(currentline, "/",asKillComments); // A comment starting with // or /* if(!asKillComments.empty()) { currentline = asKillComments[0]; // there was some commentstuff here, take the first bit to be the actual data } TrimRight(currentline); // nuke trailing whitespace // start parsing the data if(currentline.c_str()[0] == '[') // we found a new bganimation { if(!m_bgainfo.empty()) // last one wasnt empty { CheckBgaRequirements(m_bgainfo[bgano]); bgano++; } BgaCondInfo temp; m_bgainfo.push_back(temp); ClearINFO(bgano); // wipe out the old info structure. CStringArray asSplitLine; split(currentline,"[",asSplitLine); split(asSplitLine[0],"]",asSplitLine); if(!asSplitLine.empty() && asSplitLine.size() >= 1) m_bgainfo[bgano].bganame = asSplitLine[asSplitLine.size() - 1]; } else { CStringArray asSplitLine; split(currentline,":",asSplitLine); if(asSplitLine.empty()) continue; if(!asSplitLine[0].CompareNoCase("clear") && asSplitLine.size() > 1) { if(!asSplitLine[1].CompareNoCase("true") || !asSplitLine[1].CompareNoCase("cleared") || !asSplitLine[1].CompareNoCase("clear")) // true / clear (any clear condition) m_bgainfo[bgano].cleared = CBGA_CSCLEARED; else if(!asSplitLine[1].CompareNoCase("false") || !asSplitLine[1].CompareNoCase("failed")) // false / failed m_bgainfo[bgano].cleared = CBGA_CSFAILED; else if(!asSplitLine[1].CompareNoCase("maxcombo") || !asSplitLine[1].CompareNoCase("fullcombo")) // passed with maxcombo m_bgainfo[bgano].cleared = CBGA_CSMAXCOMBO; else if(!asSplitLine[1].CompareNoCase("brokencombo")) // passed with a broken combo m_bgainfo[bgano].cleared = CBGA_CSBROKECOMBO; // LOG->Trace("Clear Conditon: %d",info.cleared); } if(!asSplitLine[0].CompareNoCase("songtitle") && asSplitLine.size() > 1) { m_bgainfo[bgano].songtitle = asSplitLine[1]; // LOG->Trace("SongTitle: %s",info.songtitle.c_str()); } if(!asSplitLine[0].CompareNoCase("songartist") && asSplitLine.size() > 1) { m_bgainfo[bgano].songartist = asSplitLine[1]; // LOG->Trace("SongArtist: %s",info.songartist.c_str()); } if(!asSplitLine[0].CompareNoCase("songday") && asSplitLine.size() > 1) { CStringArray asDays; split( asSplitLine[1], ",", asDays ); for( unsigned d=0; d<asDays.size(); d++ ) { int dn = atoi(asDays[d].c_str()); if(!(dn < 1 || dn > 32)) // ignore if date is out of range { m_bgainfo[bgano].songdays.push_back(dn); } } // for(d=0; d<info.songdays.size(); d++) // { // LOG->Trace("SongDay: %d",info.songdays[d]); // } } if(!asSplitLine[0].CompareNoCase("songmonth") && asSplitLine.size() > 1) { CStringArray asMonths; split( asSplitLine[1], ",", asMonths ); for( unsigned d=0; d<asMonths.size(); d++ ) { int dn = atoi(asMonths[d].c_str()); if(!(dn < 1 || dn > 12)) // ignore if date is out of range { m_bgainfo[bgano].songmonths.push_back(dn); } } // for(d=0; d<info.songmonths.size(); d++) // { // LOG->Trace("SongMonth: %d",info.songmonths[d]); // } } // foot meter ratings if(!asSplitLine[0].CompareNoCase("songdifficulty") && asSplitLine.size() > 1) { CStringArray asDifficulties; split( asSplitLine[1], ",", asDifficulties ); for(unsigned d=0;d<asDifficulties.size();d++) { // check to see if the last character is a + bool bHandled = false; if(asDifficulties[d].c_str()[strlen(asDifficulties[d].c_str())-1] == '+') { bHandled = true; CStringArray asVal; split(asDifficulties[d],"+",asVal); int temp=0; temp = 0 - atoi(asVal[0].c_str()); // negative numbers will indicate 'greater than' for this system m_bgainfo[bgano].songmeters.push_back(temp); } if(!bHandled) // didnt find the + (gt) so find a - (range) { bool isarange=false; for(unsigned b=0; b<strlen(asDifficulties[d].c_str());b++) { if(asDifficulties[d].c_str()[b] == '-') { bHandled = isarange = true; break; } } if(isarange) { CStringArray asVal; split(asDifficulties[d],"-",asVal); int imin=0,imax=0,itmp=0; imin=atoi(asVal[0].c_str()); imax=atoi(asVal[1].c_str()); itmp=imin; while(itmp<=imax) // fill in the values between the min and max range inclusive { m_bgainfo[bgano].songmeters.push_back(itmp); itmp++; } } } if(!bHandled) // its not a range so must be a value on its own { int tmp = atoi(asDifficulties[d].c_str()); m_bgainfo[bgano].songmeters.push_back(tmp); } } } // mods that mustn't be present if(!asSplitLine[0].CompareNoCase("moddisallow") && asSplitLine.size() > 1) { m_bgainfo[bgano].dpoused = true; m_bgainfo[bgano].disallowedpo.FromString(asSplitLine[1]); } // heavy, light e.t.c. if(!asSplitLine[0].CompareNoCase("songrating") && asSplitLine.size() > 1) { CStringArray asDifficulties; split( asSplitLine[1], ",", asDifficulties ); for( unsigned d=0; d<asDifficulties.size(); d++ ) { m_bgainfo[bgano].difficulties.push_back(StringToDifficulty(asDifficulties[d])); } // for(d=0; d<info.difficulties.size(); d++) // { // LOG->Trace("Difficulty: %d",info.difficulties[d]); // } } if(!asSplitLine[0].CompareNoCase("grade") && asSplitLine.size() > 1) { CStringArray asGrades; split( asSplitLine[1], ",", asGrades ); for( unsigned d=0; d<asGrades.size(); d++ ) { m_bgainfo[bgano].grades.push_back(StringToGrade(asGrades[d])); } } if(!asSplitLine[0].CompareNoCase("style") && asSplitLine.size() > 1) { LOG->Info("Comparing Styles"); CStringArray asStyles; split( asSplitLine[1], ",", asStyles ); for( unsigned d=0; d<asStyles.size(); d++ ) { LOG->Info( "Style:%s", asStyles[d].c_str() ); m_bgainfo[bgano].styles.push_back(GAMEMAN->GameAndStringToStyle(GAMESTATE->m_pCurGame,asStyles[d])); } } } } if(bganimtouse.CompareNoCase("")!=0) { LOG->Info("Best Match BGA Was: %s",bganimtouse.c_str()); bganim.LoadFromAniDir( THEME->GetPathToB(bganimtouse) ); } } file.Close(); }
void RageModelGeometry::LoadMilkshapeAscii( const std::string& _sPath, bool bNeedsNormals ) { std::string sPath = _sPath; FixSlashesInPlace(sPath); const std::string sDir = Rage::dir_name( sPath ); RageFile f; if( !f.Open( sPath ) ) RageException::Throw( "RageModelGeometry::LoadMilkshapeAscii Could not open \"%s\": %s", sPath.c_str(), f.GetError().c_str() ); std::string sLine; int iLineNum = 0; char szName[MS_MAX_NAME]; int nFlags, nIndex; RageVec3ClearBounds( m_vMins, m_vMaxs ); while( f.GetLine( sLine ) > 0 ) { iLineNum++; if( !strncmp(sLine.c_str(), "//", 2) ) continue; int nFrame; if( sscanf(sLine.c_str(), "Frames: %d", &nFrame) == 1 ) { // ignore // m_pRageModelGeometry->nTotalFrames = nFrame; } if( sscanf(sLine.c_str(), "Frame: %d", &nFrame) == 1 ) { // ignore // m_pRageModelGeometry->nFrame = nFrame; } int nNumMeshes = 0; if( sscanf(sLine.c_str(), "Meshes: %d", &nNumMeshes) == 1 ) { ASSERT( m_Meshes.empty() ); m_Meshes.resize( nNumMeshes ); for( int i = 0; i < nNumMeshes; i++ ) { msMesh &mesh = m_Meshes[i]; vector<Rage::ModelVertex> &Vertices = mesh.Vertices; vector<msTriangle> &Triangles = mesh.Triangles; if( f.GetLine( sLine ) <= 0 ) THROW; // mesh: name, flags, material index if( sscanf (sLine.c_str(), "\"%31[^\"]\" %d %d",szName, &nFlags, &nIndex) != 3 ) THROW; mesh.sName = szName; // mesh.nFlags = nFlags; mesh.nMaterialIndex = (uint8_t) nIndex; mesh.m_iBoneIndex = -1; // // vertices // if( f.GetLine( sLine ) <= 0 ) THROW; int nNumVertices = 0; if( sscanf (sLine.c_str(), "%d", &nNumVertices) != 1 ) THROW; Vertices.resize( nNumVertices ); for( int j = 0; j < nNumVertices; j++ ) { Rage::ModelVertex &v = Vertices[j]; if( f.GetLine( sLine ) <= 0 ) THROW; if( sscanf(sLine.c_str(), "%d %f %f %f %f %f %d", &nFlags, &v.p.x, &v.p.y, &v.p.z, &v.t.x, &v.t.y, &nIndex ) != 7 ) { THROW; } // vertex.nFlags = nFlags; if( nFlags & 1 ) v.TextureMatrixScale.x = 0; if( nFlags & 2 ) v.TextureMatrixScale.y = 0; if( nFlags & 4 ) { v.t.x = v.p.x / v.t.x; v.t.y = v.p.y / v.t.y; } v.bone = (uint8_t) nIndex; RageVec3AddToBounds( v.p, m_vMins, m_vMaxs ); } // // normals // if( f.GetLine( sLine ) <= 0 ) THROW; int nNumNormals = 0; if( sscanf(sLine.c_str(), "%d", &nNumNormals) != 1 ) THROW; vector<Rage::Vector3> Normals; Normals.resize( nNumNormals ); for( int j = 0; j < nNumNormals; j++ ) { if( f.GetLine( sLine ) <= 0 ) THROW; Rage::Vector3 Normal; if( sscanf(sLine.c_str(), "%f %f %f", &Normal.x, &Normal.y, &Normal.z) != 3 ) THROW; Normal = Normal.GetNormalized(); Normals[j] = Normal; } // // triangles // if( f.GetLine( sLine ) <= 0 ) THROW; int nNumTriangles = 0; if( sscanf (sLine.c_str(), "%d", &nNumTriangles) != 1 ) THROW; Triangles.resize( nNumTriangles ); for( int j = 0; j < nNumTriangles; j++ ) { if( f.GetLine( sLine ) <= 0 ) THROW; uint16_t nIndices[3]; uint16_t nNormalIndices[3]; if( sscanf (sLine.c_str(), "%d %hd %hd %hd %hd %hd %hd %d", &nFlags, &nIndices[0], &nIndices[1], &nIndices[2], &nNormalIndices[0], &nNormalIndices[1], &nNormalIndices[2], &nIndex ) != 8 ) { THROW; } // deflate the normals into vertices for( int k=0; k<3; k++ ) { ASSERT_M( nIndices[k] < Vertices.size(), fmt::sprintf("mesh \"%s\" tri #%i accesses vertex %i, but we only have %i", szName, j, nIndices[k], int(Vertices.size())) ); ASSERT_M( nNormalIndices[k] < Normals.size(), fmt::sprintf("mesh \"%s\" tri #%i accesses normal %i, but we only have %i", szName, j, nNormalIndices[k], int(Normals.size())) ); Rage::ModelVertex& vertex = Vertices[ nIndices[k] ]; Rage::Vector3& normal = Normals[ nNormalIndices[k] ]; vertex.n = normal; //mesh.Vertices[nIndices[k]].n = Normals[ nNormalIndices[k] ]; } msTriangle& Triangle = Triangles[j]; // Triangle.nFlags = nFlags; memcpy( &Triangle.nVertexIndices, nIndices, sizeof(Triangle.nVertexIndices) ); // Triangle.nSmoothingGroup = nIndex; } } } } OptimizeBones(); if( DISPLAY->SupportsPerVertexMatrixScale() ) { if( m_Meshes.size() == 2 && m_Meshes[0].sName == m_Meshes[1].sName ) { MergeMeshes( 1, 0 ); } } // send the finalized vertices to the graphics card m_pCompiledGeometry->Set( m_Meshes, bNeedsNormals ); }