diff --git a/Encore/src/assets.cpp b/Encore/src/assets.cpp index 7ccbd5cf..ecddde53 100644 --- a/Encore/src/assets.cpp +++ b/Encore/src/assets.cpp @@ -5,480 +5,215 @@ #include "assets.h" #include #include "raygui.h" +#include "util/enclog.h" + +#include +#include class Assets; +class Asset; -Texture2D -Assets::LoadTextureFilter(const std::filesystem::path &texturePath, int &loadedAssets) { - Texture2D tex = LoadTexture(texturePath.string().c_str()); - GenTextureMipmaps(&tex); - SetTextureFilter(tex, TEXTURE_FILTER_TRILINEAR); - loadedAssets++; - return tex; -} +Assets TheAssets; // This is the single instance -Model Assets::LoadModel_(const std::filesystem::path &modelPath, int &loadedAssets) { - return LoadModel(modelPath.string().c_str()); - loadedAssets++; +Assets &Assets::getInstance() { + return TheAssets; } -Font Assets::LoadFontFilter( - const std::filesystem::path &fontPath, int fontSize, int &loadedAssets -) { - Font font = LoadFontEx(fontPath.string().c_str(), fontSize, nullptr, 250); - font.baseSize = fontSize; - font.glyphCount = 250; - int fileSize = 0; - unsigned char *fileData = LoadFileData(fontPath.string().c_str(), &fileSize); - font.glyphs = LoadFontData(fileData, fileSize, fontSize, 0, 250, FONT_SDF); - Image atlas = GenImageFontAtlas(font.glyphs, &font.recs, 250, fontSize, 4, 0); - font.texture = LoadTextureFromImage(atlas); - UnloadImage(atlas); - SetTextureFilter(font.texture, TEXTURE_FILTER_TRILINEAR); - loadedAssets++; - return font; +void Asset::CheckForFetch() { + switch (state) { + case UNLOADED: + Load(); + Encore::EncoreLog(LOG_WARNING, TextFormat("Asset %s was fetched before it was loaded. Loading immediately on main thread...", id.c_str())); + if (state == PREFINALIZED) { // TODO: Don't duplicate this logic + Encore::EncoreLog(LOG_INFO, TextFormat("Finalizing asset %s...", id.c_str())); + Finalize(); + } + break; + case LOADING: + Encore::EncoreLog(LOG_WARNING, TextFormat("Asset %s was fetched while it is being loaded. Blocking until it is loaded...", id.c_str())); + while (state == LOADING) {} // spin spin spin + if (state == PREFINALIZED) { + Encore::EncoreLog(LOG_INFO, TextFormat("Finalizing asset %s...", id.c_str())); + Finalize(); + } + break; + case PREFINALIZED: + Encore::EncoreLog(LOG_INFO, TextFormat("Finalizing asset %s...", id.c_str())); + Finalize(); + break; + default:; + } } -void Assets::FirstAssets() { - icon = LoadImage((directory / "Assets/encore_favicon-NEW.png").string().c_str()); - encoreWhiteLogo = - Assets::LoadTextureFilter((directory / "Assets/encore-white.png"), loadedAssets); - rubik = Assets::LoadFontFilter( - (directory / "Assets/fonts/Rubik-Regular.ttf"), 128, loadedAssets - ); - JetBrainsMono = LoadFontFilter( - (directory / "Assets/fonts/JetBrainsMonoNL-Regular.ttf"), 64, loadedAssets - ); -} -void Assets::LoadAssets() { - Color accentColor = { 255, 0, 255, 255 }; - Color overdriveColor = Color { 255, 200, 0, 255 }; - std::filesystem::path highwayDir = directory / "Assets" / "gameplay" / "highway"; - //smasherReg = - // Assets::LoadModel_((highwayDir / "/smasher.obj"), loadedAssets); - smasherInner = - Assets::LoadModel_((highwayDir / "smasherInner.obj"), loadedAssets); - smasherInnerTex = - LoadTexture((highwayDir / "smasherbase.png").string().c_str()); - smasherInner.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = smasherInnerTex; - - smasherOuter = - Assets::LoadModel_((highwayDir / "smasherOuter.obj"), loadedAssets); - smasherOuterTex = - LoadTexture((highwayDir / "smasherframe.png").string().c_str()); - smasherOuter.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = smasherOuterTex; - - smasherTopPressedTex = - LoadTexture((highwayDir / "smasher-on.png").string().c_str()); - smasherTopUnpressedTex = - LoadTexture((highwayDir / "smasher-off.png").string().c_str()); - - smasherBoardTex = - Assets::LoadTextureFilter(highwayDir / "board.png", loadedAssets); - smasherBoard = - Assets::LoadModel_((highwayDir / "board_x.obj"), loadedAssets); - smasherBoardEMH = - Assets::LoadModel_((highwayDir / "board_emh.obj"), loadedAssets); - - lanes = Assets::LoadModel_((highwayDir / "lanes.obj"), loadedAssets); - lanesTex = - Assets::LoadTextureFilter(highwayDir / "lanes.png", loadedAssets); - - smasherPressed = - Assets::LoadModel_((highwayDir / "smasher.obj"), loadedAssets); - smasherPressTex = - LoadTexture((highwayDir / "smasher_press.png").string().c_str()); - - star = Assets::LoadTextureFilter(directory / "Assets/ui/star.png", loadedAssets); - goldStar = - Assets::LoadTextureFilter(directory / "Assets/ui/gold-star.png", loadedAssets); - goldStarUnfilled = Assets::LoadTextureFilter( - directory / "Assets/ui/gold-star_unfilled.png", loadedAssets - ); - emptyStar = - Assets::LoadTextureFilter(directory / "Assets/ui/empty-star.png", loadedAssets); - - Highway = LoadShader( - (highwayDir / "fLighting.vsh").string().c_str(), - (highwayDir / "highwayShader.fsh").string().c_str() - ); - HighwayTexShaderLoc = GetShaderLocation(Highway, "highwayTex"); - HighwayTimeShaderLoc = GetShaderLocation(Highway, "time"); - - odFrame = Assets::LoadModel_((directory / "Assets/ui/od_frame.obj"), loadedAssets); - odBar = Assets::LoadModel_((directory / "Assets/ui/od_fill.obj"), loadedAssets); - multFrame = - Assets::LoadModel_((directory / "Assets/ui/multcircle_frame.obj"), loadedAssets); - multBar = - Assets::LoadModel_((directory / "Assets/ui/multcircle_fill.obj"), loadedAssets); - multCtr3 = Assets::LoadModel_((directory / "Assets/ui/multbar_3.obj"), loadedAssets); - multCtr5 = Assets::LoadModel_((directory / "Assets/ui/multbar_5.obj"), loadedAssets); - multNumber = - Assets::LoadModel_((directory / "Assets/ui/mult_number_plane.obj"), loadedAssets); - odMultFrame = - Assets::LoadTextureFilter(directory / "Assets/ui/mult_base.png", loadedAssets); - odMultFill = - Assets::LoadTextureFilter(directory / "Assets/ui/mult_fill.png", loadedAssets); - odMultFillActive = - Assets::LoadTextureFilter(directory / "Assets/ui/mult_fill_od.png", loadedAssets); - multNumberTex = - Assets::LoadTextureFilter(directory / "Assets/ui/mult_number.png", loadedAssets); - odMultShader = LoadShader("Assets/gameplay/highway/fLighting.vsh", "Assets/ui/odmult.fs"); - multNumberShader = LoadShader(0, "Assets/ui/multnumber.fs"); - - MultInnerDot = Assets::LoadModel_( - (highwayDir / "multiplier/MultCenterDot.obj"), loadedAssets - ); - MultFill = Assets::LoadModel_( - (highwayDir / "multiplier/MultFill.obj"), loadedAssets - ); - MultOuterFrame = Assets::LoadModel_( - (highwayDir / "multiplier/MultOuterFrame.obj"), loadedAssets - ); - MultInnerFrame = Assets::LoadModel_( - (highwayDir / "multiplier/MultInnerFrame.obj"), loadedAssets - ); - - MultFillBase = Assets::LoadTextureFilter( - (highwayDir / "multiplier/Untitled.png"), loadedAssets - ); - // why is it called "od" - MultFCTex1 = Assets::LoadTextureFilter( - (highwayDir / "multiplier/od-shine.png"), loadedAssets - ); - MultFCTex2 = Assets::LoadTextureFilter( - (highwayDir / "multiplier/od-shine2.png"), loadedAssets - ); - MultFCTex3 = Assets::LoadTextureFilter( - (highwayDir / "multiplier/od-shine3.png"), loadedAssets - ); - - FullComboIndicator = LoadShader(0, "Assets/ui/fc_ind.fsh"); - BottomTextureLoc = GetShaderLocation(FullComboIndicator, "baseTex"); - MiddleTextureLoc = GetShaderLocation(FullComboIndicator, "tex1"); - TopTextureLoc = GetShaderLocation(FullComboIndicator, "tex2"); - TimeLoc = GetShaderLocation(FullComboIndicator, "time"); - FCColorLoc = GetShaderLocation(FullComboIndicator, "color"); - FCIndLoc = GetShaderLocation(FullComboIndicator, "isFC"); - BasicColorLoc = GetShaderLocation(FullComboIndicator, "basicColor"); - MultInnerFrame.materials[0].shader = FullComboIndicator; - - MultiplierFill = LoadShader(0, (highwayDir/"multiplier/MultiplierFill.fsh").string().c_str()); - - MultTextureLoc = GetShaderLocation(MultiplierFill, "BaseTexture"); // sampler - MultiplierColorLoc = GetShaderLocation(MultiplierFill, "MultiplierColor"); // vec4 - FillPercentageLoc = GetShaderLocation(MultiplierFill, "FillPercentage"); // 0-1 float - - odLoc = GetShaderLocation(odMultShader, "overdrive"); - comboCounterLoc = GetShaderLocation(odMultShader, "comboCounter"); - multLoc = GetShaderLocation(odMultShader, "multBar"); - isBassOrVocalLoc = GetShaderLocation(odMultShader, "isBassOrVocal"); - uvOffsetXLoc = GetShaderLocation(multNumberShader, "uvOffsetX"); - uvOffsetYLoc = GetShaderLocation(multNumberShader, "uvOffsetY"); - - HighwayFade = LoadShader( - (highwayDir / "fLighting.vsh").string().c_str(), - (highwayDir / "highwayFade.frag").string().c_str() - ); - HighwayFadeStartLoc = GetShaderLocation(HighwayFade, "fadeStart"); - HighwayFadeEndLoc = GetShaderLocation(HighwayFade, "fadeEnd"); - HighwayColorLoc = GetShaderLocation(HighwayFade, "colorForAccent"); - HighwayAccentFadeLoc = GetShaderLocation(HighwayFade, "useInAccent"); - HighwayFade.locs[SHADER_LOC_COLOR_DIFFUSE] = HighwayColorLoc; - - // Highway.locs[SHADER_LOC_COLOR_DIFFUSE] = GetShaderLocation(Highway, "colDiffuse"); - // Highway.locs[SHADER_LOC_MAP_DIFFUSE] = GetShaderLocation(Highway, "highwayTex"); - HighwayColorShaderLoc = GetShaderLocation(Highway, "highwayColor"); - HighwayScrollFadeStartLoc = GetShaderLocation(Highway, "fadeStart"); - HighwayScrollFadeEndLoc = GetShaderLocation(Highway, "fadeEnd"); - - expertHighwaySides = - Assets::LoadModel_(highwayDir / "sides_x.obj", loadedAssets); - DarkerHighwayThing = - Assets::LoadModel_((highwayDir / "highway_x.obj"), loadedAssets); - expertHighway = - Assets::LoadModel_((highwayDir / "highway_x.obj"), loadedAssets); - expertHighway.materials[0].shader = Highway; - - emhHighwaySides = - Assets::LoadModel_((highwayDir / "sides_emh.obj"), loadedAssets); - emhHighway = - Assets::LoadModel_((highwayDir / "highway_emh.obj"), loadedAssets); - odHighwayEMH = Assets::LoadModel_( - (highwayDir / "overdrive_emh.obj"), loadedAssets - ); - emhHighway.materials[0].shader = Highway; - emhHighwaySides.materials[0].shader = HighwayFade; - odHighwayEMH.materials[0].shader = Highway; - odHighwayX = - Assets::LoadModel_((highwayDir / "overdrive_x.obj"), loadedAssets); - odHighwayX.materials[0].shader = Highway; - highwayTexture = - Assets::LoadTextureFilter(highwayDir / "highway.png", loadedAssets); - highwayTextureOD = Assets::LoadTextureFilter( - highwayDir / "overdrive.png", loadedAssets - ); - highwaySidesTexture = - Assets::LoadTextureFilter(highwayDir / "sides.png", loadedAssets); - - noteTopModel = - Assets::LoadModel_((directory / "Assets/notes/note_top.obj"), loadedAssets); - noteBottomModel = - Assets::LoadModel_((directory / "Assets/notes/note_bottom.obj"), loadedAssets); - - KickBottomModel = - Assets::LoadModel_((directory / "Assets/notes/kick.obj"), loadedAssets); - KickSideModel = - Assets::LoadModel_((directory / "Assets/notes/kickSides.obj"), loadedAssets); - KickBottom = - Assets::LoadTextureFilter(directory / "Assets/notes/kick.png", loadedAssets); - KickSide = - Assets::LoadTextureFilter(highwayDir / "sides.png", loadedAssets); - - CymbalInner = Assets::LoadModel_( - (directory / "Assets/notes/cymbal/CymbalWhite.obj"), loadedAssets - ); - CymbalOuter = Assets::LoadModel_( - (directory / "Assets/notes/cymbal/CymbalColor.obj"), loadedAssets - ); - CymbalBottom = Assets::LoadModel_( - (directory / "Assets/notes/cymbal/CymbalBottom.obj"), loadedAssets - ); - CymbalInner.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE; - CymbalBottom.materials[0].maps[MATERIAL_MAP_ALBEDO].color = GRAY; - - CodaLaneTex = LoadTextureFilter((directory / "Assets/notes/codaLanes.png"), loadedAssets); - CodaLane = LoadMaterialDefault(); - CodaLane.maps[MATERIAL_MAP_ALBEDO].texture = CodaLaneTex; - CodaLane.shader = HighwayFade; - - SoloSides = LoadMaterialDefault(); - SoloSides.maps[MATERIAL_MAP_ALBEDO].texture = soloTexture; - SoloSides.shader = HighwayFade; - - YargRings.push_back( - LoadTextureFilter((directory / "Assets/ui/hugh ring/rings-1.png"), loadedAssets) - ); - YargRings.push_back( - LoadTextureFilter((directory / "Assets/ui/hugh ring/rings-2.png"), loadedAssets) - ); - YargRings.push_back( - LoadTextureFilter((directory / "Assets/ui/hugh ring/rings-3.png"), loadedAssets) - ); - YargRings.push_back( - LoadTextureFilter((directory / "Assets/ui/hugh ring/rings-4.png"), loadedAssets) - ); - YargRings.push_back( - LoadTextureFilter((directory / "Assets/ui/hugh ring/rings-5.png"), loadedAssets) - ); - YargRings.push_back( - LoadTextureFilter((directory / "Assets/ui/hugh ring/rings-6.png"), loadedAssets) - ); - - BaseRingTexture = - LoadTextureFilter((directory / "Assets/ui/hugh ring/rings.png"), loadedAssets); - - InstIcons.push_back( - LoadTextureFilter((directory / "Assets/ui/hugh ring/drums-inv.png"), loadedAssets) - ); - InstIcons.push_back( - LoadTextureFilter((directory / "Assets/ui/hugh ring/bass-inv.png"), loadedAssets) - ); - InstIcons.push_back( - LoadTextureFilter((directory / "Assets/ui/hugh ring/lead-inv.png"), loadedAssets) - ); - InstIcons.push_back( - LoadTextureFilter((directory / "Assets/ui/hugh ring/keys-inv.png"), loadedAssets) - ); - InstIcons.push_back( - LoadTextureFilter((directory / "Assets/ui/hugh ring/vox-inv.png"), loadedAssets) - ); - - SoloBox = Assets::LoadModel_((highwayDir / "Solo.obj"), loadedAssets); - SoloBackground = - Assets::LoadTextureFilter(highwayDir / "SoloBox.png", loadedAssets); - SoloBox.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = SoloBackground; - - // noteTexture = Assets::LoadTextureFilter(directory / "Assets/notes/note.png", - // loadedAssets); emitTexture = Assets::LoadTextureFilter(directory / - // "Assets/notes/note_e_new.png", loadedAssets); - Scorebox = LoadTextureFilter((directory / "Assets/gameplay/ui/Scorebox.png"), loadedAssets); - Timerbox = LoadTextureFilter((directory / "Assets/gameplay/ui/Timerbox.png"), loadedAssets); - TimerboxOutline = LoadTextureFilter((directory / "Assets/gameplay/ui/TimerboxOutline.png"), loadedAssets); - - noteTopModelOD = - Assets::LoadModel_((directory / "Assets/notes/note_top_od.obj"), loadedAssets); - noteBottomModelOD = - Assets::LoadModel_((directory / "Assets/notes/note_bottom.obj"), loadedAssets); - - noteTopModelHP = - Assets::LoadModel_((directory / "Assets/notes/hopo_top.obj"), loadedAssets); - noteBottomModelHP = - Assets::LoadModel_((directory / "Assets/notes/hopo_bottom.obj"), loadedAssets); - - noteTextureOD = - Assets::LoadTextureFilter(directory / "Assets/notes/note.png", loadedAssets); - emitTextureOD = Assets::LoadTextureFilter( - directory / "Assets/notes/note_e_new.png", loadedAssets - ); - - liftModel = Assets::LoadModel_((directory / "Assets/notes/lift.obj"), loadedAssets); - liftModelOD = Assets::LoadModel_((directory / "Assets/notes/lift.obj"), loadedAssets); - - beatline = LoadModel_((highwayDir / "beatline.obj"), loadedAssets); - beatlineTex = - LoadTextureFilter((highwayDir / "beatline.png"), loadedAssets); - beatline.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = beatlineTex; - - songBackground = - Assets::LoadTextureFilter((directory / "Assets/background.png"), loadedAssets); - - redHatDisplayItalic = Assets::LoadFontFilter( - (directory / "Assets/fonts/RedHatDisplay-BlackItalic.ttf"), 128, loadedAssets - ); - redHatDisplayItalicLarge = Assets::LoadFontFilter( - (directory / "Assets/fonts/RedHatDisplay-BlackItalic.ttf"), 128, loadedAssets - ); - redHatDisplayBlack = Assets::LoadFontFilter( - (directory / "Assets/fonts/RedHatDisplay-Black.ttf"), 128, loadedAssets - ); - - rubikBoldItalic = Assets::LoadFontFilter( - (directory / "Assets/fonts/Rubik-BoldItalic.ttf"), 128, loadedAssets - ); - rubikBold = Assets::LoadFontFilter( - (directory / "Assets/fonts/Rubik-Bold.ttf"), 128, loadedAssets - ); - rubikItalic = Assets::LoadFontFilter( - (directory / "Assets/fonts/Rubik-Italic.ttf"), 128, loadedAssets - ); - - josefinSansItalic = Assets::LoadFontFilter( - (directory / "Assets/fonts/JosefinSans-Italic.ttf"), 128, loadedAssets - ); - redHatMono = Assets::LoadFontFilter(directory /"Assets/fonts/RedHatMono-Bold.ttf", 128, loadedAssets); - fxaa = LoadShader(0, (directory / "Assets/ui/fxaa.frag").string().c_str()); - texLoc = GetShaderLocation(fxaa, "texture0"); - resLoc = GetShaderLocation(fxaa, "resolution"); - sdfShader = LoadShader(0, (directory / "Assets/fonts/sdf.fs").string().c_str()); - bgShader = LoadShader(0, (directory / "Assets/ui/wavy.fs").string().c_str()); - bgTimeLoc = GetShaderLocation(bgShader, "time"); - // clapOD = LoadSound((highwayDir / "clap.ogg")); - // SetSoundVolume(clapOD, 0.375); - - discord = Assets::LoadTextureFilter( - directory / "Assets/ui/discord-mark-white.png", loadedAssets - ); - github = Assets::LoadTextureFilter( - directory / "Assets/ui/github-mark-white.png", loadedAssets - ); - - soloTexture = - Assets::LoadTextureFilter(highwayDir / "overdrive-old.png", loadedAssets); - sustainTexture = - Assets::LoadTextureFilter(directory / "Assets/notes/sustain.png", loadedAssets); - sustainHeldTexture = Assets::LoadTextureFilter( - directory / "Assets/notes/sustain-held.png", loadedAssets - ); - - // smasherReg.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = smasherRegTex; - // smasherReg.materials[0].maps[MATERIAL_MAP_ALBEDO].color = accentColor; - // smasherReg.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = smasherRegTex; - // smasherReg.materials[0].maps[MATERIAL_MAP_ALBEDO].color = accentColor; - - smasherPressed.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = smasherPressTex; - smasherPressed.materials[0].maps[MATERIAL_MAP_ALBEDO].color = accentColor; - - smasherBoard.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = smasherBoardTex; - smasherBoard.materials[0].maps[MATERIAL_MAP_ALBEDO].color = GRAY; - - smasherBoardEMH.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = smasherBoardTex; - smasherBoardEMH.materials[0].maps[MATERIAL_MAP_ALBEDO].color = GRAY; +void Asset::StartLoad() { + if (state == UNLOADED) { + state = LOADING; + loadingThread = std::thread([this](){this->Load();}); + loadingThread.detach(); + //Encore::EncoreLog(LOG_INFO, TextFormat("Loading asset %s...", id.c_str())); + } +} - lanes.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = lanesTex; - lanes.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE; +void Asset::LoadImmediate() { + Encore::EncoreLog(LOG_INFO, TextFormat("Loading asset %s immediately...", id.c_str())); + StartLoad(); + while (state == LOADING) {} +} - odFrame.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = odMultFrame; - odFrame.materials[0].maps[MATERIAL_MAP_ALBEDO].color = accentColor; - odBar.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = odMultFrame; - odBar.materials[0].maps[MATERIAL_MAP_ALBEDO].color = accentColor; - multFrame.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = odMultFrame; - multFrame.materials[0].maps[MATERIAL_MAP_ALBEDO].color = accentColor; - multBar.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = odMultFrame; - multBar.materials[0].maps[MATERIAL_MAP_ALBEDO].color = accentColor; - multCtr3.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = odMultFrame; - multCtr3.materials[0].maps[MATERIAL_MAP_ALBEDO].color = accentColor; - multCtr5.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = odMultFrame; - multCtr5.materials[0].maps[MATERIAL_MAP_ALBEDO].color = accentColor; - odBar.materials[0].maps[MATERIAL_MAP_EMISSION].texture = odMultFill; - multBar.materials[0].maps[MATERIAL_MAP_EMISSION].texture = odMultFill; - multCtr3.materials[0].maps[MATERIAL_MAP_EMISSION].texture = odMultFill; - multCtr5.materials[0].maps[MATERIAL_MAP_EMISSION].texture = odMultFill; - odBar.materials[0].shader = odMultShader; - multBar.materials[0].shader = odMultShader; - multCtr3.materials[0].shader = odMultShader; - multCtr5.materials[0].shader = odMultShader; +void FileAsset::LoadFile() { + std::ifstream file(GetPath(), std::ios::binary | std::ios::ate); + fileSize = file.tellg(); + int realFileSize = fileSize; + if (addNullTerminator) + fileSize ++; + file.seekg(0, std::ios::beg); + + fileBuffer = (char*)malloc(fileSize); + file.read(fileBuffer, realFileSize); + file.close(); + if (addNullTerminator) + fileBuffer[fileSize-1] = '\0'; +} - odMultShader.locs[SHADER_LOC_MAP_EMISSION] = - GetShaderLocation(odMultShader, "fillTex"); +void FileAsset::FreeFileBuffer() { + if (fileBuffer != nullptr) { + free(fileBuffer); + } +} +const std::filesystem::path FileAsset::GetBaseDirectory() { + return TheAssets.getDirectory() / "Assets"; +} - multNumber.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = multNumberTex; - multNumber.materials[0].shader = multNumberShader; +void FileAsset::Load() { + LoadFile(); + state = LOADED; +} - MultFill.materials[0].shader = MultiplierFill; +size_t FileAsset::GetFileSize() { + CheckForFetch(); + return fileSize; +} +char *FileAsset::FetchRaw() { + CheckForFetch(); + return fileBuffer; +} - // SetTextureWrap(highwayTextureOD, TEXTURE_WRAP_CLAMP); - - odHighwayEMH.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = highwayTextureOD; +void ShaderAsset::Load() { + AssetSet code = {}; + if (fragmentCode) + code.AddAsset(fragmentCode); + if (vertexCode) + code.AddAsset(vertexCode); + code.StartLoad(); + code.BlockUntilLoaded(); + state = PREFINALIZED; +} -odHighwayX.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = highwayTextureOD; - odHighwayX.materials[0].maps[MATERIAL_MAP_ALBEDO].color = overdriveColor; - odHighwayEMH.materials[0].maps[MATERIAL_MAP_ALBEDO].color = overdriveColor; - expertHighwaySides.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = - highwaySidesTexture; - expertHighwaySides.materials[0].maps[MATERIAL_MAP_ALBEDO].color = accentColor; - expertHighway.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = highwayTexture; - expertHighway.materials[0].maps[MATERIAL_MAP_ALBEDO].color = GRAY; - emhHighwaySides.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = highwaySidesTexture; - emhHighwaySides.materials[0].maps[MATERIAL_MAP_ALBEDO].color = accentColor; - emhHighway.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = highwayTexture; - emhHighway.materials[0].maps[MATERIAL_MAP_ALBEDO].color = GRAY; +void ShaderAsset::Finalize() { + const char *fragString = fragmentCode ? fragmentCode->FetchRaw() : nullptr; + const char *vertString = vertexCode ? vertexCode->FetchRaw() : nullptr; + shader = LoadShaderFromMemory(vertString, fragString); + for (auto &uniform : uniformPositions) { + uniform.second = GetShaderLocation(shader, uniform.first.c_str()); + } + state = LOADED; + // These destructors probably don't free the file buffers. Sad! + delete fragmentCode; + delete vertexCode; +} - noteTopModel.materials[0].maps[MATERIAL_MAP_ALBEDO].color = accentColor; - noteBottomModel.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE; +void TextureAsset::Load() { + LoadFile(); + image = LoadImageFromMemory( + reinterpret_cast(GetPath().extension().generic_u8string().c_str()), (const unsigned char*)fileBuffer, fileSize); + width = image.width; + height = image.height; + FreeFileBuffer(); + state = PREFINALIZED; +} - KickBottomModel.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = KickBottom; - KickSideModel.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = KickSide; +void TextureAsset::Finalize() { + tex = LoadTextureFromImage(image); + if (filter) { + GenTextureMipmaps(&tex); + SetTextureFilter(tex, TEXTURE_FILTER_TRILINEAR); + } + UnloadImage(image); + state = LOADED; +} - noteTopModelOD.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE; - noteBottomModelOD.materials[0].maps[MATERIAL_MAP_ALBEDO].color = overdriveColor; +void FontAsset::Load() { + auto start = std::chrono::high_resolution_clock::now(); + LoadFile(); + font = {}; + font.baseSize = fontSize; + font.glyphCount = 250; + font.glyphPadding = 4; + font.glyphs = LoadFontData((const unsigned char*)fileBuffer, fileSize, fontSize, nullptr, 250, FONT_SDF); + atlas = GenImageFontAtlas(font.glyphs, &font.recs, 250, fontSize, 4, 0); + for (int i = 0; i < font.glyphCount; i++) + { + UnloadImage(font.glyphs[i].image); + font.glyphs[i].image = ImageFromImage(atlas, font.recs[i]); + } + FreeFileBuffer(); + auto end = std::chrono::high_resolution_clock::now(); + Encore::EncoreLog(LOG_INFO, TextFormat("Generated font data for %s in %i microseconds.", id.c_str(), (std::chrono::duration_cast(end - start).count()))); + state = PREFINALIZED; +} - noteTopModelHP.materials[0].maps[MATERIAL_MAP_ALBEDO].color = accentColor; - noteBottomModelHP.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE; +void FontAsset::Finalize() { + font.texture = LoadTextureFromImage(atlas); + UnloadImage(atlas); + SetTextureFilter(font.texture, TEXTURE_FILTER_TRILINEAR); + state = LOADED; +} - liftModel.materials[0].maps[MATERIAL_MAP_ALBEDO].color = accentColor; - liftModelOD.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE; - sustainMat = LoadMaterialDefault(); - soloMat = LoadMaterialDefault(); - sustainMatHeld = LoadMaterialDefault(); - sustainMatOD = LoadMaterialDefault(); - sustainMatHeldOD = LoadMaterialDefault(); - sustainMatMiss = LoadMaterialDefault(); - soloMat.maps[MATERIAL_MAP_DIFFUSE].texture = soloTexture; - soloMat.maps[MATERIAL_MAP_DIFFUSE].color = SKYBLUE; - sustainMat.maps[MATERIAL_MAP_DIFFUSE].texture = sustainTexture; - sustainMat.maps[MATERIAL_MAP_DIFFUSE].color = - ColorTint(accentColor, { 180, 180, 180, 255 }); - sustainMatHeld.maps[MATERIAL_MAP_EMISSION].texture = sustainHeldTexture; - sustainMatHeld.maps[MATERIAL_MAP_EMISSION].color = WHITE; - sustainMatHeld.maps[MATERIAL_MAP_EMISSION].value = 1; - sustainMatHeld.maps[MATERIAL_MAP_DIFFUSE].texture = sustainHeldTexture; - sustainMatHeld.maps[MATERIAL_MAP_DIFFUSE].color = accentColor; - sustainMatOD.maps[MATERIAL_MAP_DIFFUSE].texture = sustainTexture; - sustainMatOD.maps[MATERIAL_MAP_DIFFUSE].color = { 180, 180, 180, 255 }; - sustainMatHeldOD.maps[MATERIAL_MAP_DIFFUSE].texture = sustainHeldTexture; - sustainMatHeldOD.maps[MATERIAL_MAP_DIFFUSE].color = WHITE; - sustainMatMiss.maps[MATERIAL_MAP_DIFFUSE].texture = sustainTexture; - sustainMatMiss.maps[MATERIAL_MAP_DIFFUSE].color = DARKGRAY; +// Assets that need to be loaded in order to display the cache loading screen and the +// title screen. Adding assets to this set will affect boot times (especially fonts) +AssetSet initialSet = { ASSETPTR(encoreWhiteLogo), + ASSETPTR(rubik), + ASSETPTR(favicon), + ASSETPTR(faviconTex), + ASSETPTR(redHatDisplayBlack), + ASSETPTR(sdfShader), + ASSETPTR(josefinSansItalic), + ASSETPTR(bgShader) }; +// Assets that are queued to load at boot but aren't critical for displaying the title +// screen. Adding assets to this set results in a smaller impact on boot times +AssetSet mainMenuSet = { ASSETPTR(redHatDisplayItalic), + ASSETPTR(BaseRingTexture), + ASSETPTR(rubikBold), + ASSETPTR(rubikBoldItalic), + ASSETPTR(rubikItalic), + ASSETPTR(JetBrainsMono), + ASSETPTR(discord), + ASSETPTR(github), + ASSETPTR(emptyStar), + ASSETPTR(star), + ASSETPTR(goldStar), + ASSETPTR(goldStarUnfilled), + ASSETPTR(redHatMono), + ASSETPTR(Timerbox), + ASSETPTR(TimerboxOutline), + ASSETPTR(Scorebox) }; + + + +void Assets::AddRingsAndInstruments() { + for (int i = 1; i <= 6; i++) { + TextureAsset *tex = new TextureAsset(TextFormat("ui/hugh ring/rings-%i.png", i), true); + YargRings.push_back(tex); + // Grabbing from the vec because it moved + mainMenuSet.AddAsset(tex); + } + InstIcons.push_back(new TextureAsset("ui/hugh ring/drums-inv.png", true)); + InstIcons.push_back(new TextureAsset("ui/hugh ring/bass-inv.png", true)); + InstIcons.push_back(new TextureAsset("ui/hugh ring/lead-inv.png", true)); + InstIcons.push_back(new TextureAsset("ui/hugh ring/keys-inv.png", true)); + InstIcons.push_back(new TextureAsset("ui/hugh ring/vox-inv.png", true)); + for (auto icon : InstIcons) { + mainMenuSet.AddAsset(icon); + } } diff --git a/Encore/src/assets.h b/Encore/src/assets.h index 37578547..223d3f09 100644 --- a/Encore/src/assets.h +++ b/Encore/src/assets.h @@ -1,23 +1,209 @@ #pragma once #include "raylib.h" #include "menus/uiUnits.h" +#include "util/enclog.h" +#include +#include #include +#include +#include +#include +#include #include +enum AssetState { + UNLOADED, + LOADING, + PREFINALIZED, + LOADED +}; + + +class Asset { +protected: + virtual void Load() {} + virtual void Finalize() {} + //Asset(Asset& other) {} +public: + std::atomic state = UNLOADED; + std::string id; + std::thread loadingThread ; + Asset(const std::string &id) { + this->id = id; + } + /// Empty constructor provided so vectors can initialize. Do not use! + Asset() {} + + /// Starts loading this asset. + virtual void StartLoad(); + + /// Starts loading this asset and blocks until it is loaded. + virtual void LoadImmediate(); + /// Checks if this asset is loaded. Only use in the render thread! + void CheckForFetch(); + + /// Call when you're polling the asset's for when it's loaded. + bool CanFetch() const { + return state == LOADED || state == PREFINALIZED; + } + + Asset(Asset &&other) noexcept : id(std::move(other.id)), + state(state.load()), + loadingThread() {} + +}; + +class FileAsset : public Asset { + std::filesystem::path path; +protected: + size_t fileSize; + void LoadFile(); + virtual void Load(); + void FreeFileBuffer(); + +public: + char *fileBuffer; + bool addNullTerminator = false; + + static const std::filesystem::path GetBaseDirectory(); + + FileAsset(const std::string &id) : Asset(id) { + path = GetBaseDirectory() / id; + } + FileAsset() {} + std::filesystem::path &GetPath() { + return path; + } + size_t GetFileSize(); + char *FetchRaw(); + operator const unsigned char*() { + return (const unsigned char *)FetchRaw(); + } + virtual ~FileAsset() { + //FreeFileBuffer(); + } + FileAsset(FileAsset&& other) noexcept : path(std::move(other.path)), + fileSize(other.fileSize), + fileBuffer(other.fileBuffer) {} +}; + +class ShaderAsset : public Asset { + FileAsset *fragmentCode; + FileAsset *vertexCode; + std::unordered_map uniformPositions; + const char *fStr; + const char *vStr; + std::function postFinalizeFunc; + Shader shader; +protected: + virtual void Load(); + virtual void Finalize(); +public: + ShaderAsset(const std::string &fsPath, const std::string &vsPath, std::initializer_list uniforms, std::function postFinalizeFunc) : Asset(fsPath) { + if (!fsPath.empty()) { + fragmentCode = new FileAsset(fsPath); + fragmentCode->addNullTerminator = true; + } + if (!vsPath.empty()) { + vertexCode = new FileAsset(vsPath); + vertexCode->addNullTerminator = true; + } + this->postFinalizeFunc = postFinalizeFunc; + for (auto uniform : uniforms) { + uniformPositions.emplace(uniform, 0); + } + } + + int GetUniformLoc(const std::string& uniformName) { + if (!uniformPositions.contains(uniformName)) { + Encore::EncoreLog(LOG_ERROR, TextFormat("Attempted to get unknown uniform %s on asset %s", uniformName.c_str(), id.c_str())); + return -1; + } + auto found = uniformPositions.find(uniformName); + return found->second; + } + + Shader Fetch() { + CheckForFetch(); + return shader; + } + + operator Shader() { + return Fetch(); + } +}; + +class TextureAsset : public FileAsset { + Texture2D tex; + Image image; + virtual void Load(); + virtual void Finalize(); + bool filter; +public: + int width = 0; + int height = 0; + TextureAsset(const std::string &id, bool filter) : FileAsset(id) { + this->filter = filter; + } + TextureAsset() {} + Texture2D Fetch() { + CheckForFetch(); + return tex; + } + operator Texture2D() { + return Fetch(); + } + + TextureAsset(TextureAsset &&other) noexcept : FileAsset(std::move(other)), + tex(other.tex), + image(other.image), + filter(other.filter) {} +}; + +class FontAsset : public FileAsset { + Font font; + int fontSize; + Image atlas; + virtual void Load(); + virtual void Finalize(); +public: + FontAsset(const std::string &id, int fontSize) : FileAsset(id) { + this->fontSize = fontSize; + } + Font Fetch() { + CheckForFetch(); + return font; + } + operator Font() { + return Fetch(); + } +}; + +#define ASSET(varname) TheAssets.varname +#define ASSETPTR(varname) &TheAssets.varname + + +#define NEWFILEASSET(varname, path) FileAsset varname = FileAsset(path) +#define NEWFONTASSET(varname, path, size) FontAsset varname = FontAsset(path, size) +#define NEWTEXASSET(varname, path) TextureAsset varname = TextureAsset(path, true) +#define NEWTEXASSET_NOFILTER(varname, path) TextureAsset varname = TextureAsset(path, false) +// Have to use variadic macros here because the preprocessor can't understand that the +// commas in the initializer list are not parameter seperators +#define NEWSHADERASSET(varname, ...) ShaderAsset varname = ShaderAsset(__VA_ARGS__, {}) +#define NEWSHADERASSET_POSTFINALIZE(varname, ...) ShaderAsset varname = ShaderAsset(__VA_ARGS__) + + + class Assets { private: - Assets() {} - std::vector images; std::filesystem::path directory = GetPrevDirectoryPath(GetApplicationDirectory()); - Font - LoadFontFilter(const std::filesystem::path &fontPath, int fontSize, int &loadedAssets); public: - static Assets &getInstance() { - static Assets instance; // This is the single instance - return instance; - } + Assets() {} + void AddRingsAndInstruments(); + + static Assets &getInstance(); void setDirectory(std::filesystem::path assetsDirectory) { directory = assetsDirectory; @@ -30,231 +216,131 @@ class Assets { Assets(const Assets &) = delete; void operator=(const Assets &) = delete; - int loadedAssets; - int totalAssets = 32; - Model smasherInner; - Model smasherOuter; - Texture2D smasherInnerTex; - Texture2D smasherOuterTex; - Texture2D smasherTopPressedTex; - Texture2D smasherTopUnpressedTex; - - Model smasherBoard; - Texture2D smasherBoardTex; - Model smasherBoardEMH; - - Model beatline; - Texture2D beatlineTex; - - Model lanes; - Texture2D lanesTex; - - Model smasherPressed; - Texture2D smasherPressTex; - - Texture2D goldStarUnfilled; - Texture2D star; - Texture2D goldStar; - Texture2D emptyStar; - - Texture2D Scorebox; - Texture2D Timerbox; - Texture2D TimerboxOutline; - - Model odFrame; - Model odBar; - Model multFrame; - Model multBar; - Model multCtr3; - Model multCtr5; - Model multNumber; - Texture2D odMultFrame; - Texture2D odMultFill; - Texture2D odMultFillActive; - Texture2D multNumberTex; - - Texture2D MultFillBase; - Texture2D MultFCTex1; - Texture2D MultFCTex2; - Texture2D MultFCTex3; - - Model MultInnerDot; - Model MultFill; - Model MultOuterFrame; - Model MultInnerFrame; - - int MultTextureLoc; - int MultiplierColorLoc; - int FillPercentageLoc; - - Shader MultiplierFill; - Shader FullComboIndicator; - int BottomTextureLoc; - int MiddleTextureLoc; - int TopTextureLoc; - int BasicColorLoc; - int TimeLoc; - int FCColorLoc; - int FCIndLoc; - Shader Highway; - int HighwayTexShaderLoc; - int HighwayTimeShaderLoc; - int HighwayColorShaderLoc; - int HighwayScrollFadeStartLoc; - int HighwayScrollFadeEndLoc; - int CurveMaxLoc; - Shader HighwayFade; - int HighwayFadeStartLoc; - int HighwayFadeEndLoc; - int HighwayColorLoc; - int HighwayAccentFadeLoc; - - Shader odMultShader; - Shader multNumberShader; - Shader fxaa; - - int texLoc; - int resLoc; - - int odLoc; - int comboCounterLoc; - int multLoc; - int isBassOrVocalLoc; - int uvOffsetXLoc; - int uvOffsetYLoc; - - Model expertHighwaySides; - Model expertHighway; - Model emhHighwaySides; - Model emhHighway; - Model odHighwayEMH; - Model odHighwayX; - Model DarkerHighwayThing; - Texture2D highwayTexture; - Texture2D highwayTextureOD; - Texture2D highwaySidesTexture; - - Model noteBottomModelHP; - Model noteTopModelHP; - - Model noteBottomModel; - Model noteTopModel; - Texture2D noteTexture; - Texture2D emitTexture; - - Model KickBottomModel; - Model KickSideModel; - Texture2D KickBottom; - Texture2D KickSide; - - Model CymbalInner; - Model CymbalOuter; - Model CymbalBottom; - - Model SoloBox; - Texture2D SoloBackground; - - Model noteBottomModelOD; - Model noteTopModelOD; - Texture2D noteTextureOD; - Texture2D emitTextureOD; - - Model liftModel; - Model liftModelOD; - - std::vector YargRings; - Texture2D BaseRingTexture; - std::vector InstIcons; + NEWFILEASSET(favicon, "encore_favicon-NEW.png"); + NEWTEXASSET(faviconTex, "encore_favicon-NEW.png"); + + + NEWTEXASSET(goldStarUnfilled, "ui/gold-star_unfilled.png"); + NEWTEXASSET(star, "ui/star.png"); + NEWTEXASSET(goldStar, "ui/gold-star.png"); + NEWTEXASSET(emptyStar, "ui/empty-star.png"); + + NEWTEXASSET(Scorebox, "gameplay/ui/Scorebox.png"); + NEWTEXASSET(Timerbox, "gameplay/ui/Timerbox.png"); + NEWTEXASSET(TimerboxOutline, "gameplay/ui/TimerboxOutline.png"); + + + NEWTEXASSET(BaseRingTexture, "ui/hugh ring/rings.png"); + std::vector YargRings; + std::vector InstIcons; Image icon; - Texture2D encoreWhiteLogo; + NEWTEXASSET(encoreWhiteLogo, "encore-white.png"); Texture2D songBackground; - Font redHatDisplayItalic; - Font redHatDisplayBlack; - Font redHatDisplayItalicLarge; - Font josefinSansItalic; - Font josefinSansNormal; - Font josefinSansBold; - Font redHatMono; - Font rubik; - Font rubikItalic; - Font JetBrainsMono; - Font rubikBoldItalic; - - Font rubikBold; - - // clapOD = LoadSound((directory / "Assets/highway/clap.ogg").string().c_str()); - // SetSoundVolume(clapOD, 0.375); - - Texture2D discord; - Texture2D github; - - Texture2D sustainTexture; - Texture2D sustainHeldTexture; - Texture2D soloTexture; - Material soloMat; - Material sustainMat; - Material sustainMatOD; - Material sustainMatHeld; - Material sustainMatHeldOD; - Material sustainMatMiss; - - Material SoloSides; - Material CodaLane; - Texture2D CodaLaneTex; - - Shader sdfShader; - Shader bgShader; - int bgTimeLoc; - // Sound clapOD; - void DrawTextRubik( - const char *text, float posX, float posY, float fontSize, Color color - ) const { - BeginShaderMode(sdfShader); - DrawTextEx(rubik, text, { posX, posY }, fontSize, 1, color); - EndShaderMode(); - } + // Used as a default background for the menu + NEWTEXASSET(highwayTexture, "gameplay/highway/highway.png"); + + NEWFONTASSET(redHatDisplayItalic, "fonts/RedHatDisplay-BlackItalic.ttf", 128); + NEWFONTASSET(redHatDisplayBlack, "fonts/RedHatDisplay-Black.ttf", 128); + NEWFONTASSET(redHatDisplayItalicLarge, "fonts/RedHatDisplay-Black.ttf", 128); + NEWFONTASSET(josefinSansItalic, "fonts/JosefinSans-Italic.ttf", 128); + NEWFONTASSET(josefinSansNormal, "fonts/JosefinSans-Normal.ttf", 128); + NEWFONTASSET(josefinSansBold, "fonts/JosefinSans-Bold.ttf", 128); + NEWFONTASSET(redHatMono, "fonts/RedHatMono-Bold.ttf", 128); + NEWFONTASSET(rubik, "fonts/Rubik-Regular.ttf", 128); + NEWFONTASSET(rubikItalic, "fonts/Rubik-Italic.ttf", 128); + NEWFONTASSET(JetBrainsMono, "fonts/JetBrainsMonoNL-Regular.ttf", 64); + NEWFONTASSET(rubikBoldItalic, "fonts/Rubik-BoldItalic.ttf", 128); + + NEWFONTASSET(rubikBold, "fonts/Rubik-Bold.ttf", 128); + + NEWTEXASSET(discord, "ui/discord-mark-white.png"); + NEWTEXASSET(github, "ui/github-mark-white.png"); + + + NEWSHADERASSET(sdfShader, "fonts/sdf.fs", "", {}); + NEWSHADERASSET(bgShader, "ui/wavy.fs", "", {"time"}); + void DrawTextRHDI(const char* text, float x, float y, float fontSize, Color color) { DrawTextEx(redHatDisplayItalic, text, {x, y}, fontSize, 0, color); BeginShaderMode(sdfShader); EndShaderMode(); } - void DrawTextJSN(const char *text, float posX, float posY, Color color) const { - BeginShaderMode(sdfShader); - DrawTextEx(josefinSansNormal, text, { posX, posY }, Units::getInstance().hinpct(0.05f), 1, color); - EndShaderMode(); + + float MeasureTextRubik(const char *text, float fontSize) { + return MeasureTextEx(rubik, text, fontSize, 1).x; } +}; - void DrawTextJSB(const char *text, float posX, float posY, Color color) const { - BeginShaderMode(sdfShader); - DrawTextEx(josefinSansBold, text, { posX, posY }, Units::getInstance().hinpct(0.05f), 1, color); - EndShaderMode(); +#undef NEWTEXASSET +#undef NEWTEXASSET_NOFILTER +#undef NEWFONTASSET +#undef NEWFILEASSET + +extern Assets TheAssets; +/// Used for easily loading groups of assets and polling their state as one. +class AssetSet { + std::vector assets; +public: + + AssetSet(std::initializer_list l) { + assets = std::vector(l); } - void DrawTextJSI(const char *text, float posX, float posY, Color color) const { - BeginShaderMode(sdfShader); - DrawTextEx(josefinSansItalic, text, { posX, posY }, Units::getInstance().hinpct(0.05f), 1, color); - EndShaderMode(); + void AddAsset(Asset *asset) { + assets.push_back(asset); } - float MeasureTextRubik(const char *text, float fontSize) const { - return MeasureTextEx(rubik, text, fontSize, 1).x; + + void StartLoad() { + for (int i = 0; i < assets.size(); i++) { + auto asset = assets[i]; + if (asset->state == UNLOADED) { + asset->StartLoad(); + } + } } - float MeasureTextRHDI(const char *text) const { - return MeasureTextEx(redHatDisplayItalic, text, 48, 1).x; + + bool PollLoaded(bool doFinalize = false) { + bool loaded = true; + for (int i = 0; i < assets.size(); i++) { + auto asset = assets[i]; + if (!asset->CanFetch()) { + loaded = false; + } + if (doFinalize && asset->state == PREFINALIZED) { + asset->CheckForFetch(); + } + } + return loaded; } - float MeasureTextJSN(const char *text, float fontSize) const { - return MeasureTextEx(josefinSansNormal, text, 48, 1).x; + + int CountLoaded() { + int loaded = 0; + for (int i = 0; i < assets.size(); i++) { + if (assets[i]->CanFetch()) { + loaded++; + } + } + return loaded; } - float MeasureTextJSB(const char *text, float fontSize) const { - return MeasureTextEx(josefinSansBold, text, 48, 1).x; + + int AssetCount() { + return assets.size(); } - float MeasureTextJSI(const char *text, float fontSize) const { - return MeasureTextEx(josefinSansItalic, text, 48, 1).x; + + float GetProgress() { + return static_cast(CountLoaded()) / static_cast(AssetCount()); + } + + void BlockUntilLoaded() { + while (!PollLoaded()) {} + for (int i = 0; i < assets.size(); i++) { + // This finalizes any assets that need it + // We're blocking anyways so why not + assets[i]->CheckForFetch(); + } } - static Texture2D - LoadTextureFilter(const std::filesystem::path &texturePath, int &loadedAssets); - static Model LoadModel_(const std::filesystem::path &modelPath, int &loadedAssets); - void FirstAssets(); - void LoadAssets(); }; +extern AssetSet initialSet; +extern AssetSet mainMenuSet; diff --git a/Encore/src/main.cpp b/Encore/src/main.cpp index d6b15efb..69093ea2 100644 --- a/Encore/src/main.cpp +++ b/Encore/src/main.cpp @@ -5,9 +5,12 @@ #include "util/discord.h" #include "util/enclog.h" #include "gameplay/enctime.h" + + #include #include "settings/keybinds.h" +#include "song/cacheload.h" #define assertm(exp, msg) assert((void(msg), exp)) #define RAYGUI_IMPLEMENTATION @@ -88,6 +91,22 @@ std::string commitHash = GIT_COMMIT_HASH; int minWidth = 640; int minHeight = 480; +void DrawLoadingScreen(unsigned char alpha, float progress) { + Texture icon = ASSET(faviconTex); + float fade = (1.0 - (alpha/255.0)); + fade *= fade; + unsigned char quadAlpha = 255*(1.0-fade); + float scale = (GetScreenHeight() / 1080.0f) * 0.3; + float iconScale = scale + fade * 0.5; + int iconSize = (icon.height * iconScale)/2; // Dividing by 2 for centering + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), {0, 0, 0, quadAlpha}); + + Vector2 screenCenter = {GetScreenWidth()/2.0f, GetScreenHeight()/2.0f}; + DrawRing(screenCenter, scale*300.0f, scale*320.0f, -90, 360-90, 64, {255, 255, 255, (unsigned char)(alpha/3)}); + DrawRing(screenCenter, scale*300.0f, scale*320.0f, -90, 360*progress-90, 64, {255, 255, 255, alpha}); + DrawTextureEx(icon, {GetScreenWidth()/2.0f-iconSize, GetScreenHeight()/2.0f-iconSize}, 0, iconScale, {255, 255, 255, alpha}); +} + int main(int argc, char *argv[]) { TheGameRPC.Initialize(); SetTraceLogCallback(Encore::EncoreLog); @@ -97,7 +116,6 @@ int main(int argc, char *argv[]) { SetConfigFlags(FLAG_WINDOW_RESIZABLE); glfwWindowHint(GLFW_SAMPLES, 4); - SetWindowState(FLAG_MSAA_4X_HINT); bool windowToggle = true; ArgumentList::InitArguments(argc, argv); @@ -135,29 +153,29 @@ int main(int argc, char *argv[]) { CFRelease(bundle); } #endif - TheSettingsInitializer.InitSettings(directory); + CacheLoad::StartLoad(); ThePlayerManager.SetPlayerListSaveFileLocation(directory / "players.json"); + ThePlayerManager.LoadPlayerList(); if (TheGameSettings.VerticalSync) { SetConfigFlags(FLAG_VSYNC_HINT); } Encore::EncoreLog(LOG_INFO, TextFormat("Vertical sync: %d", vsyncArg)); + InitWindow(800, 600, "Encore"); if (!TheGameSettings.Fullscreen) { - InitWindow( - GetMonitorWidth(GetCurrentMonitor()) * 0.75f, - GetMonitorHeight(GetCurrentMonitor()) * 0.75f, - "Encore" - ); - SET_WINDOW_WINDOWED(); + int x, y, width, height; + glfwGetMonitorWorkarea(glfwGetPrimaryMonitor(), &x, &y, &width, &height); + Encore::EncoreLog(LOG_INFO, TextFormat("Workarea of monitor %s: %i %i %i %i", glfwGetMonitorName(glfwGetPrimaryMonitor()), x, y, width, height)); + int windowWidth = width * 0.75; + int windowHeight = height * 0.75; + SetWindowPosition(width/2 - windowWidth/2 + x, height/2 - windowHeight/2 + y); + SetWindowSize(windowWidth, windowHeight); + ClearWindowState(FLAG_WINDOW_UNDECORATED); MaximizeWindow(); } else { - InitWindow( - GetMonitorWidth(GetCurrentMonitor()), - GetMonitorHeight(GetCurrentMonitor()), - "Encore" - ); + SetWindowSize(GetMonitorWidth(0), GetMonitorHeight(0)); SET_WINDOW_FULLSCREEN_BORDERLESS(); } bool AudioInitSuccessful = TheAudioManager.Init(); @@ -172,11 +190,19 @@ int main(int argc, char *argv[]) { SETDEFAULTSTYLE(); SetRandomSeed(std::chrono::system_clock::now().time_since_epoch().count()); - assets.FirstAssets(); - SetWindowIcon(assets.icon); - GuiSetFont(assets.rubik); - assets.LoadAssets(); - TheMenuManager.currentScreen = CACHE_LOADING_SCREEN; + initialSet.StartLoad(); + TheAssets.AddRingsAndInstruments(); + mainMenuSet.StartLoad(); + AssetSet({ASSETPTR(favicon), ASSETPTR(faviconTex)}).BlockUntilLoaded(); + SetWindowIcon(LoadImageFromMemory(".png", ASSET(favicon), ASSET(favicon).GetFileSize())); + if (!CacheLoad::finished) { + TheMenuManager.currentScreen = CACHE_LOADING_SCREEN; + } else { + TheMenuManager.currentScreen = MAIN_MENU; + } + + + if (TheGameSettings.Framerate > 0) Encore::EncoreLog( @@ -186,13 +212,12 @@ int main(int argc, char *argv[]) { Encore::EncoreLog(LOG_INFO, TextFormat("Unlocked framerate.")); TheFrameManager.removeFPSLimit = true; } - // audioManager.loadSample("Assets/highway/clap.mp3", "clap"); while (!WindowShouldClose()) { u.calcUnits(); double curTime = GetTime(); float bgTime = curTime / 5.0f; - SetShaderValue(assets.bgShader, assets.bgTimeLoc, &bgTime, SHADER_UNIFORM_FLOAT); + SetShaderValue(ASSET(bgShader), ASSET(bgShader).GetUniformLoc("time"), &bgTime, SHADER_UNIFORM_FLOAT); if (IsKeyPressed(KEY_F11) || (IsKeyPressed(KEY_LEFT_ALT) && IsKeyPressed(KEY_ENTER))) { TheGameSettings.Fullscreen = !TheGameSettings.Fullscreen; @@ -217,12 +242,27 @@ int main(int argc, char *argv[]) { BeginDrawing(); ClearBackground(DARKGRAY); - - if (TheMenuManager.onNewMenu) { - TheMenuManager.LoadMenu(); + static bool showLoading = true; + if (showLoading && !initialSet.PollLoaded(true)) { + DrawLoadingScreen(255, initialSet.GetProgress()); + } else { + static float loadingScreenFade = 1.0f; + showLoading = false; + if (TheMenuManager.onNewMenu) { + TheMenuManager.LoadMenu(); + } + TheGameRPC.Update(); + TheMenuManager.DrawMenu(); + if (loadingScreenFade > 0) { + DrawLoadingScreen(255*loadingScreenFade, 1); + float frameTime = GetFrameTime(); + // Cap the frame time here so the fade animation doesn't get skipped by the stutter caused by loading the song preview + if (frameTime > 0.032) { + frameTime = 0.032; + } + loadingScreenFade -= frameTime*5.0f; + } } - TheGameRPC.Update(); - TheMenuManager.DrawMenu(); EndDrawing(); TheFrameManager.WaitForFrame(); diff --git a/Encore/src/menus/ReadyUpMenu.cpp b/Encore/src/menus/ReadyUpMenu.cpp index 97c9317f..21ab9dba 100644 --- a/Encore/src/menus/ReadyUpMenu.cpp +++ b/Encore/src/menus/ReadyUpMenu.cpp @@ -220,12 +220,12 @@ void ReadyUpMenu::Draw() { || player.Instrument == PlasticBass) { isBassOrVocal = 1; } - SetShaderValue( - assets.odMultShader, - assets.isBassOrVocalLoc, - &isBassOrVocal, - SHADER_UNIFORM_INT - ); + // SetShaderValue( + // assets.odMultShader, + // assets.isBassOrVocalLoc, + // &isBassOrVocal, + // SHADER_UNIFORM_INT + // ); } GuiSetStyle(BUTTON, TEXT_COLOR_NORMAL, 0xcbcbcbFF); GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); diff --git a/Encore/src/menus/SongSelectMenu.cpp b/Encore/src/menus/SongSelectMenu.cpp index 0fae00b4..4d545ef0 100644 --- a/Encore/src/menus/SongSelectMenu.cpp +++ b/Encore/src/menus/SongSelectMenu.cpp @@ -315,7 +315,7 @@ void SongSelectMenu::Draw() { ); } else if (!TheSongList.listMenuEntries[i].hiddenEntry) { bool isCurSong = TheSongList.curSong && i == TheSongList.curSong->songListPos - 1; - Font &artistFont = isCurSong ? assets.josefinSansItalic : assets.josefinSansItalic; + Font artistFont = assets.josefinSansItalic; Song &songi = TheSongList.songs[TheSongList.listMenuEntries[i].songListID]; int songID = TheSongList.listMenuEntries[i].songListID; @@ -569,11 +569,25 @@ void SongSelectMenu::Draw() { float IconLeftPos = (float)(u.RightSide - AlbumHeight) + IconWidth * ResetToLeftPos; Rectangle Placement = { IconLeftPos, BoxTopPos, IconWidth, IconWidth }; Color TintColor = WHITE; - if (SongToDisplayInfo.parts[i] && SongToDisplayInfo.parts[i]->diff == -1) TintColor = DARKGRAY; - DrawTexturePro(assets.InstIcons[asdasd], { 0, 0, (float)assets.InstIcons[asdasd].width, (float)assets.InstIcons[asdasd].height }, Placement, { 0, 0 }, 0, TintColor); + int diffNumber = SongToDisplayInfo.parts[i]->diff; + if (SongToDisplayInfo.parts[i] && diffNumber == -1) TintColor = DARKGRAY; + auto instIcon = assets.InstIcons[asdasd]; + DrawTexturePro(*instIcon, { 0, 0, (float)instIcon->width, (float)instIcon->height }, Placement, { 0, 0 }, 0, TintColor); DrawTexturePro(assets.BaseRingTexture, { 0, 0, (float)assets.BaseRingTexture.width, (float)assets.BaseRingTexture.height }, Placement, { 0, 0 }, 0, ColorBrightness(WHITE, 2)); - if (SongToDisplayInfo.parts[i] && SongToDisplayInfo.parts[i]->diff > 0) - DrawTexturePro(assets.YargRings[SongToDisplayInfo.parts[i]->diff - 1], { 0, 0, (float)assets.YargRings[SongToDisplayInfo.parts[i]->diff - 1].width, (float)assets.YargRings[SongToDisplayInfo.parts[i]->diff - 1].height }, Placement, { 0, 0 }, 0, WHITE); + if (SongToDisplayInfo.parts[i] && diffNumber > 0) { + if (diffNumber > 6) { + diffNumber = 6; + } + auto ring = assets.YargRings[diffNumber - 1]; + DrawTexturePro( + *ring, + { 0, 0, (float)ring->width, (float)ring->height }, + Placement, + { 0, 0 }, + 0, + WHITE + ); + } } GameMenu::DrawBottomOvershell(); diff --git a/Encore/src/menus/cacheLoadingScreen.cpp b/Encore/src/menus/cacheLoadingScreen.cpp index 3ecc9a40..f7b0c641 100644 --- a/Encore/src/menus/cacheLoadingScreen.cpp +++ b/Encore/src/menus/cacheLoadingScreen.cpp @@ -15,6 +15,7 @@ #include "raygui.h" #include "MenuManager.h" #include "settings/settings.h" +#include "song/cacheload.h" std::vector CacheSplash = { "Want a break from the cache?", @@ -27,26 +28,10 @@ std::vector CacheSplash = { }; void cacheLoadingScreen::Load() { - std::filesystem::path assetsdir = GetApplicationDirectory(); - assetsdir /= "Assets"; - RedHatDisplay = GameMenu::LoadFontFilter(assetsdir / "fonts/RedHatDisplay-Black.ttf"); - RubikBold = GameMenu::LoadFontFilter(assetsdir / "fonts/Rubik-Bold.ttf"); - JosefinSansItalic = - GameMenu::LoadFontFilter(assetsdir / "fonts/JosefinSans-Italic.ttf"); - encoreLogo = GameMenu::LoadTextureFilter(assetsdir / "encore_favicon-NEW.png"); + SplashSel = GetRandomValue(0, CacheSplash.size() - 1); - sdfShader = LoadShader(0, (assetsdir / "fonts/sdf.fs").string().c_str()); } -// todo(3drosalia): make another class for drawing these things without having to uh. -// implement it in every menu class -std::atomic_bool finished = false; -std::atomic_bool started = false; - -void LoadCache() { - TheSongList.LoadCache(TheGameSettings.SongPaths); - finished = true; -} void cacheLoadingScreen::Draw() { Units u = Units::getInstance(); @@ -65,12 +50,12 @@ void cacheLoadingScreen::Draw() { ); GameMenu::mhDrawText( - RedHatDisplay, + ASSET(redHatDisplayBlack), "LOADING CACHE", { u.LeftSide, u.hpct(0.05f) }, u.hinpct(0.125f), WHITE, - sdfShader, + ASSET(sdfShader), LEFT ); float RubikFontSize = u.hinpct(0.05f); @@ -78,12 +63,12 @@ void cacheLoadingScreen::Draw() { int toLoad = MaxChartsToLoad; std::string LoadingText = TextFormat("%d/%d songs loaded", loaded, toLoad); GameMenu::mhDrawText( - RubikBold, + ASSET(rubikBold), LoadingText, { u.RightSide, u.hpct(0.085f) }, RubikFontSize, LIGHTGRAY, - sdfShader, + ASSET(sdfShader), RIGHT ); GameMenu::DrawBottomOvershell(); @@ -92,30 +77,30 @@ void cacheLoadingScreen::Draw() { GetScreenHeight() - u.hpct(0.14f) + u.hinpct(0.07f), u.hinpct(0.14f), u.hinpct(0.14f) }; + + auto logo = ASSETPTR(faviconTex); DrawTexturePro( - encoreLogo, - { 0, 0, (float)encoreLogo.width, (float)encoreLogo.height }, + *logo, + { 0, 0, (float)logo->width, (float)logo->height }, LogoRect, { u.hinpct(0.07f), u.hinpct(0.07f) }, 0, WHITE ); GameMenu::mhDrawText( - JosefinSansItalic, + ASSET(josefinSansItalic), CacheSplash[SplashSel], { u.LeftSide + u.hinpct(0.16), GetScreenHeight() - u.hpct(0.14f) + u.hinpct(0.055f) }, RubikFontSize / 1.5f, WHITE, - sdfShader, + ASSET(sdfShader), LEFT ); - if (!started) { - started = true; - std::thread CacheLoader(LoadCache); - CacheLoader.detach(); + if (!CacheLoad::started) { + CacheLoad::StartLoad(); } - if (finished) { + if (CacheLoad::finished) { TheMenuManager.SwitchScreen(MAIN_MENU); } } diff --git a/Encore/src/menus/cacheLoadingScreen.h b/Encore/src/menus/cacheLoadingScreen.h index dee19de4..99ac263b 100644 --- a/Encore/src/menus/cacheLoadingScreen.h +++ b/Encore/src/menus/cacheLoadingScreen.h @@ -8,13 +8,7 @@ #include "raylib.h" class cacheLoadingScreen : public Menu { - Texture2D encoreLogo; - Font RedHatDisplay; - Font RubikBold; - Font JosefinSansItalic; int SplashSel; - Texture2D LoadingScreenBackground; - Shader sdfShader; public: cacheLoadingScreen(); diff --git a/Encore/src/menus/gameMenu.cpp b/Encore/src/menus/gameMenu.cpp index 3996624f..bfa7f10c 100644 --- a/Encore/src/menus/gameMenu.cpp +++ b/Encore/src/menus/gameMenu.cpp @@ -225,6 +225,9 @@ void MainMenu::Load() { std::filesystem::path directory = GetPrevDirectoryPath(GetApplicationDirectory()); ChooseSplashText(directory); PickRandomMenuSong(); + if (!mainMenuSet.PollLoaded()) { + mainMenuSet.StartLoad(); + } } void MainMenu::KeyboardInputCallback(int key, int scancode, int action, int mods) { if (ThePlayerManager.PlayersActive == 0) { @@ -263,7 +266,7 @@ void MainMenu::AttractScreen() { }; DrawTextEx( - menuAss.josefinSansItalic, + ASSET(josefinSansItalic), SplashString.c_str(), GreetSplashPos, SplashFontSize, diff --git a/Encore/src/song/cacheload.cpp b/Encore/src/song/cacheload.cpp new file mode 100644 index 00000000..9517b924 --- /dev/null +++ b/Encore/src/song/cacheload.cpp @@ -0,0 +1,16 @@ +#include "cacheload.h" +#include "songlist.h" + +std::atomic_bool CacheLoad::finished; +std::atomic_bool CacheLoad::started; +std::thread CacheLoad::cacheLoadThread; + +void CacheLoad::StartLoad() { + if (started) return; + started = true; + cacheLoadThread = std::thread([]() { + TheSongList.LoadCache(TheGameSettings.SongPaths); + finished = true; + }); + cacheLoadThread.detach(); +} \ No newline at end of file diff --git a/Encore/src/song/cacheload.h b/Encore/src/song/cacheload.h new file mode 100644 index 00000000..1e9ab9c6 --- /dev/null +++ b/Encore/src/song/cacheload.h @@ -0,0 +1,16 @@ +#pragma once +#ifndef CACHELOAD_H +#define CACHELOAD_H +#include +#include +#include "settings/settings.h" + +namespace CacheLoad { + extern std::atomic_bool finished; + extern std::atomic_bool started; + extern std::thread cacheLoadThread; + + void StartLoad(); + +} +#endif \ No newline at end of file