2016-10-06 21:23:46 +02:00
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers , whose names
* are too numerous to list here . Please refer to the COPYRIGHT
* file distributed with this source distribution .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
*/
# include "bladerunner/font.h"
# include "bladerunner/bladerunner.h"
# include "common/debug.h"
namespace BladeRunner {
2018-01-14 12:12:06 +01:00
Font : : Font ( BladeRunnerEngine * vm ) {
_vm = vm ;
2016-10-06 21:23:46 +02:00
reset ( ) ;
}
Font : : ~ Font ( ) {
close ( ) ;
}
bool Font : : open ( const Common : : String & fileName , int screenWidth , int screenHeight , int spacing1 , int spacing2 , uint16 color ) {
reset ( ) ;
_screenWidth = screenWidth ;
_screenHeight = screenHeight ;
_spacing1 = spacing1 ;
_spacing2 = spacing2 ;
2019-04-13 01:03:48 +02:00
_defaultColor = color ;
2016-10-06 21:23:46 +02:00
_color = color ;
Common : : ScopedPtr < Common : : SeekableReadStream > stream ( _vm - > getResourceStream ( fileName ) ) ;
if ( ! stream ) {
2019-02-07 23:54:47 +01:00
warning ( " Font::open failed to open '%s' " , fileName . c_str ( ) ) ;
2016-10-06 21:23:46 +02:00
return false ;
}
_characterCount = stream - > readUint32LE ( ) ;
_maxWidth = stream - > readUint32LE ( ) ;
_maxHeight = stream - > readUint32LE ( ) ;
_dataSize = stream - > readUint32LE ( ) ;
_data = new uint16 [ _dataSize ] ;
if ( ! _data ) {
2019-02-07 23:54:47 +01:00
warning ( " Font::open failed to allocate font buffer " ) ;
2016-10-06 21:23:46 +02:00
return false ;
}
2016-10-06 22:32:27 +02:00
for ( int i = 0 ; i < _characterCount ; i + + ) {
2018-01-14 12:12:06 +01:00
_characters [ i ] . x = stream - > readUint32LE ( ) ;
_characters [ i ] . y = stream - > readUint32LE ( ) ;
_characters [ i ] . width = stream - > readUint32LE ( ) ;
_characters [ i ] . height = stream - > readUint32LE ( ) ;
_characters [ i ] . dataOffset = stream - > readUint32LE ( ) ;
2016-10-06 22:32:27 +02:00
}
2019-04-13 01:03:48 +02:00
2016-10-08 21:06:22 +02:00
for ( int i = 0 ; i < _dataSize ; i + + ) {
2016-10-06 22:32:27 +02:00
_data [ i ] = stream - > readUint16LE ( ) ;
}
2019-04-13 01:03:48 +02:00
2016-10-06 21:23:46 +02:00
return true ;
}
void Font : : close ( ) {
if ( _data ! = nullptr ) {
delete [ ] _data ;
}
reset ( ) ;
}
void Font : : setSpacing ( int spacing1 , int spacing2 ) {
if ( _data ) {
_spacing1 = spacing1 ;
_spacing2 = spacing2 ;
}
}
void Font : : setColor ( uint16 color ) {
2019-04-13 01:03:48 +02:00
_color = color ;
2016-10-06 21:23:46 +02:00
}
2018-01-14 12:12:06 +01:00
void Font : : draw ( const Common : : String & text , Graphics : : Surface & surface , int x , int y ) const {
2016-10-06 22:32:27 +02:00
if ( ! _data ) {
return ;
}
2016-10-06 21:23:46 +02:00
2016-10-08 21:06:22 +02:00
x = CLIP ( x , 0 , _screenWidth - getTextWidth ( text ) + 1 ) ;
y = CLIP ( y , 0 , _screenHeight - _maxHeight ) ;
2016-10-06 22:32:27 +02:00
2018-01-28 20:59:12 +01:00
const uint8 * character = ( const uint8 * ) text . c_str ( ) ;
2016-10-06 22:32:27 +02:00
while ( * character ! = 0 ) {
drawCharacter ( * character , surface , x , y ) ;
2018-01-14 12:12:06 +01:00
x + = _spacing1 + _characters [ * character + 1 ] . width ;
2016-10-06 22:32:27 +02:00
character + + ;
2016-10-06 21:23:46 +02:00
}
}
void Font : : drawColor ( const Common : : String & text , Graphics : : Surface & surface , int x , int y , uint16 color ) {
2019-04-13 01:03:48 +02:00
setColor ( color ) ;
2016-10-06 21:23:46 +02:00
draw ( text , surface , x , y ) ;
}
2018-03-26 23:54:58 +02:00
void Font : : drawNumber ( int num , Graphics : : Surface & surface , int x , int y ) const {
char buffer [ 20 ] ;
snprintf ( buffer , 20 , " %d " , num ) ;
draw ( buffer , surface , x , y ) ;
}
2018-01-14 12:12:06 +01:00
int Font : : getTextWidth ( const Common : : String & text ) const {
2018-01-28 20:59:12 +01:00
const uint8 * character = ( const uint8 * ) text . c_str ( ) ;
2016-10-06 21:23:46 +02:00
if ( ! _data ) {
return 0 ;
}
int totalWidth = 0 ;
if ( * character = = 0 ) {
return 0 ;
}
while ( * character ! = 0 ) {
2018-01-14 12:12:06 +01:00
totalWidth + = _spacing1 + _characters [ * character + 1 ] . width ;
2016-10-06 21:23:46 +02:00
character + + ;
}
return totalWidth - _spacing1 ;
}
2018-01-14 12:12:06 +01:00
int Font : : getTextHeight ( const Common : : String & text ) const {
2017-08-24 23:43:47 +02:00
return _maxHeight ;
}
2016-10-06 21:23:46 +02:00
void Font : : reset ( ) {
_maxWidth = 0 ;
_maxHeight = 0 ;
_characterCount = 0 ;
_data = nullptr ;
_dataSize = 0 ;
_screenWidth = 0 ;
_screenHeight = 0 ;
_spacing1 = 0 ;
_spacing2 = 0 ;
2019-04-17 23:08:35 +02:00
_color = screenPixelFormat ( ) . RGBToColor ( 255 , 255 , 255 ) ;
2016-10-06 21:23:46 +02:00
_intersperse = 0 ;
2018-01-14 12:12:06 +01:00
memset ( _characters , 0 , 256 * sizeof ( Character ) ) ;
2016-10-06 21:23:46 +02:00
}
2018-01-28 20:59:12 +01:00
void Font : : drawCharacter ( const uint8 character , Graphics : : Surface & surface , int x , int y ) const {
uint8 characterIndex = character + 1 ;
2016-10-08 21:06:22 +02:00
if ( x < 0 | | x > = _screenWidth | | y < 0 | | y > = _screenHeight | | ! _data | | characterIndex > = _characterCount ) {
2016-10-06 21:23:46 +02:00
return ;
}
2018-01-14 12:12:06 +01:00
uint16 * dstPtr = ( uint16 * ) surface . getBasePtr ( x + _characters [ characterIndex ] . x , y + _characters [ characterIndex ] . y ) ;
uint16 * srcPtr = & _data [ _characters [ characterIndex ] . dataOffset ] ;
int width = _characters [ characterIndex ] . width ;
int height = _characters [ characterIndex ] . height ;
2016-10-06 21:23:46 +02:00
if ( _intersperse & & y & 1 ) {
2016-10-08 21:06:22 +02:00
dstPtr + = surface . pitch / 2 ;
2016-10-06 21:23:46 +02:00
}
int endY = height + y - 1 ;
int currentY = y ;
2018-07-02 10:45:17 +03:00
// FIXME/TODO
// This width and height check were added as a temporary bug fix -- a sanity check which is only needed for the internal TAHOMA18.FON font.
// That font's glyph properties table is corrupted - the start of the file states that there are 0xF7 (=247) entries in the char properties table
// but that table get corrupted past the 176th entry. The image data glyph part of the FON file also only covers the 176 entries.
// So the following if clause-check will return here if the width and height values are unnaturally big.
// The bug only affects debug cases where all character glyph need to be displayed...
2018-12-16 19:45:19 +02:00
// ...or potential custom dialogue / translations that reference characters that are not within the range of ASCII values for the normal Latin characters.
2018-07-02 10:45:17 +03:00
if ( width > 100 | | height > 100 ) {
return ;
}
2016-10-06 21:23:46 +02:00
while ( currentY < = endY & & currentY < _screenHeight ) {
int currentX = x ;
int endX = width + x - 1 ;
while ( currentX < = endX & & currentX < _screenWidth ) {
2019-04-13 01:03:48 +02:00
uint8 a , r , g , b ;
gameDataPixelFormat ( ) . colorToARGB ( * srcPtr , a , r , g , b ) ;
if ( ! a ) {
if ( _color = = _defaultColor ) {
2019-06-24 21:43:43 +02:00
// Ignore the alpha in the output as it is inversed in the input
2019-04-13 01:03:48 +02:00
* dstPtr = surface . format . RGBToColor ( r , g , b ) ;
} else {
* dstPtr = _color ;
}
2016-10-06 21:23:46 +02:00
}
dstPtr + + ;
srcPtr + + ;
currentX + + ;
}
2016-10-08 21:06:22 +02:00
dstPtr + = surface . pitch / 2 - width ;
2016-10-06 21:23:46 +02:00
if ( _intersperse ) {
srcPtr + = width ;
2016-10-08 21:06:22 +02:00
dstPtr + = surface . pitch / 2 ;
2016-10-06 21:23:46 +02:00
currentY + + ;
}
currentY + + ;
}
}
2018-01-14 12:12:06 +01:00
2016-10-06 21:23:46 +02:00
} // End of namespace BladeRunner