/* ================ CG_DrawRect Coordinates are 640*480 virtual values ================= */ void CG_DrawRect( float x, float y, float width, float height, float size, const float *color ) { cgi_R_SetColor( color ); CG_DrawTopBottom(x, y, width, height, size); CG_DrawSides(x, y, width, height, size); cgi_R_SetColor( NULL ); }
/* ==================== MissionInformation_Draw ==================== */ void MissionInformation_Draw( centity_t *cent ) { int i,totalY; int iYPixelsPerLine = cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, 1.0f) * (cgi_Language_IsAsian() ? 1.2f : 1.0f ); missionInfo_Updated = qfalse; // This will stop the text from flashing cg.missionInfoFlashTime = 0; // Frame char text[1024]={0}; cgi_SP_GetStringTextString( "INGAME_OBJECTIVES", text, sizeof(text) ); cgi_R_Font_DrawString (96, missionYpos-23, text, colorTable[CT_WHITE], cgs.media.qhFontMedium, -1, 1.0f); int missionYcnt = 0; obj_graphics[0] = obj_graphics[1] = obj_graphics[2] = obj_graphics[3] = qfalse; // Print active objectives cgi_R_SetColor(colorTable[CT_BLUE3]); for (i=0;i<MAX_OBJECTIVES;++i) { if (cent->gent->client->sess.mission_objectives[i].display) { totalY = missionYpos + (iYPixelsPerLine * (missionYcnt))+(iYPixelsPerLine/2); if (obj_graphics[0]) { totalY += 32 + 4; } if (obj_graphics[1]) { totalY += 32 + 4; } if (obj_graphics[2]) { totalY += 32 + 4; } if (obj_graphics[3]) { totalY += 32 + 4; } // OBJECTIVE_STAT_PENDING CG_DrawPic( 88, totalY, 16, 16, cgs.media.messageObjCircle); // Circle in front if (cent->gent->client->sess.mission_objectives[i].status == OBJECTIVE_STAT_SUCCEEDED) { CG_DrawPic( 88, totalY, 16, 16, cgs.media.messageLitOn); // Center Dot } MissionPrint_Line(CT_BLUE3, i, missionYcnt ); } } if (!missionYcnt) { cgi_SP_GetStringTextString( "INGAME_OBJNONE", text, sizeof(text) ); // CG_DrawProportionalString(108, missionYpos, text, CG_SMALLFONT, colorTable[CT_LTBLUE1] ); cgi_R_Font_DrawString (108, missionYpos, text, colorTable[CT_LTBLUE1], cgs.media.qhFontMedium, -1, 1.0f); } }
/* ================== CG_DrawStringExt Draws a multi-colored string with a drop shadow, optionally forcing to a fixed color. Coordinates are at 640 by 480 virtual resolution ================== */ void CG_DrawStringExt( int x, int y, const char *string, const float *setColor, qboolean forceColor, qboolean shadow, int charWidth, int charHeight ) { vec4_t color; const char *s; int xx; // draw the drop shadow if (shadow) { color[0] = color[1] = color[2] = 0; color[3] = setColor[3]; cgi_R_SetColor( color ); s = string; xx = x; while ( *s ) { if ( Q_IsColorString( s ) ) { s += 2; continue; } CG_DrawChar( xx + 2, y + 2, charWidth, charHeight, *s ); xx += charWidth; s++; } } // draw the colored text s = string; xx = x; cgi_R_SetColor( setColor ); while ( *s ) { if ( Q_IsColorString( s ) ) { if ( !forceColor ) { memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) ); color[3] = setColor[3]; cgi_R_SetColor( color ); } s += 2; continue; } CG_DrawChar( xx, y, charWidth, charHeight, *s ); xx += charWidth; s++; } cgi_R_SetColor( NULL ); }
static int CG_DrawLoadForcePrintRow( const char *itemName, int forceBits,int rowIconCnt, int startIndex) { int i,endIndex=0, printedIconCnt=0; int holdX,x,y; int yOffset = 0; int width,height; vec4_t color; qhandle_t background; if (!cgi_UI_GetMenuItemInfo( "loadScreen", itemName, &x, &y, &width, &height, color, &background)) { return(0); } cgi_R_SetColor( color ); // calculate placement of weapon icons holdX = x + (width - ((MAXLOAD_FORCEICONSIZE*rowIconCnt) + (MAXLOAD_FORCEICONPAD * (rowIconCnt-1))))/2; for (i=startIndex;i<MAX_SHOWPOWERS;i++) { if (!CG_ForcePower_Valid(forceBits,i)) // Does he have this power? { continue; } if (force_icons[showPowers[i]]) { endIndex = i; CG_DrawPic( holdX, y+yOffset, MAXLOAD_FORCEICONSIZE, MAXLOAD_FORCEICONSIZE, force_icons[showPowers[i]] ); printedIconCnt++; if (printedIconCnt==MAXLOADICONSPERROW) { break; } holdX += (MAXLOAD_FORCEICONSIZE+MAXLOAD_FORCEICONPAD); } } return (endIndex); }
static void CG_LoadBar(void) { const int numticks = 9, tickwidth = 40, tickheight = 8; const int tickpadx = 20, tickpady = 12; const int capwidth = 8; const int barwidth = numticks*tickwidth+tickpadx*2+capwidth*2, barleft = ((640-barwidth)/2); const int barheight = tickheight + tickpady*2, bartop = 475-barheight; const int capleft = barleft+tickpadx, tickleft = capleft+capwidth, ticktop = bartop+tickpady; cgi_R_SetColor( colorTable[CT_WHITE]); // Draw background CG_DrawPic(barleft, bartop, barwidth, barheight, cgs.media.levelLoad); // Draw left cap (backwards) CG_DrawPic(tickleft, ticktop, -capwidth, tickheight, cgs.media.loadTickCap); // Draw bar CG_DrawPic(tickleft, ticktop, tickwidth*cg.loadLCARSStage, tickheight, cgs.media.loadTick); // Draw right cap CG_DrawPic(tickleft+tickwidth*cg.loadLCARSStage, ticktop, capwidth, tickheight, cgs.media.loadTickCap); }
// Print weapons the player is carrying // Two rows print if there are too many static void CG_DrawLoadWeapons( int weaponBits ) { int i,endIndex=0; int iconCnt,rowIconCnt; // count the number of weapons owned iconCnt = 0; for ( i = 1 ; i < MAXLOADWEAPONS ; i++ ) { if ( weaponBits & ( 1 << i ) ) { iconCnt++; } } if (!iconCnt) // If no weapons, don't display { return; } // Single line of icons if (iconCnt<=MAXLOADICONSPERROW) { CG_DrawLoadWeaponsPrintRow("weaponicons_singlerow", weaponBits, iconCnt,0); } // Two lines of icons else { // Print top row endIndex = CG_DrawLoadWeaponsPrintRow("weaponicons_row1", weaponBits, MAXLOADICONSPERROW,0); // Print second row rowIconCnt = iconCnt - MAXLOADICONSPERROW; CG_DrawLoadWeaponsPrintRow("weaponicons_row2", weaponBits, rowIconCnt,endIndex+1); } cgi_R_SetColor( NULL ); }
// Print force powers the player is using // Two rows print if there are too many static void CG_DrawLoadForcePowers( int forceBits ) { int i,endIndex=0; int iconCnt=0,rowIconCnt; // Count the number of force powers known for (i=0; i<MAX_SHOWPOWERS; ++i) { if (CG_ForcePower_Valid(forceBits, i)) { iconCnt++; } } if (!iconCnt) // If no force powers, don't display { return; } // Single line of icons if (iconCnt<=MAXLOADICONSPERROW) { CG_DrawLoadForcePrintRow("forceicons_singlerow", forceBits, iconCnt,0); } // Two lines of icons else { // Print top row endIndex = CG_DrawLoadForcePrintRow("forceicons_row1", forceBits, MAXLOADICONSPERROW,0); // Print second row rowIconCnt = iconCnt - MAXLOADICONSPERROW; CG_DrawLoadForcePrintRow("forceicons_row2", forceBits, rowIconCnt,endIndex+1); } cgi_R_SetColor( NULL ); }
/* ================ CG_FillRect Coordinates are 640*480 virtual values ================= */ void CG_FillRect( float x, float y, float width, float height, const float *color ) { cgi_R_SetColor( color ); cgi_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cgs.media.whiteShader); cgi_R_SetColor( NULL ); }
// 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; } }
/* ==================== CG_DrawInformation Draw all the status / pacifier stuff during level loading ==================== */ void CG_DrawInformation( void ) { int y; // draw the dialog background const char *info = CG_ConfigString( CS_SERVERINFO ); const char *s = Info_ValueForKey( info, "mapname" ); qhandle_t levelshot; extern SavedGameJustLoaded_e g_eSavedGameJustLoaded; // hack! (hey, it's the last week of coding, ok? // if ( g_eSavedGameJustLoaded == eFULL ) // { // levelshot = 0; //use the loaded thumbnail instead of the levelshot // } // else { levelshot = cgi_R_RegisterShaderNoMip( va( "levelshots/%s", s ) ); #ifndef FINAL_BUILD if (!levelshot && !strncmp(s, "work/",5) ) { levelshot = cgi_R_RegisterShaderNoMip( va( "levelshots/%s", s+5 ) ); } #endif if (!levelshot) { levelshot = cgi_R_RegisterShaderNoMip( "menu/art/unknownmap" ); } } if ( g_eSavedGameJustLoaded != eFULL && !strcmp(s,"yavin1") )//special case for first map! { char text[1024]={0}; // cgi_R_SetColor( colorTable[CT_BLACK] ); CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, cgs.media.whiteShader ); cgi_SP_GetStringTextString( "SP_INGAME_ALONGTIME", text, sizeof(text) ); int w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontMedium, 1.0f); cgi_R_Font_DrawString((320)-(w/2), 140, text, colorTable[CT_ICON_BLUE], cgs.media.qhFontMedium, -1, 1.0f); } else { CG_DrawLoadingScreen(levelshot, s); cgi_UI_Menu_Paint( cgi_UI_GetMenuByName( "loadscreen" ), qtrue ); //cgi_UI_MenuPaintAll(); } CG_LoadBar(); // the first 150 rows are reserved for the client connection // screen to write into // if ( cg.processedSnapshotNum == 0 ) { // still loading // print the current item being loaded #ifdef _DEBUG cgi_R_Font_DrawString( 40, 416, va("LOADING ... %s",cg.infoScreenText),colorTable[CT_LTGOLD1], cgs.media.qhFontSmall, -1, 1.0f ); #endif } // draw info string information y = 20; // map-specific message (long map name) s = CG_ConfigString( CS_MESSAGE ); if ( s[0] ) { if (s[0] == '@') { char text[1024]={0}; cgi_SP_GetStringTextString( s+1, text, sizeof(text) ); cgi_R_Font_DrawString( 15, y, va("\"%s\"",text),colorTable[CT_WHITE],cgs.media.qhFontMedium, -1, 1.0f ); } else { cgi_R_Font_DrawString( 15, y, va("\"%s\"",s),colorTable[CT_WHITE],cgs.media.qhFontMedium, -1, 1.0f ); } y += 20; } }
/* ==================== CG_DrawLoadingScreen Load screen displays the map pic, the mission briefing and weapons/force powers ==================== */ static void CG_DrawLoadingScreen( qhandle_t levelshot ,const char *mapName) { int xPos,yPos,width,height; vec4_t color; qhandle_t background; int weapons=0, forcepowers=0; // Get mission briefing for load screen if (cgi_SP_GetStringTextString( va("BRIEFINGS_%s",mapName), NULL, 0 ) == 0) { cgi_Cvar_Set( "ui_missionbriefing", "@BRIEFINGS_NONE" ); } else { cgi_Cvar_Set( "ui_missionbriefing", va("@BRIEFINGS_%s",mapName) ); } // Print background if (cgi_UI_GetMenuItemInfo( "loadScreen", "background", &xPos, &yPos, &width, &height, color, &background)) { cgi_R_SetColor( color ); CG_DrawPic( xPos, yPos, width, height, background ); } // Print level pic if (cgi_UI_GetMenuItemInfo( "loadScreen", "mappic", &xPos, &yPos, &width, &height, color, &background)) { //if (!levelshot) //{// No level shot so use screenshot. // CG_DrawPic( xPos, yPos, 1, 1, 0); //force the tess to flush // cgi_R_DrawScreenShot( xPos, yPos+height, width, -height ); //} //else { cgi_R_SetColor( color ); CG_DrawPic( xPos, yPos, width, height, levelshot ); } } // Get player weapons and force power info CG_GetLoadScreenInfo(&weapons,&forcepowers); // Print weapon icons if (weapons) { CG_DrawLoadWeapons(weapons); } // Print force power icons if (forcepowers) { CG_DrawLoadForcePowers(forcepowers); } }
static int CG_DrawLoadWeaponsPrintRow( const char *itemName, int weaponsBits,int rowIconCnt, int startIndex) { int i,endIndex=0, printedIconCnt=0; int iconSize; int holdX,x,y,pad; int yOffset = 0; int width,height; vec4_t color; qhandle_t background; if (!cgi_UI_GetMenuItemInfo( "loadScreen", itemName, &x, &y, &width, &height, color, &background)) { return(0); } cgi_R_SetColor( color ); iconSize = 60; pad = 12; // calculate placement of weapon icons holdX = x + (width - ((iconSize*rowIconCnt) + (pad * (rowIconCnt-1))))/2; for (i=startIndex;i<MAXLOADWEAPONS;i++) { if ( !(weaponsBits & ( 1 << i ))) // Does he have this weapon? { continue; } if (weaponData[i].weaponIcon[0]) { weaponInfo_t *weaponInfo; CG_RegisterWeapon( i ); weaponInfo = &cg_weapons[i]; endIndex = i; // NOTE : during loading screen always show the have ammo icon // if (!CG_WeaponCheck(i)) // { // CG_DrawPic( holdX, y+yOffset, iconSize, iconSize, weaponInfo->weaponIconNoAmmo ); // } // else { CG_DrawPic( holdX, y+yOffset, iconSize, iconSize, weaponInfo->weaponIcon ); } printedIconCnt++; if (printedIconCnt==MAXLOADICONSPERROW) { break; } holdX += (iconSize+pad); } } return (endIndex); }
/* ==================== CG_DrawDataPadObjectives Draw routine for the objective info screen of the data pad. ==================== */ void CG_DrawDataPadObjectives(const centity_t *cent ) { int i,totalY; int iYPixelsPerLine = cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, 1.0f); const short titleXPos = objectiveStartingXpos - 22; // X starting position for title text const short titleYPos = objectiveStartingYpos - 23; // Y starting position for title text const short graphic_size = 16; // Size (width and height) of graphic used to show status of objective const short graphicXpos = objectiveStartingXpos - graphic_size - 8; // Amount of X to backup from text starting position const short graphicYOffset = (iYPixelsPerLine - graphic_size)/2; // Amount of Y to raise graphic so it's in the center of the text line missionInfo_Updated = qfalse; // This will stop the text from flashing cg.missionInfoFlashTime = 0; // zero out objective graphics for (i=0;i<MAX_OBJ_GRAPHICS;i++) { obj_graphics[i] = qfalse; } // Title Text at the top char text[1024]={0}; cgi_SP_GetStringTextString( "SP_INGAME_OBJECTIVES", text, sizeof(text) ); cgi_R_Font_DrawString (titleXPos, titleYPos, text, colorTable[CT_TITLE], cgs.media.qhFontMedium, -1, 1.0f); int missionYcnt = 0; // Print all active objectives for (i=0;i<MAX_OBJECTIVES;i++) { // Is there an objective to see? if (cent->gent->client->sess.mission_objectives[i].display) { // Calculate the Y position totalY = objectiveStartingYpos + (iYPixelsPerLine * (missionYcnt))+(iYPixelsPerLine/2); // Draw graphics that show if mission has been accomplished or not cgi_R_SetColor(colorTable[CT_BLUE3]); CG_DrawPic( (graphicXpos), (totalY-graphicYOffset), graphic_size, graphic_size, cgs.media.messageObjCircle); // Circle in front if (cent->gent->client->sess.mission_objectives[i].status == OBJECTIVE_STAT_SUCCEEDED) { CG_DrawPic( (graphicXpos), (totalY-graphicYOffset), graphic_size, graphic_size, cgs.media.messageLitOn); // Center Dot } // Print current objective text ObjectivePrint_Line(CT_WHITE, i, missionYcnt ); } } // No mission text? if (!missionYcnt) { // Set the message a quarter of the way down and in the center of the text box int messageYPosition = objectiveStartingYpos + (objectiveTextBoxHeight / 4); cgi_SP_GetStringTextString( "SP_INGAME_OBJNONE", text, sizeof(text) ); int messageXPosition = objectiveStartingXpos + (objectiveTextBoxWidth/2) - (cgi_R_Font_StrLenPixels(text, cgs.media.qhFontMedium, 1.0f) /2); cgi_R_Font_DrawString ( messageXPosition, messageYPosition, text, colorTable[CT_WHITE], cgs.media.qhFontMedium, -1, 1.0f); } }
/* ==================== CG_DrawInformation Draw all the status / pacifier stuff during level loading overylays UI_DrawConnectText from ui_connect.cpp ==================== */ void CG_DrawInformation( void ) { int y; // draw the dialog background const char *info = CG_ConfigString( CS_SERVERINFO ); const char *s = Info_ValueForKey( info, "mapname" ); const qhandle_t levelshot = cgi_R_RegisterShaderNoMip( va( "levelshots/%s", s ) ); extern SavedGameJustLoaded_e g_eSavedGameJustLoaded; // hack! (hey, it's the last week of coding, ok? if ( !levelshot || g_eSavedGameJustLoaded == eFULL ) { // keep whatever's in the screen buffer so far (either the last ingame rendered-image (eg for maptransition) // or the screenshot built-in to a loaded save game... // cgi_R_DrawScreenShot( 0, 480, 640, -480 ); } else { // put up the pre-defined levelshot for this map... // cgi_R_SetColor( NULL ); CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, levelshot ); } if ( g_eSavedGameJustLoaded != eFULL && !strcmp(s,"kejim_post") )//special case for first map! { char text[1024]={0}; cgi_SP_GetStringTextString( "INGAME_ALONGTIME", text, sizeof(text) ); int w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontMedium, 1.0f); cgi_R_Font_DrawString((320)-(w/2), 140, text, colorTable[CT_ICON_BLUE], cgs.media.qhFontMedium, -1, 1.0f); } else if (cg_missionstatusscreen.integer ) { CG_MissionCompletion(); } CG_LoadBar(); // the first 150 rows are reserved for the client connection // screen to write into if ( cg.processedSnapshotNum == 0 ) { // still loading // print the current item being loaded #ifndef NDEBUG cgi_R_Font_DrawString( 48, 398, va("LOADING ... %s",cg.infoScreenText),colorTable[CT_LTGOLD1], cgs.media.qhFontSmall, -1, 1.0f ); #endif } // draw info string information y = 20; // map-specific message (long map name) s = CG_ConfigString( CS_MESSAGE ); if ( s[0] ) { if (s[0] == '@') { char text[1024]={0}; cgi_SP_GetStringTextString( s+1, text, sizeof(text) ); cgi_R_Font_DrawString( 15, y, va("\"%s\"",text),colorTable[CT_WHITE],cgs.media.qhFontMedium, -1, 1.0f ); } else { cgi_R_Font_DrawString( 15, y, va("\"%s\"",s),colorTable[CT_WHITE],cgs.media.qhFontMedium, -1, 1.0f ); } y += 20; } }