2003-07-28 01:44:38 +00:00
|
|
|
/* Copyright (C) 1994-2003 Revolution Software Ltd
|
|
|
|
*
|
|
|
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
* $Header$
|
|
|
|
*/
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// MAKETEXT - Constructs a single-frame text sprite: returns a handle to a
|
|
|
|
// FLOATING memory block containing the sprite, given a
|
|
|
|
// null-terminated string, max width allowed, pen colour and
|
|
|
|
// pointer to required character set.
|
2003-07-28 01:44:38 +00:00
|
|
|
//
|
2003-09-19 06:42:22 +00:00
|
|
|
// NB 1) The routine does not create a standard file header or
|
|
|
|
// an anim header for the text sprite - the data simply begins
|
|
|
|
// with the frame header.
|
2003-07-28 01:44:38 +00:00
|
|
|
//
|
2003-09-19 06:42:22 +00:00
|
|
|
// NB 2) If pen colour is zero, it copies the characters into
|
|
|
|
// the sprite without remapping the colours.
|
|
|
|
// ie. It can handle both the standard 2-colour font for speech
|
|
|
|
// and any multicoloured fonts for control panels, etc.
|
2003-07-28 01:44:38 +00:00
|
|
|
//
|
2003-09-19 06:42:22 +00:00
|
|
|
// Based on textsprt.c as used for Broken Sword 1, but updated
|
|
|
|
// for new system by JEL on 9oct96 and updated again (for font
|
|
|
|
// as a resource) on 5dec96.
|
|
|
|
|
|
|
|
#define MAX_LINES 30 // max character lines in output sprite
|
|
|
|
|
|
|
|
#define BORDER_COL 200 // source colour for character border (only
|
|
|
|
// needed for remapping colours)
|
|
|
|
#define LETTER_COL 193 // source colour for bulk of character ( " )
|
|
|
|
#define BORDER_PEN 194 // output colour for character border - should
|
|
|
|
// be black ( " ) but note that we have to use
|
|
|
|
// a different pen number during sequences
|
|
|
|
|
|
|
|
#define NO_COL 0 // sprite background - 0 for transparency!
|
|
|
|
#define SPACE ' '
|
|
|
|
#define FIRST_CHAR SPACE // first character in character set
|
|
|
|
#define LAST_CHAR 255 // last character in character set
|
|
|
|
#define DUD 64 // the first "chequered flag" (dud) symbol in
|
|
|
|
// our character set is in the '@' position
|
2003-07-28 01:44:38 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
2003-07-28 03:12:49 +00:00
|
|
|
#include "stdafx.h"
|
2003-07-28 01:44:38 +00:00
|
|
|
#include "driver/driver96.h"
|
|
|
|
#include "console.h"
|
|
|
|
#include "debug.h"
|
2003-09-19 06:42:22 +00:00
|
|
|
#include "defs.h" // for SPEECH_FONT_ID & CONSOLE_FONT_ID
|
2003-07-28 01:44:38 +00:00
|
|
|
#include "header.h"
|
|
|
|
#include "maketext.h"
|
|
|
|
#include "memory.h"
|
2003-09-19 06:42:22 +00:00
|
|
|
#include "protocol.h" // for FetchFrameHeader()
|
2003-07-28 01:44:38 +00:00
|
|
|
#include "resman.h"
|
2003-07-28 07:00:15 +00:00
|
|
|
#include "sword2.h"
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
extern uint32 sequenceTextLines; // see anims.cpp
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// info for each line of words in the output text sprite
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint16 width; // width of line in pixels
|
|
|
|
uint16 length; // length of line in characters
|
2003-07-28 01:44:38 +00:00
|
|
|
} _lineInfo;
|
2003-09-19 06:42:22 +00:00
|
|
|
|
|
|
|
uint16 AnalyseSentence(uint8 *sentence, uint16 maxWidth, uint32 fontRes, _lineInfo *line);
|
|
|
|
mem* BuildTextSprite(uint8 *sentence, uint32 fontRes, uint8 pen, _lineInfo *line, uint16 noOfLines);
|
|
|
|
uint16 CharWidth(uint8 ch, uint32 fontRes);
|
|
|
|
uint16 CharHeight(uint32 fontRes);
|
|
|
|
_frameHeader* FindChar(uint8 ch, uint8 *charSet);
|
|
|
|
void CopyChar(_frameHeader *charPtr, uint8 *spritePtr, uint16 spriteWidth, uint8 pen);
|
|
|
|
|
|
|
|
// global layout variables - these used to be defines, but now we're dealing
|
|
|
|
// with 2 character sets (10dec96 JEL)
|
|
|
|
|
|
|
|
int8 line_spacing; // no. of pixels to separate lines of characters in
|
|
|
|
// the output sprite - negative for overlap
|
|
|
|
int8 char_spacing; // no. of pixels to separate characters along each
|
|
|
|
// line - negative for overlap
|
|
|
|
uint8 border_pen; // output pen colour of character borders
|
|
|
|
|
|
|
|
// Global font resource id variables, set up in 'SetUpFontResources()' at
|
|
|
|
// bottom of this file
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
uint32 speech_font_id;
|
|
|
|
uint32 controls_font_id;
|
|
|
|
uint32 red_font_id;
|
|
|
|
uint32 death_font_id;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
mem* MakeTextSprite(uint8 *sentence, uint16 maxWidth, uint8 pen, uint32 fontRes) {
|
|
|
|
mem *line; // handle for the memory block which will
|
|
|
|
// contain the array of lineInfo structures
|
|
|
|
mem *textSprite; // handle for the block to contain the text
|
|
|
|
// sprite itself
|
|
|
|
uint16 noOfLines; // no of lines of text required to fit within
|
|
|
|
// a sprite of width 'maxWidth' pixels
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-27 11:02:58 +00:00
|
|
|
debug(5, "MakeTextSprite(\"%s\", maxWidth=%u)", sentence, maxWidth);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// NB. ensure sentence contains no leading/tailing/extra spaces - if
|
|
|
|
// necessary, copy to another array first, missing the extra spaces.
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
// set the global layout variables (10dec96 JEL)
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
if (fontRes == speech_font_id) {
|
|
|
|
line_spacing = -6; // overlap lines by 6 pixels
|
|
|
|
char_spacing = -3; // overlap characters by 3 pixels
|
|
|
|
} else if (fontRes == CONSOLE_FONT_ID) {
|
|
|
|
line_spacing = 0; // no space or overlap between lines
|
|
|
|
char_spacing = 1; // 1 pixel spacing between each character
|
|
|
|
} else {
|
|
|
|
line_spacing = 0;
|
|
|
|
char_spacing = 0;
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// If rendering text over a sequence we need a different colour for
|
|
|
|
// the border.
|
|
|
|
|
|
|
|
if (sequenceTextLines)
|
|
|
|
border_pen = 1;
|
2003-07-28 01:44:38 +00:00
|
|
|
else
|
|
|
|
border_pen = BORDER_PEN;
|
|
|
|
|
|
|
|
// allocate memory for array of lineInfo structures
|
2003-09-19 06:42:22 +00:00
|
|
|
|
|
|
|
line = Twalloc(MAX_LINES * sizeof(_lineInfo), MEM_locked, UID_temp);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
// get details of sentence breakdown into array of _lineInfo structures
|
|
|
|
// and get the no of lines involved
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
noOfLines = AnalyseSentence(sentence, maxWidth, fontRes, (_lineInfo *) line->ad);
|
|
|
|
|
|
|
|
// construct the sprite based on the info gathered - returns floating
|
|
|
|
// mem block
|
|
|
|
|
|
|
|
textSprite = BuildTextSprite(sentence, fontRes, pen, (_lineInfo *) line->ad, noOfLines);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
// free up the lineInfo array now
|
2003-09-19 06:42:22 +00:00
|
|
|
Free_mem(line);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
return textSprite;
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
2003-09-19 06:42:22 +00:00
|
|
|
|
|
|
|
uint16 AnalyseSentence(uint8 *sentence, uint16 maxWidth, uint32 fontRes, _lineInfo *line) {
|
2003-09-24 06:40:23 +00:00
|
|
|
uint16 pos = 0, wordWidth, wordLength, spaceNeeded;
|
2003-09-19 06:42:22 +00:00
|
|
|
uint16 lineNo = 0;
|
2003-07-28 01:44:38 +00:00
|
|
|
uint8 ch;
|
2003-09-24 06:40:23 +00:00
|
|
|
bool firstWord = true;
|
2003-09-19 06:42:22 +00:00
|
|
|
|
|
|
|
// joinWidth = how much extra space is needed to append a word to a
|
|
|
|
// line. NB. SPACE requires TWICE the 'char_spacing' to join a word
|
|
|
|
// to line
|
|
|
|
|
|
|
|
uint16 joinWidth = CharWidth(SPACE, fontRes) + 2 * char_spacing;
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// while not reached the NULL terminator
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
do {
|
|
|
|
// new word
|
|
|
|
wordWidth = 0;
|
2003-07-28 01:44:38 +00:00
|
|
|
wordLength = 0;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// get first char of word (at position 'pos')
|
|
|
|
ch = sentence[pos++];
|
|
|
|
|
|
|
|
// while not SPACE or NULL terminator
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
while ((ch != SPACE) && ch) {
|
|
|
|
wordWidth += CharWidth(ch, fontRes) + char_spacing;
|
2003-07-28 01:44:38 +00:00
|
|
|
wordLength++;
|
2003-09-19 06:42:22 +00:00
|
|
|
ch = sentence[pos++];
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// no char_spacing after final letter of word!
|
|
|
|
wordWidth -= char_spacing;
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
// 'ch' is now the SPACE or NULL following the word
|
|
|
|
// 'pos' indexes to the position following 'ch'
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
if (firstWord) {
|
|
|
|
// first word on first line, so no separating SPACE
|
|
|
|
// needed
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
line[0].width = wordWidth;
|
|
|
|
line[0].length = wordLength;
|
2003-09-24 06:40:23 +00:00
|
|
|
firstWord = false;
|
2003-09-19 06:42:22 +00:00
|
|
|
} else {
|
|
|
|
// see how much extra space this word will need to
|
|
|
|
// fit on current line (with a separating space
|
|
|
|
// character - also overlapped)
|
|
|
|
|
2003-07-28 01:44:38 +00:00
|
|
|
spaceNeeded = joinWidth + wordWidth;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
if (line[lineNo].width + spaceNeeded <= maxWidth) {
|
|
|
|
// fits this line
|
2003-07-28 01:44:38 +00:00
|
|
|
line[lineNo].width += spaceNeeded;
|
2003-09-19 06:42:22 +00:00
|
|
|
// NB. space+word characters
|
|
|
|
line[lineNo].length += 1 + wordLength;
|
|
|
|
} else {
|
|
|
|
// put word (without separating SPACE) at
|
|
|
|
// start of next line
|
|
|
|
|
|
|
|
// for next _lineInfo structure in the array
|
|
|
|
lineNo++;
|
|
|
|
|
|
|
|
// exception if lineNo >= MAX_LINES
|
|
|
|
// debug_only( lineNo < MAX_LINES );
|
|
|
|
|
2003-07-28 01:44:38 +00:00
|
|
|
line[lineNo].width = wordWidth;
|
|
|
|
line[lineNo].length = wordLength;
|
|
|
|
}
|
|
|
|
}
|
2003-09-19 06:42:22 +00:00
|
|
|
} while (ch);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// return no of lines
|
|
|
|
return lineNo + 1;
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a handle to a floating memory block containing a text sprite, given
|
|
|
|
// a pointer to a null-terminated string, pointer to required character set,
|
|
|
|
// required text pen colour (or zero to use source colours), pointer to the
|
|
|
|
// array of linInfo structures created by 'AnalyseSentence()', and the number
|
|
|
|
// of lines (ie. no. of elements in the 'line' array).
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// PC Version of BuildTextSprite
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
mem* BuildTextSprite(uint8 *sentence, uint32 fontRes, uint8 pen, _lineInfo *line, uint16 noOfLines) {
|
2003-07-28 01:44:38 +00:00
|
|
|
uint8 *linePtr, *spritePtr;
|
2003-09-19 06:42:22 +00:00
|
|
|
uint16 lineNo, pos = 0, posInLine, spriteWidth = 0, spriteHeight;
|
|
|
|
uint16 sizeOfSprite;
|
2003-07-28 01:44:38 +00:00
|
|
|
uint16 charHeight = CharHeight(fontRes);
|
|
|
|
_frameHeader *frameHeadPtr, *charPtr;
|
|
|
|
mem *textSprite;
|
|
|
|
uint8 *charSet;
|
|
|
|
|
|
|
|
// spriteWidth = width of widest line of output text
|
2003-09-19 06:42:22 +00:00
|
|
|
|
|
|
|
for (lineNo = 0; lineNo < noOfLines; lineNo++)
|
|
|
|
if (line[lineNo].width > spriteWidth)
|
2003-07-28 01:44:38 +00:00
|
|
|
spriteWidth = line[lineNo].width;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// spriteHeight = tot height of char lines + tot height of separating
|
|
|
|
// lines
|
|
|
|
|
2003-09-23 06:23:29 +00:00
|
|
|
spriteHeight = charHeight * noOfLines + line_spacing * (noOfLines - 1);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
// total size (no of pixels)
|
|
|
|
sizeOfSprite = spriteWidth * spriteHeight;
|
|
|
|
|
|
|
|
// allocate memory for sprite, and lock it ready for use
|
|
|
|
// NB. 'textSprite' is the given pointer to the handle to be used
|
2003-09-19 06:42:22 +00:00
|
|
|
textSprite = Twalloc(sizeof(_frameHeader) + sizeOfSprite, MEM_locked, UID_text_sprite);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// the handle (*textSprite) now points to UNMOVABLE memory block
|
2003-07-28 01:44:38 +00:00
|
|
|
// set up the frame header
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// point to the start of our memory block
|
|
|
|
frameHeadPtr = (_frameHeader *) textSprite->ad;
|
|
|
|
|
|
|
|
frameHeadPtr->compSize = 0;
|
|
|
|
frameHeadPtr->width = spriteWidth;
|
|
|
|
frameHeadPtr->height = spriteHeight;
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-27 11:02:58 +00:00
|
|
|
debug(5, "spriteWidth=%u", spriteWidth);
|
|
|
|
debug(5, "spriteHeight=%u", spriteHeight);
|
2003-09-19 06:42:22 +00:00
|
|
|
|
|
|
|
// ok, now point to the start (of the first line) of the sprite data
|
|
|
|
// itelf
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
linePtr = textSprite->ad + sizeof(_frameHeader);
|
|
|
|
|
|
|
|
// start with transparent sprite (no colour)
|
2003-09-19 06:42:22 +00:00
|
|
|
memset(linePtr, NO_COL, sizeOfSprite);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// open font file
|
|
|
|
charSet = res_man.Res_open(fontRes);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// fill sprite with characters, one line at a time
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
for(lineNo = 0; lineNo < noOfLines; lineNo++) {
|
|
|
|
// position the start of the line so that it is centred
|
|
|
|
// across the sprite
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
spritePtr = linePtr + (spriteWidth - line[lineNo].width) / 2;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// copy the sprite for each character in this line to the
|
|
|
|
// text sprite and inc the sprite ptr by the character's
|
|
|
|
// width minus the 'overlap'
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-29 06:48:48 +00:00
|
|
|
for (posInLine = 0; posInLine < line[lineNo].length; posInLine++) {
|
2003-09-19 06:42:22 +00:00
|
|
|
charPtr = FindChar(sentence[pos++], charSet);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
#ifdef _SWORD2_DEBUG
|
|
|
|
if (charPtr->height != charHeight)
|
2003-09-27 11:02:58 +00:00
|
|
|
Con_fatal_error("FONT ERROR: '%c' is not same height as the space", sentence[pos - 1]);
|
2003-09-19 06:42:22 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
CopyChar(charPtr, spritePtr, spriteWidth, pen);
|
2003-07-28 01:44:38 +00:00
|
|
|
spritePtr += charPtr->width + char_spacing;
|
|
|
|
}
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// skip space at end of last word in this line
|
|
|
|
pos++;
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
// move to start of next character line in text sprite
|
|
|
|
linePtr += (charHeight + line_spacing) * spriteWidth;
|
|
|
|
}
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// close font file
|
|
|
|
res_man.Res_close(fontRes);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
// unlock the sprite memory block, so it's movable
|
2003-09-19 06:42:22 +00:00
|
|
|
Float_mem(textSprite);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
return textSprite;
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the width of a character sprite, given the character's ASCII code
|
|
|
|
// and a pointer to the start of the character set.
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
uint16 CharWidth(uint8 ch, uint32 fontRes) {
|
2003-07-28 01:44:38 +00:00
|
|
|
_frameHeader *charFrame;
|
|
|
|
uint8 *charSet;
|
|
|
|
uint16 width;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// open font file
|
|
|
|
charSet = res_man.Res_open(fontRes);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// move to approp. sprite (header)
|
|
|
|
charFrame = FindChar(ch, charSet);
|
2003-07-28 01:44:38 +00:00
|
|
|
width = charFrame->width;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// close font file
|
|
|
|
res_man.Res_close(fontRes);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// return its width
|
|
|
|
return width;
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
2003-09-19 06:42:22 +00:00
|
|
|
|
2003-07-28 01:44:38 +00:00
|
|
|
// Returns the height of a character sprite, given the character's ASCII code
|
|
|
|
// and a pointer to the start of the character set.
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
uint16 CharHeight(uint32 fontRes) {
|
2003-07-28 01:44:38 +00:00
|
|
|
_frameHeader *charFrame;
|
|
|
|
uint8 *charSet;
|
|
|
|
uint16 height;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// open font file
|
|
|
|
charSet = res_man.Res_open(fontRes);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// assume all chars the same height, i.e. FIRST_CHAR is as good as any
|
|
|
|
charFrame = FindChar(FIRST_CHAR, charSet);
|
2003-07-28 01:44:38 +00:00
|
|
|
height = charFrame->height;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// close font file
|
|
|
|
res_man.Res_close(fontRes);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// return its height
|
|
|
|
return height;
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
2003-09-19 06:42:22 +00:00
|
|
|
|
2003-07-28 01:44:38 +00:00
|
|
|
// Returns a pointer to the header of a character sprite, given the character's
|
|
|
|
// ASCII code and a pointer to the start of the character set.
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
_frameHeader* FindChar(uint8 ch, uint8 *charSet) {
|
|
|
|
// if 'ch' out of range, print the 'dud' character (chequered flag)
|
|
|
|
if (ch < FIRST_CHAR)
|
|
|
|
ch = DUD;
|
|
|
|
|
|
|
|
return FetchFrameHeader(charSet, ch - FIRST_CHAR);
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
2003-09-19 06:42:22 +00:00
|
|
|
|
2003-07-28 01:44:38 +00:00
|
|
|
// Copies a character sprite from 'charPtr' to the sprite buffer at 'spritePtr'
|
|
|
|
// of width 'spriteWidth'. If pen is zero, it copies the data across directly,
|
2003-09-19 06:42:22 +00:00
|
|
|
// otherwise it maps pixels of BORDER_COL to 'border_pen', and LETTER_COL to
|
|
|
|
// 'pen'.
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
void CopyChar(_frameHeader *charPtr, uint8 *spritePtr, uint16 spriteWidth, uint8 pen) {
|
2003-07-28 01:44:38 +00:00
|
|
|
uint8 *rowPtr, *source, *dest;
|
|
|
|
uint16 rows, cols;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// now pts to sprite data for char 'ch'
|
|
|
|
source = (uint8 *) charPtr + sizeof(_frameHeader);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// pts to start of first row of char within text sprite
|
|
|
|
rowPtr = spritePtr;
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
for (rows = 0; rows < charPtr->height; rows++) {
|
|
|
|
// start at beginning of row
|
|
|
|
dest = rowPtr;
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// if required output pen is non-zero
|
|
|
|
if (pen) {
|
2003-09-21 16:11:26 +00:00
|
|
|
for (cols = 0; cols < charPtr->width; cols++) {
|
2003-09-19 06:42:22 +00:00
|
|
|
// inc source ptr along sprite data
|
|
|
|
switch (*source++) {
|
2003-09-21 16:11:26 +00:00
|
|
|
case LETTER_COL:
|
|
|
|
*dest = pen;
|
|
|
|
break;
|
|
|
|
case BORDER_COL:
|
|
|
|
// don't do a border pixel if there's
|
|
|
|
// already a bit of another character
|
|
|
|
// underneath (for overlapping!)
|
|
|
|
|
|
|
|
if (!*dest)
|
|
|
|
*dest = border_pen;
|
|
|
|
break;
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// do nothing if source pixel is zero,
|
|
|
|
// ie. transparent
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// inc dest ptr to next pixel along row
|
|
|
|
dest++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// pen is zero, so just copy character sprites
|
|
|
|
// directly into text sprite without remapping colours
|
|
|
|
memcpy(dest, source, charPtr->width);
|
2003-07-28 01:44:38 +00:00
|
|
|
source += charPtr->width;
|
|
|
|
}
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// next row down (add width of text sprite)
|
|
|
|
rowPtr += spriteWidth;
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
|
|
|
}
|
2003-09-19 06:42:22 +00:00
|
|
|
|
2003-07-30 19:25:31 +00:00
|
|
|
#ifdef _SWORD2_DEBUG
|
2003-09-19 06:42:22 +00:00
|
|
|
// allow enough for all the debug text blocks (see debug.cpp)
|
|
|
|
#define MAX_text_blocs MAX_DEBUG_TEXT_BLOCKS + 1
|
2003-07-28 01:44:38 +00:00
|
|
|
#else
|
2003-09-19 06:42:22 +00:00
|
|
|
// only need one for speech, and possibly one for "PAUSED"
|
|
|
|
#define MAX_text_blocs 2
|
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
int16 x;
|
|
|
|
int16 y;
|
|
|
|
// RDSPR_ status bits - see defintion of _spriteInfo structure for
|
|
|
|
// correct size!
|
|
|
|
uint16 type;
|
|
|
|
mem *text_mem;
|
2003-07-28 01:44:38 +00:00
|
|
|
} text_bloc;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
text_bloc text_sprite_list[MAX_text_blocs];
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
void Init_text_bloc_system(void) { //Tony16Oct96
|
|
|
|
for (int j = 0; j < MAX_text_blocs; j++)
|
|
|
|
text_sprite_list[j].text_mem = 0;
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// distance to keep speech text from edges of screen
|
|
|
|
#define TEXT_MARGIN 12
|
|
|
|
|
|
|
|
// creates a text bloc in the list and returns the bloc number the list of
|
|
|
|
// blocs are read and blitted at render time choose alignment type
|
|
|
|
// RDSPR_DISPLAYALIGN or 0
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-26 10:07:18 +00:00
|
|
|
uint32 Build_new_block(uint8 *ascii, int16 x, int16 y, uint16 width, uint8 pen, uint32 type, uint32 fontRes, uint8 justification) {
|
2003-09-19 06:42:22 +00:00
|
|
|
uint32 j = 0;
|
2003-07-28 01:44:38 +00:00
|
|
|
_frameHeader *frame_head;
|
|
|
|
int16 text_left_margin;
|
|
|
|
int16 text_right_margin;
|
|
|
|
int16 text_top_margin;
|
|
|
|
int16 text_bottom_margin;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// find a free slot
|
|
|
|
while(j < MAX_text_blocs && text_sprite_list[j].text_mem)
|
2003-07-28 01:44:38 +00:00
|
|
|
j++;
|
|
|
|
|
2003-07-30 19:25:31 +00:00
|
|
|
#ifdef _SWORD2_DEBUG
|
2003-09-19 06:42:22 +00:00
|
|
|
// we've run out - might as well stop the system
|
|
|
|
if (j == MAX_text_blocs)
|
2003-09-27 11:02:58 +00:00
|
|
|
Con_fatal_error("Build_new_block ran out of blocks!");
|
2003-07-28 01:44:38 +00:00
|
|
|
#endif
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// make the sprite!
|
|
|
|
text_sprite_list[j].text_mem = MakeTextSprite(ascii, width, pen, fontRes);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
// speech to be centred above point (x,y), but kept on-screen
|
|
|
|
// where (x,y) is a point somewhere just above the talker's head
|
|
|
|
|
|
|
|
// debug text just to be printed normally from point (x,y)
|
|
|
|
|
|
|
|
// JUSTIFICATION & POSITIONING (James updated 20jun97)
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// 'NO_JUSTIFICATION' means print sprite with top-left at (x,y)
|
|
|
|
// without margin checking - used for debug text
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
if (justification != NO_JUSTIFICATION) {
|
|
|
|
frame_head = (_frameHeader *) text_sprite_list[j].text_mem->ad;
|
|
|
|
|
|
|
|
switch (justification) {
|
2003-09-21 16:11:26 +00:00
|
|
|
// this one is always used for SPEECH TEXT; possibly
|
|
|
|
// also for pointer text
|
|
|
|
case POSITION_AT_CENTRE_OF_BASE:
|
|
|
|
x -= (frame_head->width) / 2;
|
|
|
|
y -= frame_head->height;
|
|
|
|
break;
|
|
|
|
case POSITION_AT_CENTRE_OF_TOP:
|
|
|
|
x -= (frame_head->width) / 2;
|
|
|
|
break;
|
|
|
|
case POSITION_AT_LEFT_OF_TOP:
|
|
|
|
// the given coords are already correct for this!
|
|
|
|
break;
|
|
|
|
case POSITION_AT_RIGHT_OF_TOP:
|
|
|
|
x -= frame_head->width;
|
|
|
|
break;
|
|
|
|
case POSITION_AT_LEFT_OF_BASE:
|
|
|
|
y -= frame_head->height;
|
|
|
|
break;
|
|
|
|
case POSITION_AT_RIGHT_OF_BASE:
|
|
|
|
x -= frame_head->width;
|
|
|
|
y -= frame_head->height;
|
|
|
|
break;
|
|
|
|
case POSITION_AT_LEFT_OF_CENTRE:
|
|
|
|
y -= (frame_head->height) / 2;
|
|
|
|
break;
|
|
|
|
case POSITION_AT_RIGHT_OF_CENTRE:
|
|
|
|
x -= frame_head->width;
|
|
|
|
y -= (frame_head->height) / 2;
|
|
|
|
break;
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ensure text sprite is a few pixels inside the visible screen
|
2003-09-19 06:42:22 +00:00
|
|
|
// remember - it's RDSPR_DISPLAYALIGN
|
|
|
|
|
|
|
|
text_left_margin = TEXT_MARGIN;
|
|
|
|
text_right_margin = 640 - TEXT_MARGIN - frame_head->width;
|
|
|
|
text_top_margin = TEXT_MARGIN;
|
|
|
|
text_bottom_margin = 400 - TEXT_MARGIN - frame_head->height;
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// move if too far left or too far right
|
|
|
|
|
|
|
|
if (x < text_left_margin)
|
2003-07-28 01:44:38 +00:00
|
|
|
x = text_left_margin;
|
|
|
|
else if (x > text_right_margin)
|
|
|
|
x = text_right_margin;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// move if too high or too low
|
|
|
|
|
|
|
|
if (y < text_top_margin)
|
2003-07-28 01:44:38 +00:00
|
|
|
y = text_top_margin;
|
|
|
|
else if (y > text_bottom_margin)
|
|
|
|
y = text_bottom_margin;
|
|
|
|
}
|
|
|
|
|
|
|
|
text_sprite_list[j].x = x;
|
|
|
|
text_sprite_list[j].y = y;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// always uncompressed
|
|
|
|
text_sprite_list[j].type = type | RDSPR_NOCOMPRESSION;
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
return j + 1;
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
|
|
|
|
2003-09-26 10:07:18 +00:00
|
|
|
void Print_text_blocs(void) {
|
2003-09-19 06:42:22 +00:00
|
|
|
//called by build_display
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
_frameHeader *frame;
|
2003-09-19 06:42:22 +00:00
|
|
|
_spriteInfo spriteInfo;
|
|
|
|
uint32 rv;
|
|
|
|
uint32 j;
|
|
|
|
|
|
|
|
for (j = 0; j < MAX_text_blocs; j++) {
|
|
|
|
if (text_sprite_list[j].text_mem) {
|
2003-07-28 01:44:38 +00:00
|
|
|
frame = (_frameHeader*) text_sprite_list[j].text_mem->ad;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
spriteInfo.x = text_sprite_list[j].x;
|
|
|
|
spriteInfo.y = text_sprite_list[j].y;
|
|
|
|
spriteInfo.w = frame->width;
|
|
|
|
spriteInfo.h = frame->height;
|
|
|
|
spriteInfo.scale = 0;
|
|
|
|
spriteInfo.scaledWidth = 0;
|
|
|
|
spriteInfo.scaledHeight = 0;
|
|
|
|
spriteInfo.type = text_sprite_list[j].type;
|
|
|
|
spriteInfo.blend = 0;
|
|
|
|
spriteInfo.data = text_sprite_list[j].text_mem->ad + sizeof(_frameHeader);
|
|
|
|
spriteInfo.colourTable = 0;
|
|
|
|
|
|
|
|
rv = DrawSprite(&spriteInfo);
|
2003-07-28 01:44:38 +00:00
|
|
|
if (rv)
|
2003-09-27 11:02:58 +00:00
|
|
|
error("Driver Error %.8x in Print_text_blocs", rv);
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-09-26 10:07:18 +00:00
|
|
|
void Kill_text_bloc(uint32 bloc_number) {
|
2003-09-19 06:42:22 +00:00
|
|
|
//back to real
|
|
|
|
bloc_number--;
|
|
|
|
|
|
|
|
if (text_sprite_list[bloc_number].text_mem) {
|
|
|
|
// release the floating memory and mark it as free
|
|
|
|
Free_mem(text_sprite_list[bloc_number].text_mem);
|
|
|
|
text_sprite_list[bloc_number].text_mem = 0;
|
|
|
|
} else {
|
|
|
|
// illegal kill - stop the system
|
|
|
|
Con_fatal_error("closing closed text bloc number %d", bloc_number);
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// called from InitialiseGame() in sword2.cpp
|
2003-09-19 06:42:22 +00:00
|
|
|
|
|
|
|
// resource 3258 contains text from location script for 152 (install, save &
|
|
|
|
// restore text, etc)
|
|
|
|
|
|
|
|
#define TEXT_RES 3258
|
|
|
|
|
|
|
|
// local line number of "save" (actor no. 1826)
|
|
|
|
|
|
|
|
#define SAVE_LINE_NO 1
|
|
|
|
|
2003-09-26 10:07:18 +00:00
|
|
|
void InitialiseFontResourceFlags(void) {
|
2003-07-28 01:44:38 +00:00
|
|
|
uint8 *textFile, *textLine;
|
|
|
|
uint8 language;
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// open the text resource
|
|
|
|
textFile = res_man.Res_open(TEXT_RES);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// If language is Polish or Finnish it requires alternate fonts.
|
|
|
|
// Otherwise, use regular fonts
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// get the text line (& skip the 2 chars containing the wavId)
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
textLine = FetchTextLine(textFile, SAVE_LINE_NO) + 2;
|
2003-07-28 01:44:38 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// "talenna" Finnish for "save"
|
|
|
|
// "zapisz" Polish for "save"
|
|
|
|
|
|
|
|
if (strcmp((char*) textLine, "tallenna") == 0)
|
|
|
|
language = FINNISH_TEXT;
|
|
|
|
else if (strcmp((char*) textLine, "zapisz") == 0)
|
|
|
|
language = POLISH_TEXT;
|
|
|
|
else
|
|
|
|
language = DEFAULT_TEXT;
|
|
|
|
|
|
|
|
// Set the game to use the appropriate fonts
|
|
|
|
InitialiseFontResourceFlags(language);
|
2003-07-28 01:44:38 +00:00
|
|
|
|
|
|
|
// Get the game name for the windows application
|
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// FIXME: Since SetWindowName() is stubbed, this doesn't actually do
|
|
|
|
// anything at the moment. Should it be removed?
|
|
|
|
|
|
|
|
// Get the text line - skip the 2 chars containing the wavId
|
|
|
|
|
2003-07-30 19:25:31 +00:00
|
|
|
if (g_sword2->_gameId == GID_SWORD2_DEMO)
|
2003-09-19 06:42:22 +00:00
|
|
|
textLine = FetchTextLine(textFile, 451) + 2;
|
2003-07-28 07:00:15 +00:00
|
|
|
else
|
2003-09-19 06:42:22 +00:00
|
|
|
textLine = FetchTextLine(textFile, 54) + 2;
|
|
|
|
|
|
|
|
SetWindowName((char*) textLine);
|
2003-07-28 07:00:15 +00:00
|
|
|
|
2003-09-19 06:42:22 +00:00
|
|
|
// now ok to close the text file
|
|
|
|
res_man.Res_close(TEXT_RES);
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
2003-09-19 06:42:22 +00:00
|
|
|
|
2003-07-28 01:44:38 +00:00
|
|
|
// called from the above function, and also from console.cpp
|
2003-09-19 06:42:22 +00:00
|
|
|
|
2003-09-26 10:07:18 +00:00
|
|
|
void InitialiseFontResourceFlags(uint8 language) {
|
2003-09-19 06:42:22 +00:00
|
|
|
switch (language) {
|
2003-09-21 16:11:26 +00:00
|
|
|
case FINNISH_TEXT: // special Finnish fonts
|
|
|
|
speech_font_id = FINNISH_SPEECH_FONT_ID;
|
|
|
|
controls_font_id = FINNISH_CONTROLS_FONT_ID;
|
|
|
|
red_font_id = FINNISH_RED_FONT_ID;
|
|
|
|
break;
|
|
|
|
case POLISH_TEXT: // special Polish fonts
|
|
|
|
speech_font_id = POLISH_SPEECH_FONT_ID;
|
|
|
|
controls_font_id = POLISH_CONTROLS_FONT_ID;
|
|
|
|
red_font_id = POLISH_RED_FONT_ID;
|
|
|
|
break;
|
|
|
|
default: // DEFAULT_TEXT - regular fonts
|
|
|
|
speech_font_id = ENGLISH_SPEECH_FONT_ID;
|
|
|
|
controls_font_id = ENGLISH_CONTROLS_FONT_ID;
|
|
|
|
red_font_id = ENGLISH_RED_FONT_ID;
|
|
|
|
break;
|
2003-07-28 01:44:38 +00:00
|
|
|
}
|
|
|
|
}
|