diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj b/Adventures in Lestoria/Adventures in Lestoria.vcxproj index 0e143d1e..2c240039 100644 --- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj +++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj @@ -397,6 +397,10 @@ + + + + diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters index 3f5a8d27..af5ad58c 100644 --- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters +++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters @@ -480,6 +480,9 @@ Header Files\Interface + + Header Files\Interface + diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp index e4f7ab4e..7dc6c8a6 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.cpp +++ b/Adventures in Lestoria/AdventuresInLestoria.cpp @@ -341,6 +341,8 @@ bool AiL::OnUserUpdate(float fElapsedTime){ }else lastMouseMovement+=fElapsedTime; if(!GamePaused()){ GameState::STATE->OnUserUpdate(this); + }else{ + ClearTimedOutGarbage(); } LoadingScreen::Update(); InputListener::Update(); @@ -2361,6 +2363,11 @@ void AiL::_PrepareLevel(MapName map,MusicChange changeMusic){ Audio::UpdateBGMVolume(); return true; }); + + LoadingScreen::AddPhase([&](){ + ClearGarbage(); + return true; + }); } } diff --git a/Adventures in Lestoria/BuyItemWindow.cpp b/Adventures in Lestoria/BuyItemWindow.cpp index 7c582db1..2d2b55b9 100644 --- a/Adventures in Lestoria/BuyItemWindow.cpp +++ b/Adventures in Lestoria/BuyItemWindow.cpp @@ -64,7 +64,7 @@ void Menu::InitializeBuyItemWindow(){ if(qty==99||pricePerItem*(qty+1)>game->GetPlayer()->GetMoney()){ Component(BUY_ITEM,"Increase buy amount Button")->SetGrayedOut(true); - Menu::menus[BUY_ITEM]->SetSelection(static_cast>(Component(BUY_ITEM,"Decrease buy amount Button"))); + Menu::menus[BUY_ITEM]->SetSelection("Decrease buy amount Button"sv); }else{ Component(BUY_ITEM,"Increase buy amount Button")->SetGrayedOut(false); } diff --git a/Adventures in Lestoria/ConsumableCraftItemWindow.cpp b/Adventures in Lestoria/ConsumableCraftItemWindow.cpp index 79da97f6..4016ee23 100644 --- a/Adventures in Lestoria/ConsumableCraftItemWindow.cpp +++ b/Adventures in Lestoria/ConsumableCraftItemWindow.cpp @@ -59,9 +59,23 @@ void Menu::InitializeConsumableCraftItemWindow(){ const std::string&item=Component(CONSUMABLE_CRAFT_ITEM,"Item Name Header")->GetString(A::ITEM_NAME); bool canCraft=Item(qty,item).CanEnhanceItem(qty); + bool canCraftOneHigher=Item(qty+1,item).CanEnhanceItem(qty+1); std::string colorCode=""; if(!canCraft)colorCode="#FF0000"; + if(qty==99||!canCraftOneHigher){ + Component(CONSUMABLE_CRAFT_ITEM,"Increase Craft amount Button")->SetGrayedOut(true); + Menu::menus[CONSUMABLE_CRAFT_ITEM]->SetSelection("Decrease Craft amount Button"sv); + }else{ + Component(CONSUMABLE_CRAFT_ITEM,"Increase Craft amount Button")->SetGrayedOut(false); + } + + if(qty<=1){ + Component(CONSUMABLE_CRAFT_ITEM,"Decrease Craft amount Button")->SetGrayedOut(true); + Menu::menus[CONSUMABLE_CRAFT_ITEM]->SetSelection("Increase Craft amount Button"sv); + }else{ + Component(CONSUMABLE_CRAFT_ITEM,"Decrease Craft amount Button")->SetGrayedOut(false); + } Component(CONSUMABLE_CRAFT_ITEM,"Required Materials List")->SetQuantity(qty); Component(CONSUMABLE_CRAFT_ITEM,"Craft Button")->SetGrayedOut(!canCraft); }; diff --git a/Adventures in Lestoria/ConsumableCraftingWindow.cpp b/Adventures in Lestoria/ConsumableCraftingWindow.cpp index fc21ad3a..3fa666c8 100644 --- a/Adventures in Lestoria/ConsumableCraftingWindow.cpp +++ b/Adventures in Lestoria/ConsumableCraftingWindow.cpp @@ -69,6 +69,7 @@ void Menu::InitializeConsumableCraftingWindow(){ Component(CONSUMABLE_CRAFT_ITEM,"Required Materials List")->SetItem(item); Component(CONSUMABLE_CRAFT_ITEM,"Craft Button")->SetGrayedOut(!item.lock()->CanEnhanceItem()); if(item.lock()->GetEnhancementInfo()[0].chapterAvailable<=game->GetCurrentChapter()){ + Component(CONSUMABLE_CRAFT_ITEM,"Decrease Craft amount Button")->SetGrayedOut(true); Menu::OpenMenu(CONSUMABLE_CRAFT_ITEM); }else{ SoundEffect::PlaySFX("Locked Item",SoundEffect::CENTERED); diff --git a/Adventures in Lestoria/EquipSlotButton.h b/Adventures in Lestoria/EquipSlotButton.h index 62a157d5..05b2c77b 100644 --- a/Adventures in Lestoria/EquipSlotButton.h +++ b/Adventures in Lestoria/EquipSlotButton.h @@ -59,6 +59,18 @@ public: itemRef=Item::BLANK; } } + virtual inline void Update(AiL*game)override{ + MenuIconButton::Update(game); + valid=!ISBLANK(itemRef); + + if(!valid){ + icon=nullptr; + } + + if(hovered){ + UpdateLabel(); + } + } inline const EquipSlot GetSlot()const{ return slot; } diff --git a/Adventures in Lestoria/InventoryWindow.cpp b/Adventures in Lestoria/InventoryWindow.cpp index b7a1f52d..c97ad414 100644 --- a/Adventures in Lestoria/InventoryWindow.cpp +++ b/Adventures in Lestoria/InventoryWindow.cpp @@ -206,7 +206,8 @@ void Menu::InitializeInventoryWindow(){ {game->KEY_CONFIRM,{[](MenuFuncData data){ if(!data.menu.GetSelection().expired()&& !data.menu.GetSelection().lock()->parentComponent.expired()&& - data.menu.GetSelection().lock()->parentComponent.lock()->GetName()=="Inventory Display - Accessories"){ + data.menu.GetSelection().lock()->parentComponent.lock()->GetName()=="Inventory Display - Accessories" + &&data.component.lock()->GetSubcomponentParent().expired()){ if(DYNAMIC_POINTER_CAST(data.menu.GetSelection().lock())->GetItem().lock()->IsLocked()){ return "Unlock"; }else{ @@ -225,7 +226,8 @@ void Menu::InitializeInventoryWindow(){ {game->KEY_SELECT,{[](MenuFuncData data){ if(!data.menu.GetSelection().expired()&& !data.menu.GetSelection().lock()->parentComponent.expired()&& - data.menu.GetSelection().lock()->parentComponent.lock()->GetName()=="Inventory Display - Accessories"){ + data.menu.GetSelection().lock()->parentComponent.lock()->GetName()=="Inventory Display - Accessories" + &&data.component.lock()->GetSubcomponentParent().expired()){ if(DYNAMIC_POINTER_CAST(data.menu.GetSelection().lock())->GetItem().lock()->IsLocked()){ return "Unlock"; }else{ diff --git a/Adventures in Lestoria/MenuItemItemButton.h b/Adventures in Lestoria/MenuItemItemButton.h index 4f78febd..f70d1835 100644 --- a/Adventures in Lestoria/MenuItemItemButton.h +++ b/Adventures in Lestoria/MenuItemItemButton.h @@ -149,9 +149,7 @@ protected: if(!valid){ icon=nullptr; } - if(hovered){ - UpdateLabel(); - } + UpdateLabel(); } virtual inline void DrawDecal(ViewPort&window,bool focused)override{ MenuIconButton::DrawDecal(window,focused); diff --git a/Adventures in Lestoria/MenuItemLabel.h b/Adventures in Lestoria/MenuItemLabel.h new file mode 100644 index 00000000..2f994f94 --- /dev/null +++ b/Adventures in Lestoria/MenuItemLabel.h @@ -0,0 +1,75 @@ +#pragma region License +/* +License (OLC-3) +~~~~~~~~~~~~~~~ + +Copyright 2024 Joshua Sigona + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions or derivations of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions or derivative works in binary form must reproduce the above +copyright notice. This list of conditions and the following disclaimer must be +reproduced in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may +be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +Portions of this software are copyright © 2024 The FreeType +Project (www.freetype.org). Please see LICENSE_FT.txt for more information. +All rights reserved. +*/ +#pragma endregion +#pragma once + +#include "MenuLabel.h" +#include "Item.h" + +namespace ItemLabelDescriptionType{ + enum ItemDescriptionType{ + ITEM_DESCRIPTION, + ITEM_NAME + }; +}; + +using namespace ItemLabelDescriptionType; + +class MenuItemLabel:public MenuLabel{ + std::weak_ptritemRef; + ItemDescriptionType labelType; +public: + inline MenuItemLabel(geom2d::rectrect,std::weak_ptritemRef,ItemDescriptionType labelType=ITEM_DESCRIPTION,float scale=1,ComponentAttr attributes=ComponentAttr::NONE) + :MenuLabel(rect,"",scale,attributes),itemRef(itemRef),labelType(labelType){} + inline virtual void Update(AiL*game)override{ + MenuLabel::Update(game); + + if(!itemRef.expired()){ + switch(labelType){ + case ITEM_DESCRIPTION:{ + SetLabel(itemRef.lock()->Description(NON_COMPACT)); + }break; + case ITEM_NAME:{ + SetLabel(itemRef.lock()->DisplayName()); + }break; + } + } + } + inline virtual void SetItem(std::weak_ptritemRef){ + this->itemRef=itemRef; + } +}; \ No newline at end of file diff --git a/Adventures in Lestoria/MerchantWindow.cpp b/Adventures in Lestoria/MerchantWindow.cpp index a1b295e1..5cce7b26 100644 --- a/Adventures in Lestoria/MerchantWindow.cpp +++ b/Adventures in Lestoria/MerchantWindow.cpp @@ -109,6 +109,7 @@ void Menu::InitializeMerchantWindow(){ auto inventoryDisplay=merchantWindow->ADD("Merchant Inventory Display",RowInventoryScrollableWindowComponent)(geom2d::rect{{2,28},{220,merchantWindow->size.y-44}},"Item Name Label","Item Description Label", [](MenuFuncData data){ + if(!data.component.lock()->GetSubcomponentParent().expired())return true; //We do not do anything if it's not the actual item. std::weak_ptritem=DYNAMIC_POINTER_CAST(data.component.lock()); int qty=1; @@ -138,6 +139,7 @@ void Menu::InitializeMerchantWindow(){ return true; }, [](MenuFuncData data){ + if(!data.component.lock()->GetSubcomponentParent().expired())return true; //We do not do anything if it's not the actual item. Component(data.menu.GetType(),"Item Icon")->SetItem(DYNAMIC_POINTER_CAST(data.component.lock())->GetItem()); data.menu.I(A::MERCHANT_ITEM_SLOT)=data.parentComponent.lock()->GetComponentIndex(data.component); return true; @@ -189,6 +191,7 @@ void Menu::InitializeMerchantWindow(){ auto inventoryDisplay=merchantWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)(geom2d::rect{{72,28},{150,merchantWindow->size.y-44}},"Item Name Label","Item Description Label", [](MenuFuncData data){ + if(!data.component.lock()->GetSubcomponentParent().expired())return true; //We do not do anything if it's not the actual item. std::weak_ptritem=DYNAMIC_POINTER_CAST(data.component.lock()); if(item.lock()->GetItem().lock()->IsLocked()){ SoundEffect::PlaySFX("Locked Item",SoundEffect::CENTERED); @@ -221,6 +224,7 @@ void Menu::InitializeMerchantWindow(){ return true; }, [](MenuFuncData data){ + if(!data.component.lock()->GetSubcomponentParent().expired())return true; //We do not do anything if it's not the actual item. Component(data.menu.GetType(),"Item Icon")->SetItem(DYNAMIC_POINTER_CAST(data.component.lock())->GetItem()); data.menu.I(A::ITEM_SLOT)=data.parentComponent.lock()->GetComponentIndex(data.component); return true; @@ -252,7 +256,8 @@ void Menu::InitializeMerchantWindow(){ #pragma region Inventory Description float inventoryDescriptionWidth=merchantWindow->pos.x+merchantWindow->size.x-26-224; merchantWindow->ADD("Item Description Outline",MenuLabel)(geom2d::rect{{224,28},{inventoryDescriptionWidth,merchantWindow->size.y-44}},"",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - merchantWindow->ADD("Item Icon",MenuItemItemButton)(geom2d::rect{{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END; + merchantWindow->ADD("Item Icon",MenuItemItemButton)(geom2d::rect{{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,DO_NOTHING,"Item Name Label","Item Description Label",IconButtonAttr::NOT_SELECTABLE)END + ->SetIconScale({2.f,2.f}); merchantWindow->ADD("Item Name Label",MenuLabel)(geom2d::rect{{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; merchantWindow->ADD("Item Description Label",MenuLabel)(geom2d::rect{{226,94},{inventoryDescriptionWidth-6,merchantWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; #pragma endregion @@ -358,7 +363,8 @@ void Menu::InitializeMerchantWindow(){ {game->KEY_SELECT,{[](MenuFuncData data){ if(!data.menu.GetSelection().expired()&& !data.menu.GetSelection().lock()->parentComponent.expired()&& - data.menu.GetSelection().lock()->parentComponent.lock()->GetName()=="Inventory Display - Accessories"){ + data.menu.GetSelection().lock()->parentComponent.lock()->GetName()=="Inventory Display - Accessories"&& + data.menu.GetSelection().lock()->GetSubcomponentParent().expired()){ if(DYNAMIC_POINTER_CAST(data.menu.GetSelection().lock())->GetItem().lock()->IsLocked()){ return "Unlock"; }else{ @@ -369,8 +375,8 @@ void Menu::InitializeMerchantWindow(){ },[](MenuType type){ if(!Menu::menus[type]->GetSelection().expired()&& !Menu::menus[type]->GetSelection().lock()->parentComponent.expired()&& - Menu::menus[type]->GetSelection().lock()->parentComponent.lock()->GetName()=="Inventory Display - Accessories" - &&Menu::menus[type]->GetSelection().lock()->GetSubcomponentParent().expired()){ + Menu::menus[type]->GetSelection().lock()->parentComponent.lock()->GetName()=="Inventory Display - Accessories"&& + Menu::menus[type]->GetSelection().lock()->GetSubcomponentParent().expired()){ DYNAMIC_POINTER_CAST(Menu::menus[type]->GetSelection().lock())->GetLockButton().lock()->Click(); } }}}, diff --git a/Adventures in Lestoria/PauseMenu.cpp b/Adventures in Lestoria/PauseMenu.cpp index 4da95254..93ffbe08 100644 --- a/Adventures in Lestoria/PauseMenu.cpp +++ b/Adventures in Lestoria/PauseMenu.cpp @@ -51,7 +51,8 @@ INCLUDE_GFX void Menu::InitializePauseWindow(){ Menu*pauseWindow=CreateMenu(MenuType::PAUSE,CENTERED,vi2d{96,140}); - pauseWindow->ADD("Resume Button",MenuComponent)(geom2d::rect{{6.f,0.f},{84.f,24.f}},"Resume",[](MenuFuncData data){ + pauseWindow->ADD("Resume Button",MenuComponent)(geom2d::rect{{6.f,0.f},{84.f,24.f}},"Resume",[](MenuFuncData data){void ClearGarbage(); + game->ClearGarbage(); Menu::CloseMenu(); return true; },ButtonAttr::FIT_TO_LABEL)END; diff --git a/Adventures in Lestoria/TODO.txt b/Adventures in Lestoria/TODO.txt index ea9af8d1..ce7b134e 100644 --- a/Adventures in Lestoria/TODO.txt +++ b/Adventures in Lestoria/TODO.txt @@ -10,4 +10,8 @@ should gemstones dropp from boss stages aswell? (Maybe lower droprate?) Funny text colors with text color override on blacksmith menu -Toggle for displaying error messages \ No newline at end of file +Toggle for displaying error messages + +Fix size of icons in merchant menus. +Sherman's consumable crafting menu needs enabling/disabling of +/- buttons +Label doesn't constantly update in the merchant window. \ No newline at end of file diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index f07a893b..17909534 100644 --- a/Adventures in Lestoria/Version.h +++ b/Adventures in Lestoria/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 0 #define VERSION_MINOR 5 #define VERSION_PATCH 1 -#define VERSION_BUILD 8038 +#define VERSION_BUILD 8066 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/olcPGEX_ViewPort.h b/Adventures in Lestoria/olcPGEX_ViewPort.h index 3b8024a2..7444191c 100644 --- a/Adventures in Lestoria/olcPGEX_ViewPort.h +++ b/Adventures in Lestoria/olcPGEX_ViewPort.h @@ -628,202 +628,181 @@ float olc::ViewPort::directionFromLine(vf2d lineA, vf2d lineB, vf2d point) { } void olc::ViewPort::DrawStringDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col, const olc::vf2d& scale, const float width,const bool disableDynamicScaling){ - struct DecalData{ - Decal*decal; - float expireTime=0.0f; - }; if(sText.length()==0)return; - static std::mapgarbageCollector; - std::string key{sText}; + std::string key{"DSD_"+std::string(pge->stripCol(sText))}; key+=std::to_string(width); if(!disableDynamicScaling){ key+=scale.str(); } - if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + if(!pge->garbageCollector.count(key)||pge->garbageCollector[key].originalStr!=sText){ //If the text key already exists, don't have to recreate the decal, just update the expire time. vi2d imageSize=pge->GetWrappedTextSize(sText,width,scale); - Decal*newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x)); - garbageCollector[key].decal=newDecal; + Decal*newDecal=nullptr; + if(!pge->garbageCollector.count(key)){ + newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x)); + pge->garbageCollector[key].decal=newDecal; + }else{ + newDecal=pge->garbageCollector[key].decal; + } + pge->garbageCollector[key].originalStr=sText; pge->SetDrawTarget(newDecal->sprite); pge->Clear(BLANK); pge->DrawString({0,0},sText,WHITE,1U,width/scale.x); pge->SetDrawTarget(nullptr); newDecal->Update(); } - garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; - std::erase_if(garbageCollector,[&](auto&key){ - if(key.second.expireTimeGetRuntime()){ - delete key.second.decal; - return true; - } - return false; - }); - DrawDecal(pos,garbageCollector[key].decal,scale,col); + pge->garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; + DrawDecal(pos,pge->garbageCollector[key].decal,scale,col); } void olc::ViewPort::DrawStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col, const olc::vf2d& scale){ - struct DecalData{ - Decal*decal; - float expireTime=0.0f; - }; if(sText.length()==0)return; - static std::mapgarbageCollector; - std::u32string key=font.GetFontName()+U"_"+sText; - if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. - garbageCollector[key].decal=font.RenderStringToDecal(sText,WHITE); - } - garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; - std::erase_if(garbageCollector,[&](auto&key){ - if(key.second.expireTimeGetRuntime()){ - delete key.second.decal; - return true; + std::u32string Ukey=U"DSD_"+font.GetFontName()+U"_"+pge->stripCol(sText); + std::string key=std::string(Ukey.begin(),Ukey.end()); + if(!pge->garbageCollector.count(key)||pge->garbageCollector[key].originalStr!=std::string(sText.begin(),sText.end())){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + if(pge->garbageCollector.count(key)){ + delete pge->garbageCollector[key].decal; } - return false; - }); - DrawDecal(pos,garbageCollector[key].decal,scale/4,col); + pge->garbageCollector[key].decal=font.RenderStringToDecal(sText,WHITE); + pge->garbageCollector[key].originalStr=std::string(sText.begin(),sText.end()); + } + pge->garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; + DrawDecal(pos,pge->garbageCollector[key].decal,scale/4,col); } void olc::ViewPort::DrawStringPropDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col, const olc::vf2d& scale,const float width,const bool disableDynamicScaling){ - struct DecalData{ - Decal*decal; - float expireTime=0.0f; - }; if(sText.length()==0)return; - static std::mapgarbageCollector; - std::string key{sText}; + std::string key{"DSPD"+std::string(pge->stripCol(sText))}; key+=std::to_string(width); if(!disableDynamicScaling){ key+=scale.str(); } - if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + if(!pge->garbageCollector.count(key)||pge->garbageCollector[key].originalStr!=sText){ //If the text key already exists, don't have to recreate the decal, just update the expire time. vi2d imageSize=pge->GetWrappedTextSizeProp(sText,width,scale); - Decal*newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x)); - garbageCollector[key].decal=newDecal; + Decal*newDecal=nullptr; + if(!pge->garbageCollector.count(key)){ + newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x)); + pge->garbageCollector[key].decal=newDecal; + }else{ + newDecal=pge->garbageCollector[key].decal; + } + pge->garbageCollector[key].originalStr=sText; pge->SetDrawTarget(newDecal->sprite); pge->Clear(BLANK); pge->DrawStringProp({0,0},sText,WHITE,1U,width/scale.x); pge->SetDrawTarget(nullptr); newDecal->Update(); } - garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; - std::erase_if(garbageCollector,[&](auto&key){ - if(key.second.expireTimeGetRuntime()){ - delete key.second.decal; - return true; - } - return false; - }); - DrawDecal(pos,garbageCollector[key].decal,scale,col); + pge->garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; + DrawDecal(pos,pge->garbageCollector[key].decal,scale,col); } void olc::ViewPort::DrawShadowStringDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col, const Pixel shadowCol, const olc::vf2d& scale,const float width,const float shadowSizeFactor,const bool disableDynamicScaling){ - struct DecalData{ - Decal*decal; - float expireTime=0.0f; - }; - if(sText.length()==0)return; - static std::mapgarbageCollector; - std::string key{sText}; - key+=std::to_string(width); - if(!disableDynamicScaling){ - key+=scale.str(); + if(sText.length()==0)return; + std::string key{"DSSD_"+std::string(pge->stripCol(sText))}; + key+=std::to_string(width); + if(!disableDynamicScaling){ + key+=scale.str(); + } + if(!pge->garbageCollector.count(key)||pge->garbageCollector[key].originalStr!=sText){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + vi2d imageSize=pge->GetWrappedTextSize(sText,width,scale); + Decal*newDecal=nullptr; + if(!pge->garbageCollector.count(key)){ + newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x)); + pge->garbageCollector[key].decal=newDecal; + }else{ + newDecal=pge->garbageCollector[key].decal; + } + pge->garbageCollector[key].originalStr=sText; + pge->SetDrawTarget(newDecal->sprite); + pge->Clear(BLANK); + pge->DrawString({0,0},sText,WHITE,1U,width/scale.x); + newDecal->Update(); + vf2d adjustedShadowSizeFactor=vf2d{shadowSizeFactor,shadowSizeFactor}*4/scale; + Decal*newShadowDecal=nullptr; + if(!pge->garbageCollector.count(key+"_SHADOW")){ + newShadowDecal=new Decal(new Sprite((imageSize.x/scale.x*4)+adjustedShadowSizeFactor.x*2,(imageSize.x/scale.x*4)+adjustedShadowSizeFactor.y*2)); + pge->garbageCollector[key+"_SHADOW"].decal=newShadowDecal; + }else{ + newShadowDecal=pge->garbageCollector[key+"_SHADOW"].decal; } - if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. - vi2d imageSize=pge->GetWrappedTextSize(sText,width,scale); - Decal*newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.x/scale.x)); - garbageCollector[key].decal=newDecal; - pge->SetDrawTarget(newDecal->sprite); - pge->Clear(BLANK); - pge->DrawString({0,0},sText,WHITE,1U,width/scale.x); - newDecal->Update(); - vf2d adjustedShadowSizeFactor=vf2d{shadowSizeFactor,shadowSizeFactor}*4/scale; - Decal*newShadowDecal=new Decal(new Sprite((imageSize.x/scale.x*4)+adjustedShadowSizeFactor.x*2,(imageSize.x/scale.x*4)+adjustedShadowSizeFactor.y*2)); - garbageCollector[key+"_SHADOW"].decal=newShadowDecal; - pge->SetDrawTarget(newShadowDecal->sprite); - pge->Clear(BLANK); - for(float y=-adjustedShadowSizeFactor.y;y<=adjustedShadowSizeFactor.y+0.1;y+=adjustedShadowSizeFactor.y/2){ - for(float x=-adjustedShadowSizeFactor.x;x<=adjustedShadowSizeFactor.x+0.1;x+=adjustedShadowSizeFactor.x/2){ - if(x!=0||y!=0){ - pge->DrawString(vf2d{x,y}+adjustedShadowSizeFactor, sText, WHITE,4U,width/scale.x*4); - } + pge->SetDrawTarget(newShadowDecal->sprite); + pge->Clear(BLANK); + for(float y=-adjustedShadowSizeFactor.y;y<=adjustedShadowSizeFactor.y+0.1;y+=adjustedShadowSizeFactor.y/2){ + for(float x=-adjustedShadowSizeFactor.x;x<=adjustedShadowSizeFactor.x+0.1;x+=adjustedShadowSizeFactor.x/2){ + if(x!=0||y!=0){ + pge->DrawString(vf2d{x,y}+adjustedShadowSizeFactor, sText, WHITE,4U,width/scale.x*4); } } - pge->SetDrawTarget(nullptr); - newShadowDecal->Update(); } - garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; - garbageCollector[key+"_SHADOW"].expireTime=pge->GetRuntime()+120.0f; - std::erase_if(garbageCollector,[&](auto&key){ - if(key.second.expireTimeGetRuntime()){ - delete key.second.decal; - return true; - } - return false; - }); - DrawDecal(pos-vf2d{shadowSizeFactor,shadowSizeFactor},garbageCollector[key+"_SHADOW"].decal,scale/4,shadowCol); - DrawDecal(pos,garbageCollector[key].decal,scale,col); + pge->SetDrawTarget(nullptr); + newShadowDecal->Update(); + } + pge->garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; + pge->garbageCollector[key+"_SHADOW"].expireTime=pge->GetRuntime()+120.0f; + DrawDecal(pos-vf2d{shadowSizeFactor,shadowSizeFactor},pge->garbageCollector[key+"_SHADOW"].decal,scale/4,shadowCol); + DrawDecal(pos,pge->garbageCollector[key].decal,scale,col); } void olc::ViewPort::DrawShadowStringPropDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col, const Pixel shadowCol, const olc::vf2d& scale,const float width,const float shadowSizeFactor,const bool disableDynamicScaling){ - struct DecalData{ - Decal*decal; - float expireTime=0.0f; - }; - if(sText.length()==0)return; - static std::mapgarbageCollector; - std::string key{sText}; - key+=std::to_string(width); - if(!disableDynamicScaling){ - key+=scale.str(); + if(sText.length()==0)return; + std::string key{"DSSPD"+std::string(pge->stripCol(sText))}; + key+=std::to_string(width); + if(!disableDynamicScaling){ + key+=scale.str(); + } + if(!pge->garbageCollector.count(key)||pge->garbageCollector[key].originalStr!=sText){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + vi2d imageSize=pge->GetWrappedTextSizeProp(sText,width,scale); + Decal*newDecal=nullptr; + if(!pge->garbageCollector.count(key)){ + newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x)); + pge->garbageCollector[key].decal=newDecal; + }else{ + newDecal=pge->garbageCollector[key].decal; + } + pge->garbageCollector[key].originalStr=sText; + pge->SetDrawTarget(newDecal->sprite); + pge->Clear(BLANK); + pge->DrawStringProp({0,0},sText,WHITE,1U,width/scale.x); + newDecal->Update(); + vf2d adjustedShadowSizeFactor=vf2d{shadowSizeFactor,shadowSizeFactor}*4/scale; + Decal*newShadowDecal=nullptr; + if(!pge->garbageCollector.count(key+"_SHADOW")){ + newShadowDecal=new Decal(new Sprite((imageSize.x/scale.x*4)+adjustedShadowSizeFactor.x*2,(imageSize.x/scale.x*4)+adjustedShadowSizeFactor.y*2)); + pge->garbageCollector[key+"_SHADOW"].decal=newShadowDecal; + }else{ + newShadowDecal=pge->garbageCollector[key+"_SHADOW"].decal; } - if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. - vi2d imageSize=pge->GetWrappedTextSizeProp(sText,width,scale); - Decal*newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.x/scale.x)); - garbageCollector[key].decal=newDecal; - pge->SetDrawTarget(newDecal->sprite); - pge->Clear(BLANK); - pge->DrawStringProp({0,0},sText,WHITE,1U,width/scale.x); - newDecal->Update(); - vf2d adjustedShadowSizeFactor=vf2d{shadowSizeFactor,shadowSizeFactor}*4/scale; - Decal*newShadowDecal=new Decal(new Sprite((imageSize.x/scale.x*4)+adjustedShadowSizeFactor.x*2,(imageSize.x/scale.x*4)+adjustedShadowSizeFactor.y*2)); - garbageCollector[key+"_SHADOW"].decal=newShadowDecal; - pge->SetDrawTarget(newShadowDecal->sprite); - pge->Clear(BLANK); - for(float y=-adjustedShadowSizeFactor.y;y<=adjustedShadowSizeFactor.y+0.1;y+=adjustedShadowSizeFactor.y/2){ - for(float x=-adjustedShadowSizeFactor.x;x<=adjustedShadowSizeFactor.x+0.1;x+=adjustedShadowSizeFactor.x/2){ - if(x!=0||y!=0){ - pge->DrawStringProp(vf2d{x,y}+adjustedShadowSizeFactor, sText, WHITE,4U,width/scale.x*4); - } + pge->SetDrawTarget(newShadowDecal->sprite); + pge->Clear(BLANK); + for(float y=-adjustedShadowSizeFactor.y;y<=adjustedShadowSizeFactor.y+0.1;y+=adjustedShadowSizeFactor.y/2){ + for(float x=-adjustedShadowSizeFactor.x;x<=adjustedShadowSizeFactor.x+0.1;x+=adjustedShadowSizeFactor.x/2){ + if(x!=0||y!=0){ + pge->DrawStringProp(vf2d{x,y}+adjustedShadowSizeFactor, sText, WHITE,4U,width/scale.x*4); } } - pge->SetDrawTarget(nullptr); - newShadowDecal->Update(); } - garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; - garbageCollector[key+"_SHADOW"].expireTime=pge->GetRuntime()+120.0f; - std::erase_if(garbageCollector,[&](auto&key){ - if(key.second.expireTimeGetRuntime()){ - delete key.second.decal; - return true; - } - return false; - }); - DrawDecal(pos-vf2d{shadowSizeFactor,shadowSizeFactor},garbageCollector[key+"_SHADOW"].decal,scale/4,shadowCol); - DrawDecal(pos,garbageCollector[key].decal,scale,col); + pge->SetDrawTarget(nullptr); + newShadowDecal->Update(); + } + pge->garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; + pge->garbageCollector[key+"_SHADOW"].expireTime=pge->GetRuntime()+120.0f; + DrawDecal(pos-vf2d{shadowSizeFactor,shadowSizeFactor},pge->garbageCollector[key+"_SHADOW"].decal,scale/4,shadowCol); + DrawDecal(pos,pge->garbageCollector[key].decal,scale,col); } void olc::ViewPort::DrawShadowStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col, const Pixel shadowCol, const olc::vf2d& scale,const float shadowSizeFactor){ - struct DecalData{ - Decal*decal; - float expireTime=0.0f; - }; if(sText.length()==0)return; - static std::mapgarbageCollector; - std::u32string key=font.GetFontName()+U"_"+sText; - if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. - garbageCollector[key].decal=font.RenderStringToDecal(sText,WHITE); + std::u32string Ukey=U"DSSD_"+font.GetFontName()+U"_"+pge->stripCol(sText); + std::string key=std::string(Ukey.begin(),Ukey.end()); + if(!pge->garbageCollector.count(key)||pge->garbageCollector[key].originalStr!=std::string(sText.begin(),sText.end())){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + if(pge->garbageCollector.count(key)){ + delete pge->garbageCollector[key].decal; + } + pge->garbageCollector[key].decal=font.RenderStringToDecal(sText,WHITE); + pge->garbageCollector[key].originalStr=std::string(sText.begin(),sText.end()); } - garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; - std::erase_if(garbageCollector,[&](auto&key){ + pge->garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; + std::erase_if(pge->garbageCollector,[&](auto&key){ if(key.second.expireTimeGetRuntime()){ delete key.second.decal; return true; @@ -833,36 +812,29 @@ void olc::ViewPort::DrawShadowStringDecal(Font&font, const olc::vf2d& pos, const for(float y=-shadowSizeFactor;y<=shadowSizeFactor+0.1;y+=shadowSizeFactor/2){ for(float x=-shadowSizeFactor;x<=shadowSizeFactor+0.1;x+=shadowSizeFactor/2){ if(x!=0||y!=0){ - DrawDecal(pos+vf2d{x,y},garbageCollector[key].decal,scale/4,shadowCol); + DrawDecal(pos+vf2d{x,y},pge->garbageCollector[key].decal,scale/4,shadowCol); } } } - DrawDecal(pos,garbageCollector[key].decal,scale/4,col); + DrawDecal(pos,pge->garbageCollector[key].decal,scale/4,col); } void olc::ViewPort::DrawDropShadowStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col, const Pixel shadowCol, const olc::vf2d& scale){ - struct DecalData{ - Decal*decal; - float expireTime=0.0f; - }; if(sText.length()==0)return; - static std::mapgarbageCollector; - std::u32string key=font.GetFontName()+U"_"+sText; - if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. - garbageCollector[key].decal=font.RenderStringToDecal(sText,WHITE); - } - garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; - std::erase_if(garbageCollector,[&](auto&key){ - if(key.second.expireTimeGetRuntime()){ - delete key.second.decal; - return true; + std::u32string Ukey=U"DDSSD_"+font.GetFontName()+U"_"+pge->stripCol(sText); + std::string key=std::string(Ukey.begin(),Ukey.end()); + if(!pge->garbageCollector.count(key)||pge->garbageCollector[key].originalStr!=std::string(sText.begin(),sText.end())){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + if(pge->garbageCollector.count(key)){ + delete pge->garbageCollector[key].decal; } - return false; - }); - DrawDecal(pos+vf2d{0,0.5f},garbageCollector[key].decal,scale/4,shadowCol); - DrawDecal(pos+vf2d{0.5f,0},garbageCollector[key].decal,scale/4,shadowCol); - DrawDecal(pos+vf2d{0.5f,0.5f},garbageCollector[key].decal,scale/4,shadowCol); - DrawDecal(pos,garbageCollector[key].decal,scale/4,col); + pge->garbageCollector[key].decal=font.RenderStringToDecal(sText,WHITE); + pge->garbageCollector[key].originalStr=std::string(sText.begin(),sText.end()); + } + pge->garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; + DrawDecal(pos+vf2d{0,0.5f},pge->garbageCollector[key].decal,scale/4,shadowCol); + DrawDecal(pos+vf2d{0.5f,0},pge->garbageCollector[key].decal,scale/4,shadowCol); + DrawDecal(pos+vf2d{0.5f,0.5f},pge->garbageCollector[key].decal,scale/4,shadowCol); + DrawDecal(pos,pge->garbageCollector[key].decal,scale/4,col); } void olc::ViewPort::DrawRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col)const{ diff --git a/Adventures in Lestoria/olcPixelGameEngine.h b/Adventures in Lestoria/olcPixelGameEngine.h index d0e0c353..0c8855d8 100644 --- a/Adventures in Lestoria/olcPixelGameEngine.h +++ b/Adventures in Lestoria/olcPixelGameEngine.h @@ -981,6 +981,7 @@ namespace olc // O------------------------------------------------------------------------------O class PixelGameEngine { + friend class ViewPort; struct StringDecalData{ char c; vf2d sourcePos; @@ -1021,6 +1022,9 @@ namespace olc public: // Hardware Interfaces + void ClearGarbage(); + void ClearTimedOutGarbage(); + // Returns true if window is currently in focus bool IsFocused() const; // Get the state of a specific keyboard button @@ -1349,6 +1353,13 @@ namespace olc olc::vi2d vDroppedFilesPointCache; uint8_t mosaic=1; uint8_t nTextEntryCharLimit=std::numeric_limits::max(); + struct DecalData{ + Decal*decal=nullptr; + float expireTime=0.0f; + std::string originalStr; + }; + std::unordered_mapgarbageCollector; + bool requestClear=false; // Command Console Specific bool bConsoleShow = false; @@ -1363,6 +1374,9 @@ namespace olc std::list sCommandHistory; std::list::iterator sCommandHistoryIt; + std::string stripCol(std::string_view originalText); + std::u32string stripCol(std::u32string_view originalText); + // Text Entry Specific bool bTextEntryEnable = false; std::string sTextEntryString = ""; @@ -2240,6 +2254,42 @@ namespace olc uint32_t PixelGameEngine::GetFPS() const { return nLastFPS; } + void PixelGameEngine::ClearGarbage(){ + requestClear=true; + } + void PixelGameEngine::ClearTimedOutGarbage(){ + std::erase_if(garbageCollector,[&](auto&key){ + if(key.second.expireTimegarbageCollector; - std::string key{sText}; + std::string key{"DSD"+std::string(stripCol(sText))}; key+=std::to_string(width); if(!disableDynamicScaling){ key+=scale.str(); } - if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + if(!garbageCollector.count(key)||garbageCollector[key].originalStr!=sText){ //If the text key already exists, don't have to recreate the decal, just update the expire time. vi2d imageSize=GetWrappedTextSize(sText,width,scale); - Decal*newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x)); - garbageCollector[key].decal=newDecal; + Decal*newDecal=nullptr; + if(!garbageCollector.count(key)){ + newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x)); + garbageCollector[key].decal=newDecal; + }else{ + newDecal=garbageCollector[key].decal; + } + garbageCollector[key].originalStr=sText; SetDrawTarget(newDecal->sprite); Clear(BLANK); DrawString({0,0},sText,WHITE,1U,width/scale.x); @@ -3459,33 +3510,27 @@ namespace olc newDecal->Update(); } garbageCollector[key].expireTime=GetRuntime()+120.0f; - std::erase_if(garbageCollector,[&](auto&key){ - if(key.second.expireTimegarbageCollector; - std::string key{sText}; + std::string key{"DSPD_"+std::string(stripCol(sText))}; key+=std::to_string(width); if(!disableDynamicScaling){ key+=scale.str(); } - if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + if(!garbageCollector.count(key)||garbageCollector[key].originalStr!=sText){ //If the text key already exists, don't have to recreate the decal, just update the expire time. vi2d imageSize=GetWrappedTextSizeProp(sText,width,scale); - Decal*newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x)); - garbageCollector[key].decal=newDecal; + Decal*newDecal=nullptr; + if(!garbageCollector.count(key)){ + newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x)); + garbageCollector[key].decal=newDecal; + }else{ + newDecal=garbageCollector[key].decal; + } + garbageCollector[key].originalStr=sText; SetDrawTarget(newDecal->sprite); Clear(BLANK); DrawStringProp({0,0},sText,WHITE,1U,width/scale.x); @@ -3493,39 +3538,38 @@ namespace olc newDecal->Update(); } garbageCollector[key].expireTime=GetRuntime()+120.0f; - std::erase_if(garbageCollector,[&](auto&key){ - if(key.second.expireTimegarbageCollector; - std::string key{sText}; + std::string key{"DSSD_"+std::string(stripCol(sText))}; key+=std::to_string(width); if(!disableDynamicScaling){ key+=scale.str(); } - if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + if(!garbageCollector.count(key)||garbageCollector[key].originalStr!=sText){ //If the text key already exists, don't have to recreate the decal, just update the expire time. vi2d imageSize=GetWrappedTextSize(sText,width,scale); - Decal*newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.x/scale.x)); - garbageCollector[key].decal=newDecal; + Decal*newDecal=nullptr; + if(!garbageCollector.count(key)){ + newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x)); + garbageCollector[key].decal=newDecal; + }else{ + newDecal=garbageCollector[key].decal; + } + garbageCollector[key].originalStr=sText; SetDrawTarget(newDecal->sprite); Clear(BLANK); DrawString({0,0},sText,WHITE,1U,width/scale.x); newDecal->Update(); vf2d adjustedShadowSizeFactor=vf2d{shadowSizeFactor,shadowSizeFactor}*4/scale; - Decal*newShadowDecal=new Decal(new Sprite((imageSize.x/scale.x*4)+adjustedShadowSizeFactor.x*2,(imageSize.x/scale.x*4)+adjustedShadowSizeFactor.y*2)); - garbageCollector[key+"_SHADOW"].decal=newShadowDecal; + Decal*newShadowDecal=nullptr; + if(!garbageCollector.count(key+"_SHADOW")){ + newShadowDecal=new Decal(new Sprite((imageSize.x/scale.x*4)+adjustedShadowSizeFactor.x*2,(imageSize.x/scale.x*4)+adjustedShadowSizeFactor.y*2)); + garbageCollector[key+"_SHADOW"].decal=newShadowDecal; + }else{ + newShadowDecal=garbageCollector[key+"_SHADOW"].decal; + } SetDrawTarget(newShadowDecal->sprite); Clear(BLANK); for(float y=-adjustedShadowSizeFactor.y;y<=adjustedShadowSizeFactor.y+0.1;y+=adjustedShadowSizeFactor.y/2){ @@ -3540,58 +3584,37 @@ namespace olc } garbageCollector[key].expireTime=GetRuntime()+120.0f; garbageCollector[key+"_SHADOW"].expireTime=GetRuntime()+120.0f; - std::erase_if(garbageCollector,[&](auto&key){ - if(key.second.expireTimegarbageCollector; - std::u32string key=font.GetFontName()+U"_"+sText; - if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + std::u32string Ukey=U"DSD_"+font.GetFontName()+U"_"+stripCol(sText); + std::string key=std::string(Ukey.begin(),Ukey.end()); + if(!garbageCollector.count(key)||garbageCollector[key].originalStr!=std::string(sText.begin(),sText.end())){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + if(garbageCollector.count(key)){ + delete garbageCollector[key].decal; + } garbageCollector[key].decal=font.RenderStringToDecal(sText,WHITE); + garbageCollector[key].originalStr=std::string(sText.begin(),sText.end()); } garbageCollector[key].expireTime=GetRuntime()+120.0f; - std::erase_if(garbageCollector,[&](auto&key){ - if(key.second.expireTimegarbageCollector; - std::u32string key=font.GetFontName()+U"_"+sText; - if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + std::u32string Ukey=U"DSSD_"+font.GetFontName()+U"_"+stripCol(sText); + std::string key=std::string(Ukey.begin(),Ukey.end()); + if(!garbageCollector.count(key)||garbageCollector[key].originalStr!=std::string(sText.begin(),sText.end())){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + if(garbageCollector.count(key)){ + delete garbageCollector[key].decal; + } garbageCollector[key].decal=font.RenderStringToDecal(sText,WHITE); + garbageCollector[key].originalStr=std::string(sText.begin(),sText.end()); } garbageCollector[key].expireTime=GetRuntime()+120.0f; - std::erase_if(garbageCollector,[&](auto&key){ - if(key.second.expireTimegarbageCollector; - std::u32string key=font.GetFontName()+U"_"+sText; - if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + std::u32string Ukey=U"DDSSD_"+font.GetFontName()+U"_"+stripCol(sText); + std::string key=std::string(Ukey.begin(),Ukey.end()); + if(!garbageCollector.count(key)||garbageCollector[key].originalStr!=std::string(sText.begin(),sText.end())){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + if(garbageCollector.count(key)){ + delete garbageCollector[key].decal; + } garbageCollector[key].decal=font.RenderStringToDecal(sText,WHITE); + garbageCollector[key].originalStr=std::string(sText.begin(),sText.end()); } garbageCollector[key].expireTime=GetRuntime()+120.0f; - std::erase_if(garbageCollector,[&](auto&key){ - if(key.second.expireTimegarbageCollector; - std::string key{sText}; + std::string key{"DSSPD_"+std::string(stripCol(sText))}; key+=std::to_string(width); if(!disableDynamicScaling){ key+=scale.str(); } - if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + if(!garbageCollector.count(key)||garbageCollector[key].originalStr!=sText){ //If the text key already exists, don't have to recreate the decal, just update the expire time. vi2d imageSize=GetWrappedTextSizeProp(sText,width,scale); - Decal*newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.x/scale.x)); - garbageCollector[key].decal=newDecal; + Decal*newDecal=nullptr; + if(!garbageCollector.count(key)){ + newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x)); + garbageCollector[key].decal=newDecal; + }else{ + newDecal=garbageCollector[key].decal; + } + garbageCollector[key].originalStr=sText; SetDrawTarget(newDecal->sprite); Clear(BLANK); DrawStringProp({0,0},sText,WHITE,1U,width/scale.x); newDecal->Update(); vf2d adjustedShadowSizeFactor=vf2d{shadowSizeFactor,shadowSizeFactor}*4/scale; - Decal*newShadowDecal=new Decal(new Sprite((imageSize.x/scale.x*4)+adjustedShadowSizeFactor.x*2,(imageSize.x/scale.x*4)+adjustedShadowSizeFactor.y*2)); - garbageCollector[key+"_SHADOW"].decal=newShadowDecal; + Decal*newShadowDecal=nullptr; + if(!garbageCollector.count(key+"_SHADOW")){ + newShadowDecal=new Decal(new Sprite((imageSize.x/scale.x*4)+adjustedShadowSizeFactor.x*2,(imageSize.x/scale.x*4)+adjustedShadowSizeFactor.y*2)); + garbageCollector[key+"_SHADOW"].decal=newShadowDecal; + }else{ + newShadowDecal=garbageCollector[key+"_SHADOW"].decal; + } SetDrawTarget(newShadowDecal->sprite); Clear(BLANK); for(float y=-adjustedShadowSizeFactor.y;y<=adjustedShadowSizeFactor.y+0.1;y+=adjustedShadowSizeFactor.y/2){ @@ -3664,13 +3686,6 @@ namespace olc } garbageCollector[key].expireTime=GetRuntime()+120.0f; garbageCollector[key+"_SHADOW"].expireTime=GetRuntime()+120.0f; - std::erase_if(garbageCollector,[&](auto&key){ - if(key.second.expireTime5000){ + std::for_each(garbageCollector.begin(),garbageCollector.end(),[&](auto&key){ + delete key.second.decal; + }); + garbageCollector.clear(); + requestClear=false; + } // Present Graphics to screen renderer->DisplayFrame(); diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe index 24cc67bf..7c078c44 100644 Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ