diff options
Diffstat (limited to 'src/parsec/h_supp.cpp')
| -rw-r--r-- | src/parsec/h_supp.cpp | 608 |
1 files changed, 608 insertions, 0 deletions
diff --git a/src/parsec/h_supp.cpp b/src/parsec/h_supp.cpp new file mode 100644 index 0000000..84b743a --- /dev/null +++ b/src/parsec/h_supp.cpp @@ -0,0 +1,608 @@ +/* + * PARSEC - Supporting Graphics Code + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:37 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1996-2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem headers +#include "net_defs.h" +#include "sys_defs.h" + +// drawing subsystem +#include "d_font.h" + +// local module header +#include "h_supp.h" + +// proprietary module headers +#include "con_aux.h" +#include "e_supp.h" +#include "h_cockpt.h" +#include "m_button.h" + + + +// generic string paste area -------------------------------------------------- +// +#define PASTE_STR_LEN 255 +static char paste_str[ PASTE_STR_LEN + 1 ]; + +// top y position of message area --------------------------------------------- +// +int Msg_ScreenTop; // also used by H_DRWHUD.C + + +// calculate address of hud charset of specific color ------------------------- +// +char *CalcHudCharAddress( int no ) +{ + ASSERT( ( no >= 0 ) && ( no < 6 ) ); + + int cno = HUD_CHARSETNO; + + char * adr = CharsetInfo[ cno ].charsetpointer + no * 2 * 8 * CharsetInfo[ cno ].srcwidth * 4; + + return adr; +} + + +// currently set color of hud charset ----------------------------------------- +// +PUBLIC int cur_hud_char_color = 0; + + +// offset table into hud charset for different colors ------------------------- +// +PUBLIC char* Hud_Char_ColOfs[ 6 ]; // set by H_DRWHUD::InitHudDisplay() + + +// set color of hud charset --------------------------------------------------- +// +void SetHudCharColor( int no ) +{ + ASSERT( ( no >= 0 ) && ( no < NUM_HUD_CHARSET_COLORS ) ); + CharsetDataBase = Hud_Char_ColOfs[ no ]; + cur_hud_char_color = no; +} + + +// default message area properties -------------------------------------------- +// +#define MESSAGE_AREA_SIZE 4 +#define MESSAGE_LIFETIME 4000 + +#if ( MESSAGE_AREA_SIZE > MAX_SCREENMESSAGES ) + #error "default MESSAGE_AREA_SIZE invalid!" +#endif + +#if ( PASTE_STR_LEN < MAX_MESSAGELEN ) + #error "PASTE_STR_LEN too short!" +#endif + +static int message_area_size = MESSAGE_AREA_SIZE; +static int message_lifetime = MESSAGE_LIFETIME; + + +// number of currently active texfont messages -------------------------------- +// +static int num_texfont_msgs = 0; + + +// free everything associated with a texfont message and remove from table ---- +// +PRIVATE +void FreeTexfontMessage( int msgid ) +{ + ASSERT( msgid < num_texfont_msgs ); + + FREEMEM( TexfontMsgs[ msgid ].message ); + FREEMEM( TexfontMsgs[ msgid ].itexfont ); + + if ( msgid < ( num_texfont_msgs - 1 ) ) { + memmove( &TexfontMsgs[ msgid ], &TexfontMsgs[ msgid + 1 ], + sizeof( texfontmsg_s ) * ( num_texfont_msgs - msgid - 1 ) ); + } + + num_texfont_msgs--; +} + + +// display and maintain texfont messages -------------------------------------- +// +PRIVATE +void MaintainTexfontMessages() +{ + for ( int msgid = 0; msgid < num_texfont_msgs; msgid++ ) { + + // get current alpha (manual clamping is mandatory) + TexfontMsgs[ msgid ].itexfont->Vtxs[ 0 ].A = + ( TexfontMsgs[ msgid ].curalpha < 255.0f ) ? + (byte)TexfontMsgs[ msgid ].curalpha : 255; + + // display message + D_TexfontWrite( TexfontMsgs[ msgid ].message, TexfontMsgs[ msgid ].itexfont ); + + if ( TexfontMsgs[ msgid ].starttime > 0 ) { + TexfontMsgs[ msgid ].starttime -= CurScreenRefFrames; + } + + if ( TexfontMsgs[ msgid ].starttime <= 0 ) { + + // maintain alpha fading + TexfontMsgs[ msgid ].curalpha -= TexfontMsgs[ msgid ].decalpha * CurScreenRefFrames; + if ( TexfontMsgs[ msgid ].curalpha < 0.0f ) { + TexfontMsgs[ msgid ].curalpha = TexfontMsgs[ msgid ].refalpha; + TexfontMsgs[ msgid ].maxpulses--; + } + + // maintain lifetime + TexfontMsgs[ msgid ].lifetime -= CurScreenRefFrames; + + // remove message if lifetime spent or pulse count reached + if ( ( TexfontMsgs[ msgid ].lifetime < 0 ) || + ( TexfontMsgs[ msgid ].maxpulses <= 0 ) ) { + FreeTexfontMessage( msgid ); + } + } + } +} + + +// show (make active) a texfont message --------------------------------------- +// +void ShowTexfontMessage( texfontmsg_s *msg ) +{ + ASSERT( msg != NULL ); + + //NOTE: + // messages of the same type will replace each other, + // whereas messages of different types will coexist. + + // search for msg to replace (according to type) + int msgid = 0; + for ( msgid = 0; msgid < num_texfont_msgs; msgid++ ) { + if ( TexfontMsgs[ msgid ].msgtype == msg->msgtype ) { + FreeTexfontMessage( msgid ); + msgid = num_texfont_msgs; + break; + } + } + + // guard against table size overflow + if ( msgid >= MAX_TEXFONT_MESSAGES ) { + return; + } + + // copy basic info + memcpy( &TexfontMsgs[ msgid ], msg, sizeof( texfontmsg_s ) ); + + // refalpha may be set explicitly to allow for oversaturated alpha starts + if ( msg->itexfont->Vtxs[ 0 ].A == 0 ) { + TexfontMsgs[ msgid ].curalpha = TexfontMsgs[ msgid ].refalpha; + } else { + TexfontMsgs[ msgid ].refalpha = msg->itexfont->Vtxs[ 0 ].A; + TexfontMsgs[ msgid ].curalpha = msg->itexfont->Vtxs[ 0 ].A; + } + + // must make a copy of message string + TexfontMsgs[ msgid ].message = (char *) ALLOCMEM( strlen( msg->message ) + 1 ); + if ( TexfontMsgs[ msgid ].message == NULL ) + OUTOFMEM( 0 ); + strcpy( TexfontMsgs[ msgid ].message, msg->message ); + + // must make a copy of itertexfont structure + TexfontMsgs[ msgid ].itexfont = (IterTexfont *) ALLOCMEM( sizeof( IterTexfont ) ); + if ( TexfontMsgs[ msgid ].itexfont == NULL ) + OUTOFMEM( 0 ); + memcpy( TexfontMsgs[ msgid ].itexfont, msg->itexfont, sizeof( IterTexfont ) ); + + // one more active message + num_texfont_msgs++; +} + + +// message ring buffer control ------------------------------------------------ +// +static int head_message = 0; +static int tail_message = -1; + + +// invalidate all messages (clear message area) ------------------------------- +// +inline +void InvalidateMessages() +{ + // set extraordinary indexes to denote "empty" + head_message = 0; + tail_message = -1; +} + + +// reset message area --------------------------------------------------------- +// +void ResetMessageArea() +{ + //NOTE: + // this is also called from G_BOOT::InitGlobals(). + + InvalidateMessages(); + + for ( int curmsg = 0; curmsg < MAX_SCREENMESSAGES; curmsg++ ) { + MsgMaint[ curmsg ].lifetimecount = 0; + } +} + + +// write messages and maintain their timing ----------------------------------- +// +void MaintainMessages() +{ + // second type of messages (texfont) + MaintainTexfontMessages(); + + // check message area configuration (bounds) + if ( ( AUXDATA_MESSAGE_AREA_SIZE < 1 ) || + ( AUXDATA_MESSAGE_AREA_SIZE > MAX_SCREENMESSAGES ) ) + AUXDATA_MESSAGE_AREA_SIZE = MESSAGE_AREA_SIZE; + if ( ( AUXDATA_MESSAGE_LIFETIME < 100 ) || + ( AUXDATA_MESSAGE_LIFETIME > 10000 ) ) + AUXDATA_MESSAGE_LIFETIME = MESSAGE_LIFETIME; + + // ensure config changes work correctly + if ( message_area_size != AUXDATA_MESSAGE_AREA_SIZE ) { + message_area_size = AUXDATA_MESSAGE_AREA_SIZE; + ResetMessageArea(); + } + if ( message_lifetime != AUXDATA_MESSAGE_LIFETIME ) { + message_lifetime = AUXDATA_MESSAGE_LIFETIME; + ResetMessageArea(); + } + + // select font + int msgfont, lineadv, yposofs; + if ( AUX_USE_BIG_FONT_IN_MESSAGE_AREA ) { + msgfont = MSG_CHARSETNO; + lineadv = CharsetInfo[ msgfont ].height + 2; + yposofs = 0; + } else { + msgfont = HUD_CHARSETNO; + lineadv = CharsetInfo[ msgfont ].height + 1; + yposofs = -5; + } + + D_SetWStrContext( CharsetInfo[ msgfont ].charsetpointer, + CharsetInfo[ msgfont ].geompointer, + NULL, + CharsetInfo[ msgfont ].width, + CharsetInfo[ msgfont ].height ); + + // alter font color + if ( msgfont == HUD_CHARSETNO ) + SetHudCharColor( 2 ); + + // messages should not cover left and right panel if on + int pwidth = AUX_DONT_DRAW_BLUEPRINTS ? + 16 : BitmapInfo[ BM_SHIP1_BLUEPRINT ].width * 2 + 16; + int maxlen = ( ( Screen_Width - pwidth ) / CharsetInfo[ msgfont ].width ); + if ( maxlen > MAX_MESSAGELEN ) + maxlen = MAX_MESSAGELEN; + ASSERT( maxlen > 0 ); + + int curmsg = head_message; + + int ypos = 0; + if ( InFloatingMenu ) { + ypos = 84 * NUM_MENU_ITEMS; + } else { + ypos = ( AUX_DRAW_COCKPIT && !ObjCameraActive && + ( AUX_DRAW_COCKPIT_ICONBAR || AUX_DRAW_COCKPIT_ICONBAR_BACKGROUND ) ) ? + cockpit_messagearea_yoffs : ( Msg_ScreenTop + yposofs ); + } + ASSERT( ypos >= 0 ); + + // determine whether actual drawing disabled + int drawingdisabled = InFloatingMenu ? + AUX_DISABLE_FLOATING_MENU_DRAWING : AUX_HUD_DISABLE_USER_DISPLAYS; + if ( AUX_DISABLE_MESSAGE_AREA ) { + drawingdisabled = TRUE; + } + + // display message area + for ( int curl = 0; curl < message_area_size; curl++, ypos+=lineadv ) { + + if ( MsgMaint[ curmsg ].lifetimecount > 0 ) { + + if ( !drawingdisabled ) { + + if ( !AUX_DISABLE_MSGAREA_IF_CONSOLE_OPEN || ( ConsoleSliding == 0 ) ) { + + strncpy( paste_str, MsgMaint[ curmsg ].message, maxlen ); + paste_str[ maxlen ] = 0; + + int xpos = 0; + if ( InFloatingMenu ) { + xpos = ( 325 - strlen( paste_str ) * + CharsetInfo[ msgfont ].width ) / 2; + } else { + xpos = ( Screen_Width - strlen( paste_str ) * + CharsetInfo[ msgfont ].width ) / 2; + } + if ( xpos < 0 ) { + xpos = 0; + } + + if ( ypos < ( Screen_Height - CharsetInfo[ msgfont ].height ) ) { + D_WriteString( paste_str, xpos, ypos ); + } + } + } + + MsgMaint[ curmsg ].lifetimecount -= CurScreenRefFrames; + if ( MsgMaint[ curmsg ].lifetimecount <= 0 ) { + + // [ (head==tail) means only one message ] + if ( head_message == tail_message ) { + + // set valid "emtpy" state + InvalidateMessages(); + + } else { + + // advance head to next message + if ( ++head_message >= message_area_size ) { + head_message = 0; + } + } + } + } + + if ( ++curmsg >= message_area_size ) { + curmsg = 0; + } + } +} + + +// add message to message structure ------------------------------------------- +// +void ShowMessage( const char *msg ) +{ + //NOTE: + // the message area is a ring-buffer that uses + // all entries. no entry is used as sentinel in + // the case when the ring-buffer is full. + // (when using only head and tail this is only + // possible if a non-valid index is used as flag.) + // + // [ (head==0 tail==-1) means no messages ] + // [ (head==tail) means only one message ] + // [ tail one pos before head means area full ] + + ASSERT( msg != NULL ); + + if ( tail_message != -1 ) { + + // advance tail + if ( ++tail_message >= message_area_size ) { + tail_message = 0; + } + + // [ tail one pos before head means area full ] + + // eat from head if too many entries + if ( tail_message == head_message ) { + if ( ++head_message >= message_area_size ) { + head_message = 0; + } + } + + } else { + + // [ (head==0 tail==-1) means no messages ] + + // first message in area (was empty before) + ASSERT( head_message == 0 ); + tail_message = 0; + } + + // append message at tail + strncpy( MsgMaint[ tail_message ].message, msg, MAX_MESSAGELEN ); + MsgMaint[ tail_message ].message[ MAX_MESSAGELEN ] = 0; + MsgMaint[ tail_message ].lifetimecount = message_lifetime; +} + + +// write frame rate to top left of screen ------------------------------------- +// +void WriteFrameRate() +{ + char str[ 10 ]; + int pos = 9; + + str[ pos ] = 0; + + int value = FrameRate; + do { + int digit = value % 10; + str[ --pos ] = digit + '0'; + } while ( ( value /= 10 ) > 0 ); + + D_SetWStrContext( CharsetInfo[ HUD_CHARSETNO ].charsetpointer, + CharsetInfo[ HUD_CHARSETNO ].geompointer, + NULL, + CharsetInfo[ HUD_CHARSETNO ].width, + CharsetInfo[ HUD_CHARSETNO ].height ); + SetHudCharColor( 4 ); + D_WriteString( str + pos, 4, 6 ); +} + + +// write game time to bottom left of screen ----------------------------------- +// +void WriteGameTime() +{ + //TODO: + // move this into NET_UTIL.C? + + if ( GAME_NO_SERVER() ) + return; + + char str[ 10 ]; + int pos = 9; + int ypos = Screen_Height - CharsetInfo[ HUD_CHARSETNO ].height - 6; + int xpos = 4; + + D_SetWStrContext( CharsetInfo[ HUD_CHARSETNO ].charsetpointer, + CharsetInfo[ HUD_CHARSETNO ].geompointer, + NULL, + CharsetInfo[ HUD_CHARSETNO ].width, + CharsetInfo[ HUD_CHARSETNO ].height ); + SetHudCharColor( 4 ); + + if ( CurServerName != NULL ) { + D_WriteString( CurServerName, xpos, ypos ); + xpos += ( strlen( CurServerName ) + 1 ) * CharsetInfo[ HUD_CHARSETNO ].width; + } + + if ( !GAME_RUNNING() ) + return; + + str[ pos ] = 0; + + int minutes = CurGameTime / 60; + int seconds = CurGameTime % 60; + + if ( minutes > 99 ) + minutes = 99; + + do { + int digit = seconds % 10; + str[ --pos ] = digit + '0'; + } while ( ( seconds /= 10 ) > 0 ); + + if ( ( CurGameTime % 60 ) < 10 ) + str[ --pos ] = '0'; + + str[ --pos ] = ':'; + + do { + int digit = minutes % 10; + str[ --pos ] = digit + '0'; + } while ( ( minutes /= 10 ) > 0 ); + + if ( ( CurGameTime / 60 ) < 10 ) + str[ --pos ] = '0'; + + D_WriteString( str + pos, xpos, ypos ); +} + + +// write current server ping time to top right corner of screen --------------- +// +void WriteServerPing() +{ + if ( GAME_NO_SERVER() ) + return; + + if ( !AUX_DRAW_SERVER_PING ) + return; + + if ( CurServerPing < 0 ) + return; + + char str[ 10 ]; + + snprintf( str, 9, "%d", CurServerPing ); + + int xpos = Screen_Width - strlen( str ) * CharsetInfo[ HUD_CHARSETNO ].width - 6; + int ypos = 6; + + D_SetWStrContext( CharsetInfo[ HUD_CHARSETNO ].charsetpointer, + CharsetInfo[ HUD_CHARSETNO ].geompointer, + NULL, + CharsetInfo[ HUD_CHARSETNO ].width, + CharsetInfo[ HUD_CHARSETNO ].height ); + SetHudCharColor( 4 ); + + D_WriteString( str, xpos, ypos ); +} + +// write the extra collection message ----------------------------------------- +// +void WriteExtraCollectMessage( char* pszText ) +{ +// ShowMessage( text ); + + texfont_s *texfont = FetchTexfont( "impact" ); + if ( texfont != NULL ) { + + IterTexfont itexfont; + itexfont.itertype = iter_texrgba | iter_alphablend; + itexfont.raststate = rast_texclamp; + itexfont.rastmask = rast_nomask; + itexfont.texfont = texfont; + + itexfont.Vtxs[ 0 ].U = 1.0f; + itexfont.Vtxs[ 0 ].V = 1.0f; + itexfont.Vtxs[ 0 ].R = 255; + itexfont.Vtxs[ 0 ].G = 255; + itexfont.Vtxs[ 0 ].B = 255; + itexfont.Vtxs[ 0 ].A = 180; + + int width = D_TexfontGetWidth( pszText, &itexfont ); + + itexfont.Vtxs[ 0 ].X = ( Screen_Width - width ) / 2; + itexfont.Vtxs[ 0 ].Y = 100; + + texfontmsg_s msg; + msg.message = pszText; + msg.itexfont = &itexfont; + msg.msgtype = 0; + +// msg.starttime = 1500; +// msg.lifetime = 5000; +// msg.maxpulses = 1; +// msg.decalpha = 0.5f; + + msg.starttime = 0; + msg.lifetime = 5000; + msg.maxpulses = 4; + msg.decalpha = 0.8f; + + ShowTexfontMessage( &msg ); + } +} + |
