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 ;
_color = color ;
Common : : ScopedPtr < Common : : SeekableReadStream > stream ( _vm - > getResourceStream ( fileName ) ) ;
if ( ! stream ) {
debug ( " Font::open failed to open '%s' " , fileName . c_str ( ) ) ;
return false ;
}
_characterCount = stream - > readUint32LE ( ) ;
_maxWidth = stream - > readUint32LE ( ) ;
_maxHeight = stream - > readUint32LE ( ) ;
_dataSize = stream - > readUint32LE ( ) ;
_data = new uint16 [ _dataSize ] ;
if ( ! _data ) {
debug ( " Font::open failed to allocate font buffer " ) ;
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
}
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 ( ) ;
}
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 ) {
if ( _data & & _color ! = color ) {
replaceColor ( _color , color ) ;
_color = color ;
}
}
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 ) {
if ( _color ! = color ) {
setColor ( color ) ;
}
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 ;
_color = 0x7FFF ;
_intersperse = 0 ;
2018-01-14 12:12:06 +01:00
memset ( _characters , 0 , 256 * sizeof ( Character ) ) ;
2016-10-06 21:23:46 +02:00
}
void Font : : replaceColor ( uint16 oldColor , uint16 newColor ) {
if ( ! _data | | ! _dataSize ) {
return ;
}
for ( int i = 0 ; i < _dataSize ; i + + ) {
if ( _data [ i ] = = oldColor ) {
_data [ i ] = newColor ;
}
}
}
2018-08-01 20:15:37 +03:00
// This is useful when using a duplicate of the internal font to act as shadow effect for the glyphs for subtitles
// Mainly needed for the internal font for subtitles, since an external font can have shadow already drawn for the glyphs
2018-06-18 14:10:00 +03:00
void Font : : setBlackColor ( ) {
if ( ! _data | | ! _dataSize ) {
return ;
}
for ( int i = 0 ; i < _dataSize ; i + + ) {
2018-07-02 10:45:17 +03:00
//debug("COLOR EXISTING: %d", _data[i]);
if ( _data [ i ] ! = 32768 ) { // 0x8000 is transparent
_data [ i ] = 0x0000 ; // black
}
2018-06-18 14:10:00 +03: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...
// ...or potential custom dialogue / translations that reference characters that are not within the range of Ascii values for the normal Latin characters.
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 ) {
2016-10-08 21:06:22 +02:00
if ( ( * srcPtr & 0x8000 ) = = 0 ) {
2016-10-06 21:23:46 +02:00
* dstPtr = * srcPtr ;
}
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