// load kerning informations static void LoadKerning(GFont2D& Font, const FT_Face Face, const GReal Scale, const GString& MetricsFile) { FT_Vector v; FT_Error err; GInt32 i, j, k; GKerningEntry entry; GDynArray<GKerningEntry> kerningTable; if (MetricsFile.length() > 0) err = FT_Attach_File(Face, StrUtils::ToAscii(MetricsFile)); // if the face has not kerning infos just return if ((Face->face_flags & FT_FACE_FLAG_KERNING) == 0) return; j = (GInt32)Face->num_glyphs; for (i = 0; i < j; i++) { for (k = 0; k < j; k++) { // get kerning for pair (i, k) err = FT_Get_Kerning(Face, i, k, FT_KERNING_UNSCALED, &v); if ((err == 0) && ((v.x != 0) || (v.y != 0))) { entry.GlyphIndexLeft = i; entry.GlyphIndexRight = k; entry.Kerning.Set((GReal)v.x * Scale, (GReal)v.y * Scale); kerningTable.push_back(entry); } } } Font.SetKerning(kerningTable); }
static GString getDifficultyAuthor(T const *Diff) { GString candidate = GameState::GetInstance().GetSongDatabase()->GetArtistForDifficulty(Diff->ID); if (!candidate.length()) candidate = Diff->Author; return candidate; }
GError GPlugLoader::LoadFilePlug(const GChar8 *FullLibraryName) { GPlugHandle handle = NULL; // we don't wanna a null filename if (!FullLibraryName) return G_INVALID_PARAMETER; // unplug current library UnloadPlug(); #if defined(G_OS_WIN) && !defined(__CYGWIN__) handle = LoadLibraryA(FullLibraryName); #elif defined(G_OS_HPUX) // BIND_FIRST is necessary for some reason handle = shl_load(FullLibraryName, BIND_DEFERRED | BIND_FIRST | BIND_VERBOSE, 0); // other Unix (it works also on MacOSX and Tiger) #else handle = dlopen(FullLibraryName, RTLD_LAZY | RTLD_GLOBAL); // dlopen will not work with files in the current directory unless // they are prefaced with './' (DB - Nov 5, 2003). // So we must check if file was expressed as a local file (without path) GString fPath = StrUtils::ExtractFilePath(FullLibraryName); if ((!handle) && (fPath.length() <= 0)) { GString localLibraryName = GString("./") + GString(FullLibraryName); handle = dlopen(StrUtils::ToAscii(localLibraryName), RTLD_LAZY | RTLD_GLOBAL); } #endif if (!handle) return G_INVALID_FORMAT; gPlugHandle = handle; return G_NO_ERROR; }
void ReadMetadata (GString line, OsuLoadInfo* Info) { auto Command = line.substr(0, line.find_first_of(":")); // Lines are Information:Content auto Content = line.substr(line.find_first_of(":") + 1, line.length() - line.find_first_of(":")); #ifdef VERBOSE_DEBUG printf("Command found: %s | Contents: %s\n", Command.c_str(), Content.c_str()); #endif Utility::Trim(Content); if (Command == "Title") { Info->OsuSong->SongName = Content; }else if (Command == "Artist") { Info->OsuSong->SongAuthor = Content; }else if (Command == "Version") { Info->Diff->Name = Content; }else if (Command == "TitleUnicode") { if (Content.length() > 1) Info->OsuSong->SongName = Content; }else if (Command == "ArtistUnicode") { if (Content.length() > 1) Info->OsuSong->SongAuthor = Content; } else if (Command == "Creator") { Info->Diff->Author = Content; } }
void InitApp() { #ifdef _DEBUG SysUtils::RedirectIOToConsole(); #endif GString s; gKernel = new GKernel(); gFont = (GFont2D *)gKernel->CreateNew(G_FONT2D_CLASSID); // Depth Into The Screen gX = -0.4f; gY = -0.3f; gZ = -2.3f; // build path for data (textures) gDataPath = SysUtils::AmanithPath(); if (gDataPath.length() > 0) gDataPath += "data/"; s = StrUtils::OSFixPath(gDataPath + "crazk.ttf", G_FALSE); gFont->Load(StrUtils::ToAscii(s), "scale=0"); gWireFrame = G_TRUE; gFillDraw = G_TRUE; gDeviation = (GReal)0.000003; gCurrentChar = 'S'; gChar = gFont->CharByCode(gCurrentChar, 0); GenerateTessellation(gChar, gDeviation); }
// Inserts a filename, if it already exists, updates it. // Returns the ID of the filename. int SongDatabase::InsertFilename(Directory Fn) { int ret; int idOut; int lmt; SC(sqlite3_bind_text(st_FilenameQuery, 1, Fn.c_path(), Fn.path().length(), SQLITE_STATIC)); if (sqlite3_step(st_FilenameQuery) == SQLITE_ROW) { idOut = sqlite3_column_int(st_FilenameQuery, 0); lmt = sqlite3_column_int(st_FilenameQuery, 1); int lastLmt = Utility::GetLMT(Fn.path()); // Update the last-modified-time of this file, and its hash if it has changed. if (lmt != lastLmt) { GString Hash = Utility::GetSha256ForFile(Fn); SC(sqlite3_bind_int(st_UpdateLMT, 1, lastLmt)); SC(sqlite3_bind_text(st_UpdateLMT, 2, Hash.c_str(), Hash.length(), SQLITE_STATIC)); SC(sqlite3_bind_text(st_UpdateLMT, 3, Fn.c_path(), Fn.path().length(), SQLITE_STATIC)); SCS(sqlite3_step(st_UpdateLMT)); SC(sqlite3_reset(st_UpdateLMT)); } }else { GString Hash = Utility::GetSha256ForFile(Fn); // There's no entry, got to insert it. SC(sqlite3_bind_text(st_FilenameInsertQuery, 1, Fn.c_path(), Fn.path().length(), SQLITE_STATIC)); SC(sqlite3_bind_int(st_FilenameInsertQuery, 2, Utility::GetLMT(Fn.path()))); SC(sqlite3_bind_text(st_FilenameInsertQuery, 3, Hash.c_str(), Hash.length(), SQLITE_STATIC)); SCS(sqlite3_step(st_FilenameInsertQuery)); // This should not fail. Otherwise, there are bigger problems to worry about... SC(sqlite3_reset(st_FilenameInsertQuery)); // okay, then return the ID. SC(sqlite3_reset(st_FilenameQuery)); SC(sqlite3_bind_text(st_FilenameQuery, 1, Fn.c_path(), Fn.path().length(), SQLITE_STATIC)); sqlite3_step(st_FilenameQuery); idOut = sqlite3_column_int(st_FilenameQuery, 0); } SC(sqlite3_reset(st_FilenameQuery)); return idOut; }
GError GProperty::SetName(const GString& NewName) { if (NewName.length() <= 0) return G_INVALID_PARAMETER; gName = NewName; gUpperName = StrUtils::Upper(gName); return G_NO_ERROR; }
GString SJIStoU8 (GString Line) { #ifdef WIN32 wchar_t u16s[MAX_STRING_SIZE]; char mbs[MAX_STRING_SIZE]; size_t len = MultiByteToWideChar(932, 0, Line.c_str(), Line.length(), u16s, MAX_STRING_SIZE); len = WideCharToMultiByte(CP_UTF8, 0, u16s, len, mbs, MAX_STRING_SIZE, NULL, NULL); mbs[len] = 0; return GString(mbs); #elif defined(DARWIN) // Note: for OS X/Darwin/More than likely most BSD variants, iconv behaves a bit differently. iconv_t conv; char buf[MAX_STRING_SIZE]; char* out = buf; size_t srcLength = Line.length(); size_t dstLength = MAX_STRING_SIZE; const char* in = Line.c_str(); conv = iconv_open("UTF-8", "SHIFT_JIS"); iconv(conv, (char**)&in, &srcLength, (char**)&out, &dstLength); iconv_close(conv); // We have to use buf instead of out here. For whatever reason, iconv on Darwin doesn't get us what we would expect if we just use out. return GString(buf); #else char buf[MAX_STRING_SIZE]; iconv_t conv; char** out = &buf; const char* in = Line.c_str(); size_t BytesLeftSrc = Line.length(); size_t BytesLeftDst = MAX_STRING_SIZE; conv = iconv_open("UTF-8", "SHIFT_JIS"); bool success = (iconv(conv, (char **)&in, &BytesLeftSrc, out, &BytesLeftDst) > -1); iconv_close(conv); if (success) return GString(*out); else { Log::Printf("Failure converting character sets."); return GString(); } #endif }
// remove the specified property form internal list GBool GAnimElement::RemoveProperty(const GString& Name) { if (Name.length() <= 0) return G_FALSE; GUInt32 propIndex; GProperty *tmpProp; tmpProp = FindProperty(Name, propIndex); return RemoveProperty(propIndex); }
std::wstring Widen(GString Line) { wchar_t u16s[2048]; // Ought to be enough for everyone. #ifndef WIN32 mbstowcs(u16s, Line.c_str(), 2048); #else memset(u16s, 0, sizeof(wchar_t) * 2048); size_t len = MultiByteToWideChar(CP_UTF8, 0, Line.c_str(), Line.length(), u16s, 2048); #endif return std::wstring(u16s); }
int InitGL(GLvoid) { gKernel = new GKernel(); gImage = (GPixelMap *)gKernel->CreateNew(G_PIXELMAP_CLASSID); // build path for data (textures) gDataPath = SysUtils::AmanithPath(); if (gDataPath.length() > 0) gDataPath += "data/"; gRotAngle = 0; gRotationVel = (GReal)0.05; gStrokeOpacity = 1; gFillOpacity = 1; gZoomFactor = 2; gAnim = G_FALSE; gTranslation.Set(256, 256); gStrokeCompOp = G_SRC_OVER_OP; gFillCompOp = G_SRC_OVER_OP; gDrawBoard->SetRenderingQuality(G_HIGH_RENDERING_QUALITY); GString s; GError err; GDynArray<GKeyValue> colKeys; // color gradient colKeys.clear(); colKeys.push_back(GKeyValue((GReal)0.00, GVector4((GReal)0.95, (GReal)0.92, (GReal)0.0, (GReal)1.0))); colKeys.push_back(GKeyValue((GReal)1.00, GVector4((GReal)0.1, (GReal)0.3, (GReal)0.8, (GReal)0.7))); gLinGrad = gDrawBoard->CreateLinearGradient(GPoint2(-60, -44), GPoint2(60, 44), colKeys, G_HERMITE_COLOR_INTERPOLATION, G_PAD_COLOR_RAMP_SPREAD); // background s = gDataPath + "compground.png"; err = gImage->Load(StrUtils::ToAscii(s), "expandpalette=true"); if (err == G_NO_ERROR) { gBackGround = gDrawBoard->CreatePattern(gImage, G_LOW_IMAGE_QUALITY, G_REPEAT_TILE); gBackGround->SetLogicalWindow(GPoint2(0, 0), GPoint2(512, 512)); } else gBackGround = NULL; gDrawBoard->SetStrokeWidth(10); gDrawBoard->SetStrokeGradient(gLinGrad); gDrawBoard->SetFillGradient(gLinGrad); gDrawBoard->SetFillPattern(gBackGround); DrawTitle(); return TRUE; }
vector<GString> TokenSplit(const GString& str, const GString &token, bool compress) { vector<GString> ret; size_t len = str.length(); auto it = &str[0]; auto next = strpbrk(str.c_str(), token.c_str()); // next token instance for (; next != nullptr; next = strpbrk(it, token.c_str())) { if (!compress || it - next != 0) ret.push_back(GString(it, next)); it = next + 1; } if (it != next && len) ret.push_back(GString(it, &str[len])); return ret; }
// returns if difficulty exists in the database. And difficulty ID. bool SongDatabase::DifficultyExists(int FileID, GString DifficultyName, int *IDOut) { int ret; SC(sqlite3_bind_int (st_GetDiffIDFile, 1, FileID)); SC(sqlite3_bind_text(st_GetDiffIDFile, 2, DifficultyName.c_str(), DifficultyName.length(), SQLITE_STATIC)); int r = sqlite3_step(st_GetDiffIDFile); if (IDOut) { if (r == SQLITE_ROW) *IDOut = sqlite3_column_int(st_GetDiffIDFile, 0); else *IDOut = 0; } SC(sqlite3_reset(st_GetDiffIDFile)); return r == SQLITE_ROW; }
int KeyTranslate(GString K) { for (uint32 i = 0; i < SpecialKeys.size(); i++) { GString Key = K; Utility::ToLower(Key); GString Target = GString(SpecialKeys.at(i).KeyString); Utility::ToLower(Target); if (Key == Target) return SpecialKeys.at(i).boundkey; } if (K.length()) { if (Utility::IsNumeric(K.c_str())) return atoi(K.c_str()); else return (int)K[0]; } else return 0; }
void InitApp() { #ifdef _DEBUG SysUtils::RedirectIOToConsole(); #endif GError err; // create a new kernel gKernel = new GKernel(); // build path for data GString dataPath = SysUtils::AmanithPath(); if (dataPath.length() > 0) dataPath += "data/"; // load glyphs and triangulate them err = LoadAndTesselateGlyphs(dataPath + "cards.ttf", (GReal)1e-7); if (err != G_NO_ERROR) { perror("Fail to load cards.ttf"); abort(); } // load cards and animations err = LoadCardsAndAnimations(dataPath + "cards.xml"); if (err != G_NO_ERROR) { perror("Fail to load cards.xml"); abort(); } // load and initialize background LoadBackGraoundAndLogo(dataPath + "stars.png"); // initialize random generator GMath::SeedRandom(); // begin with 7 cards gMaxCards = 7; gLogicTick = 0.13; gBackGroundTime = 0; gBackGroundTimeStep = 0.0003; gAnimCards.resize(gMaxCards); }
GString RemoveComments(const GString Str) { GString Result; int k = 0; int AwatingEOL = 0; ptrdiff_t len = Str.length() - 1; for (ptrdiff_t i = 0; i < len; i++) { if (AwatingEOL) { if (Str[i] != '\n') continue; else { AwatingEOL = 0; continue; } } else { if (Str[i] == '/' && Str[i + 1] == '/') { AwatingEOL = true; continue; } else { Result.push_back(Str.at(i)); k++; } } } Utility::ReplaceAll(Result, "[\\n\\r ]", ""); return Result; }
void ReadDifficulty (GString line, OsuLoadInfo* Info) { GString Command = line.substr(0, line.find_first_of(":")); // Lines are Information:Content GString Content = line.substr(line.find_first_of(":") + 1, line.length() - line.find_first_of(":")); Utility::Trim(Content); // We ignore everything but the key count! if (Command == "CircleSize") { Info->Diff->Channels = atoi(Content.c_str()); }else if (Command == "SliderMultiplier") { Info->SliderVelocity = latof(Content.c_str()) * 100; } else if (Command == "HPDrainRate") { Info->TimingInfo->HP = latof(Content.c_str()); } else if (Command == "OverallDifficulty") { Info->TimingInfo->OD = latof(Content.c_str()); } }
GString GetSVGText(int diffIndex, double intervalduration = 1, double peakMargin = 1.2) { std::stringstream out; vector<int> dataPoints = GetDataPoints(diffIndex, intervalduration); auto peak_it = std::max_element(dataPoints.begin(), dataPoints.end()); float peakf = *peak_it; double peak = *peak_it * peakMargin; out << "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n"; auto ptIdx = 0; float ImageHeight = CfgValNPS("GraphHeight", 300); float GraphYOffset = CfgValNPS("GraphYOffs", 50); float GraphXOffset = CfgValNPS("GraphXOffs", 100); float IntervalWidth = 10; float GraphWidth = dataPoints.size() * IntervalWidth; float RealGraphWidth = CfgValNPS("Width", 1000); float XRatio = RealGraphWidth / GraphWidth; Vec2 BL(GraphXOffset, GraphYOffset + ImageHeight); Vec2 BR(RealGraphWidth, 0); Vec2 TL(GraphXOffset, GraphYOffset); BR += BL; GString DiffAuth = Song->GetDifficulty(diffIndex)->Author; if (!DiffAuth.length()) DiffAuth = "an anonymous charter"; float avgNPS = Song->GetDifficulty(diffIndex)->TotalScoringObjects / Song->GetDifficulty(diffIndex)->Duration; out << Utility::Format("<text x=\"%d\" y=\"%d\" fill=\"black\">%s - %s (%s) by %s (Max NPS: %.2f/Avg NPS: %.2f)</text>\n", 20, 20, Song->SongName, Song->SongAuthor, Song->GetDifficulty(diffIndex)->Name, DiffAuth, peakf / intervalduration, avgNPS); out << Utility::Format("\t<line x1 = \"%d\" y1 = \"%d\" x2 = \"%d\" y2 = \"%d\" style = \"stroke:rgb(0,0,0);stroke-width:4\"/>\n", BL.x, BL.y, BR.x, BR.y); out << Utility::Format("\t<line x1 = \"%d\" y1 = \"%d\" x2 = \"%d\" y2 = \"%d\" style = \"stroke:rgb(0,0,0);stroke-width:4\"/>\n", TL.x, TL.y, BL.x, BL.y); auto ptAmt = 5; for (auto i = 1; i <= ptAmt; i++) { float X = (BL.x - GraphXOffset / 2); float Y = (BL.y - i * (ImageHeight / ptAmt / peakMargin)); float Value = (peakf * i / ptAmt / intervalduration); out << Utility::Format("\t<text x=\"%d\" y=\"%d\" fill=\"black\">%.2f</text>\n", X, Y, Value); out << Utility::Format("\t<line x1 = \"%d\" y1 = \"%d\" x2 = \"%d\" y2 = \"%d\" style = \"stroke:rgb(0,0,0);stroke-width:0.5\"/>\n", X, Y, GraphXOffset + RealGraphWidth, Y); } for (auto point : dataPoints) { double relativeFreq = point / peak; double relFreqNext; int x1, y1, x2, y2; if (ptIdx + 1 < dataPoints.size()) { relFreqNext = dataPoints[ptIdx + 1] / peak; } else relFreqNext = 0; x1 = IntervalWidth * ptIdx * XRatio + GraphXOffset; y1 = ImageHeight - ImageHeight * relativeFreq + GraphYOffset; x2 = IntervalWidth * (ptIdx + 1) * XRatio + GraphXOffset; y2 = ImageHeight - ImageHeight * relFreqNext + GraphYOffset; out << Utility::Format("\t<line x1 = \"%d\" y1 = \"%d\" x2 = \"%d\" y2 = \"%d\" style = \"stroke:rgb(255,0,0);stroke-width:2\"/>\n", x1, y1, x2, y2); ptIdx++; } out << "</svg>"; return out.str(); }
bool CDx9FragmentProgram::load(const GString str) { return load(str.c_str(),str.length()); }
QGLWidgetTest::QGLWidgetTest(const QGLFormat& Format, QWidget *parent) : QGLWidget(Format, parent) { #else QGLWidgetTest::QGLWidgetTest(QWidget * parent) : QGLWidget(parent) { #endif #ifdef _DEBUG SysUtils::RedirectIOToConsole(); #endif GError err; // create a new kernel gKernel = new GKernel(); // build path for data GString dataPath = SysUtils::AmanithPath(); if (dataPath.length() > 0) dataPath += "data/"; // load glyphs and triangulate them err = LoadAndTesselateGlyphs(dataPath + "cards.ttf", (GReal)1e-7); if (err != G_NO_ERROR) { perror("Fail to load cards.ttf"); abort(); } // load cards and animations err = LoadCardsAndAnimations(dataPath + "cards.xml"); if (err != G_NO_ERROR) { perror("Fail to load cards.xml"); abort(); } // load and initialize background LoadBackGraoundAndLogo(dataPath + "stars.png"); // initialize random generator GMath::SeedRandom(); // begin with 9 cards gMaxCards = 9; gBlockAnim = G_FALSE; gLogicTick = 0.5; gAnimCards.resize(gMaxCards); // resize the window QWidget *d = (QWidget *)QApplication::desktop(); GInt32 winSize = GMath::Min(d->width(), d->height()); this->resize(winSize-64, winSize-64); } //------------------------------------------------------------ void QGLWidgetTest::LoadBackGraoundAndLogo(const GString& FileName) { GError err; // create and load background texture gBackGround = (GPixelMap *)gKernel->CreateNew(G_PIXELMAP_CLASSID); if (!gBackGround) { perror("Fail to create background GPixelMap"); abort(); } // use 'expandpalette' option just to ensure full color format (so artists can manipulate starts.png as // they want to do err = gBackGround->Load(StrUtils::ToAscii(FileName), "expandpalette=true"); if (err != G_NO_ERROR) { perror("Fail to load stars.png"); abort(); } gBackGroundAnimUV = (GAnimTRSNode2D *)gKernel->CreateNew(G_ANIMTRSNODE2D_CLASSID); gBackGroundAnimColor = (GThreeHermiteProperty1D *)gKernel->CreateNew(G_THREEHERMITEPROPERTY1D_CLASSID); if (!gBackGroundAnimUV || !gBackGroundAnimColor) { perror("Fail to create background animations"); abort(); } // set uv animation gBackGroundAnimUV->SetPivotPosition(GPoint2(0.5, 0.5), G_FALSE); GHermiteProperty1D *p; GDynArray<GKeyValue> tmpKeys; // x-position tmpKeys.clear(); p = (GHermiteProperty1D *)gBackGroundAnimUV->Property("transform")->Property("position")->Property("x"); p->SetOORAfter(G_LOOP_OOR); tmpKeys.push_back(GKeyValue((GTimeValue)0.00, (GReal)-2)); tmpKeys.push_back(GKeyValue((GTimeValue)0.33, (GReal)2)); tmpKeys.push_back(GKeyValue((GTimeValue)0.67, (GReal)0)); tmpKeys.push_back(GKeyValue((GTimeValue)1.00, (GReal)-2)); p->SetKeys(tmpKeys); // y-position tmpKeys.clear(); p = (GHermiteProperty1D *)gBackGroundAnimUV->Property("transform")->Property("position")->Property("y"); p->SetOORAfter(G_LOOP_OOR); tmpKeys.push_back(GKeyValue((GTimeValue)0.00, (GReal)1)); tmpKeys.push_back(GKeyValue((GTimeValue)0.33, (GReal)2)); tmpKeys.push_back(GKeyValue((GTimeValue)0.67, (GReal)-2)); tmpKeys.push_back(GKeyValue((GTimeValue)1.00, (GReal)1)); p->SetKeys(tmpKeys); // rotation tmpKeys.clear(); p = (GHermiteProperty1D *)gBackGroundAnimUV->Property("transform")->Property("rotation"); p->SetOORAfter(G_LOOP_OOR); tmpKeys.push_back(GKeyValue((GTimeValue)0.00, (GReal)0)); tmpKeys.push_back(GKeyValue((GTimeValue)0.25, (GReal)1.57 * 2)); tmpKeys.push_back(GKeyValue((GTimeValue)0.50, (GReal)3.14 * 2)); tmpKeys.push_back(GKeyValue((GTimeValue)0.75, (GReal)4.71 * 2)); tmpKeys.push_back(GKeyValue((GTimeValue)1.00, (GReal)6.28 * 2)); p->SetKeys(tmpKeys); // x-scale tmpKeys.clear(); p = (GHermiteProperty1D *)gBackGroundAnimUV->Property("transform")->Property("scale")->Property("x"); p->SetOORAfter(G_LOOP_OOR); tmpKeys.push_back(GKeyValue((GTimeValue)0.00, (GReal)1)); tmpKeys.push_back(GKeyValue((GTimeValue)0.33, (GReal)3)); tmpKeys.push_back(GKeyValue((GTimeValue)0.67, (GReal)0.9)); tmpKeys.push_back(GKeyValue((GTimeValue)1.00, (GReal)1)); p->SetKeys(tmpKeys); // y-scale tmpKeys.clear(); p = (GHermiteProperty1D *)gBackGroundAnimUV->Property("transform")->Property("scale")->Property("y"); p->SetOORAfter(G_LOOP_OOR); tmpKeys.push_back(GKeyValue((GTimeValue)0.00, (GReal)1)); tmpKeys.push_back(GKeyValue((GTimeValue)0.33, (GReal)3)); tmpKeys.push_back(GKeyValue((GTimeValue)0.67, (GReal)0.9)); tmpKeys.push_back(GKeyValue((GTimeValue)1.00, (GReal)1)); p->SetKeys(tmpKeys); // red color tmpKeys.clear(); p = (GHermiteProperty1D *)gBackGroundAnimColor->Property("x"); p->SetOORAfter(G_LOOP_OOR); tmpKeys.push_back(GKeyValue((GTimeValue)0.00, (GReal)0.7)); tmpKeys.push_back(GKeyValue((GTimeValue)0.50, (GReal)0.0)); tmpKeys.push_back(GKeyValue((GTimeValue)0.75, (GReal)0.0)); tmpKeys.push_back(GKeyValue((GTimeValue)1.00, (GReal)0.7)); p->SetKeys(tmpKeys); // green color tmpKeys.clear(); p = (GHermiteProperty1D *)gBackGroundAnimColor->Property("y"); p->SetOORAfter(G_LOOP_OOR); tmpKeys.push_back(GKeyValue((GTimeValue)0.00, (GReal)0.0)); tmpKeys.push_back(GKeyValue((GTimeValue)0.50, (GReal)0.1)); tmpKeys.push_back(GKeyValue((GTimeValue)0.75, (GReal)0.7)); tmpKeys.push_back(GKeyValue((GTimeValue)1.00, (GReal)0.0)); p->SetKeys(tmpKeys); // blue color tmpKeys.clear(); p = (GHermiteProperty1D *)gBackGroundAnimColor->Property("z"); p->SetOORAfter(G_LOOP_OOR); tmpKeys.push_back(GKeyValue((GTimeValue)0.00, (GReal)0.5)); tmpKeys.push_back(GKeyValue((GTimeValue)0.50, (GReal)0.6)); tmpKeys.push_back(GKeyValue((GTimeValue)0.75, (GReal)0.3)); tmpKeys.push_back(GKeyValue((GTimeValue)1.00, (GReal)0.5)); p->SetKeys(tmpKeys); // now set up logo gAnimLogo = (GAnimTRSNode2D *)gKernel->CreateNew(G_ANIMTRSNODE2D_CLASSID); gAnimLogo->SetPivotPosition(GPoint2((GReal)0.550, (GReal)0.540), G_FALSE); gAnimLogo->Property("transform")->Property("position")->Property("x")->SetDefaultValue(GKeyValue((GReal)0.6)); gAnimLogo->Property("transform")->Property("position")->Property("y")->SetDefaultValue(GKeyValue((GReal)-1.23)); // x-scale tmpKeys.clear(); gAnimLogo->Property("transform")->Property("scale")->Property("y")->SetDefaultValue(GKeyValue((GReal)1.5)); p = (GHermiteProperty1D *)gAnimLogo->Property("transform")->Property("scale")->Property("x"); p->SetOORAfter(G_LOOP_OOR); tmpKeys.push_back(GKeyValue((GTimeValue)0.00, (GReal)1.5)); tmpKeys.push_back(GKeyValue((GTimeValue)0.50, (GReal)-1.5)); tmpKeys.push_back(GKeyValue((GTimeValue)1.00, (GReal)1.5)); p->SetKeys(tmpKeys); gBackGroundTime = 0; gBackGroundTimeStep = (GReal)0.001; }
void ReadObjects (GString line, OsuLoadInfo* Info) { auto Spl = Utility::TokenSplit(line); int Track = GetTrackFromPosition(latof(Spl[0].c_str()), Info->Diff->Channels); int Hitsound; NoteData Note; SplitResult Spl2; /* A few of these "ifs" are just since v11 and v12 store hold endtimes in different locations. Or not include some information at all... */ int splitType = 5; if (Spl.size() == 7) splitType = 6; else if (Spl.size() == 5) splitType = 4; if (splitType != 4) // only 5 entries Spl2 = Utility::TokenSplit(Spl[splitType], ":"); double startTime = latof(Spl[2].c_str()) / 1000.0; int NoteType = atoi(Spl[3].c_str()); if (NoteType & NOTE_HOLD) { float endTime; if (splitType == 5 && Spl2.size()) endTime = latof(Spl2[0].c_str()) / 1000.0; else if (splitType == 6) endTime = latof(Spl[5].c_str()) / 1000.0; else // what really? a hold that doesn't bother to tell us when it ends? endTime = 0; Note.StartTime = startTime; Note.EndTime = endTime; if (startTime > endTime) { // Okay then, we'll transform this into a regular note.. Log::Printf("NoteLoaderOM: object at track %d has startTime > endTime (%f and %f)\n", Track, startTime, endTime); Note.EndTime = 0; Info->Diff->TotalScoringObjects += 1; Info->Diff->TotalNotes++; }else { Info->Diff->TotalScoringObjects += 2; Info->Diff->TotalHolds++; } }else if (NoteType & NOTE_NORMAL) { Note.StartTime = startTime; Info->Diff->TotalNotes++; Info->Diff->TotalScoringObjects++; }else if (NoteType & NOTE_SLIDER) { // 6=repeats 7=length float sliderRepeats = latof(Spl[6].c_str()); float sliderLength = latof(Spl[7].c_str()); float Multiplier = Info->GetSliderMultiplierAt(startTime); float finalSize = sliderLength * sliderRepeats * Multiplier; float beatDuration = (finalSize / Info->SliderVelocity); float bpm = (60000.0 / Info->GetBeatspaceAt(startTime)); float finalLength = beatDuration * spb(bpm); if (0 > finalLength) Log::LogPrintf("Line %d: o!m loader warning: object at track %d has startTime > endTime (%f and %f)\n", Info->Line, Track, startTime, finalLength + startTime); Note.StartTime = startTime; Note.EndTime = finalLength + startTime; Info->Diff->TotalScoringObjects += 2; Info->Diff->TotalHolds++; } Hitsound = atoi(Spl[4].c_str()); GString Sample = GetSampleFilename(Info, Spl2, NoteType, Hitsound, startTime); if (Sample.length()) { if (Info->Sounds.find(Sample) == Info->Sounds.end()) { Info->Sounds[Sample] = Info->last_sound_index; Info->last_sound_index++; } Note.Sound = Info->Sounds[Sample]; } Info->Diff->TotalObjects++; Info->Notes[Track].push_back(Note); Info->Diff->Duration = max(max (Note.StartTime, Note.EndTime)+1, Info->Diff->Duration); }
shared_ptr<osb::SpriteList> ReadOSBEvents(std::istream& event_str) { auto list = make_shared<osb::SpriteList>(); int previous_lead = 100; shared_ptr<osb::BGASprite> sprite = nullptr; shared_ptr<osb::Loop> loop = nullptr; bool readingLoop = false; GString line; while (std::getline(event_str, line)) { int lead_spaces; line = line.substr(line.find("//")); // strip comments lead_spaces = line.find_first_not_of("\t _"); line = line.substr(lead_spaces, line.length() - lead_spaces + 1); vector<GString> split_result; boost::split(split_result, line, boost::is_any_of(",")); for (auto &&s : split_result) boost::algorithm::to_lower(s); if (!line.length() || !split_result.size()) continue; if (lead_spaces < previous_lead && !readingLoop) { if (split_result[0] == "sprite") { Vec2 new_position(latof(split_result[3]), latof(split_result[4])); sprite = make_shared<osb::BGASprite>(split_result[1], OriginFromString(split_result[2]), new_position); list->push_back(sprite); } } else { if (!sprite) throw std::runtime_error("OSB command unpaired with sprite."); // If it's a loop, check if we're out of it. // If we're out of it, read a regular event, otherwise, read an event to the loop if (readingLoop) { if (lead_spaces < previous_lead) { readingLoop = false; // We're done reading the loop - unroll it. auto loop_events = loop->Unroll(); for (auto i = 0; i < osb::EVT_COUNT; i++) for (auto evt : (*loop_events)[i]) sprite->AddEvent(evt); } else loop->AddEvent(ParseEvent(split_result)); } // It's not a command on the loop, or we weren't reading a loop in the first place. // Read a regular command. // Not "else" because we do want to execute this if we're no longer reading the loop. if (!readingLoop) { auto ev = ParseEvent(split_result); // A loop began - set that we are reading a loop and set this loop as where to add the following commands. if (ev->GetEventType() == osb::EVT_LOOP) { loop = static_pointer_cast<osb::Loop>(ev); readingLoop = true; }else // add this event, if not a loop to this sprite. It'll be unrolled once outside. sprite->AddEvent(ev); } } previous_lead = lead_spaces; } return list; }
void NoteLoaderOM::LoadObjectsFromFile(GString filename, GString prefix, Song *Out) { #if (!defined _WIN32) || (defined STLP) std::ifstream filein (filename.c_str()); #else std::ifstream filein (Utility::Widen(filename).c_str()); #endif std::regex versionfmt("osu file format v(\\d+)"); if (!filein.is_open()) throw std::exception("Could not open file."); auto Diff = make_shared<Difficulty>(); OsuLoadInfo Info; Info.TimingInfo = make_shared<OsuManiaTimingInfo>(); Info.OsuSong = Out; Info.SliderVelocity = 1.4; Info.Diff = Diff; Info.last_sound_index = 1; Diff->Data = make_shared<DifficultyLoadInfo>(); Diff->Data->TimingInfo = Info.TimingInfo; // osu! stores bpm information as the time in ms that a beat lasts. Diff->BPMType = Difficulty::BT_BEATSPACE; Out->SongDirectory = prefix; Diff->Filename = filename; Out->SongDirectory = prefix + "/"; /* Just like BMS, osu!mania charts have timing data separated by files and a set is implied using folders. */ GString Line; getline(filein, Line); int version = -1; std::smatch sm; // "search" was picked instead of "match" since a line can have a bunch of // junk before the version declaration if (regex_search(Line.cbegin(), Line.cend(), sm, versionfmt)) version = atoi(sm[1].str().c_str()); else throw std::exception("Invalid .osu file."); // "osu file format v" if (version < 10) // why throw std::exception(Utility::Format("Unsupported osu! file version (%d < 10)", version).c_str()); Info.Version = version; osuReadingMode ReadingMode = RNotKnown, ReadingModeOld = RNotKnown; try { while (filein) { Info.Line++; getline(filein, Line); Utility::ReplaceAll(Line, "\r", ""); if (!Line.length()) continue; SetReadingMode(Line, ReadingMode); if (ReadingMode != ReadingModeOld || ReadingMode == RNotKnown) // Skip this line since it changed modes, or it's not a valid section yet { if (ReadingModeOld == RTiming) stable_sort(Info.HitsoundSections.begin(), Info.HitsoundSections.end()); if (ReadingModeOld == RGeneral) if (!Info.ReadAModeTag) throw std::exception("Not an osu!mania chart."); ReadingModeOld = ReadingMode; continue; } switch (ReadingMode) { case RGeneral: if (!ReadGeneral(Line, &Info)) // don't load charts that we can't work with { throw std::exception("osu! file unusable on raindrop."); } break; case RMetadata: ReadMetadata(Line, &Info); break; case RDifficulty: ReadDifficulty(Line, &Info); break; case REvents: ReadEvents(Line, &Info); break; case RTiming: ReadTiming(Line, &Info); break; case RHitobjects: ReadObjects(Line, &Info); break; default: break; } } if (Diff->TotalObjects) { // Calculate an alleged offset Offsetize(&Info); // Okay then, convert timing data into a measure-based format raindrop can use. MeasurizeFromTimingData(&Info); CopyTimingData(&Info); // Then copy notes into these measures. PushNotesToMeasures(&Info); // Copy all sounds we registered for (auto i : Info.Sounds) Diff->SoundList[i.second] = i.first; // Calculate level as NPS Diff->Level = Diff->TotalScoringObjects / Diff->Duration; Out->Difficulties.push_back(Diff); } } catch (std::exception &e) { // rethrow with line info throw std::exception(Utility::Format("Line %d: %s", Info.Line, e.what()).c_str()); } }