void Con_DrawRightFloatingTextLine( const int linePosition, const float *color, const char* text ) { int i, x; float currentWidthLocation = 0; const int charHeight = SCR_ConsoleFontCharHeight(); const int positionFromTop = consoleState.margin.top + consoleState.border.top + consoleState.padding.top + charHeight; i = strlen( text ); currentWidthLocation = cls.glconfig.vidWidth - SCR_ConsoleFontStringWidth( text, i ) - consoleState.margin.sides - consoleState.padding.sides; re.SetColor( color ); for ( x = 0; x < i; x++ ) { int ch = Q_UTF8_CodePoint( &text[ x ] ); SCR_DrawConsoleFontUnichar( currentWidthLocation, positionFromTop + ( linePosition * charHeight ), ch ); currentWidthLocation += SCR_ConsoleFontUnicharWidth( ch ); } }
/* ================ Con_DrawConsoleScrollbackIndicator ================ */ void Con_DrawConsoleScrollbackIndicator( int lineDrawPosition ) { int i; vec4_t color; // draw arrows to show the buffer is backscrolled const int hatWidth = SCR_ConsoleFontUnicharWidth( '^' ); color[ 0 ] = 1.0f; color[ 1 ] = 1.0f; color[ 2 ] = 1.0f; color[ 3 ] = 0.66f * consoleState.currentAlphaFactor; re.SetColor( color ); for ( i = 0; i < consoleState.textWidthInChars; i += 4 ) { SCR_DrawConsoleFontUnichar( consoleState.margin.sides + consoleState.padding.sides + ( i + 1.5 ) * hatWidth, lineDrawPosition, '^' ); } }
void SCR_DrawConsoleFontUnichar( float x, float y, int ch ) { if ( cls.useLegacyConsoleFont ) { SCR_DrawSmallUnichar( ( int ) x, ( int ) y, ch ); return; } if ( ch != ' ' ) { glyphInfo_t *glyph = Glyph( ch ); float yadj = glyph->top; float xadj = ( SCR_ConsoleFontUnicharWidth( ch ) - glyph->xSkip ) / 2.0; re.DrawStretchPic( x + xadj, y - yadj, glyph->imageWidth, glyph->imageHeight, glyph->s, glyph->t, glyph->s2, glyph->t2, glyph->glyph ); } }
/* ================ Con_DrawConsoleContent ================ */ void Con_DrawConsoleContent( void ) { float currentWidthLocation = 0; int x; float lineDrawPosition, lineDrawLowestPosition; int row; int currentColor; vec4_t color; const int charHeight = SCR_ConsoleFontCharHeight(); const int charPadding = SCR_ConsoleFontCharVPadding(); const int textDistanceToTop = consoleState.margin.top + consoleState.padding.top + consoleState.border.top - charPadding - 1; // draw from the bottom up lineDrawPosition = consoleState.height + consoleState.margin.top - consoleState.padding.bottom - consoleState.border.top - charPadding - 1; if (lineDrawPosition <= textDistanceToTop) { return; } // draw the input prompt, user text, and cursor if desired // moved back here (have observed render issues to do with time taken) Con_DrawInput( lineDrawPosition, Con_MarginFadeAlpha( 1, lineDrawPosition, textDistanceToTop, lineDrawPosition, charHeight ) ); lineDrawPosition -= charHeight; if (lineDrawPosition <= textDistanceToTop) { return; } if(con_debug->integer) { Con_DrawRightFloatingTextLine( 3, NULL, va( "Buffer (lines): ScrollbackLength %d/%d CurrentIndex %d", consoleState.usedScrollbackLengthInLines, consoleState.maxScrollbackLengthInLines, consoleState.currentLine) ); Con_DrawRightFloatingTextLine( 4, NULL, va( "Display (lines): From %d to %d (%d a %i px)", consoleState.currentLine-consoleState.maxScrollbackLengthInLines, consoleState.scrollLineIndex, consoleState.visibleAmountOfLines, charHeight ) ); } /* * if we scrolled back, give feedback, * unless it's the last line (which will be rendered partly transparent anyway) * so that we dont indicate scrollback each time a single line gets added */ if ( floor( consoleState.bottomDisplayedLine ) < consoleState.currentLine - 1 ) { // draw arrows to show the buffer is backscrolled Con_DrawConsoleScrollbackIndicator( lineDrawPosition ); } lineDrawPosition -= charHeight; row = consoleState.bottomDisplayedLine; if ( consoleState.horizontalCharOffset == 0 ) { row--; } lineDrawLowestPosition = lineDrawPosition; if ( consoleState.bottomDisplayedLine - floor( consoleState.bottomDisplayedLine ) != 0.0f ) { lineDrawPosition += charHeight - ( consoleState.bottomDisplayedLine - floor( consoleState.bottomDisplayedLine ) ) * charHeight; ++row; } currentColor = 7; color[ 0 ] = g_color_table[ currentColor ][ 0 ]; color[ 1 ] = g_color_table[ currentColor ][ 1 ]; color[ 2 ] = g_color_table[ currentColor ][ 2 ]; for ( ; row >= 0 && lineDrawPosition > textDistanceToTop; lineDrawPosition -= charHeight, row-- ) { conChar_t *text; if ( consoleState.currentLine - row >= consoleState.maxScrollbackLengthInLines ) { // past scrollback wrap point continue; } if ( row == consoleState.lastReadLineIndex - 1 && consoleState.lastReadLineIndex != consoleState.currentLine && consoleState.currentLine - consoleState.lastReadLineIndex < consoleState.usedScrollbackLengthInLines) { Con_DrawScrollbackMarkerline( lineDrawPosition ); } text = consoleState.text + CON_LINE( row ); currentWidthLocation = consoleState.margin.sides + consoleState.padding.sides; for ( x = 0; x < consoleState.textWidthInChars && text[x].ch; ++x ) { if ( text[ x ].ink != currentColor ) { currentColor = text[ x ].ink; color[ 0 ] = g_color_table[ currentColor ][ 0 ]; color[ 1 ] = g_color_table[ currentColor ][ 1 ]; color[ 2 ] = g_color_table[ currentColor ][ 2 ]; } color[ 3 ] = Con_MarginFadeAlpha( consoleState.currentAlphaFactor, lineDrawPosition, textDistanceToTop, lineDrawLowestPosition, charHeight ); re.SetColor( color ); SCR_DrawConsoleFontUnichar( currentWidthLocation, floor( lineDrawPosition + 0.5 ), text[ x ].ch ); currentWidthLocation += SCR_ConsoleFontUnicharWidth( text[ x ].ch ); } } Con_DrawConsoleScrollbar( ); re.SetColor( NULL ); //set back to white }
/* ================ Con_CheckResize If the line width has changed, reformat the buffer. ================ */ qboolean Con_CheckResize( void ) { int i, textWidthInChars, oldwidth, oldtotallines, numlines, numchars; conChar_t buf[ CON_TEXTSIZE ]; qboolean ret = qtrue; if ( cls.glconfig.vidWidth ) { const int consoleVidWidth = cls.glconfig.vidWidth - 2 * (consoleState.margin.sides + consoleState.padding.sides ); textWidthInChars = consoleVidWidth / SCR_ConsoleFontUnicharWidth( 'W' ); } else { textWidthInChars = 0; } if ( textWidthInChars == consoleState.textWidthInChars ) { // nothing } else if ( textWidthInChars < 1 ) // video hasn't been initialized yet { consoleState.textWidthInChars = DEFAULT_CONSOLE_WIDTH; consoleState.maxScrollbackLengthInLines = CON_TEXTSIZE / consoleState.textWidthInChars; Con_Clear(); consoleState.currentLine = consoleState.maxScrollbackLengthInLines - 1; consoleState.bottomDisplayedLine = consoleState.currentLine; consoleState.scrollLineIndex = consoleState.currentLine; ret = qfalse; } else { oldwidth = consoleState.textWidthInChars; consoleState.textWidthInChars = textWidthInChars; oldtotallines = consoleState.maxScrollbackLengthInLines; consoleState.maxScrollbackLengthInLines = CON_TEXTSIZE / consoleState.textWidthInChars; numlines = oldwidth < 0 ? 0 : oldtotallines; if ( consoleState.maxScrollbackLengthInLines < numlines ) { numlines = consoleState.maxScrollbackLengthInLines; } numchars = oldwidth; if ( consoleState.textWidthInChars < numchars ) { numchars = consoleState.textWidthInChars; } Com_Memcpy( buf, consoleState.text, sizeof( consoleState.text ) ); Con_Clear(); for ( i = 0; i < numlines; i++ ) { conChar_t* destination = consoleState.text + ( consoleState.maxScrollbackLengthInLines - 1 - i ) * consoleState.textWidthInChars; memcpy( destination, buf + ( ( consoleState.currentLine - i + oldtotallines ) % oldtotallines ) * oldwidth, numchars * sizeof( conChar_t ) ); if( destination[0].ch ) consoleState.usedScrollbackLengthInLines++; } consoleState.currentLine = consoleState.maxScrollbackLengthInLines - 1; consoleState.bottomDisplayedLine = consoleState.currentLine; consoleState.scrollLineIndex = consoleState.currentLine; } if ( con_prompt ) { char prompt[ MAX_STRING_CHARS ]; Q_strncpyz( prompt, con_prompt->string, sizeof( prompt ) ); Q_CleanStr( prompt ); g_console_field_width = consoleState.textWidthInChars - 8 - Q_UTF8_Strlen( prompt ); g_consoleField.SetWidth(g_console_field_width); } return ret; }
/* ================ Con_DrawSolidConsole Draws the console with the solid background ================ */ void Con_DrawSolidConsole( float frac ) { int i, x, y; int rows; int row; int lines; // qhandle_t conShader; int currentColor; vec4_t color; float yVer; float totalwidth; float currentWidthLocation = 0; const int charHeight = SCR_ConsoleFontCharHeight(); if ( scr_conUseOld->integer ) { lines = cls.glconfig.vidHeight * frac; if ( lines <= 0 ) { return; } if ( lines > cls.glconfig.vidHeight ) { lines = cls.glconfig.vidHeight; } } else { lines = cls.glconfig.vidHeight * frac; } lines += charHeight / ( CONSOLE_FONT_VPADDING + 1 ); // on wide screens, we will center the text if (!scr_conUseOld->integer) { con.xadjust = 15; } SCR_AdjustFrom640 (&con.xadjust, NULL, NULL, NULL); // draw the background if ( scr_conUseOld->integer ) { yVer = 5 + charHeight; y = frac * SCREEN_HEIGHT; if ( y < 1 ) { y = 0; } else { if ( scr_conUseShader->integer ) { SCR_DrawPic( 0, 0, SCREEN_WIDTH, y, cls.consoleShader ); } else { // This will be overwritten, so i'll just abuse it here, no need to define another array color[ 0 ] = scr_conColorRed->value; color[ 1 ] = scr_conColorGreen->value; color[ 2 ] = scr_conColorBlue->value; color[ 3 ] = scr_conColorAlpha->value; SCR_FillRect( 0, 0, SCREEN_WIDTH, y, color ); } } color[ 0 ] = scr_conBarColorRed->value; color[ 1 ] = scr_conBarColorGreen->value; color[ 2 ] = scr_conBarColorBlue->value; color[ 3 ] = scr_conBarColorAlpha->value; SCR_FillRect( 0, y, SCREEN_WIDTH, scr_conBarSize->value, color ); } else { yVer = 10; SCR_AdjustFrom640( NULL, &yVer, NULL, NULL ); yVer = floor( yVer + 5 + charHeight ); color[ 0 ] = scr_conColorRed->value; color[ 1 ] = scr_conColorGreen->value; color[ 2 ] = scr_conColorBlue->value; color[ 3 ] = frac * 2 * scr_conColorAlpha->value; SCR_FillRect( 10, 10, 620, 460 * scr_conHeight->integer * 0.01, color ); color[ 0 ] = scr_conBarColorRed->value; color[ 1 ] = scr_conBarColorGreen->value; color[ 2 ] = scr_conBarColorBlue->value; color[ 3 ] = frac * 2 * scr_conBarColorAlpha->value; SCR_FillRect( 10, 10, 620, 1, color ); //top SCR_FillRect( 10, 460 * scr_conHeight->integer * 0.01 + 10, 621, 1, color ); //bottom SCR_FillRect( 10, 10, 1, 460 * scr_conHeight->integer * 0.01, color ); //left SCR_FillRect( 630, 10, 1, 460 * scr_conHeight->integer * 0.01, color ); //right } // draw the version number color[ 0 ] = 1.0f; color[ 1 ] = 1.0f; color[ 2 ] = 1.0f; color[ 3 ] = ( scr_conUseOld->integer ? 0.75f : frac * 0.75f ); re.SetColor( color ); i = strlen( Q3_VERSION ); totalwidth = SCR_ConsoleFontStringWidth( Q3_VERSION, i ) + cl_conXOffset->integer; if ( !scr_conUseOld->integer ) { totalwidth += 30; } currentWidthLocation = cls.glconfig.vidWidth - totalwidth; for ( x = 0; x < i; x++ ) { int ch = Q_UTF8CodePoint( &Q3_VERSION[ x ] ); SCR_DrawConsoleFontUnichar( currentWidthLocation, yVer, ch ); currentWidthLocation += SCR_ConsoleFontUnicharWidth( ch ); } // engine string i = strlen( Q3_ENGINE ); totalwidth = SCR_ConsoleFontStringWidth( Q3_ENGINE, i ) + cl_conXOffset->integer; if ( !scr_conUseOld->integer ) { totalwidth += 30; } currentWidthLocation = cls.glconfig.vidWidth - totalwidth; for ( x = 0; x < i; x++ ) { int ch = Q_UTF8CodePoint( &Q3_ENGINE[ x ] ); SCR_DrawConsoleFontUnichar( currentWidthLocation, yVer + charHeight, ch ); currentWidthLocation += SCR_ConsoleFontUnicharWidth( ch ); } // draw the input prompt, user text, and cursor if desired // moved back here (have observed render issues to do with time taken) Con_DrawInput(); // draw the text con.vislines = lines; rows = ( lines ) / SCR_ConsoleFontCharHeight() - 3; // rows of text to draw if ( scr_conUseOld->integer ) { rows++; } y = lines - ( SCR_ConsoleFontCharHeight() * 3 ) + 10; // draw from the bottom up if ( con.display != con.current ) { // draw arrows to show the buffer is backscrolled const int hatWidth = SCR_ConsoleFontUnicharWidth( '^' ); color[ 0 ] = 1.0f; color[ 1 ] = 0.0f; color[ 2 ] = 0.0f; color[ 3 ] = ( scr_conUseOld->integer ? 1.0f : frac * 2.0f ); re.SetColor( color ); for ( x = 0; x < con.linewidth - ( scr_conUseOld->integer ? 0 : 4 ); x += 4 ) { SCR_DrawConsoleFontUnichar( con.xadjust + ( x + 1 ) * hatWidth, y, '^' ); } y -= charHeight; rows--; } row = con.display; if ( con.x == 0 ) { row--; } currentColor = 7; color[ 0 ] = g_color_table[ currentColor ][ 0 ]; color[ 1 ] = g_color_table[ currentColor ][ 1 ]; color[ 2 ] = g_color_table[ currentColor ][ 2 ]; color[ 3 ] = ( scr_conUseOld->integer ? 1.0f : frac * 2.0f ); re.SetColor( color ); for ( i = 0; i < rows; i++, y -= charHeight, row-- ) { conChar_t *text; if ( row < 0 ) { break; } if ( con.current - row >= con.totallines ) { // past scrollback wrap point continue; } text = con.text + CON_LINE( row ); currentWidthLocation = cl_conXOffset->integer; for ( x = 0; x < con.linewidth && text[x].ch; ++x ) { if ( text[ x ].ink != currentColor ) { currentColor = text[ x ].ink; color[ 0 ] = g_color_table[ currentColor ][ 0 ]; color[ 1 ] = g_color_table[ currentColor ][ 1 ]; color[ 2 ] = g_color_table[ currentColor ][ 2 ]; color[ 3 ] = ( scr_conUseOld->integer ? 1.0f : frac * 2.0f ); re.SetColor( color ); } SCR_DrawConsoleFontUnichar( con.xadjust + currentWidthLocation, y, text[ x ].ch ); currentWidthLocation += SCR_ConsoleFontUnicharWidth( text[ x ].ch ); } } re.SetColor( NULL ); }
/* ================ Con_CheckResize If the line width has changed, reformat the buffer. ================ */ void Con_CheckResize( void ) { int i, width, oldwidth, oldtotallines, numlines, numchars; conChar_t buf[ CON_TEXTSIZE ]; if ( cls.glconfig.vidWidth ) { if ( scr_conUseOld->integer ) { width = cls.glconfig.vidWidth / SCR_ConsoleFontUnicharWidth( 'W' ); } else { float adjust = 30; SCR_AdjustFrom640( &adjust, NULL, NULL, NULL ); width = ( cls.glconfig.vidWidth - adjust ) / SCR_ConsoleFontUnicharWidth( 'W' ); } g_consoleField.widthInChars = width - Q_PrintStrlen( cl_consolePrompt->string ) - 1; } else { width = 0; } if ( width == con.linewidth ) { // nothing } else if ( width < 1 ) // video hasn't been initialized yet { width = DEFAULT_CONSOLE_WIDTH; con.linewidth = width; con.totallines = CON_TEXTSIZE / con.linewidth; Con_Clear(); con.current = con.totallines - 1; con.display = con.current; } else { SCR_AdjustFrom640( &con.xadjust, NULL, NULL, NULL ); oldwidth = con.linewidth; con.linewidth = width; oldtotallines = con.totallines; con.totallines = CON_TEXTSIZE / con.linewidth; numlines = oldtotallines; if ( con.totallines < numlines ) { numlines = con.totallines; } numchars = oldwidth; if ( con.linewidth < numchars ) { numchars = con.linewidth; } Com_Memcpy( buf, con.text, sizeof( con.text ) ); Con_Clear(); for ( i = 0; i < numlines; i++ ) { memcpy( con.text + ( con.totallines - 1 - i ) * con.linewidth, buf + ( ( con.current - i + oldtotallines ) % oldtotallines ) * oldwidth, numchars * sizeof( conChar_t ) ); } con.current = con.totallines - 1; con.display = con.current; } g_console_field_width = g_consoleField.widthInChars = con.linewidth - 7 - ( cl_consolePrompt ? Q_UTF8Strlen( cl_consolePrompt->string ) : 0 ); }