@ -385,6 +385,7 @@ return 0;
# include <cmath>
# include <cstdint>
# include <string>
# include <string_view>
# include <iostream>
# include <streambuf>
# include <sstream>
@ -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 < int > : : max ( ) ) ;
olc : : vi2d GetTextSizeProp ( std : : string_view s , const int width = std : : numeric_limits < int > : : 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 < float > : : 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 < float > : : 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 colorOverrid e )
{
olc : : vf2d spos = { 0.0f , 0.0f } ;
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 ' ;
@ -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 colorOverrid e )
{
olc : : vf2d spos = { 0.0f , 0.0f } ;
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 ' ;
@ -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 ;
}
return size * 8 ;
lettersWidth + = 8.0f ;
}
}
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 ;
}
size . y * = 8 ;
return size ;
lettersWidth + = vFontSpacing [ c - 32 ] . y ;
}
}
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 )