1 /*
2 ===========================================================================
3 Copyright (C) 2000 - 2013, Raven Software, Inc.
4 Copyright (C) 2001 - 2013, Activision, Inc.
5 Copyright (C) 2013 - 2015, OpenJK contributors
6
7 This file is part of the OpenJK source code.
8
9 OpenJK is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 ===========================================================================
21 */
22
23 // cg_text.c --
24
25 // this line must stay at top so the whole PCH thing works...
26 #include "cg_headers.h"
27
28 #include "cg_media.h"
29
30
31 //int precacheWav_i; // Current high index of precacheWav array
32 //precacheWav_t precacheWav[MAX_PRECACHEWAV];
33
34
35 //int precacheText_i; // Current high index of precacheText array
36 //precacheText_t precacheText[MAX_PRECACHETEXT];
37
38
39 extern vec4_t textcolor_caption;
40 extern vec4_t textcolor_center;
41 extern vec4_t textcolor_scroll;
42
43
44 // display text in a supplied box, start at top left and going down by however many pixels I feel like internally,
45 // return value is NULL if all fitted, else char * of next char to continue from that didn't fit.
46 //
47 // (coords are in the usual 640x480 virtual space)...
48 //
49 // ( if you get the same char * returned as what you passed in, then none of it fitted at all (box too small) )
50 //
51 // this is execrable, and should NOT have had to've been done now, but...
52 //
53 float gfAdvanceHack = 0.0f; // MUST default to this
54 int giLinesOutput; // hack-city after release, only used by one function
55 //
CG_DisplayBoxedText(int iBoxX,int iBoxY,int iBoxWidth,int iBoxHeight,const char * psText,int iFontHandle,float fScale,const vec4_t v4Color)56 const char *CG_DisplayBoxedText(int iBoxX, int iBoxY, int iBoxWidth, int iBoxHeight,
57 const char *psText, int iFontHandle, float fScale,
58 const vec4_t v4Color)
59 {
60 giLinesOutput = 0;
61 cgi_R_SetColor( v4Color );
62
63 // Setup a reasonable vertical spacing (taiwanese & japanese need 1.5 fontheight, so use that for all)...
64 //
65 const int iFontHeight = cgi_R_Font_HeightPixels(iFontHandle, fScale);
66 const int iFontHeightAdvance = (int) ( ((gfAdvanceHack == 0.0f) ? 1.5f : gfAdvanceHack) * (float) iFontHeight);
67 int iYpos = iBoxY; // start print pos
68
69 // this could probably be simplified now, but it was converted from something else I didn't originally write,
70 // and it works anyway so wtf...
71 //
72 const char *psCurrentTextReadPos = psText;
73 const char *psReadPosAtLineStart = psCurrentTextReadPos;
74 const char *psBestLineBreakSrcPos = psCurrentTextReadPos;
75 const char *psLastGood_s; // needed if we get a full screen of chars with no punctuation or space (see usage notes)
76 while( *psCurrentTextReadPos && (iYpos + iFontHeight < (iBoxY + iBoxHeight)) )
77 {
78 char sLineForDisplay[2048]; // ott
79
80 // construct a line...
81 //
82 psCurrentTextReadPos = psReadPosAtLineStart;
83 sLineForDisplay[0] = '\0';
84 while ( *psCurrentTextReadPos )
85 {
86 psLastGood_s = psCurrentTextReadPos;
87
88 // read letter...
89 //
90 qboolean bIsTrailingPunctuation;
91 int iAdvanceCount;
92 unsigned int uiLetter = cgi_AnyLanguage_ReadCharFromString(psCurrentTextReadPos, &iAdvanceCount, &bIsTrailingPunctuation);
93 psCurrentTextReadPos += iAdvanceCount;
94
95 // concat onto string so far...
96 //
97 if (uiLetter == 32 && sLineForDisplay[0] == '\0')
98 {
99 psReadPosAtLineStart++;
100 continue; // unless it's a space at the start of a line, in which case ignore it.
101 }
102
103 if (uiLetter > 255)
104 {
105 Q_strcat(sLineForDisplay, sizeof(sLineForDisplay),va("%c%c",uiLetter >> 8, uiLetter & 0xFF));
106 }
107 else
108 {
109 Q_strcat(sLineForDisplay, sizeof(sLineForDisplay),va("%c",uiLetter & 0xFF));
110 }
111
112 if (uiLetter == '\n')
113 {
114 // explicit new line...
115 //
116 sLineForDisplay[ strlen(sLineForDisplay)-1 ] = '\0'; // kill the CR
117 psReadPosAtLineStart = psCurrentTextReadPos;
118 psBestLineBreakSrcPos = psCurrentTextReadPos;
119 break; // print this line
120 }
121 else
122 if ( cgi_R_Font_StrLenPixels(sLineForDisplay, iFontHandle, fScale) >= iBoxWidth )
123 {
124 // reached screen edge, so cap off string at bytepos after last good position...
125 //
126 if (uiLetter > 255 && bIsTrailingPunctuation && !cgi_Language_UsesSpaces())
127 {
128 // Special case, don't consider line breaking if you're on an asian punctuation char of
129 // a language that doesn't use spaces...
130 //
131 }
132 else
133 {
134 if (psBestLineBreakSrcPos == psReadPosAtLineStart)
135 {
136 // aarrrggh!!!!! we'll only get here is someone has fed in a (probably) garbage string,
137 // since it doesn't have a single space or punctuation mark right the way across one line
138 // of the screen. So far, this has only happened in testing when I hardwired a taiwanese
139 // string into this function while the game was running in english (which should NEVER happen
140 // normally). On the other hand I suppose it'psCurrentTextReadPos entirely possible that some taiwanese string
141 // might have no punctuation at all, so...
142 //
143 psBestLineBreakSrcPos = psLastGood_s; // force a break after last good letter
144 }
145
146 sLineForDisplay[ psBestLineBreakSrcPos - psReadPosAtLineStart ] = '\0';
147 psReadPosAtLineStart = psCurrentTextReadPos = psBestLineBreakSrcPos;
148 break; // print this line
149 }
150 }
151
152 // record last-good linebreak pos... (ie if we've just concat'd a punctuation point (western or asian) or space)
153 //
154 if (bIsTrailingPunctuation || uiLetter == ' ' || (uiLetter > 255 && !cgi_Language_UsesSpaces()))
155 {
156 psBestLineBreakSrcPos = psCurrentTextReadPos;
157 }
158 }
159
160 // ... and print it...
161 //
162 cgi_R_Font_DrawString(iBoxX, iYpos, sLineForDisplay, v4Color, iFontHandle, -1, fScale);
163 iYpos += iFontHeightAdvance;
164 giLinesOutput++;
165
166 // and echo to console in dev mode...
167 //
168 if ( cg_developer.integer )
169 {
170 // Com_Printf( "%psCurrentTextReadPos\n", sLineForDisplay );
171 }
172 }
173 return psReadPosAtLineStart;
174 }
175
176
177
178 /*
179 ===============================================================================
180
181 CAPTION TEXT
182
183 ===============================================================================
184 */
CG_CaptionTextStop(void)185 void CG_CaptionTextStop(void)
186 {
187 cg.captionTextTime = 0;
188 }
189
190 // try and get the correct StripEd text (with retry) for a given reference...
191 //
192 // returns 0 if failed, else strlen...
193 //
cg_SP_GetStringTextStringWithRetry(const char * psReference,char * psDest,int iSizeofDest)194 static int cg_SP_GetStringTextStringWithRetry( const char *psReference, char *psDest, int iSizeofDest)
195 {
196 int iReturn;
197
198 if (psReference[0] == '#')
199 {
200 // then we know the striped package name is already built in, so do NOT try prepending anything else...
201 //
202 return cgi_SP_GetStringTextString( va("%s",psReference+1), psDest, iSizeofDest );
203 }
204
205 for (int i=0; i<STRIPED_LEVELNAME_VARIATIONS; i++)
206 {
207 if (cgs.stripLevelName[i][0]) // entry present?
208 {
209 iReturn = cgi_SP_GetStringTextString( va("%s_%s",cgs.stripLevelName[i],psReference), psDest, iSizeofDest );
210 if (iReturn)
211 {
212 return iReturn;
213 }
214 }
215 }
216
217 return 0;
218 }
219
220 // slightly confusingly, the char arg for this function is an audio filename of the form "path/path/filename",
221 // the "filename" part of which should be the same as the StripEd reference we're looking for in the current
222 // level's string package...
223 //
CG_CaptionText(const char * str,int sound)224 void CG_CaptionText( const char *str, int sound)
225 {
226 const char *s, *holds;
227 int i;
228 int holdTime;
229 char text[8192]={0};
230
231 const float fFontScale = cgi_Language_IsAsian() ? 0.8f : 1.0f;
232
233 holds = strrchr(str,'/');
234 if (!holds)
235 {
236 #ifndef FINAL_BUILD
237 Com_Printf("WARNING: CG_CaptionText given audio filename with no '/':'%s'\n",str);
238 #endif
239 return;
240 }
241 i = cg_SP_GetStringTextStringWithRetry( holds+1, text, sizeof(text) );
242 //ensure we found a match
243 if (!i)
244 {
245 #ifndef FINAL_BUILD
246 // we only care about some sound dirs...
247 if (!Q_stricmpn(str,"sound/chars/",12)) // whichever language it is, it'll be pathed as english at this point
248 {
249 Com_Printf("WARNING: CG_CaptionText given invalid text key: '%s'\n", str);
250 }
251 else
252 {
253 // anything else is probably stuff we don't care about. It certainly shouldn't be speech, anyway
254 }
255 #endif
256 return;
257 }
258
259 const int fontHeight = (int) ((cgi_Language_IsAsian() ? 1.4f : 1.0f) * (float) cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, fFontScale)); // taiwanese & japanese need 1.5 fontheight spacing
260
261 cg.captionTextTime = cg.time;
262 if (in_camera) {
263 cg.captionTextY = SCREEN_HEIGHT - (client_camera.bar_height_dest/2); // ths is now a centre'd Y, not a start Y
264 } else { //get above the hud
265 cg.captionTextY = (int) (0.88f*((float)SCREEN_HEIGHT - (float)fontHeight * 1.5f)); // do NOT move this, it has to fit in between the weapon HUD and the datapad update.
266 }
267 cg.captionTextCurrentLine = 0;
268
269 // count the number of lines for centering
270 cg.scrollTextLines = 1;
271
272 memset (cg.captionText, 0, sizeof(cg.captionText));
273
274 // Break into individual lines
275 i = 0; // this could be completely removed and replace by "cg.scrollTextLines-1", but wtf?
276
277 s=(const char*)&text;
278 // tai...
279 // s="�ɨ������դh�w�g�w���F�A�ڤ]��Ҧ��o�{���i���u�ө��v�C�ܤ����a�A��hĵ�����ǥ�è�o�{�F�@�Ǫ��p�A�dzƦb�����e���Ⱦ���E�ǧJ��o�C�L���˦��~��ϸ`�A��L�F�h�h���ơC�{�b�L�����H��A�åB�¯٭n�����f�r�C�ھڳ̷s�����i�A�ǧJ��o�H�ΥL���ҦФw�g�������ڤF�����C�ڨ��R�Ӱl���ǧJ��o�H�αϥX�Ҧ��H��C�o�ä��e���C";
280 // kor...
281 // s="Wp:��Ÿ���̴� �ָ�. ���� ���Ѵ�� �װ� ������ ����ϰڴ�.��Ÿ���̴� �ָ�. ���� ���Ѵ�� �װ� ������ ����ϰڴ�.";
282 holds = s;
283
284 int iPlayingTimeMS = cgi_S_GetSampleLength(sound);
285 int iLengthInChars = strlen(s);//cgi_R_Font_StrLenChars(s); // strlen is also good for MBCS in this instance, since it's for timing
286 if (iLengthInChars == 0)
287 {
288 iLengthInChars = 1;
289 }
290 cg.captionLetterTime = iPlayingTimeMS / iLengthInChars;
291
292 const char *psBestLineBreakSrcPos = s;
293 const char *psLastGood_s; // needed if we get a full screen of chars with no punctuation or space (see usage notes)
294 while( *s )
295 {
296 psLastGood_s = s;
297
298 // read letter...
299 //
300 qboolean bIsTrailingPunctuation;
301 int iAdvanceCount;
302 unsigned int uiLetter = cgi_AnyLanguage_ReadCharFromString(s, &iAdvanceCount, &bIsTrailingPunctuation);
303 s += iAdvanceCount;
304
305 // concat onto string so far...
306 //
307 if (uiLetter == 32 && cg.captionText[i][0] == '\0')
308 {
309 holds++;
310 continue; // unless it's a space at the start of a line, in which case ignore it.
311 }
312
313 if (uiLetter > 255)
314 {
315 Q_strcat(cg.captionText[i],sizeof(cg.captionText[i]),va("%c%c",uiLetter >> 8, uiLetter & 0xFF));
316 }
317 else
318 {
319 Q_strcat(cg.captionText[i],sizeof(cg.captionText[i]),va("%c",uiLetter & 0xFF));
320 }
321
322 if (uiLetter == '\n')
323 {
324 // explicit new line...
325 //
326 cg.captionText[i][ strlen(cg.captionText[i])-1 ] = '\0'; // kill the CR
327 i++;
328 holds = s;
329 psBestLineBreakSrcPos = s;
330 cg.scrollTextLines++;
331 }
332 else
333 if ( cgi_R_Font_StrLenPixels(cg.captionText[i], cgs.media.qhFontMedium, fFontScale) >= SCREEN_WIDTH)
334 {
335 // reached screen edge, so cap off string at bytepos after last good position...
336 //
337 if (uiLetter > 255 && bIsTrailingPunctuation && !cgi_Language_UsesSpaces())
338 {
339 // Special case, don't consider line breaking if you're on an asian punctuation char of
340 // a language that doesn't use spaces...
341 //
342 }
343 else
344 {
345 if (psBestLineBreakSrcPos == holds)
346 {
347 // aarrrggh!!!!! we'll only get here is someone has fed in a (probably) garbage string,
348 // since it doesn't have a single space or punctuation mark right the way across one line
349 // of the screen. So far, this has only happened in testing when I hardwired a taiwanese
350 // string into this function while the game was running in english (which should NEVER happen
351 // normally). On the other hand I suppose it's entirely possible that some taiwanese string
352 // might have no punctuation at all, so...
353 //
354 psBestLineBreakSrcPos = psLastGood_s; // force a break after last good letter
355 }
356
357 cg.captionText[i][ psBestLineBreakSrcPos - holds ] = '\0';
358 holds = s = psBestLineBreakSrcPos;
359 i++;
360 cg.scrollTextLines++;
361 }
362 }
363
364 // record last-good linebreak pos... (ie if we've just concat'd a punctuation point (western or asian) or space)
365 //
366 if (bIsTrailingPunctuation || uiLetter == ' ' || (uiLetter > 255 && !cgi_Language_UsesSpaces()))
367 {
368 psBestLineBreakSrcPos = s;
369 }
370 }
371
372
373 // calc the length of time to hold each 2 lines of text on the screen.... presumably this works?
374 //
375 holdTime = strlen(cg.captionText[0]);
376 if (cg.scrollTextLines > 1)
377 {
378 holdTime += strlen(cg.captionText[1]); // strlen is also good for MBCS in this instance, since it's for timing
379 }
380 cg.captionNextTextTime = cg.time + (holdTime * cg.captionLetterTime);
381
382 cg.scrollTextTime = 0; // No scrolling during captions
383
384 //Echo to console in dev mode
385 if ( cg_developer.integer )
386 {
387 Com_Printf( "%s\n", cg.captionText[0] ); // ste: was [i], but surely sentence 0 is more useful than last?
388 }
389 }
390
391
CG_DrawCaptionText(void)392 void CG_DrawCaptionText(void)
393 {
394 int i;
395 int x, y, w;
396 int holdTime;
397
398 if ( !cg.captionTextTime )
399 {
400 return;
401 }
402
403 const float fFontScale = cgi_Language_IsAsian() ? 0.8f : 1.0f;
404
405 if (cg_skippingcin.integer != 0)
406 {
407 cg.captionTextTime = 0;
408 return;
409 }
410
411 if ( cg.captionNextTextTime < cg.time )
412 {
413 cg.captionTextCurrentLine += 2;
414
415 if (cg.captionTextCurrentLine >= cg.scrollTextLines)
416 {
417 cg.captionTextTime = 0;
418 return;
419 }
420 else
421 {
422 holdTime = strlen(cg.captionText[cg.captionTextCurrentLine]);
423 if (cg.scrollTextLines >= cg.captionTextCurrentLine)
424 {
425 // ( strlen is also good for MBCS in this instance, since it's for timing -ste)
426 //
427 holdTime += strlen(cg.captionText[cg.captionTextCurrentLine + 1]);
428 }
429
430 cg.captionNextTextTime = cg.time + (holdTime * cg.captionLetterTime);//50);
431 }
432 }
433
434 // Give a color if one wasn't given
435 if((textcolor_caption[0] == 0) && (textcolor_caption[1] == 0) &&
436 (textcolor_caption[2] == 0) && (textcolor_caption[3] == 0))
437 {
438 VectorCopy4( colorTable[CT_WHITE], textcolor_caption );
439 }
440
441 cgi_R_SetColor(textcolor_caption);
442
443 // Set Y of the first line (varies if only printing one line of text)
444 // (this all works, please don't mess with it)
445 const int fontHeight = (int) ((cgi_Language_IsAsian() ? 1.4f : 1.0f) * (float) cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, fFontScale));
446 const bool bPrinting2Lines = !!(cg.captionText[ cg.captionTextCurrentLine+1 ][0]);
447 y = cg.captionTextY - ( (float)fontHeight * (bPrinting2Lines ? 1 : 0.5f)); // captionTextY was a centered Y pos, not a top one
448 y -= cgi_Language_IsAsian() ? 0 : 4;
449
450 for (i= cg.captionTextCurrentLine;i< cg.captionTextCurrentLine + 2;++i)
451 {
452 w = cgi_R_Font_StrLenPixels(cg.captionText[i], cgs.media.qhFontMedium, fFontScale);
453 if (w)
454 {
455 x = (SCREEN_WIDTH-w) / 2;
456 cgi_R_Font_DrawString(x, y, cg.captionText[i], textcolor_caption, cgs.media.qhFontMedium, -1, fFontScale);
457 y += fontHeight;
458 }
459 }
460
461 cgi_R_SetColor( NULL );
462 }
463
464 /*
465 ===============================================================================
466
467 SCROLL TEXT
468
469 ===============================================================================
470
471 CG_ScrollText - split text up into seperate lines
472
473 'str' arg is StripEd string reference, eg "CREDITS_RAVEN"
474
475 */
476 int giScrollTextPixelWidth = SCREEN_WIDTH;
CG_ScrollText(const char * str,int iPixelWidth)477 void CG_ScrollText( const char *str, int iPixelWidth )
478 {
479 const char *s,*holds;
480 int i;//, len;//, numChars;
481
482 giScrollTextPixelWidth = iPixelWidth;
483
484 // first, ask the strlen of the final string...
485 //
486 i = cgi_SP_GetStringTextString( str, NULL, 0 );
487
488 //ensure we found a match
489 if (!i)
490 {
491 #ifndef FINAL_BUILD
492 Com_Printf("WARNING: CG_ScrollText given invalid text key :'%s'\n",str);
493 #endif
494 return;
495 }
496 //
497 // malloc space to hold it...
498 //
499 char *psText = (char *) cgi_Z_Malloc( i+1, TAG_TEMP_WORKSPACE );
500 //
501 // now get the string...
502 //
503 i = cgi_SP_GetStringTextString( str, psText, i+1 );
504 //ensure we found a match
505 if (!i)
506 {
507 assert(0); // should never get here now, but wtf?
508 cgi_Z_Free(psText);
509 #ifndef FINAL_BUILD
510 Com_Printf("WARNING: CG_ScrollText given invalid text key :'%s'\n",str);
511 #endif
512 return;
513 }
514
515 cg.scrollTextTime = cg.time;
516 cg.printTextY = SCREEN_HEIGHT;
517 cg.scrollTextLines = 1;
518
519 s = psText;
520 i = 0;
521 holds = s;
522
523 const char *psBestLineBreakSrcPos = s;
524 const char *psLastGood_s; // needed if we get a full screen of chars with no punctuation or space (see usage notes)
525 while( *s )
526 {
527 psLastGood_s = s;
528
529 // read letter...
530 //
531 qboolean bIsTrailingPunctuation;
532 int iAdvanceCount;
533 unsigned int uiLetter = cgi_AnyLanguage_ReadCharFromString(s, &iAdvanceCount, &bIsTrailingPunctuation);
534 s += iAdvanceCount;
535
536 // concat onto string so far...
537 //
538 if (uiLetter == 32 && cg.printText[i][0] == '\0')
539 {
540 holds++;
541 continue; // unless it's a space at the start of a line, in which case ignore it.
542 }
543
544 if (uiLetter > 255)
545 {
546 Q_strcat(cg.printText[i],sizeof(cg.printText[i]),va("%c%c",uiLetter >> 8, uiLetter & 0xFF));
547 }
548 else
549 {
550 Q_strcat(cg.printText[i],sizeof(cg.printText[i]),va("%c",uiLetter & 0xFF));
551 }
552
553 // record last-good linebreak pos... (ie if we've just concat'd a punctuation point (western or asian) or space)
554 //
555 if (bIsTrailingPunctuation || uiLetter == ' ')
556 {
557 psBestLineBreakSrcPos = s;
558 }
559
560 if (uiLetter == '\n')
561 {
562 // explicit new line...
563 //
564 cg.printText[i][ strlen(cg.printText[i])-1 ] = '\0'; // kill the CR
565 i++;
566 assert (i < (int)(sizeof(cg.printText)/sizeof(cg.printText[0])) );
567 if (i >= (int)(sizeof(cg.printText)/sizeof(cg.printText[0])) )
568 {
569 break;
570 }
571 holds = s;
572 cg.scrollTextLines++;
573 }
574 else
575 if ( cgi_R_Font_StrLenPixels(cg.printText[i], cgs.media.qhFontMedium, 1.0f) >= iPixelWidth)
576 {
577 // reached screen edge, so cap off string at bytepos after last good position...
578 //
579 if (psBestLineBreakSrcPos == holds)
580 {
581 // aarrrggh!!!!! we'll only get here is someone has fed in a (probably) garbage string,
582 // since it doesn't have a single space or punctuation mark right the way across one line
583 // of the screen. So far, this has only happened in testing when I hardwired a taiwanese
584 // string into this function while the game was running in english (which should NEVER happen
585 // normally). On the other hand I suppose it's entirely possible that some taiwanese string
586 // might have no punctuation at all, so...
587 //
588 psBestLineBreakSrcPos = psLastGood_s; // force a break after last good letter
589 }
590
591 cg.printText[i][ psBestLineBreakSrcPos - holds ] = '\0';
592 holds = s = psBestLineBreakSrcPos;
593 i++;
594 assert (i < (int)(sizeof(cg.printText)/sizeof(cg.printText[0])) );
595 cg.scrollTextLines++;
596 }
597 }
598
599 cg.captionTextTime = 0; // No captions during scrolling
600 cgi_Z_Free(psText);
601 }
602
603
604 // draws using [textcolor_scroll]...
605 //
606 #define SCROLL_LPM (1/50.0) // 1 line per 50 ms
CG_DrawScrollText(void)607 void CG_DrawScrollText(void)
608 {
609 int i;
610 int x,y;
611 const int fontHeight = (int) (1.5f * (float) cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, 1.0f)); // taiwanese & japanese need 1.5 fontheight spacing
612
613 if ( !cg.scrollTextTime )
614 {
615 return;
616 }
617
618 cgi_R_SetColor( textcolor_scroll );
619
620 y = cg.printTextY - (cg.time - cg.scrollTextTime) * SCROLL_LPM;
621
622 // cgi_R_Font_DrawString(320, 200, va("Scrolltext printing @ %d",y), colorTable[CT_LTGOLD1], cgs.media.qhFontMedium, -1, 1.0f);
623
624 // See if text has finished scrolling off screen
625 if ((y + cg.scrollTextLines * fontHeight) < 1)
626 {
627 cg.scrollTextTime = 0;
628 return;
629 }
630
631 for (i=0;i<cg.scrollTextLines;++i)
632 {
633
634 // Is this line off top of screen?
635 if ((y + ((i +1) * fontHeight)) < 1)
636 {
637 y += fontHeight;
638 continue;
639 }
640 // or past bottom of screen?
641 else if (y > SCREEN_HEIGHT)
642 {
643 break;
644 }
645
646 // w = cgi_R_Font_StrLenPixels(cg.printText[i], cgs.media.qhFontMedium, 1.0f);
647 // if (w)
648 {
649 x = (SCREEN_WIDTH - giScrollTextPixelWidth) / 2;
650 cgi_R_Font_DrawString(x,y, cg.printText[i], textcolor_scroll, cgs.media.qhFontMedium, -1, 1.0f);
651 y += fontHeight;
652 }
653 }
654
655 cgi_R_SetColor( NULL );
656 }
657
658
659 /*
660 ===============================================================================
661
662 CENTER PRINTING
663
664 ===============================================================================
665 */
666
667
668 /*
669 ==============
670 CG_CenterPrint
671
672 Called for important messages that should stay in the center of the screen
673 for a few moments
674 ==============
675 */
CG_CenterPrint(const char * str,int y)676 void CG_CenterPrint( const char *str, int y) {
677 char *s;
678
679 // Find text to match the str given
680 if (*str == '@')
681 {
682 int i;
683
684 i = cgi_SP_GetStringTextString( str+1, cg.centerPrint, sizeof(cg.centerPrint) );
685
686 if (!i)
687 {
688 Com_Printf (S_COLOR_RED"CG_CenterPrint: cannot find reference '%s' in StringPackage!\n",str);
689 Q_strncpyz( cg.centerPrint, str, sizeof(cg.centerPrint) );
690 }
691 }
692 else
693 {
694 Q_strncpyz( cg.centerPrint, str, sizeof(cg.centerPrint) );
695 }
696
697 cg.centerPrintTime = cg.time;
698 cg.centerPrintY = y;
699
700 // count the number of lines for centering
701 cg.centerPrintLines = 1;
702 s = cg.centerPrint;
703 while( *s ) {
704 if (*s == '\n')
705 cg.centerPrintLines++;
706 s++;
707 }
708
709 }
710
711
712 /*
713 ===================
714 CG_DrawCenterString
715 ===================
716 */
CG_DrawCenterString(void)717 void CG_DrawCenterString( void )
718 {
719 char *start;
720 unsigned int l;
721 int x, y, w;
722 float *color;
723
724 if ( !cg.centerPrintTime ) {
725 return;
726 }
727
728 color = CG_FadeColor( cg.centerPrintTime, 1000 * 3 );
729 if ( !color ) {
730 return;
731 }
732
733 if((textcolor_center[0] == 0) && (textcolor_center[1] == 0) &&
734 (textcolor_center[2] == 0) && (textcolor_center[3] == 0))
735 {
736 VectorCopy4( colorTable[CT_WHITE], textcolor_center );
737 }
738
739 start = cg.centerPrint;
740
741 const int fontHeight = cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, 1.0f);
742 y = cg.centerPrintY - (cg.centerPrintLines * fontHeight) / 2;
743
744 while ( 1 ) {
745 char linebuffer[1024];
746
747 // this is kind of unpleasant when dealing with MBCS, but...
748 //
749 const char *psString = start;
750 int iOutIndex = 0;
751 for ( l = 0; l < sizeof(linebuffer)-1; l++ ) {
752 int iAdvanceCount;
753 unsigned int uiLetter = cgi_AnyLanguage_ReadCharFromString(psString, &iAdvanceCount);
754 psString += iAdvanceCount;
755 if (!uiLetter || uiLetter == '\n'){
756 break;
757 }
758 if (uiLetter > 255)
759 {
760 linebuffer[iOutIndex++] = uiLetter >> 8;
761 linebuffer[iOutIndex++] = uiLetter & 0xFF;
762 }
763 else
764 {
765 linebuffer[iOutIndex++] = uiLetter & 0xFF;
766 }
767 }
768 linebuffer[iOutIndex++] = '\0';
769
770 w = cgi_R_Font_StrLenPixels(linebuffer, cgs.media.qhFontMedium, 1.0f);
771
772 x = ( SCREEN_WIDTH - w ) / 2;
773
774 cgi_R_Font_DrawString(x,y,linebuffer, textcolor_center, cgs.media.qhFontMedium, -1, 1.0f);
775
776 y += fontHeight;
777
778 while ( *start && ( *start != '\n' ) ) {
779 start++;
780 }
781 if ( !*start ) {
782 break;
783 }
784 start++;
785 }
786
787 }
788