2007-05-30 21:56:52 +00: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 .
2003-12-16 02:10:15 +00:00
*
* 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 .
2014-02-18 01:34:25 +00:00
*
2003-12-16 02:10:15 +00:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2008-01-05 12:45:14 +00:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
2003-12-16 02:10:15 +00:00
* GNU General Public License for more details .
2014-02-18 01:34:25 +00:00
*
2003-12-16 02:10:15 +00:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
2005-10-18 01:30:26 +00:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
2003-12-16 02:10:15 +00:00
*
*/
2007-09-19 08:40:12 +00:00
2011-04-24 08:34:27 +00:00
# include "common/textconsole.h"
2006-03-29 15:59:37 +00:00
2004-10-21 12:43:49 +00:00
# include "sword1/text.h"
# include "sword1/resman.h"
# include "sword1/objectman.h"
# include "sword1/swordres.h"
# include "sword1/sworddefs.h"
2009-02-28 10:46:33 +00:00
# include "sword1/screen.h"
# include "sword1/sword1.h"
2003-12-16 02:10:15 +00:00
2004-01-11 15:47:41 +00:00
namespace Sword1 {
2003-12-16 02:10:15 +00:00
# define OVERLAP 3
# define SPACE ' '
2011-09-07 21:54:34 +00:00
# define MAX_LINES 30
2003-12-16 02:10:15 +00:00
2004-01-11 15:47:41 +00:00
Text : : Text ( ObjectMan * pObjMan , ResMan * pResMan , bool czechVersion ) {
2003-12-16 02:10:15 +00:00
_objMan = pObjMan ;
_resMan = pResMan ;
_textCount = 0 ;
2004-11-09 04:06:10 +00:00
_fontId = ( czechVersion ) ? CZECH_GAME_FONT : GAME_FONT ;
2011-09-07 21:54:34 +00:00
_font = ( uint8 * ) _resMan - > openFetchRes ( _fontId ) ;
2004-11-09 04:06:10 +00:00
2010-10-12 04:19:58 +00:00
_joinWidth = charWidth ( SPACE ) - 2 * OVERLAP ;
2006-11-12 19:05:51 +00:00
_charHeight = _resMan - > getUint16 ( _resMan - > fetchFrame ( _font , 0 ) - > height ) ; // all chars have the same height
2007-04-28 07:27:53 +00:00
for ( int i = 0 ; i < MAX_TEXT_OBS ; i + + )
_textBlocks [ i ] = NULL ;
2003-12-16 02:10:15 +00:00
}
2009-11-02 21:54:57 +00:00
Text : : ~ Text ( ) {
2007-04-28 07:27:53 +00:00
for ( int i = 0 ; i < MAX_TEXT_OBS ; i + + )
free ( _textBlocks [ i ] ) ;
2004-11-09 04:06:10 +00:00
//_resMan->resClose(_fontId); => wiped automatically by _resMan->flush();
2003-12-20 09:12:54 +00:00
}
2004-01-11 15:47:41 +00:00
uint32 Text : : lowTextManager ( uint8 * ascii , int32 width , uint8 pen ) {
2003-12-16 02:10:15 +00:00
_textCount + + ;
if ( _textCount > MAX_TEXT_OBS )
2009-05-31 10:02:16 +00:00
error ( " Text::lowTextManager: MAX_TEXT_OBS exceeded " ) ;
2003-12-16 02:10:15 +00:00
uint32 textObjId = ( TEXT_sect * ITM_PER_SEC ) - 1 ;
do {
textObjId + + ;
2005-05-08 21:49:52 +00:00
} while ( _objMan - > fetchObject ( textObjId ) - > o_status ) ;
2003-12-16 02:10:15 +00:00
// okay, found a free text object
_objMan - > fetchObject ( textObjId ) - > o_status = STAT_FORE ;
makeTextSprite ( ( uint8 ) textObjId , ascii , ( uint16 ) width , pen ) ;
return textObjId ;
}
2011-05-17 13:05:20 +00:00
void Text : : makeTextSprite ( uint8 slot , const uint8 * text , uint16 maxWidth , uint8 pen ) {
2003-12-16 02:10:15 +00:00
LineInfo lines [ MAX_LINES ] ;
uint16 numLines = analyzeSentence ( text , maxWidth , lines ) ;
2009-05-24 15:17:42 +00:00
2003-12-16 02:10:15 +00:00
uint16 sprWidth = 0 ;
2003-12-23 00:59:18 +00:00
uint16 lineCnt ;
for ( lineCnt = 0 ; lineCnt < numLines ; lineCnt + + )
2003-12-16 02:10:15 +00:00
if ( lines [ lineCnt ] . width > sprWidth )
sprWidth = lines [ lineCnt ] . width ;
2009-02-28 10:46:33 +00:00
2003-12-16 02:10:15 +00:00
uint16 sprHeight = _charHeight * numLines ;
uint32 sprSize = sprWidth * sprHeight ;
2004-01-11 15:47:41 +00:00
assert ( ! _textBlocks [ slot ] ) ; // if this triggers, the speechDriver failed to call Text::releaseText.
2011-09-07 21:54:34 +00:00
_textBlocks [ slot ] = ( FrameHeader * ) malloc ( sprSize + sizeof ( FrameHeader ) ) ;
2003-12-16 02:10:15 +00:00
2008-10-13 18:41:12 +00:00
memcpy ( _textBlocks [ slot ] - > runTimeComp , " Nu " , 4 ) ;
2011-09-07 21:54:34 +00:00
_textBlocks [ slot ] - > compSize = 0 ;
_textBlocks [ slot ] - > width = _resMan - > toUint16 ( sprWidth ) ;
_textBlocks [ slot ] - > height = _resMan - > toUint16 ( sprHeight ) ;
_textBlocks [ slot ] - > offsetX = 0 ;
_textBlocks [ slot ] - > offsetY = 0 ;
2003-12-16 02:10:15 +00:00
2011-09-07 21:54:34 +00:00
uint8 * linePtr = ( ( uint8 * ) _textBlocks [ slot ] ) + sizeof ( FrameHeader ) ;
2003-12-16 02:10:15 +00:00
memset ( linePtr , NO_COL , sprSize ) ;
2003-12-23 00:59:18 +00:00
for ( lineCnt = 0 ; lineCnt < numLines ; lineCnt + + ) {
2003-12-16 02:10:15 +00:00
uint8 * sprPtr = linePtr + ( sprWidth - lines [ lineCnt ] . width ) / 2 ; // center the text
2009-05-24 15:17:42 +00:00
for ( uint16 pos = 0 ; pos < lines [ lineCnt ] . length ; pos + + )
2003-12-16 02:10:15 +00:00
sprPtr + = copyChar ( * text + + , sprPtr , sprWidth , pen ) - OVERLAP ;
text + + ; // skip space at the end of the line
2009-09-30 16:16:53 +00:00
if ( SwordEngine : : isPsx ( ) ) //Chars are half height in psx version
2009-02-28 10:46:33 +00:00
linePtr + = ( _charHeight / 2 ) * sprWidth ;
else
linePtr + = _charHeight * sprWidth ;
2003-12-16 02:10:15 +00:00
}
}
2004-01-11 15:47:41 +00:00
uint16 Text : : charWidth ( uint8 ch ) {
2003-12-16 02:10:15 +00:00
if ( ch < SPACE )
ch = 64 ;
2006-11-12 19:05:51 +00:00
return _resMan - > getUint16 ( _resMan - > fetchFrame ( _font , ch - SPACE ) - > width ) ;
2003-12-16 02:10:15 +00:00
}
2011-05-17 13:05:20 +00:00
uint16 Text : : analyzeSentence ( const uint8 * text , uint16 maxWidth , LineInfo * line ) {
2003-12-16 02:10:15 +00:00
uint16 lineNo = 0 ;
bool firstWord = true ;
while ( * text ) {
uint16 wordWidth = 0 ;
uint16 wordLength = 0 ;
while ( ( * text ! = SPACE ) & & * text ) {
wordWidth + = charWidth ( * text ) - OVERLAP ;
wordLength + + ;
text + + ;
}
if ( * text = = SPACE )
text + + ;
wordWidth + = OVERLAP ; // no overlap on final letter of word!
2011-09-07 21:54:34 +00:00
if ( firstWord ) { // first word on first line, so no separating SPACE needed
2003-12-16 02:10:15 +00:00
line [ 0 ] . width = wordWidth ;
line [ 0 ] . length = wordLength ;
firstWord = false ;
} else {
// see how much extra space this word will need to fit on current line
// (with a separating space character - also overlapped)
uint16 spaceNeeded = _joinWidth + wordWidth ;
2010-10-12 04:19:58 +00:00
if ( line [ lineNo ] . width + spaceNeeded < = maxWidth ) {
2003-12-16 02:10:15 +00:00
line [ lineNo ] . width + = spaceNeeded ;
line [ lineNo ] . length + = 1 + wordLength ; // NB. space+word characters
2011-09-07 21:54:34 +00:00
} else { // put word (without separating SPACE) at start of next line
2003-12-16 02:10:15 +00:00
lineNo + + ;
2010-10-12 04:19:58 +00:00
assert ( lineNo < MAX_LINES ) ;
2003-12-16 02:10:15 +00:00
line [ lineNo ] . width = wordWidth ;
line [ lineNo ] . length = wordLength ;
}
}
}
2011-09-07 21:54:34 +00:00
return lineNo + 1 ; // return no of lines
2003-12-16 02:10:15 +00:00
}
2004-01-11 15:47:41 +00:00
uint16 Text : : copyChar ( uint8 ch , uint8 * sprPtr , uint16 sprWidth , uint8 pen ) {
2012-06-05 21:26:51 +00:00
if ( ch < SPACE )
ch = 64 ;
2003-12-16 02:10:15 +00:00
FrameHeader * chFrame = _resMan - > fetchFrame ( _font , ch - SPACE ) ;
2011-09-07 21:54:34 +00:00
uint8 * chData = ( ( uint8 * ) chFrame ) + sizeof ( FrameHeader ) ;
2003-12-16 02:10:15 +00:00
uint8 * dest = sprPtr ;
2009-02-28 10:46:33 +00:00
uint8 * decBuf = NULL ;
uint8 * decChr ;
uint16 frameHeight = 0 ;
2009-05-24 15:17:42 +00:00
2009-09-30 16:16:53 +00:00
if ( SwordEngine : : isPsx ( ) ) {
2011-09-07 21:54:34 +00:00
frameHeight = _resMan - > getUint16 ( chFrame - > height ) / 2 ;
2009-09-30 16:16:53 +00:00
if ( _fontId = = CZECH_GAME_FONT ) { //Czech game fonts are compressed
2011-09-07 21:54:34 +00:00
decBuf = ( uint8 * ) malloc ( ( _resMan - > getUint16 ( chFrame - > width ) ) * ( _resMan - > getUint16 ( chFrame - > height ) / 2 ) ) ;
2009-02-28 10:46:33 +00:00
Screen : : decompressHIF ( chData , decBuf ) ;
decChr = decBuf ;
} else //Normal game fonts are not compressed
decChr = chData ;
} else {
frameHeight = _resMan - > getUint16 ( chFrame - > height ) ;
decChr = chData ;
}
2009-05-24 15:17:42 +00:00
2009-02-28 10:46:33 +00:00
for ( uint16 cnty = 0 ; cnty < frameHeight ; cnty + + ) {
2006-11-12 19:05:51 +00:00
for ( uint16 cntx = 0 ; cntx < _resMan - > getUint16 ( chFrame - > width ) ; cntx + + ) {
2009-02-28 10:46:33 +00:00
if ( * decChr = = LETTER_COL )
2003-12-16 02:10:15 +00:00
dest [ cntx ] = pen ;
2009-02-28 10:46:33 +00:00
else if ( ( ( * decChr = = BORDER_COL ) | | ( * decChr = = BORDER_COL_PSX ) ) & & ( ! dest [ cntx ] ) ) // don't do a border if there's already a color underneath (chars can overlap)
2003-12-16 02:10:15 +00:00
dest [ cntx ] = BORDER_COL ;
2009-02-28 10:46:33 +00:00
decChr + + ;
2003-12-16 02:10:15 +00:00
}
dest + = sprWidth ;
}
2009-02-28 10:46:33 +00:00
free ( decBuf ) ;
2006-11-12 19:05:51 +00:00
return _resMan - > getUint16 ( chFrame - > width ) ;
2003-12-16 02:10:15 +00:00
}
2004-01-11 15:47:41 +00:00
FrameHeader * Text : : giveSpriteData ( uint32 textTarget ) {
2003-12-16 02:10:15 +00:00
// textTarget is the resource ID of the Compact linking the textdata.
// that's 0x950000 for slot 0 and 0x950001 for slot 1. easy, huh? :)
textTarget & = ITM_ID ;
2007-04-28 07:27:53 +00:00
assert ( textTarget < MAX_TEXT_OBS ) ;
2003-12-16 02:10:15 +00:00
return _textBlocks [ textTarget ] ;
}
2008-10-13 18:41:12 +00:00
void Text : : releaseText ( uint32 id , bool updateCount ) {
2003-12-16 02:10:15 +00:00
id & = ITM_ID ;
2007-04-28 07:27:53 +00:00
assert ( id < MAX_TEXT_OBS ) ;
2003-12-20 09:12:54 +00:00
if ( _textBlocks [ id ] ) {
free ( _textBlocks [ id ] ) ;
_textBlocks [ id ] = NULL ;
2008-10-13 18:41:12 +00:00
if ( updateCount )
_textCount - - ;
2003-12-20 09:12:54 +00:00
}
2003-12-16 02:10:15 +00:00
}
2004-01-11 15:47:41 +00:00
} // End of namespace Sword1