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;
|
||||
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.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){
|
||||
|
@ -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;
|
||||
|
@ -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){
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(){
|
||||
|
@ -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
|
||||
|
@ -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<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 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 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);
|
||||
@ -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::vector<PixelGameEngine::StringDecalData>letters;
|
||||
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(sText.length()==0)return;
|
||||
static std::map<std::string,DecalData>garbageCollector;
|
||||
std::string key{sText};
|
||||
if(!disableDynamicScaling){
|
||||
key+=scale.str();
|
||||
}
|
||||
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;
|
||||
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();
|
||||
}
|
||||
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;
|
||||
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){
|
||||
@ -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::vector<PixelGameEngine::StringDecalData>letters;
|
||||
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(sText.length()==0)return;
|
||||
static std::map<std::string,DecalData>garbageCollector;
|
||||
std::string key{sText};
|
||||
if(!disableDynamicScaling){
|
||||
key+=scale.str();
|
||||
}
|
||||
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;
|
||||
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();
|
||||
}
|
||||
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;
|
||||
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){
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
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<int>::max(),const float scale=1);
|
||||
olc::vi2d GetWrappedTextSizeProp(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 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(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 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<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 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 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);
|
||||
@ -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::vector<PixelGameEngine::StringDecalData>letters;
|
||||
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(sText.length()==0)return;
|
||||
static std::map<std::string,DecalData>garbageCollector;
|
||||
std::string key{sText};
|
||||
if(!disableDynamicScaling){
|
||||
key+=scale.str();
|
||||
}
|
||||
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;
|
||||
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();
|
||||
}
|
||||
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){
|
||||
DrawPartialDecal(pos + drawingMarker, fontRenderable.Decal(), letter.sourcePos, letter.sourceSize, scale, letter.col);
|
||||
drawingMarker.x += 8.0f * scale.x;
|
||||
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;
|
||||
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(sText.length()==0)return;
|
||||
static std::map<std::string,DecalData>garbageCollector;
|
||||
std::string key{sText};
|
||||
if(!disableDynamicScaling){
|
||||
key+=scale.str();
|
||||
}
|
||||
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;
|
||||
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();
|
||||
}
|
||||
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){
|
||||
DrawPartialDecal(pos + drawingMarker, GetFontDecal(), letter.sourcePos, letter.sourceSize, scale, letter.col);
|
||||
drawingMarker.x += float(vFontSpacing[letter.c - 32].y) * scale.x;
|
||||
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){
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3653,7 +3509,7 @@ namespace olc
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3750,9 +3606,12 @@ namespace olc
|
||||
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;
|
||||
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<float>::max()){
|
||||
adjustedWidth/=scale.x;
|
||||
}
|
||||
int lettersWidth=0;
|
||||
float maxWidth=0;
|
||||
bool wrappingOccurred=false;
|
||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user