void CG_Credits_Init( LPCSTR psStripReference, vec4_t *pv4Color) { // could make these into parameters later, but for now... // ghFontHandle = cgs.media.qhFontMedium; gfFontScale = 1.0f; memcpy(gv4Color,pv4Color,sizeof(gv4Color)); // memcpy so we can poke into alpha channel // first, ask the strlen of the final string... // int iStrLen = cgi_SP_GetStringTextString( psStripReference, NULL, 0 ); if (!iStrLen) { #ifndef FINAL_BUILD Com_Printf("WARNING: CG_Credits_Init(): invalid text key :'%s'\n", psStripReference); #endif return; } // // malloc space to hold it... // char *psMallocText = (char *) cgi_Z_Malloc( iStrLen+1, TAG_TEMP_WORKSPACE ); // // now get the string... // iStrLen = cgi_SP_GetStringTextString( psStripReference, psMallocText, iStrLen+1 ); //ensure we found a match if (!iStrLen) { assert(0); // should never get here now, but wtf? cgi_Z_Free(psMallocText); #ifndef FINAL_BUILD Com_Printf("WARNING: CG_Credits_Init(): invalid text key :'%s'\n", psStripReference); #endif return; } // read whole string in and process as cards, lines etc... // typedef enum { eNothing = 0, eLine, eDotEntry, eTitle, eCard, eFinished, } Mode_e; Mode_e eMode = eNothing; qboolean bCardsFinished = qfalse; int iLineNumber = 0; const char *psTextParse = psMallocText; while (*psTextParse != NULL) { // read a line... // char sLine[MAX_LINE_BYTES]; sLine[0]='\0'; qboolean bWasCommand = qtrue; while (1) { qboolean bIsTrailingPunctuation; unsigned int uiLetter = cgi_AnyLanguage_ReadCharFromString(&psTextParse, &bIsTrailingPunctuation); // concat onto string so far... // if (uiLetter == 32 && sLine[0] == '\0') { continue; // unless it's a space at the start of a line, in which case ignore it. } if (uiLetter == '\n' || uiLetter == '\0' ) { // have we got a command word?... // if (!Q_stricmpn(sLine,"(#",2)) { // yep... // if (!stricmp(sLine, "(#CARD)")) { if (!bCardsFinished) { eMode = eCard; } else { #ifndef FINAL_BUILD Com_Printf( S_COLOR_YELLOW "CG_Credits_Init(): No current support for cards after scroll!\n" ); #endif eMode = eNothing; } break; } else if (!stricmp(sLine, "(#TITLE)")) { eMode = eTitle; bCardsFinished = qtrue; break; } else if (!stricmp(sLine, "(#LINE)")) { eMode = eLine; bCardsFinished = qtrue; break; } else if (!stricmp(sLine, "(#DOTENTRY)")) { eMode = eDotEntry; bCardsFinished = qtrue; break; } else { #ifndef FINAL_BUILD Com_Printf( S_COLOR_YELLOW "CG_Credits_Init(): bad keyword \"%s\"!\n", sLine ); #endif eMode = eNothing; } } else { // I guess not... // bWasCommand = qfalse; break; } } else { // must be a letter... // if (uiLetter > 255) { Q_strcat(sLine, sizeof(sLine), va("%c%c",uiLetter >> 8, uiLetter & 0xFF)); } else { Q_strcat(sLine, sizeof(sLine), va("%c",uiLetter & 0xFF)); } } }
// display text in a supplied box, start at top left and going down by however many pixels I feel like internally, // return value is NULL if all fitted, else char * of next char to continue from that didn't fit. // // (coords are in the usual 640x480 virtual space)... // // ( if you get the same char * returned as what you passed in, then none of it fitted at all (box too small) ) // const char *CG_DisplayBoxedText(int iBoxX, int iBoxY, int iBoxWidth, int iBoxHeight, const char *psText, int iFontHandle, float fScale, const vec4_t v4Color) { cgi_R_SetColor( v4Color ); // Setup a reasonable vertical spacing (taiwanese & japanese need 1.5 fontheight, so use that for all)... // const int iFontHeight = cgi_R_Font_HeightPixels(iFontHandle, fScale); const int iFontHeightAdvance = (int) (1.5f * (float) iFontHeight); int iYpos = iBoxY; // start print pos // findmeste // test stuff, remove later // psText = "賽卓哥爾博士已經安全了,我也把所有發現報告給「商店」。很不幸地,瑞士警局有些白癡發現了一些狀況,準備在機場逮捕亞歷西•納克瑞得。他偽裝成外交使節,穿過了層層防備。現在他握有人質,並且威脅要散播病毒。根據最搆sCurrentTextReadPos的報告,納克瑞得以及他的黨羽已經完全佔據了機場。我受命來追捕納克瑞得以及救出所有人質。這並不容易。"; // this could probably be simplified now, but it was converted from something else I didn't originally write, // and it works anyway so wtf... // const char *psCurrentTextReadPos = psText; const char *psReadPosAtLineStart = psCurrentTextReadPos; const char *psBestLineBreakSrcPos = psCurrentTextReadPos; const char *psLastGood_s; // needed if we get a full screen of chars with no punctuation or space (see usage notes) while( *psCurrentTextReadPos && (iYpos + iFontHeight < (iBoxY + iBoxHeight)) ) { char sLineForDisplay[2048]; // ott // construct a line... // psCurrentTextReadPos = psReadPosAtLineStart; sLineForDisplay[0] = '\0'; while ( *psCurrentTextReadPos ) { psLastGood_s = psCurrentTextReadPos; // read letter... // qboolean bIsTrailingPunctuation; unsigned int uiLetter = cgi_AnyLanguage_ReadCharFromString(&psCurrentTextReadPos, &bIsTrailingPunctuation); // concat onto string so far... // if (uiLetter == 32 && sLineForDisplay[0] == '\0') { psReadPosAtLineStart++; continue; // unless it's a space at the start of a line, in which case ignore it. } if (uiLetter > 255) { Q_strcat(sLineForDisplay, sizeof(sLineForDisplay),va("%c%c",uiLetter >> 8, uiLetter & 0xFF)); } else { Q_strcat(sLineForDisplay, sizeof(sLineForDisplay),va("%c",uiLetter & 0xFF)); } if (uiLetter == '\n') { // explicit new line... // sLineForDisplay[ strlen(sLineForDisplay)-1 ] = '\0'; // kill the CR psReadPosAtLineStart = psCurrentTextReadPos; psBestLineBreakSrcPos = psCurrentTextReadPos; break; // print this line } else if ( cgi_R_Font_StrLenPixels(sLineForDisplay, iFontHandle, fScale) >= iBoxWidth ) { // reached screen edge, so cap off string at bytepos after last good position... // if (uiLetter > 255 && bIsTrailingPunctuation && !cgi_Language_UsesSpaces()) { // Special case, don't consider line breaking if you're on an asian punctuation char of // a language that doesn't use spaces... // } else { if (psBestLineBreakSrcPos == psReadPosAtLineStart) { // aarrrggh!!!!! we'll only get here is someone has fed in a (probably) garbage string, // since it doesn't have a single space or punctuation mark right the way across one line // of the screen. So far, this has only happened in testing when I hardwired a taiwanese // string into this function while the game was running in english (which should NEVER happen // normally). On the other hand I suppose it'psCurrentTextReadPos entirely possible that some taiwanese string // might have no punctuation at all, so... // psBestLineBreakSrcPos = psLastGood_s; // force a break after last good letter } sLineForDisplay[ psBestLineBreakSrcPos - psReadPosAtLineStart ] = '\0'; psReadPosAtLineStart = psCurrentTextReadPos = psBestLineBreakSrcPos; break; // print this line } } // record last-good linebreak pos... (ie if we've just concat'd a punctuation point (western or asian) or space) // if (bIsTrailingPunctuation || uiLetter == ' ' || (uiLetter > 255 && !cgi_Language_UsesSpaces())) { psBestLineBreakSrcPos = psCurrentTextReadPos; } }