Completed image caching technique for rendering text using the normal engine draw functions.
This commit is contained in:
parent
8581633cab
commit
5d1e0b5a7a
@ -1213,7 +1213,7 @@ void Crawler::RenderHud(){
|
|||||||
std::stringstream castTimeDisplay;
|
std::stringstream castTimeDisplay;
|
||||||
castTimeDisplay<<std::fixed<<std::setprecision(1)<<timer;
|
castTimeDisplay<<std::fixed<<std::setprecision(1)<<timer;
|
||||||
DrawShadowStringPropDecal(vf2d{ScreenWidth()/2+90.f,ScreenHeight()-80.f}-vf2d{float(GetTextSizeProp(castTimeDisplay.str()).x),0},castTimeDisplay.str(),WHITE,BLACK);
|
DrawShadowStringPropDecal(vf2d{ScreenWidth()/2+90.f,ScreenHeight()-80.f}-vf2d{float(GetTextSizeProp(castTimeDisplay.str()).x),0},castTimeDisplay.str(),WHITE,BLACK);
|
||||||
DrawShadowStringPropDecal(vf2d{ScreenWidth()/2.f-GetTextSizeProp(castText).x*2/2,ScreenHeight()-64.f},castText,WHITE,BLACK,{2,3},2.f);
|
DrawShadowStringPropDecal(vf2d{ScreenWidth()/2.f-GetTextSizeProp(castText).x*2/2,ScreenHeight()-64.f},castText,WHITE,BLACK,{2,3},std::numeric_limits<float>::max(),2.f);
|
||||||
};
|
};
|
||||||
|
|
||||||
if(GetPlayer()->GetCastInfo().castTimer>0){
|
if(GetPlayer()->GetCastInfo().castTimer>0){
|
||||||
|
@ -45,6 +45,7 @@ Input::Input(InputType type,int key)
|
|||||||
:type(type),key(key){}
|
:type(type),key(key){}
|
||||||
|
|
||||||
bool Input::Pressed(){
|
bool Input::Pressed(){
|
||||||
|
if(!game->IsFocused())return false;
|
||||||
switch(type){
|
switch(type){
|
||||||
case KEY:{
|
case KEY:{
|
||||||
return game->GetKey(Key(key)).bPressed;
|
return game->GetKey(Key(key)).bPressed;
|
||||||
@ -61,6 +62,7 @@ bool Input::Pressed(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Input::Held(){
|
bool Input::Held(){
|
||||||
|
if(!game->IsFocused())return false;
|
||||||
switch(type){
|
switch(type){
|
||||||
case KEY:{
|
case KEY:{
|
||||||
return game->GetKey(Key(key)).bHeld;
|
return game->GetKey(Key(key)).bHeld;
|
||||||
@ -77,6 +79,7 @@ bool Input::Held(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Input::Released(){
|
bool Input::Released(){
|
||||||
|
if(!game->IsFocused())return false;
|
||||||
switch(type){
|
switch(type){
|
||||||
case KEY:{
|
case KEY:{
|
||||||
return game->GetKey(Key(key)).bReleased;
|
return game->GetKey(Key(key)).bReleased;
|
||||||
|
@ -144,7 +144,7 @@ void Menu::CheckClickAndPerformMenuSelect(Crawler*game){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Menu::HoverMenuSelect(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(buttons[selection.y][selection.x]->draggable){
|
||||||
if(buttonHoldTime<"ThemeGlobal.MenuHoldTime"_F){
|
if(buttonHoldTime<"ThemeGlobal.MenuHoldTime"_F){
|
||||||
CheckClickAndPerformMenuSelect(game);
|
CheckClickAndPerformMenuSelect(game);
|
||||||
@ -158,7 +158,7 @@ void Menu::HoverMenuSelect(Crawler*game){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Menu::MenuSelect(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});
|
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(buttonStillValid){
|
||||||
if(buttons[selection.y][selection.x]->menuDest!=MenuType::ENUM_END){
|
if(buttons[selection.y][selection.x]->menuDest!=MenuType::ENUM_END){
|
||||||
@ -253,6 +253,7 @@ void Menu::Update(Crawler*game){
|
|||||||
}
|
}
|
||||||
|
|
||||||
KeyboardButtonNavigation(game,pos);
|
KeyboardButtonNavigation(game,pos);
|
||||||
|
|
||||||
for(auto&[key,value]:buttons){
|
for(auto&[key,value]:buttons){
|
||||||
for(auto&button:value){
|
for(auto&button:value){
|
||||||
if(button->renderInMain){
|
if(button->renderInMain){
|
||||||
|
@ -67,7 +67,7 @@ protected:
|
|||||||
inline virtual void DrawDecal(ViewPort&window,bool focused)override{
|
inline virtual void DrawDecal(ViewPort&window,bool focused)override{
|
||||||
MenuComponent::DrawDecal(window,focused);
|
MenuComponent::DrawDecal(window,focused);
|
||||||
vf2d adjustedScale={scale,scale};
|
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){
|
if(fitToLabel){
|
||||||
float sizeRatio=((labelTextSize*adjustedScale).x)/(rect.size.x-2);
|
float sizeRatio=((labelTextSize*adjustedScale).x)/(rect.size.x-2);
|
||||||
|
@ -59,10 +59,9 @@ protected:
|
|||||||
}
|
}
|
||||||
virtual void inline DrawDecal(ViewPort&window,bool focused)override{
|
virtual void inline DrawDecal(ViewPort&window,bool focused)override{
|
||||||
if(label.length()>0){
|
if(label.length()>0){
|
||||||
std::string wrappedText=util::WrapText(game,label,int(rect.size.x-1),true,scale);
|
vf2d drawPos=rect.middle()-vf2d{game->GetWrappedTextSizeProp(label,int(rect.size.x-1),scale)}*scale/2; //Assume centered.
|
||||||
vf2d drawPos=rect.middle()-vf2d{game->GetTextSizeProp(wrappedText)}*scale/2; //Assume centered.
|
|
||||||
if(!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){
|
if(background){
|
||||||
window.FillRectDecal(rect.pos,rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),hoverEffect/"ThemeGlobal.HighlightTime"_F));
|
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);
|
window.DrawRectDecal(rect.pos,rect.size);
|
||||||
}
|
}
|
||||||
if(showDefaultLabel){
|
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){
|
if(shadow){
|
||||||
window.DrawShadowStringPropDecal(drawPos,wrappedText,WHITE,BLACK,scale);
|
window.DrawShadowStringPropDecal(drawPos,label,WHITE,BLACK,scale,int(rect.size.x-1));
|
||||||
}else{
|
}else{
|
||||||
window.DrawStringPropDecal(drawPos,wrappedText,WHITE,scale);
|
window.DrawStringPropDecal(drawPos,label,WHITE,scale,int(rect.size.x-1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,8 +91,8 @@ void State_GameRun::OnUserUpdate(Crawler*game){
|
|||||||
}
|
}
|
||||||
void State_GameRun::Draw(Crawler*game){
|
void State_GameRun::Draw(Crawler*game){
|
||||||
game->RenderHud();
|
game->RenderHud();
|
||||||
//FontTest(); //Enable to test font coloring.
|
FontTest(); //Enable to test font coloring.
|
||||||
FontSpriteTest(); //Enable to test font coloring.
|
//FontSpriteTest(); //Enable to test font coloring.
|
||||||
}
|
}
|
||||||
|
|
||||||
void State_GameRun::FontTest(){
|
void State_GameRun::FontTest(){
|
||||||
|
@ -39,7 +39,7 @@ All rights reserved.
|
|||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 2
|
#define VERSION_MINOR 2
|
||||||
#define VERSION_PATCH 1
|
#define VERSION_PATCH 1
|
||||||
#define VERSION_BUILD 4398
|
#define VERSION_BUILD 4434
|
||||||
|
|
||||||
#define stringify(a) stringify_(a)
|
#define stringify(a) stringify_(a)
|
||||||
#define stringify_(a) #a
|
#define stringify_(a) #a
|
||||||
|
@ -116,9 +116,9 @@ namespace olc {
|
|||||||
const vf2d &pos2,
|
const vf2d &pos2,
|
||||||
Pixel p = WHITE) const;
|
Pixel p = WHITE) const;
|
||||||
// Draws a multiline string as a decal, with tinting and scaling
|
// 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<float>::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<float>::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 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<float>::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<float>::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<float>::max(),const float shadowSizeFactor=1);
|
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<float>::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<float>::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<float>::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 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);
|
- (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){
|
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){
|
||||||
static std::vector<PixelGameEngine::StringDecalData>letters;
|
struct DecalData{
|
||||||
letters.clear();
|
Decal*decal;
|
||||||
bool wrappingOccurred=false;
|
float expireTime=0.0f;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
for (int skip=0,index=-1;auto c : sText)
|
if(sText.length()==0)return;
|
||||||
{
|
static std::map<std::string,DecalData>garbageCollector;
|
||||||
index++;
|
std::string key{sText};
|
||||||
if(skip){
|
if(!disableDynamicScaling){
|
||||||
skip--;
|
key+=scale.str();
|
||||||
continue;
|
}
|
||||||
}
|
if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time.
|
||||||
if(c==' '||c=='\t'){
|
vi2d imageSize=pge->GetWrappedTextSize(sText,width,scale);
|
||||||
for(PixelGameEngine::StringDecalData&letter:letters){
|
Decal*newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x));
|
||||||
DrawPartialDecal(pos + drawingMarker, pge->GetFontDecal(), letter.sourcePos, letter.sourceSize, scale, letter.col);
|
garbageCollector[key].decal=newDecal;
|
||||||
drawingMarker.x += 8.0f * scale.x;
|
pge->SetDrawTarget(newDecal->sprite);
|
||||||
}
|
pge->Clear(BLANK);
|
||||||
letters.clear();
|
pge->DrawString({0,0},sText,WHITE,1U,width/scale.x);
|
||||||
wrappingOccurred=false;
|
pge->SetDrawTarget(nullptr);
|
||||||
}
|
newDecal->Update();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
garbageCollector[key].expireTime=pge->GetRuntime()+120.0f;
|
||||||
|
std::erase_if(garbageCollector,[&](auto&key){
|
||||||
|
if(key.second.expireTime<pge->GetRuntime()){
|
||||||
|
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){
|
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);
|
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){
|
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){
|
||||||
static std::vector<PixelGameEngine::StringDecalData>letters;
|
struct DecalData{
|
||||||
letters.clear();
|
Decal*decal;
|
||||||
bool wrappingOccurred=false;
|
float expireTime=0.0f;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
for (int skip=0,index=-1;auto c : sText)
|
if(sText.length()==0)return;
|
||||||
{
|
static std::map<std::string,DecalData>garbageCollector;
|
||||||
index++;
|
std::string key{sText};
|
||||||
if(skip){
|
if(!disableDynamicScaling){
|
||||||
skip--;
|
key+=scale.str();
|
||||||
continue;
|
}
|
||||||
}
|
if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time.
|
||||||
if(c==' '||c=='\t'){
|
vi2d imageSize=pge->GetWrappedTextSizeProp(sText,width,scale);
|
||||||
for(PixelGameEngine::StringDecalData&letter:letters){
|
Decal*newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x));
|
||||||
DrawPartialDecal(pos + drawingMarker, pge->GetFontDecal(), letter.sourcePos, letter.sourceSize, scale, letter.col);
|
garbageCollector[key].decal=newDecal;
|
||||||
drawingMarker.x += float(pge->vFontSpacing[letter.c - 32].y) * scale.x;
|
pge->SetDrawTarget(newDecal->sprite);
|
||||||
}
|
pge->Clear(BLANK);
|
||||||
letters.clear();
|
pge->DrawStringProp({0,0},sText,WHITE,1U,width/scale.x);
|
||||||
wrappingOccurred=false;
|
pge->SetDrawTarget(nullptr);
|
||||||
}
|
newDecal->Update();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
garbageCollector[key].expireTime=pge->GetRuntime()+120.0f;
|
||||||
|
std::erase_if(garbageCollector,[&](auto&key){
|
||||||
|
if(key.second.expireTime<pge->GetRuntime()){
|
||||||
|
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){
|
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 y=-shadowSizeFactor;y<=shadowSizeFactor+0.1;y+=shadowSizeFactor/2){
|
||||||
for(float x=-shadowSizeFactor;x<=shadowSizeFactor+0.1;x+=shadowSizeFactor/2){
|
for(float x=-shadowSizeFactor;x<=shadowSizeFactor+0.1;x+=shadowSizeFactor/2){
|
||||||
if(x!=0||y!=0){
|
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 y=-shadowSizeFactor;y<=shadowSizeFactor+0.1;y+=shadowSizeFactor/2){
|
||||||
for(float x=-shadowSizeFactor;x<=shadowSizeFactor+0.1;x+=shadowSizeFactor/2){
|
for(float x=-shadowSizeFactor;x<=shadowSizeFactor+0.1;x+=shadowSizeFactor/2){
|
||||||
if(x!=0||y!=0){
|
if(x!=0||y!=0){
|
||||||
DrawStringPropDecal(pos+vf2d{x,y}, sText, shadowCol,scale,width,true);
|
DrawStringPropDecal(pos+vf2d{x,y}, sText, shadowCol,scale,width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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<float>::max(),const float shadowSizeFactor=1);
|
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<float>::max(),const float shadowSizeFactor=1);
|
||||||
olc::vi2d GetTextSize(std::string_view s);
|
olc::vi2d GetTextSize(std::string_view s);
|
||||||
olc::vi2d GetTextSizeProp(std::string_view s);
|
olc::vi2d GetTextSizeProp(std::string_view s);
|
||||||
olc::vi2d GetWrappedTextSize(std::string_view s,const float width=std::numeric_limits<int>::max(),const float scale=1);
|
olc::vi2d GetWrappedTextSize(std::string_view s,const float width=std::numeric_limits<int>::max(),const vf2d scale={1,1});
|
||||||
olc::vi2d GetWrappedTextSizeProp(std::string_view s,const float width=std::numeric_limits<int>::max(),const float scale=1);
|
olc::vi2d GetWrappedTextSizeProp(std::string_view s,const float width=std::numeric_limits<int>::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<float>::max(),const bool colorOverride=false);
|
void DrawString(const olc::vi2d& pos, std::string_view sText, Pixel col = olc::WHITE, uint32_t scale = 1,const float width=std::numeric_limits<float>::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<float>::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<float>::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 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);
|
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
|
// 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<float>::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<float>::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 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<float>::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<float>::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<float>::max(),const float shadowSizeFactor=1);
|
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<float>::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<float>::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<float>::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 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; }
|
{ return bHasInputFocus; }
|
||||||
|
|
||||||
HWButton PixelGameEngine::GetKey(Key k) const
|
HWButton PixelGameEngine::GetKey(Key k) const
|
||||||
{ return pKeyboardState[k]; }
|
{ return IsFocused()?pKeyboardState[k]:HWButton{}; }
|
||||||
|
|
||||||
HWButton PixelGameEngine::GetMouse(uint32_t b) const
|
HWButton PixelGameEngine::GetMouse(uint32_t b) const
|
||||||
{ return pMouseState[b]; }
|
{ return IsFocused()?pMouseState[b]:HWButton{}; }
|
||||||
|
|
||||||
int32_t PixelGameEngine::GetMouseX() const
|
int32_t PixelGameEngine::GetMouseX() const
|
||||||
{ return vMousePos.x; }
|
{ return vMousePos.x; }
|
||||||
@ -2210,7 +2210,7 @@ namespace olc
|
|||||||
{ return vMousePos; }
|
{ return vMousePos; }
|
||||||
|
|
||||||
int32_t PixelGameEngine::GetMouseWheel() const
|
int32_t PixelGameEngine::GetMouseWheel() const
|
||||||
{ return nMouseWheelDelta; }
|
{ return IsFocused()?nMouseWheelDelta:0; }
|
||||||
|
|
||||||
int32_t PixelGameEngine::ScreenWidth() const
|
int32_t PixelGameEngine::ScreenWidth() const
|
||||||
{ return vScreenSize.x; }
|
{ 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)
|
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); }
|
{ 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::vector<PixelGameEngine::StringDecalData>letters;
|
struct DecalData{
|
||||||
letters.clear();
|
Decal*decal;
|
||||||
bool wrappingOccurred=false;
|
float expireTime=0.0f;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
for (int skip=0,index=-1;auto c : sText)
|
if(sText.length()==0)return;
|
||||||
{
|
static std::map<std::string,DecalData>garbageCollector;
|
||||||
index++;
|
std::string key{sText};
|
||||||
if(skip){
|
if(!disableDynamicScaling){
|
||||||
skip--;
|
key+=scale.str();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for(PixelGameEngine::StringDecalData&letter:letters){
|
if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time.
|
||||||
DrawPartialDecal(pos + drawingMarker, fontRenderable.Decal(), letter.sourcePos, letter.sourceSize, scale, letter.col);
|
vi2d imageSize=GetWrappedTextSize(sText,width,scale);
|
||||||
drawingMarker.x += 8.0f * scale.x;
|
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.expireTime<GetRuntime()){
|
||||||
|
delete key.second.decal;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
DrawDecal(pos,garbageCollector[key].decal,scale,col);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PixelGameEngine::DrawStringPropDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col, const olc::vf2d& scale, const float width,const bool colorOverride)
|
void PixelGameEngine::DrawStringPropDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col, const olc::vf2d& scale, const float width,const bool disableDynamicScaling)
|
||||||
{
|
{
|
||||||
static std::vector<PixelGameEngine::StringDecalData>letters;
|
struct DecalData{
|
||||||
letters.clear();
|
Decal*decal;
|
||||||
bool wrappingOccurred=false;
|
float expireTime=0.0f;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
for (int skip=0,index=-1;auto c : sText)
|
if(sText.length()==0)return;
|
||||||
{
|
static std::map<std::string,DecalData>garbageCollector;
|
||||||
index++;
|
std::string key{sText};
|
||||||
if(skip){
|
if(!disableDynamicScaling){
|
||||||
skip--;
|
key+=scale.str();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for(PixelGameEngine::StringDecalData&letter:letters){
|
if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time.
|
||||||
DrawPartialDecal(pos + drawingMarker, GetFontDecal(), letter.sourcePos, letter.sourceSize, scale, letter.col);
|
vi2d imageSize=GetWrappedTextSizeProp(sText,width,scale);
|
||||||
drawingMarker.x += float(vFontSpacing[letter.c - 32].y) * scale.x;
|
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<GetRuntime()){
|
||||||
|
delete key.second.decal;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
DrawDecal(pos,garbageCollector[key].decal,scale,col);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PixelGameEngine::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){
|
void PixelGameEngine::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 y=-shadowSizeFactor;y<=shadowSizeFactor+0.1;y+=shadowSizeFactor/2){
|
||||||
for(float x=-shadowSizeFactor;x<=shadowSizeFactor+0.1;x+=shadowSizeFactor/2){
|
for(float x=-shadowSizeFactor;x<=shadowSizeFactor+0.1;x+=shadowSizeFactor/2){
|
||||||
if(x!=0||y!=0){
|
if(x!=0||y!=0){
|
||||||
DrawStringDecal(pos+vf2d{x,y}, sText, shadowCol,scale,width,true);
|
DrawStringDecal(pos+vf2d{x,y}, sText, shadowCol,scale,width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3653,7 +3509,7 @@ namespace olc
|
|||||||
for(float y=-shadowSizeFactor;y<=shadowSizeFactor+0.1;y+=shadowSizeFactor/2){
|
for(float y=-shadowSizeFactor;y<=shadowSizeFactor+0.1;y+=shadowSizeFactor/2){
|
||||||
for(float x=-shadowSizeFactor;x<=shadowSizeFactor+0.1;x+=shadowSizeFactor/2){
|
for(float x=-shadowSizeFactor;x<=shadowSizeFactor+0.1;x+=shadowSizeFactor/2){
|
||||||
if(x!=0||y!=0){
|
if(x!=0||y!=0){
|
||||||
DrawStringPropDecal(pos+vf2d{x,y}, sText, shadowCol,scale,width,true);
|
DrawStringPropDecal(pos+vf2d{x,y}, sText, shadowCol,scale,width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3750,9 +3606,12 @@ namespace olc
|
|||||||
DrawRotatedStringPropDecal(pos, sText,fAngle,center,col,scale);
|
DrawRotatedStringPropDecal(pos, sText,fAngle,center,col,scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
olc::vi2d PixelGameEngine::GetWrappedTextSize(std::string_view s,const float width,const float scale)
|
olc::vi2d PixelGameEngine::GetWrappedTextSize(std::string_view s,const float width,const vf2d scale)
|
||||||
{
|
{
|
||||||
float adjustedWidth=width/scale;
|
float adjustedWidth=width;
|
||||||
|
if(width!=std::numeric_limits<float>::max()){
|
||||||
|
adjustedWidth/=scale.x;
|
||||||
|
}
|
||||||
int lettersWidth=0;
|
int lettersWidth=0;
|
||||||
float maxWidth=0;
|
float maxWidth=0;
|
||||||
bool wrappingOccurred=false;
|
bool wrappingOccurred=false;
|
||||||
@ -3819,6 +3678,7 @@ namespace olc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawingMarker.x += lettersWidth;
|
drawingMarker.x += lettersWidth;
|
||||||
|
maxWidth=std::max(maxWidth,drawingMarker.x);
|
||||||
return vi2d(vf2d{maxWidth,planningMarker.y+8}*scale);
|
return vi2d(vf2d{maxWidth,planningMarker.y+8}*scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3993,9 +3853,12 @@ namespace olc
|
|||||||
return size;
|
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<float>::max()){
|
||||||
|
adjustedWidth/=scale.x;
|
||||||
|
}
|
||||||
int lettersWidth=0;
|
int lettersWidth=0;
|
||||||
float maxWidth=0;
|
float maxWidth=0;
|
||||||
bool wrappingOccurred=false;
|
bool wrappingOccurred=false;
|
||||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user