//adds text to full screen video void addVideoText(SEQ_DISPLAY *psSeqDisplay, UDWORD sequence) { UDWORD i, x, y; if (psSeqDisplay->numText > 0) { debug( LOG_NEVER, "avt seq=%d [%s]\n", sequence, psSeqDisplay->ppTextMsg[0] ); //add each message, first at the top // FIXME We should perhaps get font size, and use that to calculate offset(s) ? x = VIDEO_TEXT_TOP_X; y = VIDEO_TEXT_TOP_Y; seq_AddTextForVideo(psSeqDisplay->ppTextMsg[0], x, y, TEXT_START_FRAME, TEXT_END_FRAME, SEQ_TEXT_POSITION); //startframe endFrame //add each message, the rest at the bottom x = VIDEO_TEXT_BOTTOM_X; // calculate the real bottom... NOTE, game assumes all videos to be 640x480 y = (double)pie_GetVideoBufferHeight() / 480. * (double)VIDEO_TEXT_BOTTOM_Y; i = 1; while (i < psSeqDisplay->numText) { seq_AddTextForVideo(psSeqDisplay->ppTextMsg[i], x, y, TEXT_START_FRAME, TEXT_END_FRAME, SEQ_TEXT_POSITION); //startframe endFrame //initialise after the first setting x = y = 0; i++; } } }
static bool seq_AddTextFromFile(const char *pTextName, SEQ_TEXT_POSITIONING textJustification) { char aTextName[MAX_STR_LENGTH]; char *pTextBuffer, *pCurrentLine, *pText; UDWORD fileSize; SDWORD xOffset, yOffset; double startTime, endTime; const char *seps = "\n"; // NOTE: The original game never had a fullscreen mode for FMVs on >640x480 screens. // They would just use double sized videos, and move the text to that area. // We just use the full screen for text right now, instead of using offsets. // However, depending on reaction, we may use the old style again. D_H2 = 0; //( pie_GetVideoBufferHeight()- 480)/2; D_W2 = 0; //( pie_GetVideoBufferWidth() - 640)/2; ssprintf(aTextName, "sequenceaudio/%s", pTextName); if (loadFileToBufferNoError(aTextName, fileLoadBuffer, FILE_LOAD_BUFFER_SIZE, &fileSize) == false) //Did I mention this is lame? -Q { return false; } pTextBuffer = fileLoadBuffer; pCurrentLine = strtok(pTextBuffer, seps); while (pCurrentLine != NULL) { if (*pCurrentLine != '/') { if (sscanf(pCurrentLine, "%d %d %lf %lf", &xOffset, &yOffset, &startTime, &endTime) == 4) { // Since all the positioning was hardcoded to specific values, we now calculate the // ratio of our screen, compared to what the game expects and multiply that to x, y. // This makes the text always take up the full screen, instead of original style. xOffset = (double)pie_GetVideoBufferWidth() / 640. * (double)xOffset; yOffset = (double)pie_GetVideoBufferHeight() / 480. * (double)yOffset; //get the text pText = strrchr(pCurrentLine, '"'); ASSERT(pText != NULL, "error parsing text file"); if (pText != NULL) { *pText = (UBYTE)0; } pText = strchr(pCurrentLine, '"'); ASSERT(pText != NULL, "error parsing text file"); if (pText != NULL) { seq_AddTextForVideo(_(&pText[1]), xOffset, yOffset, startTime, endTime, textJustification); } } } //get next line pCurrentLine = strtok(NULL, seps); } return true; }
// add a string at x,y or add string below last line if x and y are 0 bool seq_AddTextForVideo(const char *pText, SDWORD xOffset, SDWORD yOffset, double startTime, double endTime, SEQ_TEXT_POSITIONING textJustification) { SDWORD sourceLength, currentLength; char *currentText; static SDWORD lastX; // make sure we take xOffset into account, we don't always start at 0 const unsigned int buffer_width = pie_GetVideoBufferWidth() - xOffset; iV_SetFont(font_scaled); ASSERT(aSeqList[currentSeq].currentText < MAX_TEXT_OVERLAYS, "too many text lines"); sourceLength = strlen(pText); currentLength = sourceLength; currentText = &(aSeqList[currentSeq].aText[aSeqList[currentSeq].currentText].pText[0]); //if the string is bigger than the buffer get the last end of the last fullword in the buffer if (currentLength >= MAX_STR_LENGTH) { currentLength = MAX_STR_LENGTH - 1; //get end of the last word while ((pText[currentLength] != ' ') && (currentLength > 0)) { currentLength--; } currentLength--; } memcpy(currentText, pText, currentLength); currentText[currentLength] = 0;//terminate the string what ever //check the string is shortenough to print //if not take a word of the end and try again while (iV_GetTextWidth(currentText) > buffer_width) { currentLength--; while ((pText[currentLength] != ' ') && (currentLength > 0)) { currentLength--; } currentText[currentLength] = 0;//terminate the string what ever } currentText[currentLength] = 0;//terminate the string what ever //check if x and y are 0 and put text on next line if (((xOffset == 0) && (yOffset == 0)) && (currentLength > 0)) { aSeqList[currentSeq].aText[aSeqList[currentSeq].currentText].x = lastX; aSeqList[currentSeq].aText[aSeqList[currentSeq].currentText].y = aSeqList[currentSeq].aText[aSeqList[currentSeq].currentText - 1].y + iV_GetTextLineSize(); } else { aSeqList[currentSeq].aText[aSeqList[currentSeq].currentText].x = xOffset + D_W2; aSeqList[currentSeq].aText[aSeqList[currentSeq].currentText].y = yOffset + D_H2; } lastX = aSeqList[currentSeq].aText[aSeqList[currentSeq].currentText].x; if (textJustification && currentLength == sourceLength) { static const int MIN_JUSTIFICATION = 40; static const int FOLLOW_ON_JUSTIFICATION = 160; //justify this text const int justification = buffer_width - iV_GetTextWidth(currentText); if (textJustification == SEQ_TEXT_JUSTIFY && justification > MIN_JUSTIFICATION) { aSeqList[currentSeq].aText[aSeqList[currentSeq].currentText].x += (justification / 2); } else if (textJustification == SEQ_TEXT_FOLLOW_ON && justification > FOLLOW_ON_JUSTIFICATION) { } } //set start and finish times for the objects aSeqList[currentSeq].aText[aSeqList[currentSeq].currentText].startTime = startTime; aSeqList[currentSeq].aText[aSeqList[currentSeq].currentText].endTime = endTime; aSeqList[currentSeq].aText[aSeqList[currentSeq].currentText].bSubtitle = textJustification; aSeqList[currentSeq].currentText++; if (aSeqList[currentSeq].currentText >= MAX_TEXT_OVERLAYS) { aSeqList[currentSeq].currentText = 0; } //check text is okay on the screen if (currentLength < sourceLength) { //RECURSE x= 0 y = 0 for nextLine if (textJustification == SEQ_TEXT_JUSTIFY) { textJustification = SEQ_TEXT_POSITION; } seq_AddTextForVideo(&pText[currentLength + 1], 0, 0, startTime, endTime, textJustification); } return true; }