diff --git a/Crawler/Crawler.cpp b/Crawler/Crawler.cpp index 25fa564b..619e8068 100644 --- a/Crawler/Crawler.cpp +++ b/Crawler/Crawler.cpp @@ -1213,7 +1213,7 @@ void Crawler::RenderHud(){ std::stringstream castTimeDisplay; castTimeDisplay<::max(),2.f); }; if(GetPlayer()->GetCastInfo().castTimer>0){ diff --git a/Crawler/Key.cpp b/Crawler/Key.cpp index 4ed7cf78..3b424fe5 100644 --- a/Crawler/Key.cpp +++ b/Crawler/Key.cpp @@ -45,6 +45,7 @@ Input::Input(InputType type,int key) :type(type),key(key){} bool Input::Pressed(){ + if(!game->IsFocused())return false; switch(type){ case KEY:{ return game->GetKey(Key(key)).bPressed; @@ -61,6 +62,7 @@ bool Input::Pressed(){ } bool Input::Held(){ + if(!game->IsFocused())return false; switch(type){ case KEY:{ return game->GetKey(Key(key)).bHeld; @@ -77,6 +79,7 @@ bool Input::Held(){ } bool Input::Released(){ + if(!game->IsFocused())return false; switch(type){ case KEY:{ return game->GetKey(Key(key)).bReleased; diff --git a/Crawler/Menu.cpp b/Crawler/Menu.cpp index 381f0a7e..db2a417c 100644 --- a/Crawler/Menu.cpp +++ b/Crawler/Menu.cpp @@ -144,7 +144,7 @@ void Menu::CheckClickAndPerformMenuSelect(Crawler*game){ } void Menu::HoverMenuSelect(Crawler*game){ - if(selection==vi2d{-1,-1}||buttons[selection.y][selection.x]->disabled)return; + if(!game->IsFocused()||selection==vi2d{-1,-1}||buttons[selection.y][selection.x]->disabled)return; if(buttons[selection.y][selection.x]->draggable){ if(buttonHoldTime<"ThemeGlobal.MenuHoldTime"_F){ CheckClickAndPerformMenuSelect(game); @@ -158,7 +158,7 @@ void Menu::HoverMenuSelect(Crawler*game){ } void Menu::MenuSelect(Crawler*game){ - if(selection==vi2d{-1,-1}||(buttons[selection.y][selection.x]->disabled||buttons[selection.y][selection.x]->grayedOut))return; + if(!game->IsFocused()||selection==vi2d{-1,-1}||(buttons[selection.y][selection.x]->disabled||buttons[selection.y][selection.x]->grayedOut))return; bool buttonStillValid=buttons[selection.y][selection.x]->onClick(MenuFuncData{*this,game,buttons[selection.y][selection.x],(ScrollableWindowComponent*)buttons[selection.y][selection.x]->parentComponent}); if(buttonStillValid){ if(buttons[selection.y][selection.x]->menuDest!=MenuType::ENUM_END){ @@ -253,6 +253,7 @@ void Menu::Update(Crawler*game){ } KeyboardButtonNavigation(game,pos); + for(auto&[key,value]:buttons){ for(auto&button:value){ if(button->renderInMain){ diff --git a/Crawler/MenuLabel.h b/Crawler/MenuLabel.h index 67a71580..4f2ede14 100644 --- a/Crawler/MenuLabel.h +++ b/Crawler/MenuLabel.h @@ -67,7 +67,7 @@ protected: inline virtual void DrawDecal(ViewPort&window,bool focused)override{ MenuComponent::DrawDecal(window,focused); vf2d adjustedScale={scale,scale}; - vf2d labelTextSize=vf2d(game->GetWrappedTextSizeProp(label,rect.size.x,adjustedScale.x)); + vf2d labelTextSize=vf2d(game->GetWrappedTextSizeProp(label,rect.size.x,adjustedScale)); if(fitToLabel){ float sizeRatio=((labelTextSize*adjustedScale).x)/(rect.size.x-2); diff --git a/Crawler/PopupMenuLabel.h b/Crawler/PopupMenuLabel.h index 1df3116c..af1e7fe0 100644 --- a/Crawler/PopupMenuLabel.h +++ b/Crawler/PopupMenuLabel.h @@ -59,10 +59,9 @@ protected: } virtual void inline DrawDecal(ViewPort&window,bool focused)override{ if(label.length()>0){ - std::string wrappedText=util::WrapText(game,label,int(rect.size.x-1),true,scale); - vf2d drawPos=rect.middle()-vf2d{game->GetTextSizeProp(wrappedText)}*scale/2; //Assume centered. + vf2d drawPos=rect.middle()-vf2d{game->GetWrappedTextSizeProp(label,int(rect.size.x-1),scale)}*scale/2; //Assume centered. if(!centered){ - drawPos=vf2d{rect.pos.x+2,rect.middle().y-game->GetTextSizeProp(wrappedText).y/2}; //We should at least vertically align here. + drawPos=vf2d{rect.pos.x+2,rect.middle().y-game->GetWrappedTextSizeProp(label,int(rect.size.x-1),scale).y/2}; //We should at least vertically align here. } if(background){ window.FillRectDecal(rect.pos,rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),hoverEffect/"ThemeGlobal.HighlightTime"_F)); @@ -71,12 +70,12 @@ protected: window.DrawRectDecal(rect.pos,rect.size); } if(showDefaultLabel){ - window.DrawStringPropDecal(rect.pos+rect.size/2-game->GetTextSizeProp(label)/2,label); + window.DrawStringPropDecal(rect.pos+rect.size/2-game->GetWrappedTextSizeProp(label,int(rect.size.x-1),scale)/2,label,WHITE,{1,1},int(rect.size.x-1)); } if(shadow){ - window.DrawShadowStringPropDecal(drawPos,wrappedText,WHITE,BLACK,scale); + window.DrawShadowStringPropDecal(drawPos,label,WHITE,BLACK,scale,int(rect.size.x-1)); }else{ - window.DrawStringPropDecal(drawPos,wrappedText,WHITE,scale); + window.DrawStringPropDecal(drawPos,label,WHITE,scale,int(rect.size.x-1)); } } } diff --git a/Crawler/State_GameRun.cpp b/Crawler/State_GameRun.cpp index cbcd82cf..e72b2a80 100644 --- a/Crawler/State_GameRun.cpp +++ b/Crawler/State_GameRun.cpp @@ -91,8 +91,8 @@ void State_GameRun::OnUserUpdate(Crawler*game){ } void State_GameRun::Draw(Crawler*game){ game->RenderHud(); - //FontTest(); //Enable to test font coloring. - FontSpriteTest(); //Enable to test font coloring. + FontTest(); //Enable to test font coloring. + //FontSpriteTest(); //Enable to test font coloring. } void State_GameRun::FontTest(){ diff --git a/Crawler/Version.h b/Crawler/Version.h index 26651b89..d15156ee 100644 --- a/Crawler/Version.h +++ b/Crawler/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 0 #define VERSION_MINOR 2 #define VERSION_PATCH 1 -#define VERSION_BUILD 4398 +#define VERSION_BUILD 4434 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Crawler/olcPGEX_ViewPort.h b/Crawler/olcPGEX_ViewPort.h index 290b60cb..29e0c317 100644 --- a/Crawler/olcPGEX_ViewPort.h +++ b/Crawler/olcPGEX_ViewPort.h @@ -116,9 +116,9 @@ namespace olc { const vf2d &pos2, Pixel p = WHITE) const; // Draws a multiline string as a decal, with tinting and scaling - void DrawStringDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f },const float width=std::numeric_limits::max(),const bool colorOverride=false); + void DrawStringDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f },const float width=std::numeric_limits::max(),const bool disableDynamicScaling=false); void DrawStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); - void DrawStringPropDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }, const float width=std::numeric_limits::max(),const bool colorOverride=false); + void DrawStringPropDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }, const float width=std::numeric_limits::max(),const bool disableDynamicScaling=false); void DrawShadowStringDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float width=std::numeric_limits::max(),const float shadowSizeFactor=1); void DrawShadowStringPropDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float width=std::numeric_limits::max(),const float shadowSizeFactor=1); void DrawShadowStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float shadowSizeFactor=1); @@ -628,108 +628,36 @@ float olc::ViewPort::directionFromLine(vf2d lineA, vf2d lineB, vf2d point) { - (point.x - lineA.x) * (lineB.y - lineA.y); } -void olc::ViewPort::DrawStringDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col, const olc::vf2d& scale, const float width,const bool colorOverride){ - static std::vectorletters; - letters.clear(); - bool wrappingOccurred=false; - olc::vf2d planningMarker = { 0.0f, 0.0f }; - olc::vf2d drawingMarker = { 0.0f, 0.0f }; - Pixel textCol=col; - const auto hexToNumber=[](char c){ - if(c<='9')return c-'0'; - return (c-'A')+10; +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; }; - for (int skip=0,index=-1;auto c : sText) - { - index++; - if(skip){ - skip--; - continue; - } - if(c==' '||c=='\t'){ - for(PixelGameEngine::StringDecalData&letter:letters){ - DrawPartialDecal(pos + drawingMarker, pge->GetFontDecal(), letter.sourcePos, letter.sourceSize, scale, letter.col); - drawingMarker.x += 8.0f * scale.x; - } - letters.clear(); - wrappingOccurred=false; - } - if(wrappingOccurred){ - if(c!=' '&&c!='\t'){ - wrappingOccurred=false; - }else{ - continue; - } - } - if(c=='\r')continue; //Ignore carriage returns. Stupid Linux. - if (c == '\n') - { - planningMarker.x = 0; planningMarker.y += 8.0f * scale.y; - } - else if (c == ' ') - { - drawingMarker.x += 8.0f * scale.x; - planningMarker.x += 8.0f * scale.x; - } - else if (c == '\t') - { - drawingMarker.x += 8.0f * float(nTabSizeInSpaces) * scale.x; - planningMarker.x += 8.0f * float(nTabSizeInSpaces) * scale.x; - } - else if (c>=-128&&c<-105) - { - textCol={PixelGameEngine::charToColor[c].r,PixelGameEngine::charToColor[c].g,PixelGameEngine::charToColor[c].b,col.a}; - } - else if (c==PixelGameEngine::Reset[0]) - { - textCol=col; - } - else if (c=='#') - { - skip=6; - textCol=BLACK; - for(int i=1;i<7;i++){ - if(i<3){ - textCol.r*=16; - textCol.r+=hexToNumber(sText[index+i]); - }else - if(i<5){ - textCol.g*=16; - textCol.g+=hexToNumber(sText[index+i]); - }else{ - textCol.b*=16; - textCol.b+=hexToNumber(sText[index+i]); - } - } - if(textCol==WHITE)textCol=col; - } - else - { - int32_t ox = (c - 32) % 16; - int32_t oy = (c - 32) / 16; - planningMarker.x += 8.0f * scale.x; - if(planningMarker.x>width){ - if(drawingMarker.x==0){ //The text has overflowed a full line, so we have to dump the line. - for(PixelGameEngine::StringDecalData&letter:letters){ - DrawPartialDecal(pos + drawingMarker, pge->GetFontDecal(), letter.sourcePos, letter.sourceSize, scale, letter.col); - drawingMarker.x += 8.0f * scale.x; - } - letters.clear(); - } - planningMarker.x = 0; planningMarker.y += 8.0f * scale.y; - drawingMarker=planningMarker; - wrappingOccurred=true; - for(PixelGameEngine::StringDecalData&letter:letters){ - planningMarker.x += 8.0f * scale.x; - } - } - letters.emplace_back(c,vf2d{ float(ox) * 8.0f, float(oy) * 8.0f }, vf2d{ 8.0f, 8.0f },colorOverride?col:textCol); - } - } - for(PixelGameEngine::StringDecalData&letter:letters){ - DrawPartialDecal(pos + drawingMarker, pge->GetFontDecal(), letter.sourcePos, letter.sourceSize, scale, letter.col); - drawingMarker.x += 8.0f * scale.x; + if(sText.length()==0)return; + static std::mapgarbageCollector; + std::string key{sText}; + 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. + 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; + 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); } void olc::ViewPort::DrawStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col, const olc::vf2d& scale){ @@ -754,115 +682,43 @@ void olc::ViewPort::DrawStringDecal(Font&font, const olc::vf2d& pos, const std:: DrawDecal(pos,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 colorOverride){ - static std::vectorletters; - letters.clear(); - bool wrappingOccurred=false; - olc::vf2d planningMarker = { 0.0f, 0.0f }; - olc::vf2d drawingMarker = { 0.0f, 0.0f }; - Pixel textCol=col; - const auto hexToNumber=[](char c){ - if(c<='9')return c-'0'; - return (c-'A')+10; +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; }; - for (int skip=0,index=-1;auto c : sText) - { - index++; - if(skip){ - skip--; - continue; - } - if(c==' '||c=='\t'){ - for(PixelGameEngine::StringDecalData&letter:letters){ - DrawPartialDecal(pos + drawingMarker, pge->GetFontDecal(), letter.sourcePos, letter.sourceSize, scale, letter.col); - drawingMarker.x += float(pge->vFontSpacing[letter.c - 32].y) * scale.x; - } - letters.clear(); - wrappingOccurred=false; - } - if(wrappingOccurred){ - if(c!=' '&&c!='\t'){ - wrappingOccurred=false; - }else{ - continue; - } - } - if(c=='\r')continue; //Ignore carriage returns. Stupid Linux. - if (c == '\n') - { - planningMarker.x = 0; planningMarker.y += 8.0f * scale.y; - } - else if (c == ' ') - { - drawingMarker.x += float(pge->vFontSpacing[' ' - 32].y) * scale.x; - planningMarker.x += float(pge->vFontSpacing[' ' - 32].y) * scale.x; - } - else if (c == '\t') - { - drawingMarker.x += 8.0f * float(nTabSizeInSpaces) * scale.x; - planningMarker.x += 8.0f * float(nTabSizeInSpaces) * scale.x; - } - else if (c>=-128&&c<-105) - { - textCol={PixelGameEngine::charToColor[c].r,PixelGameEngine::charToColor[c].g,PixelGameEngine::charToColor[c].b,col.a}; - } - else if (c==PixelGameEngine::Reset[0]) - { - textCol=col; - } - else if (c=='#') - { - skip=6; - textCol=BLACK; - for(int i=1;i<7;i++){ - if(i<3){ - textCol.r*=16; - textCol.r+=hexToNumber(sText[index+i]); - }else - if(i<5){ - textCol.g*=16; - textCol.g+=hexToNumber(sText[index+i]); - }else{ - textCol.b*=16; - textCol.b+=hexToNumber(sText[index+i]); - } - } - if(textCol==WHITE)textCol=col; - } - else - { - int32_t ox = (c - 32) % 16; - int32_t oy = (c - 32) / 16; - planningMarker.x += float(pge->vFontSpacing[c - 32].y) * scale.x; - if(planningMarker.x>width){ - if(drawingMarker.x==0){ //The text has overflowed a full line, so we have to dump the line. - for(PixelGameEngine::StringDecalData&letter:letters){ - DrawPartialDecal(pos + drawingMarker, pge->GetFontDecal(), letter.sourcePos, letter.sourceSize, scale, letter.col); - drawingMarker.x += float(pge->vFontSpacing[letter.c - 32].y) * scale.x; - } - letters.clear(); - } - planningMarker.x = 0; planningMarker.y += 8.0f * scale.y; - drawingMarker=planningMarker; - wrappingOccurred=true; - for(PixelGameEngine::StringDecalData&letter:letters){ - planningMarker.x += float(pge->vFontSpacing[letter.c - 32].y) * scale.x; - } - } - letters.emplace_back(c,vf2d{ float(ox) * 8.0f + float(pge->vFontSpacing[c - 32].x), float(oy) * 8.0f }, vf2d{ float(pge->vFontSpacing[c - 32].y), 8.0f },colorOverride?col:textCol); - } - } - for(PixelGameEngine::StringDecalData&letter:letters){ - DrawPartialDecal(pos + drawingMarker, pge->GetFontDecal(), letter.sourcePos, letter.sourceSize, scale, letter.col); - drawingMarker.x += float(pge->vFontSpacing[letter.c - 32].y) * scale.x; + if(sText.length()==0)return; + static std::mapgarbageCollector; + std::string key{sText}; + 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. + 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; + 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); } 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){ 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){ - DrawStringDecal(pos+vf2d{x,y}, sText, shadowCol,scale,width,true); + DrawStringDecal(pos+vf2d{x,y}, sText, shadowCol,scale,width); } } } @@ -873,7 +729,7 @@ void olc::ViewPort::DrawShadowStringPropDecal(const olc::vf2d& pos, std::string_ 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){ - DrawStringPropDecal(pos+vf2d{x,y}, sText, shadowCol,scale,width,true); + DrawStringPropDecal(pos+vf2d{x,y}, sText, shadowCol,scale,width); } } } diff --git a/Crawler/olcPixelGameEngine.h b/Crawler/olcPixelGameEngine.h index e9e34bff..4659903d 100644 --- a/Crawler/olcPixelGameEngine.h +++ b/Crawler/olcPixelGameEngine.h @@ -1122,8 +1122,8 @@ namespace olc void DrawShadowStringProp(const olc::vi2d& pos, std::string_view sText, Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float width=std::numeric_limits::max(),const float shadowSizeFactor=1); olc::vi2d GetTextSize(std::string_view s); olc::vi2d GetTextSizeProp(std::string_view s); - olc::vi2d GetWrappedTextSize(std::string_view s,const float width=std::numeric_limits::max(),const float scale=1); - olc::vi2d GetWrappedTextSizeProp(std::string_view s,const float width=std::numeric_limits::max(),const float scale=1); + olc::vi2d GetWrappedTextSize(std::string_view s,const float width=std::numeric_limits::max(),const vf2d scale={1,1}); + olc::vi2d GetWrappedTextSizeProp(std::string_view s,const float width=std::numeric_limits::max(),const vf2d scale={1,1}); void DrawString(const olc::vi2d& pos, std::string_view sText, Pixel col = olc::WHITE, uint32_t scale = 1,const float width=std::numeric_limits::max(),const bool colorOverride=false); void DrawString(int32_t x, int32_t y, std::string_view sText, Pixel col = olc::WHITE, uint32_t scale = 1,const float width=std::numeric_limits::max(),const bool colorOverride=false); @@ -1149,9 +1149,9 @@ namespace olc void DrawRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center = { 0.0f, 0.0f }, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE); void DrawPartialRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale = { 1.0f, 1.0f }, const olc::Pixel& tint = olc::WHITE); // Draws a multiline string as a decal, with tiniting and scaling - void DrawStringDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f },const float width=std::numeric_limits::max(),const bool colorOverride=false); + void DrawStringDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f },const float width=std::numeric_limits::max(),const bool disableDynamicScaling=false); void DrawStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); - void DrawStringPropDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }, const float width=std::numeric_limits::max(),const bool colorOverride=false); + void DrawStringPropDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }, const float width=std::numeric_limits::max(),const bool disableDynamicScaling=false); void DrawShadowStringDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float width=std::numeric_limits::max(),const float shadowSizeFactor=1); void DrawShadowStringPropDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float width=std::numeric_limits::max(),const float shadowSizeFactor=1); void DrawShadowStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float shadowSizeFactor=1); @@ -2195,10 +2195,10 @@ namespace olc { return bHasInputFocus; } HWButton PixelGameEngine::GetKey(Key k) const - { return pKeyboardState[k]; } + { return IsFocused()?pKeyboardState[k]:HWButton{}; } HWButton PixelGameEngine::GetMouse(uint32_t b) const - { return pMouseState[b]; } + { return IsFocused()?pMouseState[b]:HWButton{}; } int32_t PixelGameEngine::GetMouseX() const { return vMousePos.x; } @@ -2210,7 +2210,7 @@ namespace olc { return vMousePos; } int32_t PixelGameEngine::GetMouseWheel() const - { return nMouseWheelDelta; } + { return IsFocused()?nMouseWheelDelta:0; } int32_t PixelGameEngine::ScreenWidth() const { return vScreenSize.x; } @@ -3352,221 +3352,77 @@ namespace olc void PixelGameEngine::DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint) { DrawPartialWarpedDecal(decal, &pos[0], source_pos, source_size, tint); } - void PixelGameEngine::DrawStringDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col, const olc::vf2d& scale,const float width,const bool colorOverride) + void PixelGameEngine::DrawStringDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col, const olc::vf2d& scale,const float width,const bool disableDynamicScaling) { - static std::vectorletters; - letters.clear(); - bool wrappingOccurred=false; - olc::vf2d planningMarker = { 0.0f, 0.0f }; - olc::vf2d drawingMarker = { 0.0f, 0.0f }; - Pixel textCol=col; - const auto hexToNumber=[](char c){ - if(c<='9')return c-'0'; - return (c-'A')+10; + struct DecalData{ + Decal*decal; + float expireTime=0.0f; }; - for (int skip=0,index=-1;auto c : sText) - { - index++; - if(skip){ - skip--; - continue; - } - if(c==' '||c=='\t'){ - for(PixelGameEngine::StringDecalData&letter:letters){ - DrawPartialDecal(pos + drawingMarker, fontRenderable.Decal(), letter.sourcePos, letter.sourceSize, scale, letter.col); - drawingMarker.x += 8.0f * scale.x; - } - letters.clear(); - wrappingOccurred=false; - } - if(wrappingOccurred){ - if(c!=' '&&c!='\t'){ - wrappingOccurred=false; - }else{ - continue; - } - } - if(c=='\r')continue; //Ignore carriage returns. Stupid Linux. - if (c == '\n') - { - planningMarker.x = 0; planningMarker.y += 8.0f * scale.y; - } - else if (c == ' ') - { - drawingMarker.x += 8.0f * scale.x; - planningMarker.x += 8.0f * scale.x; - } - else if (c == '\t') - { - drawingMarker.x += 8.0f * float(nTabSizeInSpaces) * scale.x; - planningMarker.x += 8.0f * float(nTabSizeInSpaces) * scale.x; - } - else if (c>=-128&&c<-105) - { - textCol={PixelGameEngine::charToColor[c].r,PixelGameEngine::charToColor[c].g,PixelGameEngine::charToColor[c].b,col.a}; - } - else if (c==PixelGameEngine::Reset[0]) - { - textCol=col; - } - else if (c=='#') - { - skip=6; - textCol=BLACK; - for(int i=1;i<7;i++){ - if(i<3){ - textCol.r*=16; - textCol.r+=hexToNumber(sText[index+i]); - }else - if(i<5){ - textCol.g*=16; - textCol.g+=hexToNumber(sText[index+i]); - }else{ - textCol.b*=16; - textCol.b+=hexToNumber(sText[index+i]); - } - } - if(textCol==WHITE)textCol=col; - } - else - { - int32_t ox = (c - 32) % 16; - int32_t oy = (c - 32) / 16; - planningMarker.x += 8.0f * scale.x; - if(planningMarker.x>width){ - if(drawingMarker.x==0){ //The text has overflowed a full line, so we have to dump the line. - for(PixelGameEngine::StringDecalData&letter:letters){ - DrawPartialDecal(pos + drawingMarker, fontRenderable.Decal(), letter.sourcePos, letter.sourceSize, scale, letter.col); - drawingMarker.x += 8.0f * scale.x; - } - letters.clear(); - } - planningMarker.x = 0; planningMarker.y += 8.0f * scale.y; - drawingMarker=planningMarker; - wrappingOccurred=true; - for(PixelGameEngine::StringDecalData&letter:letters){ - planningMarker.x += 8.0f * scale.x; - } - } - letters.emplace_back(c,vf2d{ float(ox) * 8.0f, float(oy) * 8.0f }, vf2d{ 8.0f, 8.0f },colorOverride?col:textCol); - } + if(sText.length()==0)return; + static std::mapgarbageCollector; + std::string key{sText}; + if(!disableDynamicScaling){ + key+=scale.str(); } - for(PixelGameEngine::StringDecalData&letter:letters){ - DrawPartialDecal(pos + drawingMarker, fontRenderable.Decal(), letter.sourcePos, letter.sourceSize, scale, letter.col); - drawingMarker.x += 8.0f * scale.x; + if(!garbageCollector.count(key)){ //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; + SetDrawTarget(newDecal->sprite); + Clear(BLANK); + DrawString({0,0},sText,WHITE,1U,width/scale.x); + SetDrawTarget(nullptr); + newDecal->Update(); } + garbageCollector[key].expireTime=GetRuntime()+120.0f; + std::erase_if(garbageCollector,[&](auto&key){ + if(key.second.expireTimeletters; - letters.clear(); - bool wrappingOccurred=false; - olc::vf2d planningMarker = { 0.0f, 0.0f }; - olc::vf2d drawingMarker = { 0.0f, 0.0f }; - Pixel textCol=col; - const auto hexToNumber=[](char c){ - if(c<='9')return c-'0'; - return (c-'A')+10; + struct DecalData{ + Decal*decal; + float expireTime=0.0f; }; - for (int skip=0,index=-1;auto c : sText) - { - index++; - if(skip){ - skip--; - continue; - } - if(c==' '||c=='\t'){ - for(PixelGameEngine::StringDecalData&letter:letters){ - DrawPartialDecal(pos + drawingMarker, GetFontDecal(), letter.sourcePos, letter.sourceSize, scale, letter.col); - drawingMarker.x += float(vFontSpacing[letter.c - 32].y) * scale.x; - } - letters.clear(); - wrappingOccurred=false; - } - if(wrappingOccurred){ - if(c!=' '&&c!='\t'){ - wrappingOccurred=false; - }else{ - continue; - } - } - if(c=='\r')continue; //Ignore carriage returns. Stupid Linux. - if (c == '\n') - { - planningMarker.x = 0; planningMarker.y += 8.0f * scale.y; - } - else if (c == ' ') - { - drawingMarker.x += float(vFontSpacing[' ' - 32].y) * scale.x; - planningMarker.x += float(vFontSpacing[' ' - 32].y) * scale.x; - } - else if (c == '\t') - { - drawingMarker.x += 8.0f * float(nTabSizeInSpaces) * scale.x; - planningMarker.x += 8.0f * float(nTabSizeInSpaces) * scale.x; - } - else if (c>=-128&&c<-105) - { - textCol={PixelGameEngine::charToColor[c].r,PixelGameEngine::charToColor[c].g,PixelGameEngine::charToColor[c].b,col.a}; - } - else if (c==PixelGameEngine::Reset[0]) - { - textCol=col; - } - else if (c=='#') - { - skip=6; - textCol=BLACK; - for(int i=1;i<7;i++){ - if(i<3){ - textCol.r*=16; - textCol.r+=hexToNumber(sText[index+i]); - }else - if(i<5){ - textCol.g*=16; - textCol.g+=hexToNumber(sText[index+i]); - }else{ - textCol.b*=16; - textCol.b+=hexToNumber(sText[index+i]); - } - } - if(textCol==WHITE)textCol=col; - } - else - { - int32_t ox = (c - 32) % 16; - int32_t oy = (c - 32) / 16; - planningMarker.x += float(vFontSpacing[c - 32].y) * scale.x; - if(planningMarker.x>width){ - if(drawingMarker.x==0){ //The text has overflowed a full line, so we have to dump the line. - for(PixelGameEngine::StringDecalData&letter:letters){ - DrawPartialDecal(pos + drawingMarker, GetFontDecal(), letter.sourcePos, letter.sourceSize, scale, letter.col); - drawingMarker.x += float(vFontSpacing[letter.c - 32].y) * scale.x; - } - letters.clear(); - } - planningMarker.x = 0; planningMarker.y += 8.0f * scale.y; - drawingMarker=planningMarker; - wrappingOccurred=true; - for(PixelGameEngine::StringDecalData&letter:letters){ - planningMarker.x += float(vFontSpacing[letter.c - 32].y) * scale.x; - } - } - letters.emplace_back(c,vf2d{ float(ox) * 8.0f + float(vFontSpacing[c - 32].x), float(oy) * 8.0f }, vf2d{ float(vFontSpacing[c - 32].y), 8.0f },colorOverride?col:textCol); - } + if(sText.length()==0)return; + static std::mapgarbageCollector; + std::string key{sText}; + if(!disableDynamicScaling){ + key+=scale.str(); } - for(PixelGameEngine::StringDecalData&letter:letters){ - DrawPartialDecal(pos + drawingMarker, GetFontDecal(), letter.sourcePos, letter.sourceSize, scale, letter.col); - drawingMarker.x += float(vFontSpacing[letter.c - 32].y) * scale.x; + if(!garbageCollector.count(key)){ //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; + SetDrawTarget(newDecal->sprite); + Clear(BLANK); + DrawStringProp({0,0},sText,WHITE,1U,width/scale.x); + SetDrawTarget(nullptr); + newDecal->Update(); } + garbageCollector[key].expireTime=GetRuntime()+120.0f; + std::erase_if(garbageCollector,[&](auto&key){ + if(key.second.expireTime::max()){ + adjustedWidth/=scale.x; + } int lettersWidth=0; float maxWidth=0; bool wrappingOccurred=false; @@ -3819,6 +3678,7 @@ namespace olc } } drawingMarker.x += lettersWidth; + maxWidth=std::max(maxWidth,drawingMarker.x); return vi2d(vf2d{maxWidth,planningMarker.y+8}*scale); } @@ -3993,9 +3853,12 @@ namespace olc return size; } - olc::vi2d PixelGameEngine::GetWrappedTextSizeProp(std::string_view s,const float width,const float scale) + olc::vi2d PixelGameEngine::GetWrappedTextSizeProp(std::string_view s,const float width,const vf2d scale) { - float adjustedWidth=width/scale; + float adjustedWidth=width; + if(width!=std::numeric_limits::max()){ + adjustedWidth/=scale.x; + } int lettersWidth=0; float maxWidth=0; bool wrappingOccurred=false; diff --git a/x64/Release/Crawler.exe b/x64/Release/Crawler.exe index a0f6ba51..56182b71 100644 Binary files a/x64/Release/Crawler.exe and b/x64/Release/Crawler.exe differ