diff --git a/Crawler/InventoryConsumableWindow.cpp b/Crawler/InventoryConsumableWindow.cpp index 41e54c0f..7f56edd5 100644 --- a/Crawler/InventoryConsumableWindow.cpp +++ b/Crawler/InventoryConsumableWindow.cpp @@ -55,7 +55,7 @@ void Menu::InitializeConsumableInventoryWindow(){ inventoryWindow->I(A::LOADOUT_SLOT)=0; - auto consumableWindow=inventoryWindow->ADD("inventory",InventoryScrollableWindowComponent)({{1,20},{windowSize.x,96.f}},"Consumables","itemName","itemDescription", + auto consumableWindow=inventoryWindow->ADD("inventory",InventoryScrollableWindowComponent)({{0,15},{windowSize.x,96.f}},"Consumables","itemName","itemDescription", [&](MenuFuncData data){ MenuItemButton*button=(MenuItemButton*)data.component; data.game->ClearLoadoutItem(data.menu.I(A::LOADOUT_SLOT)); @@ -81,9 +81,9 @@ void Menu::InitializeConsumableInventoryWindow(){ Menu::AddInventoryListener(consumableWindow,"Consumables"); //We don't have to actually populate the inventory list because now when an item gets added, it will automatically add the correct component in for us. - inventoryWindow->ADD("Inventory Type Label",MenuLabel)({{0,0},{windowSize.x-1,18}},"Consumables",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; - inventoryWindow->ADD("itemName",MenuLabel)(geom2d::rect(vf2d{2,95.f},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW)END; - inventoryWindow->ADD("itemDescription",MenuLabel)(geom2d::rect(vf2d{2,122.f},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW)END; + inventoryWindow->ADD("Inventory Type Label",MenuLabel)({{0,-5},{windowSize.x-1,18}},"Consumables",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; + inventoryWindow->ADD("itemName",MenuLabel)(geom2d::rect(vf2d{2,90.f},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW)END; + inventoryWindow->ADD("itemDescription",MenuLabel)(geom2d::rect(vf2d{2,117.f},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW)END; - auto okButton=inventoryWindow->ADD("OK Button",MenuComponent)({{windowSize.x/2-24,178.f},{48,12}},"Ok",[](MenuFuncData data){Menu::CloseMenu();return true;})END; + auto okButton=inventoryWindow->ADD("OK Button",MenuComponent)({{windowSize.x/2-24,173.f},{48,12}},"Ok",[](MenuFuncData data){Menu::CloseMenu();return true;})END; } \ No newline at end of file diff --git a/Crawler/MenuComponent.cpp b/Crawler/MenuComponent.cpp index 1d7a9ded..931260d1 100644 --- a/Crawler/MenuComponent.cpp +++ b/Crawler/MenuComponent.cpp @@ -119,13 +119,15 @@ void MenuComponent::DrawDecal(ViewPort&window,bool focused){ } if(showDefaultLabel){ vf2d adjustedScale=labelScaling; + vi2d labelTextSize=game->GetTextSizeProp(label,rect.size.x); + if(fitToLabel){ - float sizeRatio=((game->GetTextSizeProp(label)*adjustedScale).x)/(rect.size.x-2); + float sizeRatio=((labelTextSize*adjustedScale).x)/(rect.size.x-2); if(sizeRatio>1){ adjustedScale.x/=sizeRatio; } } - window.DrawStringPropDecal(rect.pos+V(A::DRAW_OFFSET)+rect.size/2-vf2d(game->GetTextSizeProp(label))/2.f*adjustedScale,label,WHITE,adjustedScale); + window.DrawStringPropDecal(rect.pos+V(A::DRAW_OFFSET)+rect.size/2-vf2d(labelTextSize)/2.f*adjustedScale,label,WHITE,adjustedScale,rect.size.x); } if(selected){ switch(selectionType){ diff --git a/Crawler/MenuLabel.h b/Crawler/MenuLabel.h index fe5c8714..314ed5dd 100644 --- a/Crawler/MenuLabel.h +++ b/Crawler/MenuLabel.h @@ -66,27 +66,25 @@ protected: } inline virtual void DrawDecal(ViewPort&window,bool focused)override{ MenuComponent::DrawDecal(window,focused); - std::string adjustedText=label; - if(!fitToLabel){ - adjustedText=util::WrapText(game,label,int(rect.size.x),true,{float(scale),float(scale)}); - } vf2d adjustedScale={scale,scale}; + vf2d labelTextSize=game->GetTextSizeProp(label,rect.size.x); + if(fitToLabel){ - float sizeRatio=((game->GetTextSizeProp(label)*adjustedScale).x)/(rect.size.x-2); + float sizeRatio=((labelTextSize*adjustedScale).x)/(rect.size.x-2); if(sizeRatio>1){ adjustedScale.x/=sizeRatio; } } - vf2d drawPos=rect.middle()-vf2d{game->GetTextSizeProp(adjustedText)}*float(adjustedScale.x)/2; //Assume centered. + vf2d drawPos=rect.middle()-vf2d{labelTextSize}*float(adjustedScale.x)/2; //Assume centered. if(!centered){ - drawPos=vf2d{rect.pos.x+2,rect.middle().y-game->GetTextSizeProp(adjustedText).y/2}; //We should at least vertically align here. + drawPos=vf2d{rect.pos.x+2,rect.middle().y-labelTextSize.y/2}; //We should at least vertically align here. } if(shadow){ - window.DrawShadowStringPropDecal(drawPos,adjustedText,WHITE,BLACK,adjustedScale); + window.DrawShadowStringPropDecal(drawPos,label,WHITE,BLACK,adjustedScale,rect.size.x); }else{ - window.DrawStringPropDecal(drawPos,adjustedText,WHITE,adjustedScale); + window.DrawStringPropDecal(drawPos,label,WHITE,adjustedScale,rect.size.x); } } }; \ No newline at end of file diff --git a/Crawler/State_GameRun.cpp b/Crawler/State_GameRun.cpp index 938a014e..0662cfea 100644 --- a/Crawler/State_GameRun.cpp +++ b/Crawler/State_GameRun.cpp @@ -50,7 +50,7 @@ void State_GameRun::OnStateChange(GameState*prevState){ Menu::CloseAllMenus(); } game->GetPlayer()->SetState(State::NORMAL); - port=ViewPort::rectViewPort({0,0},{72,100},{75,100}); + port=ViewPort::rectViewPort({0,0},{240,240},{24,24}); } void State_GameRun::OnUserUpdate(Crawler*game){ game->bossDisplayTimer=std::max(0.f,game->bossDisplayTimer-game->GetElapsedTime()); @@ -76,20 +76,20 @@ void State_GameRun::OnUserUpdate(Crawler*game){ } void State_GameRun::Draw(Crawler*game){ game->RenderHud(); - //FontTest(); //Enable to test font coloring. + FontTest(); //Enable to test font coloring. } void State_GameRun::FontTest(){ - port.DrawStringDecal({8,8},"#FFFFFFThis is a #000066test of hex"); - port.DrawStringDecal({8,16},"#FF0000This is a #BFA6F9test of hex"); - port.DrawStringDecal({8,24},"#00FF00This is a #E9A6F9test of hex"); - port.DrawStringDecal({8,32},"#0000FFThis is a #F9E8A6test of hex"); - port.DrawShadowStringDecal({8,40},"#FFFFFFThis is a #000066test of hex"); - port.DrawShadowStringDecal({8,48},"#FF0000This is a #BFA6F9test of hex"); - port.DrawShadowStringDecal({8,56},"#00FF00This is a #E9A6F9test of hex"); - port.DrawShadowStringDecal({8,64},"#0000FFThis is a #F9E8A6test of hex"); - port.DrawShadowStringDecal(VisualNovel::font,{8,72},U"#FFFFFFThis is a #000066test of hex"); - port.DrawShadowStringDecal(VisualNovel::font,{8,80},U"#FF0000This is a #BFA6F9test of hex"); - port.DrawShadowStringDecal(VisualNovel::font,{8,88},U"#00FF00This is a #E9A6F9test of hex"); - port.DrawShadowStringDecal(VisualNovel::font,{8,96},U"#0000FFThis is a #F9E8A6test of hex"); + port.DrawStringDecal({8,24*0},"#FF0000This is a #BFA6F9test of hex",WHITE,{1,1},72); + port.DrawStringDecal({8,24*1},"#00FF00This is a #E9A6F9test of hex",WHITE,{1,1},72); + port.DrawStringDecal({8,24*2},"#0000FFThis is a #F9E8A6test of hex",WHITE,{1,1},72); + port.DrawShadowStringDecal({8,24*3},"#FFFFFFThis is a #000066test of hex",WHITE,BLACK,{1,1},72); + port.DrawShadowStringDecal({8,24*4},"#FF0000This is a #BFA6F9test of hex",WHITE,BLACK,{1,1},72); + port.DrawShadowStringPropDecal({8,24*5},"#00FF00This is a #E9A6F9test of hex",WHITE,BLACK,{1,1},72); + port.DrawShadowStringPropDecal({8,24*6},"#0000FFThis is a #F9E8A6test of hex",WHITE,BLACK,{1,1},72); + /*port.DrawShadowStringDecal(VisualNovel::font,{8,24*7},U"#FFFFFFThis is a #000066test of hex",WHITE,BLACK,{1,1},72); + port.DrawShadowStringDecal(VisualNovel::font,{8,24*8},U"#FF0000This is a #BFA6F9test of hex",WHITE,BLACK,{1,1},72); + port.DrawShadowStringDecal(VisualNovel::font,{8,24*9},U"#00FF00This is a #E9A6F9test of hex",WHITE,BLACK,{1,1},72); + port.DrawShadowStringDecal(VisualNovel::font,{8,24*10},U"#0000FFThis is a #F9E8A6test of hex",WHITE,BLACK,{1,1},72);*/ + port.drawEdges(); } \ No newline at end of file diff --git a/Crawler/Version.h b/Crawler/Version.h index 67d5a37f..bd6ae5da 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 4274 +#define VERSION_BUILD 4334 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Crawler/olcPGEX_ViewPort.h b/Crawler/olcPGEX_ViewPort.h index cbf7d721..43bfb70a 100644 --- a/Crawler/olcPGEX_ViewPort.h +++ b/Crawler/olcPGEX_ViewPort.h @@ -116,11 +116,11 @@ 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, const std::string& sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); + 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(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, const std::string& sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); - void DrawShadowStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float shadowSizeFactor=1); - void DrawShadowStringPropDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float shadowSizeFactor=1); + 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 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); void DrawDropShadowStringDecal(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 }); @@ -628,8 +628,12 @@ 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, const std::string& sText, const Pixel col, const olc::vf2d& scale){ - olc::vf2d spos = { 0.0f, 0.0f }; +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'; @@ -642,19 +646,44 @@ void olc::ViewPort::DrawStringDecal(const olc::vf2d& pos, const std::string& sTe 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') { - spos.x = 0; spos.y += 8.0f * scale.y; + 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') { - spos.x += 8.0f * float(nTabSizeInSpaces) * scale.x; + 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; @@ -672,15 +701,35 @@ void olc::ViewPort::DrawStringDecal(const olc::vf2d& pos, const std::string& sTe textCol.b+=hexToNumber(sText[index+i]); } } + if(textCol==WHITE)textCol=col; } else { int32_t ox = (c - 32) % 16; int32_t oy = (c - 32) / 16; - DrawPartialDecal(pos + spos, pge->GetFontDecal(), {float(ox) * 8.0f, float(oy) * 8.0f}, {8.0f, 8.0f}, scale, textCol); - spos.x += 8.0f * scale.x; + 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; + } } void olc::ViewPort::DrawStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col, const olc::vf2d& scale){ @@ -705,8 +754,12 @@ 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, const std::string& sText, const Pixel col, const olc::vf2d& scale){ - olc::vf2d spos = { 0.0f, 0.0f }; +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'; @@ -719,14 +772,35 @@ void olc::ViewPort::DrawStringPropDecal(const olc::vf2d& pos, const std::string& 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') { - spos.x = 0; spos.y += 8.0f * scale.y; + 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') { - spos.x += 8.0f * float(nTabSizeInSpaces) * scale.x; + drawingMarker.x += 8.0f * float(nTabSizeInSpaces) * scale.x; + planningMarker.x += 8.0f * float(nTabSizeInSpaces) * scale.x; } else if (c>=-128&&c<-105) { @@ -753,45 +827,57 @@ void olc::ViewPort::DrawStringPropDecal(const olc::vf2d& pos, const std::string& textCol.b+=hexToNumber(sText[index+i]); } } + if(textCol==WHITE)textCol=col; } else { int32_t ox = (c - 32) % 16; int32_t oy = (c - 32) / 16; - DrawPartialDecal(pos + spos, pge->GetFontDecal(), { float(ox) * 8.0f + float(pge->vFontSpacing[c - 32].x), float(oy) * 8.0f }, { float(pge->vFontSpacing[c - 32].y), 8.0f }, scale, textCol); - spos.x += float(pge->vFontSpacing[c - 32].y) * scale.x; + 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; + } } -void olc::ViewPort::DrawShadowStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col, const Pixel shadowCol, const olc::vf2d& scale,const float shadowSizeFactor){ - std::string strippedText=sText; - std::erase_if(strippedText,[](char chr){return chr<0;}); - int skip=0; - std::erase_if(strippedText,[&](char chr){if(skip>0){skip--;return true;}if(chr=='#'){skip=6;return true;}return false;}); +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}, strippedText, shadowCol,scale); + DrawStringDecal(pos+vf2d{x,y}, sText, shadowCol,scale,width,true); } } } - DrawStringDecal(pos, sText, col,scale); + DrawStringDecal(pos, sText, col,scale,width); } -void olc::ViewPort::DrawShadowStringPropDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col, const Pixel shadowCol, const olc::vf2d& scale,const float shadowSizeFactor){ - std::string strippedText=sText; - std::erase_if(strippedText,[](char chr){return chr<0;}); - int skip=0; - std::erase_if(strippedText,[&](char chr){if(skip>0){skip--;return true;}if(chr=='#'){skip=6;return true;}return false;}); +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){ 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}, strippedText, shadowCol,scale); + DrawStringPropDecal(pos+vf2d{x,y}, sText, shadowCol,scale,width,true); } } } - DrawStringPropDecal(pos, sText, col,scale); + DrawStringPropDecal(pos, sText, col,scale,width); } 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){ diff --git a/Crawler/olcPixelGameEngine.h b/Crawler/olcPixelGameEngine.h index d224b45e..5eadcf8d 100644 --- a/Crawler/olcPixelGameEngine.h +++ b/Crawler/olcPixelGameEngine.h @@ -385,6 +385,7 @@ return 0; #include #include #include +#include #include #include #include @@ -747,9 +748,6 @@ namespace olc - - - // O------------------------------------------------------------------------------O // | olc::ResourcePack - A virtual scrambled filesystem to pack your assets into | // O------------------------------------------------------------------------------O @@ -968,6 +966,14 @@ namespace olc // O------------------------------------------------------------------------------O class PixelGameEngine { + struct StringDecalData{ + char c; + vf2d sourcePos; + vf2d sourceSize; + Pixel col; + StringDecalData(char c,vf2d sourcePos,vf2d sourceSize,Pixel col) + :c(c),sourcePos(sourcePos),sourceSize(sourceSize),col(col){}; + }; public: PixelGameEngine(); virtual ~PixelGameEngine(); @@ -1114,8 +1120,8 @@ namespace olc void DrawShadowString(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float shadowSizeFactor=1); void DrawStringProp(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); void DrawShadowStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float shadowSizeFactor=1); - olc::vi2d GetTextSize(const std::string& s); - olc::vi2d GetTextSizeProp(const std::string& s); + olc::vi2d GetTextSize(std::string_view s,const int width=std::numeric_limits::max()); + olc::vi2d GetTextSizeProp(std::string_view s,const int width=std::numeric_limits::max()); void DrawString(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); void DrawString(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); @@ -1141,9 +1147,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, const std::string& sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); + 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(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, const std::string& 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 DrawShadowStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float shadowSizeFactor=1); void DrawShadowStringPropDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },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); @@ -3344,9 +3350,13 @@ 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, const std::string& sText, const Pixel col, const olc::vf2d& scale) + void PixelGameEngine::DrawStringDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col, const olc::vf2d& scale,const float width,const bool colorOverride) { - olc::vf2d spos = { 0.0f, 0.0f }; + 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'; @@ -3359,18 +3369,43 @@ namespace olc 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') { - spos.x = 0; spos.y += 8.0f * scale.y; + 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') { - spos.x += 8.0f * float(nTabSizeInSpaces) * scale.x; + drawingMarker.x += 8.0f * float(nTabSizeInSpaces) * scale.x; + planningMarker.x += 8.0f * float(nTabSizeInSpaces) * scale.x; } else if (c>=-128&&c<-105) { - textCol={charToColor[c].r,charToColor[c].g,charToColor[c].b,col.a}; + 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=='#') { @@ -3389,20 +3424,44 @@ namespace olc textCol.b+=hexToNumber(sText[index+i]); } } + if(textCol==WHITE)textCol=col; } else { int32_t ox = (c - 32) % 16; int32_t oy = (c - 32) / 16; - DrawPartialDecal(pos + spos, fontRenderable.Decal(), {float(ox) * 8.0f, float(oy) * 8.0f}, {8.0f, 8.0f}, scale, textCol); - spos.x += 8.0f * scale.x; + 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); } } + for(PixelGameEngine::StringDecalData&letter:letters){ + DrawPartialDecal(pos + drawingMarker, fontRenderable.Decal(), letter.sourcePos, letter.sourceSize, scale, letter.col); + drawingMarker.x += 8.0f * scale.x; + } } - void PixelGameEngine::DrawStringPropDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col, const olc::vf2d& scale) + void PixelGameEngine::DrawStringPropDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col, const olc::vf2d& scale, const float width,const bool colorOverride) { - olc::vf2d spos = { 0.0f, 0.0f }; + 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'; @@ -3415,20 +3474,41 @@ namespace olc 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') { - spos.x = 0; spos.y += 8.0f * scale.y; + 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') { - spos.x += 8.0f * float(nTabSizeInSpaces) * scale.x; + drawingMarker.x += 8.0f * float(nTabSizeInSpaces) * scale.x; + planningMarker.x += 8.0f * float(nTabSizeInSpaces) * scale.x; } else if (c>=-128&&c<-105) { - textCol={charToColor[c].r,charToColor[c].g,charToColor[c].b,col.a}; + textCol={PixelGameEngine::charToColor[c].r,PixelGameEngine::charToColor[c].g,PixelGameEngine::charToColor[c].b,col.a}; } - else if (c==Reset[0]) + else if (c==PixelGameEngine::Reset[0]) { textCol=col; } @@ -3449,15 +3529,35 @@ namespace olc textCol.b+=hexToNumber(sText[index+i]); } } + if(textCol==WHITE)textCol=col; } else { int32_t ox = (c - 32) % 16; int32_t oy = (c - 32) / 16; - DrawPartialDecal(pos + spos, fontRenderable.Decal(), { float(ox) * 8.0f + float(vFontSpacing[c - 32].x), float(oy) * 8.0f }, { float(vFontSpacing[c - 32].y), 8.0f }, scale, textCol); - spos.x += float(vFontSpacing[c - 32].y) * scale.x; + 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); } } + 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; + } } void PixelGameEngine::DrawShadowStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col, const Pixel shadowCol, const olc::vf2d& scale,const float shadowSizeFactor){ @@ -3664,30 +3764,76 @@ namespace olc DrawRotatedStringPropDecal(pos, sText,fAngle,center,col,scale); } - olc::vi2d PixelGameEngine::GetTextSize(const std::string& s) + olc::vi2d PixelGameEngine::GetTextSize(std::string_view s,const int width) { - olc::vi2d size = { 0,1 }; - olc::vi2d pos = { 0,1 }; - for (int skip=0;auto c : s) + int lettersWidth=0; + int maxWidth=0; + bool wrappingOccurred=false; + olc::vf2d planningMarker = { 0.0f, 0.0f }; + olc::vf2d drawingMarker = { 0.0f, 0.0f }; + for (int skip=0,index=-1;auto c : s) { + index++; if(skip){ skip--; continue; } + if(c==' '||c=='\t'){ + drawingMarker.x+=lettersWidth; + lettersWidth=0; + wrappingOccurred=false; + } + if(wrappingOccurred){ + if(c!=' '&&c!='\t'){ + wrappingOccurred=false; + maxWidth=std::max(maxWidth,int(drawingMarker.x)); + }else{ + continue; + } + } if(c=='\r')continue; //Ignore carriage returns. Stupid Linux. - if (c == '\n') { pos.y++; pos.x = 0; } - else if (c == '\t') { pos.x += nTabSizeInSpaces; } - else if(c<0)continue; + if (c == '\n') + { + planningMarker.x = 0; planningMarker.y += 8.0f; + } + else if (c == ' ') + { + drawingMarker.x += 8.0f; + planningMarker.x += 8.0f; + } + else if (c == '\t') + { + drawingMarker.x += 8.0f * float(nTabSizeInSpaces); + planningMarker.x += 8.0f * float(nTabSizeInSpaces); + } + else if (c>=-128&&c<-105||c==PixelGameEngine::Reset[0]) + { + continue; + } else if (c=='#') { skip=6; - continue; } - else pos.x++; - size.x = std::max(size.x, pos.x); - size.y = std::max(size.y, pos.y); + else + { + planningMarker.x += 8.0f; + if(planningMarker.x>=width){ + if(drawingMarker.x==0){ //The text has overflowed a full line, so we have to dump the line. + drawingMarker.x+=lettersWidth; + lettersWidth=0; + maxWidth=std::max(maxWidth,int(drawingMarker.x)); + } + planningMarker.x = 0; planningMarker.y += 8.0f; + drawingMarker=planningMarker; + wrappingOccurred=true; + planningMarker.x+=lettersWidth; + } + lettersWidth+=8.0f; + } } - return size * 8; + drawingMarker.x += lettersWidth; + maxWidth=std::max(maxWidth,int(drawingMarker.x)); + return {maxWidth,int(planningMarker.y+8)}; } void PixelGameEngine::DrawString(const olc::vi2d& pos, const std::string& sText, Pixel col, uint32_t scale) @@ -3779,32 +3925,76 @@ namespace olc SetPixelMode(m); } - olc::vi2d PixelGameEngine::GetTextSizeProp(const std::string& s) + olc::vi2d PixelGameEngine::GetTextSizeProp(std::string_view s,const int width) { - olc::vi2d size = { 0,1 }; - olc::vi2d pos = { 0,1 }; - for (int skip=0;auto c : s) + int lettersWidth=0; + int maxWidth=0; + bool wrappingOccurred=false; + olc::vf2d planningMarker = { 0.0f, 0.0f }; + olc::vf2d drawingMarker = { 0.0f, 0.0f }; + for (int skip=0,index=-1;auto c : s) { + index++; if(skip){ skip--; continue; } + if(c==' '||c=='\t'){ + drawingMarker.x+=lettersWidth; + lettersWidth=0; + wrappingOccurred=false; + maxWidth=std::max(maxWidth,int(drawingMarker.x)); + } + if(wrappingOccurred){ + if(c!=' '&&c!='\t'){ + wrappingOccurred=false; + }else{ + continue; + } + } if(c=='\r')continue; //Ignore carriage returns. Stupid Linux. - if (c == '\n') { pos.y += 1; pos.x = 0; } - else if (c == '\t') { pos.x += nTabSizeInSpaces * 8; } - else if(c<0)continue; + if (c == '\n') + { + planningMarker.x = 0; planningMarker.y += 8.0f; + } + else if (c == ' ') + { + drawingMarker.x += vFontSpacing[c-32].y; + planningMarker.x += vFontSpacing[c-32].y; + } + else if (c == '\t') + { + drawingMarker.x += 8.0f * float(nTabSizeInSpaces); + planningMarker.x += 8.0f * float(nTabSizeInSpaces); + } + else if (c>=-128&&c<-105||c==PixelGameEngine::Reset[0]) + { + continue; + } else if (c=='#') { skip=6; - continue; } - else pos.x += vFontSpacing[c - 32].y; - size.x = std::max(size.x, pos.x); - size.y = std::max(size.y, pos.y); + else + { + planningMarker.x += vFontSpacing[c-32].y; + if(planningMarker.x>=width){ + if(drawingMarker.x==0){ //The text has overflowed a full line, so we have to dump the line. + drawingMarker.x+=lettersWidth; + lettersWidth=0; + maxWidth=std::max(maxWidth,int(drawingMarker.x)); + } + planningMarker.x = 0; planningMarker.y += 8.0f; + drawingMarker=planningMarker; + wrappingOccurred=true; + planningMarker.x+=lettersWidth; + } + lettersWidth+=vFontSpacing[c-32].y; + } } - - size.y *= 8; - return size; + drawingMarker.x += lettersWidth; + maxWidth=std::max(maxWidth,int(drawingMarker.x)); + return {maxWidth,int(planningMarker.y+8)}; } void PixelGameEngine::DrawStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col, uint32_t scale) diff --git a/x64/Release/Crawler.exe b/x64/Release/Crawler.exe index 3301331b..a0f6ba51 100644 Binary files a/x64/Release/Crawler.exe and b/x64/Release/Crawler.exe differ