# pragma once
# include "olcPGEX_TTF.h"
# include "olcUTIL_Geometry2D.h"
# include <algorithm>
# include <array>
# include <cmath>
# include <cstdint>
# include <iostream>
# include <vector>
# include <limits>
// Declarations
namespace olc {
class ViewPort : public olc : : PGEX {
public :
ViewPort ( ) ;
ViewPort ( std : : vector < vf2d > vertices , vf2d offset = { 0 , 0 } ) ;
geom2d : : rect < float > rect { } ;
virtual ~ ViewPort ( ) ;
void addPoint ( vf2d point ) ;
void clear ( ) ;
void drawEdges ( ) ;
void setOffset ( vf2d offset ) ;
const vf2d & GetOffset ( ) ;
static ViewPort rectViewPort ( vf2d topLeft ,
vf2d size ,
olc : : vf2d offset = { 0 , 0 } ) ;
void DrawDecal ( const olc : : vf2d & pos ,
olc : : Decal * decal ,
const olc : : vf2d & scale = { 1.0f , 1.0f } ,
const olc : : Pixel & tint = olc : : WHITE ) const ;
void DrawRectDecal ( const olc : : vf2d & pos , const olc : : vf2d & size , const olc : : Pixel col = olc : : WHITE ) const ;
void DrawPartialDecal ( const olc : : vf2d & pos ,
olc : : Decal * decal ,
const olc : : vf2d & source_pos ,
const olc : : vf2d & source_size ,
const olc : : vf2d & scale = { 1.0f , 1.0f } ,
const olc : : Pixel & tint = olc : : WHITE ) const ;
void DrawPartialDecal ( const vf2d & pos ,
const vf2d & size ,
Decal * decal ,
const vf2d source_pos ,
const vf2d & source_size ,
const Pixel & tint = olc : : WHITE ) const ;
void DrawExplicitDecal ( olc : : Decal * decal ,
const olc : : vf2d * pos ,
const olc : : vf2d * uv ,
const olc : : Pixel * col ,
const float * ws ,
uint32_t elements = 4 ) const ;
void DrawWarpedDecal ( Decal * decal ,
const vf2d ( & pos ) [ 4 ] ,
const Pixel & tint = WHITE ) const ;
void DrawWarpedDecal ( Decal * decal ,
const vf2d * pos ,
const Pixel & tint = WHITE ) const ;
void DrawWarpedDecal ( Decal * decal ,
const std : : array < vf2d , 4 > & pos ,
const Pixel & tint = WHITE ) const ;
void DrawPartialWarpedDecal ( Decal * decal ,
const vf2d ( & pos ) [ 4 ] ,
const vf2d & source_pos ,
const vf2d & source_size ,
const Pixel & tint = WHITE ) const ;
void DrawPartialWarpedDecal ( Decal * decal ,
const vf2d * pos ,
const vf2d & source_pos ,
const vf2d & source_size ,
const Pixel & tint = WHITE ) const ;
void DrawPartialWarpedDecal ( Decal * decal ,
const std : : array < vf2d , 4 > & pos ,
const vf2d & source_pos ,
const vf2d & source_size ,
const Pixel & tint = WHITE ) const ;
void DrawRotatedDecal ( const vf2d & pos ,
Decal * decal ,
const float fAngle ,
const vf2d & center = { 0.0f , 0.0f } ,
const vf2d & scale = { 1.0f , 1.0f } ,
const Pixel & tint = WHITE ) const ;
void DrawPartialRotatedDecal ( const vf2d & pos ,
Decal * decal ,
const float fAngle ,
const vf2d & center ,
const vf2d & source_pos ,
const vf2d & source_size ,
const vf2d & scale = { 1.0f , 1.0f } ,
const Pixel & tint = WHITE ) const ;
void FillRectDecal ( const vf2d & pos ,
const vf2d & size ,
const Pixel col = WHITE ) const ;
void GradientFillRectDecal ( const vf2d & pos ,
const vf2d & size ,
const Pixel colTL ,
const Pixel colBL ,
const Pixel colBR ,
const Pixel colTR ) const ;
void DrawPolygonDecal ( Decal * decal ,
const std : : vector < vf2d > & pos ,
const std : : vector < vf2d > & uv ,
const Pixel tint = WHITE ) const ;
void DrawPolygonDecal ( Decal * decal ,
const std : : vector < vf2d > & pos ,
const std : : vector < float > & depth ,
const std : : vector < vf2d > & uv ,
const Pixel tint = WHITE ) const ;
void DrawPolygonDecal ( Decal * decal ,
const std : : vector < vf2d > & pos ,
const std : : vector < vf2d > & uv ,
const std : : vector < Pixel > & tint ) const ;
void DrawLineDecal ( const vf2d & pos1 ,
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 ( ) ) ;
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 ( ) ) ;
void DrawShadowStringDecal ( const olc : : vf2d & pos , std : : string_view sText , const Pixel col = WHITE , const Pixel shadowCol = BLACK , const olc : : vf2d & scale = { 1.f , 1.f } ) ;
void DrawShadowStringDecal ( const olc : : vf2d & pos , std : : string_view sText , const Pixel col , const Pixel shadowCol , const olc : : vf2d & scale , const olc : : vf2d & shadowScale , const float width = std : : numeric_limits < float > : : max ( ) ) ;
void DrawShadowStringPropDecal ( const olc : : vf2d & pos , std : : string_view sText , const Pixel col = WHITE , const Pixel shadowCol = BLACK , const olc : : vf2d & scale = { 1.f , 1.f } ) ;
void DrawShadowStringPropDecal ( const olc : : vf2d & pos , std : : string_view sText , const Pixel col , const Pixel shadowCol , const olc : : vf2d & scale , const olc : : vf2d & shadowScale , const float width = std : : numeric_limits < float > : : max ( ) ) ;
void DrawShadowStringDecal ( Font & font , const olc : : vf2d & pos , const std : : u32string & sText , const Pixel col = olc : : WHITE , const Pixel shadowCol = olc : : BLACK , const olc : : vf2d & scale = { 1.0f , 1.0f } , const float shadowSizeFactor = 1 ) ;
void DrawDropShadowStringDecal ( Font & font , const olc : : vf2d & pos , const std : : u32string & sText , const Pixel col = olc : : WHITE , const Pixel shadowCol = olc : : BLACK , const olc : : vf2d & scale = { 1.0f , 1.0f } ) ;
private :
void drawClippedDecal ( Decal * decal ,
const vf2d * points ,
const vf2d * uvs ,
const Pixel * col ,
const float * ws ,
uint32_t elements = 0 ) const ;
static float lineSegmentIntersect ( vf2d lineA ,
vf2d lineB ,
vf2d segmentA ,
vf2d segmentB ) ;
static float directionFromLine ( vf2d lineA , vf2d lineB , vf2d point ) ;
std : : vector < vf2d > clipVertices ;
olc : : vf2d offset ;
} ;
} // namespace olc
// Definitions
# ifdef OLC_PGEX_VIEWPORT
# undef OLC_PGEX_VIEWPORT
olc : : ViewPort : : ViewPort ( ) {
}
olc : : ViewPort : : ~ ViewPort ( ) {
}
olc : : ViewPort : : ViewPort ( std : : vector < vf2d > vertices , olc : : vf2d offset )
: clipVertices { vertices } ,
offset { offset } {
}
void olc : : ViewPort : : addPoint ( vf2d point ) {
clipVertices . push_back ( point ) ;
}
void olc : : ViewPort : : clear ( ) {
clipVertices . clear ( ) ;
}
void olc : : ViewPort : : drawEdges ( ) {
for ( auto i = 0u ; i < clipVertices . size ( ) ; i + + ) {
auto current = clipVertices [ i ] + offset ;
auto next = clipVertices [ ( i + 1 ) % clipVertices . size ( ) ] + offset ;
pge - > DrawLineDecal ( current , next , olc : : RED ) ;
}
}
void olc : : ViewPort : : setOffset ( vf2d offset ) {
this - > offset = offset ;
}
const vf2d & olc : : ViewPort : : GetOffset ( ) {
return offset ;
}
olc : : ViewPort
olc : : ViewPort : : rectViewPort ( vf2d topLeft , vf2d size , olc : : vf2d offset ) {
olc : : ViewPort newPort = { {
topLeft ,
{ topLeft . x , topLeft . y + size . y } ,
topLeft + size ,
{ topLeft . x + size . x , topLeft . y } ,
} ,
offset } ;
newPort . rect = { topLeft , size } ;
return newPort ;
}
void olc : : ViewPort : : DrawDecal ( const olc : : vf2d & pos ,
olc : : Decal * decal ,
const olc : : vf2d & scale ,
const olc : : Pixel & tint ) const {
std : : vector < olc : : vf2d > points {
pos ,
{ pos . x , pos . y + decal - > sprite - > height * scale . y } ,
{ pos . x + decal - > sprite - > width * scale . x ,
pos . y + decal - > sprite - > height * scale . y } ,
{ pos . x + decal - > sprite - > width * scale . x , pos . y } ,
} ;
DrawWarpedDecal ( decal , points . data ( ) , tint ) ;
}
void olc : : ViewPort : : DrawPartialDecal ( const olc : : vf2d & pos ,
olc : : Decal * decal ,
const olc : : vf2d & source_pos ,
const olc : : vf2d & source_size ,
const olc : : vf2d & scale ,
const olc : : Pixel & tint ) const {
DrawPartialDecal ( pos , source_size * scale , decal , source_pos , source_size , tint ) ;
}
void olc : : ViewPort : : DrawPartialDecal ( const vf2d & pos ,
const vf2d & size ,
Decal * decal ,
const vf2d source_pos ,
const vf2d & source_size ,
const Pixel & tint ) const {
std : : vector < vf2d > points {
pos ,
{ pos . x , pos . y + size . y } ,
pos + size ,
{ pos . x + size . x , pos . y } ,
} ;
DrawPartialWarpedDecal ( decal , points . data ( ) , source_pos , source_size , tint ) ;
}
void olc : : ViewPort : : DrawExplicitDecal ( olc : : Decal * decal ,
const olc : : vf2d * pos ,
const olc : : vf2d * uv ,
const olc : : Pixel * col ,
const float * ws ,
uint32_t elements ) const {
drawClippedDecal ( decal , pos , uv , col , ws , elements ) ;
}
void olc : : ViewPort : : DrawWarpedDecal ( Decal * decal ,
const vf2d ( & pos ) [ 4 ] ,
const Pixel & tint ) const {
DrawWarpedDecal ( decal , ( const vf2d * ) pos , tint ) ;
}
void olc : : ViewPort : : DrawWarpedDecal ( Decal * decal ,
const vf2d * pos ,
const Pixel & tint ) const {
std : : vector < float > w { 1 , 1 , 1 , 1 } ;
std : : vector < olc : : vf2d > newPos ;
newPos . resize ( 4 ) ;
std : : vector < vf2d > uvs {
{ 0 , 0 } ,
{ 0 , 1 } ,
{ 1 , 1 } ,
{ 1 , 0 } ,
} ;
std : : vector < Pixel > cols {
tint ,
tint ,
tint ,
tint ,
} ;
olc : : vf2d vInvScreenSize = { 1.0f / pge - > GetScreenSize ( ) . x , 1.0f / pge - > GetScreenSize ( ) . y } ;
olc : : vf2d center ;
float rd = ( ( pos [ 2 ] . x - pos [ 0 ] . x ) * ( pos [ 3 ] . y - pos [ 1 ] . y ) - ( pos [ 3 ] . x - pos [ 1 ] . x ) * ( pos [ 2 ] . y - pos [ 0 ] . y ) ) ;
if ( rd ! = 0 )
{
rd = 1.0f / rd ;
float rn = ( ( pos [ 3 ] . x - pos [ 1 ] . x ) * ( pos [ 0 ] . y - pos [ 1 ] . y ) - ( pos [ 3 ] . y - pos [ 1 ] . y ) * ( pos [ 0 ] . x - pos [ 1 ] . x ) ) * rd ;
float sn = ( ( pos [ 2 ] . x - pos [ 0 ] . x ) * ( pos [ 0 ] . y - pos [ 1 ] . y ) - ( pos [ 2 ] . y - pos [ 0 ] . y ) * ( pos [ 0 ] . x - pos [ 1 ] . x ) ) * rd ;
if ( ! ( rn < 0.f | | rn > 1.f | | sn < 0.f | | sn > 1.f ) ) center = pos [ 0 ] + rn * ( pos [ 2 ] - pos [ 0 ] ) ;
float d [ 4 ] ; for ( int i = 0 ; i < 4 ; i + + ) d [ i ] = ( pos [ i ] - center ) . mag ( ) ;
for ( int i = 0 ; i < 4 ; i + + )
{
float q = d [ i ] = = 0.0f ? 1.0f : ( d [ i ] + d [ ( i + 2 ) & 3 ] ) / d [ ( i + 2 ) & 3 ] ;
uvs [ i ] * = q ; w [ i ] * = q ;
}
drawClippedDecal ( decal , pos , uvs . data ( ) , cols . data ( ) , w . data ( ) , 4 ) ;
}
}
void olc : : ViewPort : : DrawWarpedDecal ( Decal * decal ,
const std : : array < vf2d , 4 > & pos ,
const Pixel & tint ) const {
DrawWarpedDecal ( decal , pos . data ( ) , tint ) ;
}
void olc : : ViewPort : : DrawPartialWarpedDecal ( Decal * decal ,
const vf2d ( & pos ) [ 4 ] ,
const vf2d & source_pos ,
const vf2d & source_size ,
const Pixel & tint ) const {
DrawPartialWarpedDecal ( decal ,
( const vf2d * ) pos ,
source_pos ,
source_size ,
tint ) ;
}
void olc : : ViewPort : : DrawPartialWarpedDecal ( Decal * decal ,
const vf2d * pos ,
const vf2d & source_pos ,
const vf2d & source_size ,
const Pixel & tint ) const {
olc : : vf2d sourceUvPos =
source_pos
/ olc : : vf2d { static_cast < float > ( decal - > sprite - > width ) ,
static_cast < float > ( decal - > sprite - > height ) } ;
olc : : vf2d sourceUvSize =
source_size
/ olc : : vf2d { static_cast < float > ( decal - > sprite - > width ) ,
static_cast < float > ( decal - > sprite - > height ) } ;
std : : vector < vf2d > uvs {
sourceUvPos ,
{ sourceUvPos . x , sourceUvPos . y + sourceUvSize . y } ,
sourceUvPos + sourceUvSize ,
{ sourceUvPos . x + sourceUvSize . x , sourceUvPos . y } ,
} ;
std : : vector < Pixel > cols {
tint ,
tint ,
tint ,
tint ,
} ;
std : : vector < float > ws { 1 , 1 , 1 , 1 } ;
olc : : vf2d center ;
float rd = ( ( pos [ 2 ] . x - pos [ 0 ] . x ) * ( pos [ 3 ] . y - pos [ 1 ] . y ) - ( pos [ 3 ] . x - pos [ 1 ] . x ) * ( pos [ 2 ] . y - pos [ 0 ] . y ) ) ;
if ( rd ! = 0 )
{
rd = 1.0f / rd ;
float rn = ( ( pos [ 3 ] . x - pos [ 1 ] . x ) * ( pos [ 0 ] . y - pos [ 1 ] . y ) - ( pos [ 3 ] . y - pos [ 1 ] . y ) * ( pos [ 0 ] . x - pos [ 1 ] . x ) ) * rd ;
float sn = ( ( pos [ 2 ] . x - pos [ 0 ] . x ) * ( pos [ 0 ] . y - pos [ 1 ] . y ) - ( pos [ 2 ] . y - pos [ 0 ] . y ) * ( pos [ 0 ] . x - pos [ 1 ] . x ) ) * rd ;
if ( ! ( rn < 0.f | | rn > 1.f | | sn < 0.f | | sn > 1.f ) ) center = pos [ 0 ] + rn * ( pos [ 2 ] - pos [ 0 ] ) ;
float d [ 4 ] ; for ( int i = 0 ; i < 4 ; i + + ) d [ i ] = ( pos [ i ] - center ) . mag ( ) ;
for ( int i = 0 ; i < 4 ; i + + )
{
float q = d [ i ] = = 0.0f ? 1.0f : ( d [ i ] + d [ ( i + 2 ) & 3 ] ) / d [ ( i + 2 ) & 3 ] ;
uvs [ i ] * = q ; ws [ i ] * = q ;
}
drawClippedDecal ( decal , pos , uvs . data ( ) , cols . data ( ) , ws . data ( ) , 4 ) ;
}
}
void olc : : ViewPort : : DrawPartialWarpedDecal ( Decal * decal ,
const std : : array < vf2d , 4 > & pos ,
const vf2d & source_pos ,
const vf2d & source_size ,
const Pixel & tint ) const {
DrawPartialWarpedDecal ( decal , pos . data ( ) , source_pos , source_size , tint ) ;
}
void olc : : ViewPort : : DrawRotatedDecal ( const vf2d & pos ,
Decal * decal ,
const float fAngle ,
const vf2d & center ,
const vf2d & scale ,
const Pixel & tint ) const {
auto sin = std : : sin ( fAngle ) ;
auto cos = std : : cos ( fAngle ) ;
std : : vector < vf2d > points {
- center * scale ,
olc : : vf2d { - center . x , decal - > sprite - > height - center . y } * scale ,
olc : : vf2d { decal - > sprite - > width - center . x ,
decal - > sprite - > height - center . y }
* scale ,
olc : : vf2d { decal - > sprite - > width - center . x , - center . y } * scale ,
} ;
for ( auto i = 0u ; i < points . size ( ) ; i + + ) {
points [ i ] = pos
+ olc : : vf2d { points [ i ] . x * cos - points [ i ] . y * sin ,
points [ i ] . x * sin + points [ i ] . y * cos } ;
}
DrawWarpedDecal ( decal , points . data ( ) , tint ) ;
}
void olc : : ViewPort : : DrawPartialRotatedDecal ( const vf2d & pos ,
Decal * decal ,
const float fAngle ,
const vf2d & center ,
const vf2d & source_pos ,
const vf2d & source_size ,
const vf2d & scale ,
const Pixel & tint ) const {
auto sin = std : : sin ( fAngle ) ;
auto cos = std : : cos ( fAngle ) ;
std : : vector < vf2d > points {
- center * scale ,
olc : : vf2d { - center . x , source_size . y - center . y } * scale ,
( source_size - center ) * scale ,
olc : : vf2d { source_size . x - center . x , - center . y } * scale ,
} ;
for ( auto i = 0u ; i < points . size ( ) ; i + + ) {
points [ i ] = pos
+ olc : : vf2d { points [ i ] . x * cos - points [ i ] . y * sin ,
points [ i ] . x * sin + points [ i ] . y * cos } ;
}
DrawPartialWarpedDecal ( decal , points . data ( ) , source_pos , source_size , tint ) ;
}
void olc : : ViewPort : : FillRectDecal ( const vf2d & pos ,
const vf2d & size ,
const Pixel col ) const {
std : : vector < vf2d > points {
pos ,
{ pos . x , pos . y + size . y } ,
pos + size ,
{ pos . x + size . x , pos . y } ,
} ;
std : : vector < vf2d > uvs {
{ 0 , 0 } ,
{ 0 , 1 } ,
{ 1 , 1 } ,
{ 1 , 0 } ,
} ;
DrawPolygonDecal ( nullptr , points , uvs , col ) ;
}
void olc : : ViewPort : : GradientFillRectDecal ( const vf2d & pos ,
const vf2d & size ,
const Pixel colTL ,
const Pixel colBL ,
const Pixel colBR ,
const Pixel colTR ) const {
std : : vector < vf2d > points {
pos ,
{ pos . x , pos . y + size . y } ,
pos + size ,
{ pos . x + size . x , pos . y } ,
} ;
std : : vector < vf2d > uvs {
{ 0 , 0 } ,
{ 0 , 1 } ,
{ 1 , 1 } ,
{ 1 , 0 } ,
} ;
std : : vector < Pixel > colors {
colTL ,
colBL ,
colBR ,
colTR ,
} ;
std : : vector < float > w { 1 , 1 , 1 , 1 } ;
drawClippedDecal ( nullptr , points . data ( ) , uvs . data ( ) , colors . data ( ) , w . data ( ) , points . size ( ) ) ;
}
void olc : : ViewPort : : DrawPolygonDecal ( Decal * decal ,
const std : : vector < vf2d > & pos ,
const std : : vector < vf2d > & uv ,
const Pixel tint ) const {
std : : vector < Pixel > colors ;
colors . resize ( pos . size ( ) ) ;
for ( auto i = 0u ; i < colors . size ( ) ; i + + ) {
colors [ i ] = tint ;
}
std : : vector < float > w { 1 , 1 , 1 , 1 } ;
drawClippedDecal ( decal , pos . data ( ) , uv . data ( ) , colors . data ( ) , w . data ( ) , pos . size ( ) ) ;
}
void olc : : ViewPort : : DrawPolygonDecal ( Decal * decal ,
const std : : vector < vf2d > & pos ,
const std : : vector < float > & ,
const std : : vector < vf2d > & uv ,
const Pixel tint ) const {
DrawPolygonDecal ( decal , pos , uv , tint ) ;
}
void olc : : ViewPort : : DrawPolygonDecal ( Decal * decal ,
const std : : vector < vf2d > & pos ,
const std : : vector < vf2d > & uv ,
const std : : vector < Pixel > & tint ) const {
std : : vector < float > w { 1 , 1 , 1 , 1 } ;
drawClippedDecal ( decal , pos . data ( ) , uv . data ( ) , tint . data ( ) , w . data ( ) , pos . size ( ) ) ;
}
void olc : : ViewPort : : DrawLineDecal ( const vf2d & pos1 ,
const vf2d & pos2 ,
Pixel p ) const {
vf2d posA = pos1 ;
vf2d posB = pos2 ;
for ( auto i = 0u ; i < clipVertices . size ( ) ; i + + ) {
auto clipA = clipVertices [ i ] ;
auto clipB = clipVertices [ ( i + 1 ) % clipVertices . size ( ) ] ;
auto intersection = lineSegmentIntersect ( clipA , clipB , posA , posB ) ;
if ( intersection < 0 | | intersection > 1 ) {
continue ;
}
auto clipDirection = directionFromLine ( clipA , clipB , posA ) ;
auto intersectionPoint = posA + ( posB - posA ) * intersection ;
if ( clipDirection > = 0 ) {
posA = intersectionPoint ;
} else {
posB = intersectionPoint ;
}
}
pge - > DrawLineDecal ( posA + offset , posB + offset , p ) ;
}
void olc : : ViewPort : : drawClippedDecal ( Decal * decal ,
const vf2d * points ,
const vf2d * uvs ,
const Pixel * col ,
const float * ws ,
uint32_t elements ) const {
std : : vector < vf2d > outputList { points , points + elements } ;
std : : vector < vf2d > outputUvs { uvs , uvs + elements } ;
std : : vector < float > outputWs { ws , ws + elements } ;
std : : vector < Pixel > outputCols { col , col + elements } ;
vf2d min = { std : : numeric_limits < float > : : max ( ) , std : : numeric_limits < float > : : max ( ) } , max ;
bool pointsOutside = false ;
if ( rect ! = geom2d : : rect < float > { } ) {
for ( vf2d & points : outputList ) {
if ( ! geom2d : : contains ( rect , points ) ) {
pointsOutside = true ;
break ;
}
}
} else { pointsOutside = true ; }
if ( ! pointsOutside ) goto render ;
for ( auto i = 0u ; i < clipVertices . size ( ) ; i + + ) {
auto clipA = clipVertices [ i ] ;
auto clipB = clipVertices [ ( i + 1 ) % clipVertices . size ( ) ] ;
auto inputList { outputList } ;
auto inputUvs { outputUvs } ;
auto inputWs { outputWs } ;
auto inputCols { outputCols } ;
outputList . clear ( ) ;
outputUvs . clear ( ) ;
outputWs . clear ( ) ;
outputCols . clear ( ) ;
for ( auto i = 0u ; i < inputList . size ( ) ; i + + ) {
auto polygonA = inputList [ i ] ;
auto polygonB = inputList [ ( i + 1 ) % inputList . size ( ) ] ;
auto uvA = inputUvs [ i ] ;
auto uvB = inputUvs [ ( i + 1 ) % inputList . size ( ) ] ;
auto Wa = inputWs [ i ] ;
auto Wb = inputWs [ ( i + 1 ) % inputList . size ( ) ] ;
auto colA = inputCols [ i ] ;
auto colB = inputCols [ ( i + 1 ) % inputList . size ( ) ] ;
auto intersection =
lineSegmentIntersect ( clipA , clipB , polygonA , polygonB ) ;
auto intersectionPoint =
polygonA + ( polygonB - polygonA ) * intersection ;
auto intersectionUv = uvA + ( uvB - uvA ) * intersection ;
auto intersectionW = Wa + ( Wb - Wa ) * intersection ;
auto intersectionCol = PixelLerp ( colA , colB , intersection ) ;
float aDirection = directionFromLine ( clipA , clipB , polygonA ) ;
float bDirection = directionFromLine ( clipA , clipB , polygonB ) ;
if ( bDirection < = 0 ) {
if ( aDirection > 0 ) {
outputList . push_back ( intersectionPoint ) ;
outputUvs . push_back ( intersectionUv ) ;
outputWs . push_back ( intersectionW ) ;
outputCols . push_back ( intersectionCol ) ;
}
outputList . push_back ( polygonB ) ;
outputUvs . push_back ( uvB ) ;
outputWs . push_back ( Wb ) ;
outputCols . push_back ( colB ) ;
} else if ( aDirection < = 0 ) {
outputList . push_back ( intersectionPoint ) ;
outputUvs . push_back ( intersectionUv ) ;
outputWs . push_back ( intersectionW ) ;
outputCols . push_back ( intersectionCol ) ;
}
}
}
if ( outputList . size ( ) = = 0 ) {
return ;
}
render :
for ( auto & point : outputList ) {
point + = offset ;
}
pge - > DrawExplicitDecal ( decal ,
outputList . data ( ) ,
outputUvs . data ( ) ,
outputCols . data ( ) ,
outputWs . data ( ) ,
outputList . size ( ) ) ;
}
float olc : : ViewPort : : lineSegmentIntersect ( vf2d lineA ,
vf2d lineB ,
vf2d segmentA ,
vf2d segmentB ) {
return ( ( lineA . x - segmentA . x ) * ( lineA . y - lineB . y )
- ( lineA . y - segmentA . y ) * ( lineA . x - lineB . x ) )
/ ( ( lineA . x - lineB . x ) * ( segmentA . y - segmentB . y )
- ( lineA . y - lineB . y ) * ( segmentA . x - segmentB . x ) ) ;
}
float olc : : ViewPort : : directionFromLine ( vf2d lineA , vf2d lineB , vf2d point ) {
return ( lineB . x - lineA . x ) * ( point . 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 ) {
Pixel textCol = col ;
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 } ;
const auto hexToNumber = [ ] ( char c ) {
if ( c < = ' 9 ' ) return c - ' 0 ' ;
return ( c - ' A ' ) + 10 ;
} ;
for ( int skip = 0 , index = - 1 ; auto c : sText )
{
index + + ;
if ( skip ) {
skip - - ;
continue ;
}
if ( c = = ' ' | | c = = ' \t ' | | c = = ' \n ' ) {
for ( PixelGameEngine : : StringDecalData & letter : letters ) {
DrawPartialDecal ( pos + drawingMarker , pge - > 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 ' & & c ! = ' \n ' ) {
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 ;
for ( PixelGameEngine : : StringDecalData & letter : letters ) {
DrawPartialDecal ( pos + drawingMarker , pge - > fontRenderable . Decal ( ) , letter . sourcePos , letter . sourceSize , scale , letter . col ) ;
drawingMarker . x + = 8.0f * scale . x ;
}
letters . clear ( ) ;
drawingMarker . x = 0 ; drawingMarker . 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 - > fontRenderable . Decal ( ) , letter . sourcePos , letter . sourceSize , scale , letter . col ) ;
drawingMarker . x + = 8.0f * scale . x ;
}
letters . clear ( ) ;
} else {
drawingMarker . x - = pge - > vFontSpacing [ ' ' - 32 ] . y * scale . x ; //Don't include the space in the sizing when wrapping.
}
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 } , textCol ) ;
}
}
for ( PixelGameEngine : : StringDecalData & letter : letters ) {
DrawPartialDecal ( pos + drawingMarker , pge - > fontRenderable . Decal ( ) , letter . sourcePos , letter . sourceSize , scale , letter . col ) ;
drawingMarker . x + = 8.0f * scale . x ;
}
}
void olc : : ViewPort : : DrawStringDecal ( Font & font , const olc : : vf2d & pos , const std : : u32string & sText , const Pixel col , const olc : : vf2d & scale ) {
if ( sText . length ( ) = = 0 ) return ;
std : : u32string originalKey { pge - > stripCol ( sText ) } ;
std : : u32string renderStr { pge - > stripLeadingCol ( sText ) } ;
std : : u32string Ukey = U " DSD_ " + font . GetFontName ( ) + U " _ " + originalKey ;
std : : string key = std : : string ( Ukey . begin ( ) , Ukey . end ( ) ) ;
const bool RerenderRequired = pge - > garbageCollector . count ( key ) & & pge - > garbageCollector [ key ] . originalStr ! = std : : string ( renderStr . begin ( ) , renderStr . end ( ) ) ;
if ( ! pge - > garbageCollector . count ( key ) | | RerenderRequired ) { //If the text key already exists, don't have to recreate the decal, just update the expire time.
delete pge - > garbageCollector [ key ] . decal ;
pge - > garbageCollector [ key ] . decal = font . RenderStringToDecal ( renderStr , WHITE ) ;
pge - > garbageCollector [ key ] . originalStr = std : : string ( originalKey . begin ( ) , originalKey . end ( ) ) ;
}
pge - > garbageCollector [ key ] . expireTime = pge - > GetRunTime ( ) + 120.0f ;
DrawDecal ( pos , pge - > garbageCollector [ key ] . decal , scale / 4 , pge - > GetFinalRenderColor ( col , sText ) ) ;
}
void olc : : ViewPort : : DrawStringPropDecal ( const olc : : vf2d & pos , std : : string_view sText , const Pixel col , const olc : : vf2d & scale , const float width ) {
Pixel textCol = col ;
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 } ;
const auto hexToNumber = [ ] ( char c ) {
if ( c < = ' 9 ' ) return c - ' 0 ' ;
return ( c - ' A ' ) + 10 ;
} ;
for ( int skip = 0 , index = - 1 ; auto c : sText )
{
index + + ;
if ( skip ) {
skip - - ;
continue ;
}
if ( c = = ' ' | | c = = ' \t ' | | c = = ' \n ' ) {
for ( PixelGameEngine : : StringDecalData & letter : letters ) {
DrawPartialDecal ( pos + drawingMarker , pge - > fontRenderable . Decal ( ) , letter . sourcePos , letter . sourceSize , scale , letter . col ) ;
drawingMarker . x + = float ( pge - > vFontSpacing [ letter . c - 32 ] . y ) * scale . x ;
}
letters . clear ( ) ;
wrappingOccurred = false ;
}
if ( wrappingOccurred ) {
if ( c ! = ' ' & & c ! = ' \t ' & & c ! = ' \n ' ) {
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 ;
for ( PixelGameEngine : : StringDecalData & letter : letters ) {
DrawPartialDecal ( pos + drawingMarker , pge - > fontRenderable . Decal ( ) , letter . sourcePos , letter . sourceSize , scale , letter . col ) ;
drawingMarker . x + = float ( pge - > vFontSpacing [ letter . c - 32 ] . y ) * scale . x ;
}
letters . clear ( ) ;
drawingMarker . x = 0 ; drawingMarker . 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 - > fontRenderable . Decal ( ) , letter . sourcePos , letter . sourceSize , scale , letter . col ) ;
drawingMarker . x + = float ( pge - > vFontSpacing [ letter . c - 32 ] . y ) * scale . x ;
}
letters . clear ( ) ;
} else {
drawingMarker . x - = float ( pge - > vFontSpacing [ ' ' - 32 ] . y ) * scale . x ; //Don't include the space in the sizing when wrapping.
}
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 } , textCol ) ;
}
}
for ( PixelGameEngine : : StringDecalData & letter : letters ) {
DrawPartialDecal ( pos + drawingMarker , pge - > fontRenderable . Decal ( ) , letter . sourcePos , letter . sourceSize , scale , letter . col ) ;
drawingMarker . x + = float ( pge - > vFontSpacing [ letter . c - 32 ] . y ) * scale . x ;
}
}
void olc : : ViewPort : : DrawShadowStringDecal ( const olc : : vf2d & pos , std : : string_view sText , const Pixel col , const Pixel shadowCol , const olc : : vf2d & scale ) {
DrawShadowStringDecal ( pos , sText , col , shadowCol , scale , scale ) ;
}
void olc : : ViewPort : : DrawShadowStringDecal ( const olc : : vf2d & pos , std : : string_view sText , const Pixel col , const Pixel shadowCol , const olc : : vf2d & scale , const olc : : vf2d & shadowScale , const float width ) {
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 } ;
const auto hexToNumber = [ ] ( char c ) {
if ( c < = ' 9 ' ) return c - ' 0 ' ;
return ( c - ' A ' ) + 10 ;
} ;
for ( int skip = 0 , index = - 1 ; auto c : sText )
{
index + + ;
if ( skip ) {
skip - - ;
continue ;
}
if ( c = = ' ' | | c = = ' \t ' | | c = = ' \n ' ) {
for ( PixelGameEngine : : StringDecalData & letter : letters ) {
DrawPartialRotatedDecal ( pos + drawingMarker + vf2d { 5.f , 5.f } * scale - shadowScale , pge - > fontRenderableShadow . Decal ( ) , 0.f , { 5.f , 5.f } , letter . sourcePos , letter . sourceSize , shadowScale , shadowCol ) ;
drawingMarker . x + = 8.0f * scale . x ;
}
letters . clear ( ) ;
wrappingOccurred = false ;
}
if ( wrappingOccurred ) {
if ( c ! = ' ' & & c ! = ' \t ' & & c ! = ' \n ' ) {
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 ;
for ( PixelGameEngine : : StringDecalData & letter : letters ) {
DrawPartialRotatedDecal ( pos + drawingMarker + vf2d { 5.f , 5.f } * scale - shadowScale , pge - > fontRenderableShadow . Decal ( ) , 0.f , { 5.f , 5.f } , letter . sourcePos , letter . sourceSize , shadowScale , shadowCol ) ;
drawingMarker . x + = 8.0f * scale . x ;
}
letters . clear ( ) ;
drawingMarker . x = 0 ; drawingMarker . 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 ) { }
else if ( c = = PixelGameEngine : : Reset [ 0 ] ) { }
else if ( c = = ' # ' )
{
skip = 6 ;
}
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 ) {
DrawPartialRotatedDecal ( pos + drawingMarker + vf2d { 5.f , 5.f } * scale - shadowScale , pge - > fontRenderableShadow . Decal ( ) , 0.f , { 5.f , 5.f } , letter . sourcePos , letter . sourceSize , shadowScale , shadowCol ) ;
drawingMarker . x + = 8.0f * scale . x ;
}
letters . clear ( ) ;
} else {
drawingMarker . x - = pge - > vFontSpacing [ ' ' - 32 ] . y * scale . x ; //Don't include the space in the sizing when wrapping.
}
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 ) * 10.0f , float ( oy ) * 10.0f } , vf2d { 10.0f , 10.0f } , shadowCol ) ;
}
}
for ( PixelGameEngine : : StringDecalData & letter : letters ) {
DrawPartialRotatedDecal ( pos + drawingMarker + vf2d { 5.f , 5.f } * scale - shadowScale , pge - > fontRenderableShadow . Decal ( ) , 0.f , { 5.f , 5.f } , letter . sourcePos , letter . sourceSize , shadowScale , shadowCol ) ;
drawingMarker . x + = 8.0f * scale . x ;
}
DrawStringDecal ( pos , sText , col , scale , width ) ;
}
void olc : : ViewPort : : DrawShadowStringPropDecal ( const olc : : vf2d & pos , std : : string_view sText , const Pixel col , const Pixel shadowCol , const olc : : vf2d & scale ) {
DrawShadowStringPropDecal ( pos , sText , col , shadowCol , scale , scale ) ;
}
void olc : : ViewPort : : DrawShadowStringPropDecal ( const olc : : vf2d & pos , std : : string_view sText , const Pixel col , const Pixel shadowCol , const olc : : vf2d & scale , const olc : : vf2d & shadowScale , const float width ) {
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 } ;
const auto hexToNumber = [ ] ( char c ) {
if ( c < = ' 9 ' ) return c - ' 0 ' ;
return ( c - ' A ' ) + 10 ;
} ;
for ( int skip = 0 , index = - 1 ; auto c : sText )
{
index + + ;
if ( skip ) {
skip - - ;
continue ;
}
if ( c = = ' ' | | c = = ' \t ' | | c = = ' \n ' ) {
for ( PixelGameEngine : : StringDecalData & letter : letters ) {
DrawPartialRotatedDecal ( pos + drawingMarker + vf2d { 5.f , 5.f } * scale - shadowScale , pge - > fontRenderableShadow . Decal ( ) , 0.f , { 5.f , 5.f } , letter . sourcePos , letter . sourceSize , shadowScale , shadowCol ) ;
drawingMarker . x + = float ( pge - > vFontSpacing [ letter . c - 32 ] . y ) * scale . x ;
}
letters . clear ( ) ;
wrappingOccurred = false ;
}
if ( wrappingOccurred ) {
if ( c ! = ' ' & & c ! = ' \t ' & & c ! = ' \n ' ) {
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 ;
for ( PixelGameEngine : : StringDecalData & letter : letters ) {
DrawPartialRotatedDecal ( pos + drawingMarker + vf2d { 5.f , 5.f } * scale - shadowScale , pge - > fontRenderableShadow . Decal ( ) , 0.f , { 5.f , 5.f } , letter . sourcePos , letter . sourceSize , shadowScale , shadowCol ) ;
drawingMarker . x + = float ( pge - > vFontSpacing [ letter . c - 32 ] . y ) * scale . x ;
}
letters . clear ( ) ;
drawingMarker . x = 0 ; drawingMarker . 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 ) { }
else if ( c = = PixelGameEngine : : Reset [ 0 ] ) { }
else if ( c = = ' # ' )
{
skip = 6 ;
}
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 ) {
DrawPartialRotatedDecal ( pos + drawingMarker + vf2d { 5.f , 5.f } * scale - shadowScale , pge - > fontRenderableShadow . Decal ( ) , 0.f , { 5.f , 5.f } , letter . sourcePos , letter . sourceSize , shadowScale , shadowCol ) ;
drawingMarker . x + = float ( pge - > vFontSpacing [ letter . c - 32 ] . y ) * scale . x ;
}
letters . clear ( ) ;
} else {
drawingMarker . x - = pge - > vFontSpacing [ ' ' - 32 ] . y * scale . x ; //Don't include the space in the sizing when wrapping.
}
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 ) * 10.0f + float ( pge - > vFontSpacing [ c - 32 ] . x ) , float ( oy ) * 10.0f } , vf2d { float ( pge - > vFontSpacing [ c - 32 ] . y ) + 2 , 10.0f } , shadowCol ) ;
}
}
for ( PixelGameEngine : : StringDecalData & letter : letters ) {
DrawPartialRotatedDecal ( pos + drawingMarker + vf2d { 5.f , 5.f } * scale - shadowScale , pge - > fontRenderableShadow . Decal ( ) , 0.f , { 5.f , 5.f } , letter . sourcePos , letter . sourceSize , shadowScale , shadowCol ) ;
drawingMarker . x + = float ( pge - > vFontSpacing [ letter . c - 32 ] . y ) * scale . x ;
}
DrawStringPropDecal ( pos , sText , col , scale , width ) ;
}
void olc : : ViewPort : : DrawShadowStringDecal ( Font & font , const olc : : vf2d & pos , const std : : u32string & sText , const Pixel col , const Pixel shadowCol , const olc : : vf2d & scale , const float shadowSizeFactor ) {
if ( sText . length ( ) = = 0 ) return ;
std : : u32string originalKey { pge - > stripCol ( sText ) } ;
std : : u32string renderStr { pge - > stripLeadingCol ( sText ) } ;
std : : u32string Ukey = U " DSSD_ " + font . GetFontName ( ) + U " _ " + originalKey ;
std : : string key = std : : string ( Ukey . begin ( ) , Ukey . end ( ) ) ;
const bool RerenderRequired = pge - > garbageCollector . count ( key ) & & pge - > garbageCollector [ key ] . originalStr ! = std : : string ( renderStr . begin ( ) , renderStr . end ( ) ) ;
if ( ! pge - > garbageCollector . count ( key ) | | RerenderRequired ) { //If the text key already exists, don't have to recreate the decal, just update the expire time.
delete pge - > garbageCollector [ key ] . decal ;
pge - > garbageCollector [ key ] . decal = font . RenderStringToDecal ( renderStr , WHITE ) ;
pge - > garbageCollector [ key ] . originalStr = std : : string ( renderStr . begin ( ) , renderStr . end ( ) ) ;
}
pge - > garbageCollector [ key ] . expireTime = pge - > GetRunTime ( ) + 120.0f ;
std : : erase_if ( pge - > garbageCollector , [ & ] ( auto & key ) {
if ( key . second . expireTime < pge - > GetRunTime ( ) ) {
delete key . second . decal ;
return true ;
}
return false ;
} ) ;
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 ) {
DrawDecal ( pos + vf2d { x , y } , pge - > garbageCollector [ key ] . decal , scale / 4 , shadowCol ) ;
}
}
}
DrawDecal ( pos , pge - > garbageCollector [ key ] . decal , scale / 4 , pge - > GetFinalRenderColor ( col , sText ) ) ;
}
void olc : : ViewPort : : DrawDropShadowStringDecal ( Font & font , const olc : : vf2d & pos , const std : : u32string & sText , const Pixel col , const Pixel shadowCol , const olc : : vf2d & scale ) {
if ( sText . length ( ) = = 0 ) return ;
std : : u32string originalKey { pge - > stripCol ( sText ) } ;
std : : u32string renderStr { pge - > stripLeadingCol ( sText ) } ;
std : : u32string Ukey = U " DDSSD_ " + font . GetFontName ( ) + U " _ " + originalKey ;
std : : string key = std : : string ( Ukey . begin ( ) , Ukey . end ( ) ) ;
const bool RerenderRequired = pge - > garbageCollector . count ( key ) & & pge - > garbageCollector [ key ] . originalStr ! = std : : string ( renderStr . begin ( ) , renderStr . end ( ) ) ;
if ( ! pge - > garbageCollector . count ( key ) | | RerenderRequired ) { //If the text key already exists, don't have to recreate the decal, just update the expire time.
delete pge - > garbageCollector [ key ] . decal ;
pge - > garbageCollector [ key ] . decal = font . RenderStringToDecal ( renderStr , WHITE ) ;
pge - > garbageCollector [ key ] . originalStr = std : : string ( renderStr . begin ( ) , renderStr . end ( ) ) ;
}
pge - > garbageCollector [ key ] . expireTime = pge - > GetRunTime ( ) + 120.0f ;
DrawDecal ( pos + vf2d { 0 , 0.5f } , pge - > garbageCollector [ key ] . decal , scale / 4 , shadowCol ) ;
DrawDecal ( pos + vf2d { 0.5f , 0 } , pge - > garbageCollector [ key ] . decal , scale / 4 , shadowCol ) ;
DrawDecal ( pos + vf2d { 0.5f , 0.5f } , pge - > garbageCollector [ key ] . decal , scale / 4 , shadowCol ) ;
DrawDecal ( pos , pge - > garbageCollector [ key ] . decal , scale / 4 , pge - > GetFinalRenderColor ( col , sText ) ) ;
}
void olc : : ViewPort : : DrawRectDecal ( const olc : : vf2d & pos , const olc : : vf2d & size , const olc : : Pixel col ) const {
FillRectDecal ( pos , { size . x + 1 , 1 } , col ) ;
FillRectDecal ( pos + vf2d { 0 , size . y - 1 + 1 } , { size . x + 1 , 1 } , col ) ;
FillRectDecal ( pos + vf2d { 0 , 1 } , { 1 , size . y - 1 * 2 + 1 } , col ) ;
FillRectDecal ( pos + vf2d { size . x - 1 + 1 , 1 } , { 1 , size . y - 1 * 2 + 1 } , col ) ;
}
# endif