text.c

Go to the documentation of this file.
00001 
00025 #include "color.h"
00026 #include "render.h"
00027 #include "text.h"
00028 #include "genconmac.h"
00029 #include "states.h"
00030 #include <SDL_ttf.h>
00031 #include <string.h>
00032 #include <assert.h>
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035 #include <locale.h>
00036 #include <errno.h>
00037 
00038 #if defined(USE_GETTEXT) || defined(DOXYGEN)
00039 #include <wchar.h>
00040 #include <iconv.h>
00041 #if !defined(WIN32) || defined(DOXYGEN)
00042 
00048 static iconv_t strconvdescr;
00055 static iconv_t strconvntou;
00062 static iconv_t strconvuton;
00063 #endif
00064 #endif
00065 
00066 #ifndef TEXT_MAX_LINES
00067 
00070 #define TEXT_MAX_LINES  16
00071 #endif
00072 
00073 extern char binPath[128];
00074 
00075 // Probably should always compile in the English strings. If fwide() determines
00076 // that stdout is not wide, use English output to stdout, but still use wide
00077 // characters for the user's set language for the GUI.
00078 
00079 rtsa_char * strings[STRING_MAX];
00080 
00081 RenderItem textItems[TEXTITEM_MAX];
00082 
00088 static TTF_Font *fonts[FONT_MAX];
00089 
00096 static int spaceWidth[FONT_MAX];
00097 
00103 static int fontHeight[FONT_MAX];
00104 
00105 Bool TextInit() {
00106     #ifdef USE_GETTEXT
00107     int loop;
00108     char *codeset = NULL, *localeDir = NULL, *localeName = NULL;
00109     // setup the default locale
00110     localeName = setlocale(LC_ALL, "");
00111     #ifndef NDEBUG
00112     // use a non-defulat directory for the translations
00113     localeDir = bindtextdomain("rtsa", "./locale");
00114     #endif
00115     // set the domain using the program's name
00116     textdomain("rtsa");
00117     #ifndef WIN32
00118     // not MS 
00119     // use the native wide character type for strings returned by gettext()
00120     codeset = bind_textdomain_codeset("rtsa", "wchar_t");
00121     // conversion used on strings prior to being given to SDL_ttf
00122     strconvdescr = iconv_open("UTF-16", "wchar_t");
00123     // conversion used on strings before being sent over the network
00124     strconvntou = iconv_open("UTF-16BE", "wchar_t");
00125     // conversion used on strings received over the network
00126     strconvuton = iconv_open("wchar_t", "UTF-16BE");
00127     #else
00128     // MS Windows
00129     // endianness must be specified -- some iconv libraries on win32 will
00130     // default to big-endian
00131     codeset = bind_textdomain_codeset("rtsa", "UTF-16LE");
00132     #endif
00133     #ifndef NDEBUG
00134     if (localeName) {
00135         #ifdef WIN32
00136         prnout(L"Using locale %S\n", localeName);
00137         #else
00138         prnout(L"Using locale %s\n", localeName);
00139         #endif
00140     }
00141     if (localeDir) {
00142         #ifdef WIN32
00143         prnout(L"Getting translated stings from path: %S\n", localeDir);
00144         #else
00145         prnout(L"Getting translated stings from path: %s\n", localeDir);
00146         #endif
00147     }
00148 
00149     if (codeset) {
00150         #ifdef WIN32
00151         // A printf call here causes a crash. Don't yet understand why.
00152         prnout(L"Using %S character encoding\n", codeset);
00153         #else
00154         prnout(L"Using %s character encoding\n", codeset);
00155         #endif
00156     }
00157     else {
00158         // This may cuase a crash on Windows.
00159         prnout(
00160         L"No character encoding set. Check your enviornment for problems.\n");
00161     }
00162     #endif
00163     #endif
00164     
00165     // The label for the red team.
00166     // This string is not yet used and is included to support future
00167     // development. It is safe to leave it with the English default value.
00168     strings[STRING_REDTEAM]      = _("Red team");
00169     // The label for the blue team.
00170     // This string is not yet used and is included to support future
00171     // development. It is safe to leave it with the English default value.
00172     strings[STRING_BLUETEAM]     = _("Blue team");
00173     // The announcement that the red team's flag is currently held by a member
00174     // of the blue team.
00175     // This string is not yet used and is included to support future
00176     // development. It is safe to leave it with the English default value.
00177     strings[STRING_REDFLAGHELD]  = _("Red flag held by blue team");
00178     // The announcement that the blue team successfully captured the red team's
00179     // flag.
00180     // This string is not yet used and is included to support future
00181     // development. It is safe to leave it with the English default value.
00182     strings[STRING_REDFLAGCAP]   = _("Blue team scores!");
00183     // The announcement that the red team has won the game.
00184     // This string is not yet used and is included to support future
00185     // development. It is safe to leave it with the English default value.
00186     strings[STRING_REDWIN]       = _("Red team wins!");
00187     // The announcement that the blue team's flag is currently held by a member
00188     // of the red team. 
00189     // This string is not yet used and is included to support future
00190     // development. It is safe to leave it with the English default value.
00191     strings[STRING_BLUEFLAGHELD] = _("Blue flag held by red team");
00192     // The announcement that the red team successfully captured the blue team's
00193     // flag.
00194     // This string is not yet used and is included to support future
00195     // development. It is safe to leave it with the English default value.
00196     strings[STRING_BLUEFLAGCAP]  = _("Red team scores!");
00197     // The announcement that the blue team has won the game.
00198     // This string is not yet used and is included to support future
00199     // development. It is safe to leave it with the English default value.
00200     strings[STRING_BLUEWIN]      = _("Blue team wins!");
00201     #ifdef USE_GETTEXT
00202     // A notice that a player (%1$ls) has shot a teammate (%2%ls).
00203     strings[STRING_TEAMKILL]      = _("%ls shot teammate %ls");
00204     // A notice that the local player has shot a teammate (%ls).
00205     strings[STRING_LOCALTEAMKILLER] = _("You shot %ls, a teammate!");
00206     // A notice that the local player has been shot by a teammate (%ls).
00207     strings[STRING_LOCALTEAMKILLED] = _("Your teammate %ls shot you!");
00208     // A notice that a player (%1$ls) has shot an opponent (%2$ls) and now
00209     // has a personal score of %3$d.
00210     strings[STRING_KILL]          = _("%ls shot %ls for a score of %d");
00211     // A notice that the local player has shot an opponent (%1$ls) and now
00212     // has a personal score of %2$d.
00213     strings[STRING_LOCALKILL]     = _("You shot %ls, your score is %d");
00214     #else
00215     strings[STRING_TEAMKILL]        = "%s shot teammate %s";
00216     strings[STRING_LOCALTEAMKILLER] = "You shot %s, a teammate!";
00217     strings[STRING_LOCALTEAMKILLED] = "Your teammate %s shot you!";
00218     strings[STRING_KILL]            = "%s shot %s for a score of %d";
00219     strings[STRING_LOCALKILL]       = "You shot %s, your score is %d";
00220     #endif  
00221     // A prompt for the user to press fire to make their tank respawn. This
00222     // message is displayed in the middle of the screen when the player first
00223     // joins the game and after their tank has been destroyed.
00224     strings[STRING_RESPAWN]      = _("Press fire to spawn your tank");
00225     // The game's title. It appears on the title and menu screens, and if
00226     // visible, the game window's title bar. On systems with older versions
00227     // of SDL (before 1.2.10), the title bar will always have the English
00228     // string, but the title and menu screens will have the translated string.
00229     // If the platform doesn't support UTF/UCS for the title bar, oh well.
00230     strings[STRING_TITLE]         = _("Retro Tank Super Attack");
00231     // The author's name and email address.
00232     strings[STRING_AUTH]          = _("by Jeff Jackowski (jeffj@ro.com)");
00233     // A message stating who did the translation displayed on the title
00234     // screen. This string is not displayed when set to the default
00235     // "translator", as it is for English.
00236     strings[STRING_TRANS]         = _("translator");
00237     #ifdef USE_GETTEXT
00238     // Copyright notice.
00239     strings[STRING_COPYRIGHT]     = _("Copyright \xC2\xA9 2007");
00240     #else
00241     strings[STRING_COPYRIGHT]     = "Copyright \xA9 2007";
00242     #endif
00243     // GPL notice. This will display on the title screen at the bottom.
00244     // The official GPL is only in English, although a number of unofficial
00245     // translations exist to help everyone understand its terms.
00246     // The translations are listed at:
00247     //   http://www.gnu.org/licenses/translations.html
00248     strings[STRING_GPL] = _( \
00249     "Retro Tank Super Attack comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions as defined by the GPL. For more details, see the GPL at: http://www.gnu.org/copyleft/gpl.html");
00250     // A prompt for the user to select a team to join.
00251     strings[STRING_CHOSETEAM]     = _("Chose your team");
00252     // A prompt for the user to press the fire button for more network play
00253     // options. Since there are no options yet, it is ok to make this a space
00254     // to prevent the prompt from being visible.
00255     strings[STRING_FIREOPT]       = _("Press fire for options");
00256     // A prompt for the user to press the fire button to continue on to the
00257     // next screen.
00258     strings[STRING_FIRECONT]      = _("Press fire to continue");
00259     // A message informing the user that the game is looking for a server on
00260     // the LAN.
00261     strings[STRING_NETLOOKING]    = _("Looking for server . . .");
00262     // A status message indicating that the game is attempting to contact a
00263     // server (hostname is %s) and is waiting for a response.
00264     strings[STRING_NETCONTACT]    = _("Contacting %s");
00265     // A message telling the user that the game has contacted a server
00266     // (hostname is %s) and is waiting on game option/config data before the
00267     // user can join the game in progress.
00268     strings[STRING_NETRCVCFG]     = _("Connected to %s, awaiting game options");
00269     // A message telling the user that the game has contacted a server
00270     // (hostname is %s) and the user can join the game now.
00271     strings[STRING_NETCLIENT]     = _("Connected to %s");
00272     // A message informing the user that the game client is disconnecting from
00273     // the server.
00274     strings[STRING_NETCLIDISCONN] = _("Disconnecting from server . . .");
00275     // A status message indicating that the game is running as a server. The
00276     // machine's hostname, or IP address if the name lookup fails, is %s.
00277     strings[STRING_NETSERVER]     = _("Running as server %s");
00278     // A message informing the user that the server is disconnecting all game
00279     // clients.
00280     strings[STRING_NETSRVDISCONN] = _("Disconnecting all clients . . .");
00281     // A message telling the user that the server (hostname %s) will not allow
00282     // the game client to connect.
00283     strings[STRING_NETDENY]       = _("Server %s denied the connection");
00284     // A status message indicating the game has disconnected from the server
00285     // or all clients.
00286     strings[STRING_NETDISCONN]    = _("Disconnected");
00287     #ifdef USE_GETTEXT
00288     // An error message informing the user that the process of finding a server
00289     // on the LAN could not be performed. This does not mean that a server
00290     // could not be found, but that the finding could not be done. The error
00291     // string is %ls and its translations are in net.c.
00292     strings[STRING_NETSEARCHERR]  = _("Error prevented server discovery (%ls)");
00293     // An error message indicating that the game could not run as a server.
00294     // The error string is %ls and its translations are in net.c.
00295     strings[STRING_NETSRVERR]     = _("Error prevented running a server (%ls)");
00296     // An error message telling the user that the game acting as a client
00297     // could not connect to a server. The error is %ls.
00298     strings[STRING_NETCONERR]     = \
00299     _("Error prevented connecting to the server (%ls)");
00300     #else
00301     strings[STRING_NETSEARCHERR]  = "Error prevented server discovery (%s)";
00302     strings[STRING_NETSRVERR]     = "Error prevented running a server (%s)";
00303     strings[STRING_NETCONERR]     = 
00304     "Error prevented connecting to the server (%s)";
00305     #endif
00306     // A status message showing this computer's network address (%s, not
00307     // hostname).
00308     strings[STRING_NETADDR]       = _("Local address: %s");
00309     // A message informing the user that time synchronization with the server
00310     // is in progress.
00311     strings[STRING_NETSYNC]       = _("Performing time synchronization");
00312     // A message with the latency result of time synchronization. The latency
00313     // value is given as a double (I recommed using %0.1lf for one digit after
00314     // the decimal point). The units are milliseconds.
00315     strings[STRING_NETLAT]        = _("Latency: %0.1lfms");
00316     // The player name used when a name cannot be determined from the
00317     // environment variables. Normally a username can be found in the
00318     // environment on UNIX-like and Windows systems.
00319     strings[STRING_DEFAULTNAME]   = _("Anonymous");
00320     
00321     // The time format. The first parameter (%02d) is the number of minutes,
00322     // the second is the number of seconds.
00323     // This string is not yet used and is included to support future
00324     // development. It is safe to leave it with the English default value.
00325     strings[STRING_TIMEFORM]      = _("%02d:%02d");
00326     // The time that remains for the round of combat.
00327     // This string is not yet used and is included to support future
00328     // development. It is safe to leave it with the English default value.
00329     strings[STRING_TIMELEFT]      = _("Time left:");
00330     
00331     // A format for status output showing a summary of information read from
00332     // the battlefield file(s). This output is only shown on the console
00333     // (stdout.txt on Windows) to assist people in creating their own battle
00334     // fields. The string is only shown on the console (stdout.txt or debug
00335     // console on Windows) and not the GUI.
00336     //
00337     // Be sue to add the approprite line breaks ('\n'), including one at the
00338     // end of the string.
00339     strings[STRING_BF_STAT] = \
00340     _("Finished parsing the battlefield configuration file successfully\nStats:\n       Red  Blue\nSpawn  %3d   %3d\nGoal   %3d   %3d\nObstacles    %3d\n");
00341     // A success/debugging message sent to the console (stdout.txt on Windows)
00342     // that indicates the battlefield data is ready for network transmission.
00343     strings[STRING_CMPLOPT] = \
00344     _("Compiled %i network messages that describe the game options\n");
00345     #ifdef USE_GETTEXT
00346     // The sting used to present errors with line numbers encountered while
00347     // reading the battlefield fil(e) to the user. The first parameter (%1$s)
00348     // is the name of the file. The second parameter (%2$i) is the line number
00349     // where the problem can be found. The third (%3$ls) is the error string.
00350     // OK to use just %s and %i so long as the ordering is maintained.
00351     strings[STRING_ERR_READ] = \
00352     _("Error in file %s at line %i: %ls");
00353     // The sting used to present errors without line numbers encountered while
00354     // reading the battlefield fil(e) to the user. These errors are not
00355     // attributed to any particular section of the file(s). The only parameter
00356     // (%ls) is the error string.
00357     strings[STRING_ERR_PROC] = \
00358     _("Error while processing the battlefield: %ls");
00359     #else
00360     strings[STRING_ERR_READ] = \
00361     _("Error in file %s at line %i: %s");
00362     strings[STRING_ERR_PROC] = \
00363     _("Error while processing the battlefield: %s");
00364     #endif
00365     // Too little memory to handle the battlefield file.
00366     strings[STRING_ERR_MEM]       = _("Inadequate memory");
00367     // The battlefield file (%s) could not be opened.
00368     strings[STRING_ERR_FOPEN]     = _("Could not open file: %s");
00369     // The battlefield file ends after the start of an include statement before
00370     // the name of the file to include. So, the word include, followed maybe
00371     // by whitespace, then the end of the file.
00372     strings[STRING_ERR_EOFINC]   = _("End of file in include statement");
00373     // The name of a battlefield file (%s) to include continues to the end of
00374     // the file. It should be terminated by either a semicolon (;) or the end
00375     // of a line.
00376     strings[STRING_ERR_EOFNAME]  = _("End of file in file name: %s");
00377     // The name of a battlefield file to include is too long. The maximum
00378     // length is 127 characters. Only the first ten characters of the file name
00379     // will be used in the output (%s).
00380     strings[STRING_ERR_NAMELONG] = _("File name too long: %s...");
00381     // The size of the battlefield is too small. Each dimension should be at
00382     // least 32. This is just a sanity check to keep the game from being
00383     // unplayable. %1$d is the specified horizontal size, and %2$d is the
00384     // vertical size. OK to use %d twice; it will always be horizontal then
00385     // vertical.
00386     strings[STRING_ERR_FLDSMALL] = _("Field size, %dx%d, too small");
00387     // The size of the battlefield is too large. The size is currently limited
00388     // to 2048 in each dimension. The two parameters are the same as above.
00389     strings[STRING_ERR_FLDLARGE] = _("Field size, %dx%d, too large");
00390     // The battlefield's size is not specified. It is specified with the size
00391     // keyword. It should appear at least once in the battlefield files. Only
00392     // the first occurrence is used.
00393     strings[STRING_ERR_NOSIZE]   = _("Battlefield size not specified");
00394     // An invalid keyword (%s) is in the battlefield file.
00395     strings[STRING_ERR_INVLDKEY] = _("Invalid keyword: %s");
00396     // No spawn area was specified for the red (player's) team.
00397     strings[STRING_ERR_NOREDSPN] = _("Spawn area for red team not specified");
00398     // No spawn area was specified for the blue team.
00399     strings[STRING_ERR_NOBLSPN] = _("Spawn area for blue team not specified");
00400     // No goal area specified for the red team. For capture-the-flag games,
00401     // a goal area must be given for each team.
00402     // This string is not yet used and is included to support future
00403     // development. It is safe to leave it with the English default value.
00404     strings[STRING_ERR_NOREDGOAL]  = _("Goal area for red team not specified");
00405     // No goal area specified for the blue team. For capture-the-flag games,
00406     // a goal area must be given for each team.
00407     // This string is not yet used and is included to support future
00408     // development. It is safe to leave it with the English default value.
00409     strings[STRING_ERR_NOBLGOAL]   = _("Goal area for blue team not specified");
00410     // Illegal use of a backslash in the path to a battlefield file.
00411     // Backslashes are not allowed because they are only supported on Windows.
00412     // Slashes work on almost all modern operating systems, including Windows,
00413     // so they should be used instead to enhance multi-platform compatibility.
00414     strings[STRING_ERR_BACKSLASH] \
00415     = _("Illegal backslashes used in file path: %s");
00416     // General I/O error while reading from a battlefield file.
00417     strings[STRING_ERR_IO]       = _("I/O error while reading");
00418     // Line break before the end of a token.
00419     strings[STRING_ERR_EOL]      = _("Token has line break");
00420     // Too few parameters were given to a statement in a battlefield file.
00421     strings[STRING_ERR_PARAM] \
00422     = _("Too few parameters for statement");
00423     // A specified coordinate is out of the allowable range. The current
00424     // maximum is 2047, and the minimum is 0.
00425     strings[STRING_ERR_XYRANGE]  = _("X or Y coordinate out of range");
00426     // A specified height or width is out of the allowable range. The current
00427     // maximum is 2047, and the minimum is 1.
00428     strings[STRING_ERR_WHRANGE]  = _("Bad width or height");
00429     // An invalid team (%s) was specified as the owning team of either a goal
00430     // or spawn area.
00431     strings[STRING_ERR_BADOWN]   = _("Bad team owning area: %s");
00432     // Message for no network error. Specified in case the error string
00433     // is requested when there was no error.
00434     strings[STRING_ERR_NONE]     = _("No error");
00435     // Message indicating that a non-blocking network operation is
00436     // waiting on data, so there is no data to process now.
00437     strings[STRING_ERR_WOULDBLOCK] = \
00438     _("Non-blocking operation waiting on data");
00439     // An error message indicating that an invalid file descriptor was
00440     // used for a socket in a network function call.
00441     strings[STRING_ERR_BADF]     = _("Invalid file descriptor for the socket");
00442     // An error indicating that a buffer pointer is bad and attempting
00443     // to access its data will result in a segmentation fault (crash).
00444     strings[STRING_ERR_FAULT] = \
00445     _("Fault reading or writing to the given pointer(s)");
00446     // A message indicating that an operation was interrupted before it
00447     // could complete.
00448     strings[STRING_ERR_INTR]     = _("Operation interrupted");
00449     // A general error message indicating that something is invalid.
00450     strings[STRING_ERR_INVAL]    = _("Bad invalidness");
00451     // An error message indicating that a file descriptor used in a
00452     // network function call is not actually a socket.
00453     strings[STRING_ERR_NOTSOCK]  = _("Not a socket");
00454     // An error message indicating that the requested socket address is
00455     // already being used. This will happen if an attempt is made to
00456     // run two game serers on the same computer, or if there are two
00457     // game processes running and looking for a server.
00458     strings[STRING_ERR_ADDRINUSE] = _("Address & port already in use");
00459     // An error message indicating that the network is down. Could be
00460     // caused by having no availble network interfaces.
00461     strings[STRING_ERR_NETDOWN]  = _("Network is down");
00462     // An error message indicating an unreachable network. Could be
00463     // cuased by a bad routing table.
00464     strings[STRING_ERR_NETUNREACH] = _("Network unreachable");
00465     // An error indicating that the remote end closed a connection.
00466     // Since this game uses UDP and not TCP, this shouldn't happen, but
00467     // is here for completeness anyway.
00468     strings[STRING_ERR_CONNRESET] = _("Connection closed by remote end");
00469     // An error indicating that the remote end did not accept incomming
00470     // data. This could happen if a connection between a client and
00471     // server is established, and then one of them crashes. The still
00472     // running process should recieve this error.
00473     strings[STRING_ERR_CONNREFUSED] = _("Previously sent data was refused");
00474     // An error indicating that a host was unreachable. Happens when
00475     // there is no route to the destination host.
00476     strings[STRING_ERR_HOSTUNREACH] = _("Host unreachable");
00477     // An error issued to the console (stderr) giving a specific error for a
00478     // failed hostname lookup. Since this string is not presented on the GUI,
00479     // consider translating it is a low priority.
00480     strings[STRING_ERR_HOSTLOOK]  = _("Hostname lookup error: %s\n");
00481     // An error message displayed on the console (stderr) indicating that
00482     // SDL could not be initialized. Without SDL, the game cannot provide
00483     // a GUI or accept input. The error string (%s) is provided by SDL
00484     // and is likely only in English.
00485     strings[STRING_ERR_SDL]       = _("Unable to initialize SDL: %s\n");
00486     // An error message displayed on the console (stderr) indicating that
00487     // the query for information about the availble video output failed.
00488     // Without this information, proper video output cannot be established.
00489     // The error string (%s) is provided by SDL and is likely only in
00490     // English.
00491     strings[STRING_ERR_VIDQ]      = _("Video query failed: %s\n");
00492     // An error message displayed on the console (stderr) indicating that
00493     // the game was unable to get video output in the requested mode
00494     // (resolution, color depth, etc..). No video, no game. The error
00495     // string (%s) is provided by SDL and is likely only in English.
00496     strings[STRING_ERR_VIDMODE]   = _("Unable to set video mode: %s\n");
00497     // An error message displayed on the console (stderr) indicating that
00498     // the SDL_ttf font rendering library failed to initialize. Without
00499     // this library, the game cannot display text in its graphical output
00500     // which would make it hard to use, so the game will quit instead.
00501     // The error string (%s) is provided by SDL_ttf and is likely only in
00502     // English.
00503     strings[STRING_ERR_TTFINIT]   = _("Unable to initalize SDL_ttf: %s\n");
00504     // An error message displayed on the console (stderr) indicating that
00505     // the game's rendering system failed to initialize properly, preventing
00506     // graphical output.
00507     strings[STRING_ERR_RENDER] = \
00508     _("Unable to initalize the rendering system\n");
00509     // An error displayed on the console (stderr) indicating that a font file
00510     // (%s) could not be opened.
00511     strings[STRING_ERR_FNTOPEN]   = _("Could not open font file: %s\n");
00512     // An error message displayed on the console (stderr) indicating that
00513     // the game failed to load and initialize its fonts.
00514     strings[STRING_ERR_FNTINIT]   = _("Unable to initalize the fonts\n");
00515     // An error message indicating that the requested audio output is
00516     // not available. The game will attempt to continue without sound,
00517     // but the error is still sent to stderr. The error description (%s)
00518     // comes directly from SDL_mixer and is likely in English.
00519     strings[STRING_ERR_OPENAUDIO] = _("Failed to open audio output: %s\n");
00520     // An error message given when one of the game's sound files could
00521     // not be loaded. The file name is %s.
00522     strings[STRING_ERR_LOADSND]  = _("Failed to load sound from file %s\n");
00523     // A message indicating that none of the game's sounds could be loaded.
00524     // When this occurs, the game will run without sound.
00525     strings[STRING_ERR_NOSNDS]   = _("No sounds could be loaded\n");    
00526     // A catch-all message for all other errors.
00527     strings[STRING_ERR_DEFAULT]   = _("Some unbogus error");
00528     // A status message output on the console (stdout) telling curious
00529     // users that the video output is single buffered.
00530     strings[STRING_STAT_SINGLEBUFF] = _("Video output is single-buffered\n");
00531     // A status message output on the console (stdout) telling curious
00532     // users that the video output is double buffered.
00533     strings[STRING_STAT_DOUBLEBUFF] = _("Video output is double-buffered\n");
00534     // A status message output on the console (stdout) telling curious
00535     // users that the video output has no hardware acceleration.
00536     strings[STRING_STAT_NOHWACCEL] = \
00537     _("Video output lacks hardware acceleration\n");
00538     // A status message output on the console (stdout) telling curious
00539     // users that the video output benifits from hardware acceleration.
00540     strings[STRING_STAT_HWACCEL]  = _("Video output is hardware accelerated\n");
00541     // A status message output on the console (stdout) telling curious
00542     // users that the video output surface (where things are drawn to)
00543     // resides system memory.
00544     strings[STRING_STAT_OUTSYSMEM] = \
00545     _("Video output surface is stored in system memory\n");
00546     // A status message output on the console (stdout) telling curious
00547     // users that the video output surface (where things are drawn to)
00548     // resides in memory belonging to the graphics hardware rather than
00549     // system/main memory.
00550     strings[STRING_STAT_OUTGRPMEM] = \
00551     _("Video output surface is stored in the graphics hardware's memory\n");
00552     // A status message output on the console (stdout) telling curious
00553     // users the name of the video driver that the game will use.
00554     strings[STRING_STAT_VIDDRNAME] = _("Video driver is %s\n");
00555     // A status message output on the console (stdout) telling curious
00556     // users that the game has found and will use a joystick or
00557     // similar controller. The first parameter (%1$s) is the name of
00558     // the controller. The second (%2$d) is the number of axes found
00559     // on the controller. The final parameter (%3$d) is the number
00560     // of buttons on the controller.
00561     strings[STRING_STAT_JOYSTICK] = \
00562     _("Using joystick %s:\n\tAxes: %d\n\tButtons: %d\n");
00563     // A warning indicating that the game could not initalize audio output.
00564     // When this happens, the game will attempt to continue without audio.
00565     strings[STRING_STAT_NOAUDIO] = \
00566     _("Could not initialize audio; continuing without sound\n");
00567     // An informational message showing that the game has entered its state
00568     // loop from where everything else runs.
00569     strings[STRING_STAT_ENTERSTATE] = _("Entering state loop\n");
00570     // An informational message showing that the game has left its state
00571     // loop and will begin to shutdown all of its innards.
00572     strings[STRING_STAT_EXITSTATE] = _("Exited state loop; shutting down\n");
00573     
00574     #ifdef USE_GETTEXT
00575     // see if ASCII stuff is in the strings
00576     //  This is a part of gettext I find annoying.
00577     if (strcmp((char*)(strings[STRING_REDTEAM]), "Red team") == 0) {
00578         char *src;
00579         wchar_t *dest;
00580         size_t srcLen, destLen;
00581         // fix all strings
00582         #ifndef WIN32
00583         iconv_t descr = iconv_open("wchar_t", "UTF-8");
00584         #else
00585         iconv_t descr = iconv_open("UTF-16LE", "UTF-8");
00586         #endif
00587         // error?
00588         if (descr == (iconv_t)-1) {
00589             #if defined(WIN32) && !defined(NDEBUG)
00590             int err = errno; // so we can look before next printf causes crash
00591             #endif
00592             // must have wide character strings, so now die
00593             prnfile(stderr,
00594             L"Cannot convert internal strings to wide character strings\nError code: %d\n",
00595             errno);
00596             exit(1);
00597         }
00598         #ifndef NDEBUG
00599         prnout(
00600         L"Translated strings were not loaded; using internal English strings instead\n");
00601         #endif
00602         // lop through the strings
00603         for (loop = 0; loop < STRING_MAX; loop++) {
00604             // grab a source pointer and find the length of the source
00605             srcLen = (int)strlen(src = (char*)strings[loop]);
00606             // allocate space for the destination
00607             strings[loop] = dest = malloc(
00608             destLen = (srcLen + 1) * sizeof(wchar_t));
00609             // convert the string
00610             iconv(descr, &src, &srcLen, (char**)&dest, &destLen);
00611             *dest = 0;
00612         }
00613         iconv_close(descr);
00614     }
00615     #ifdef WIN32        
00616     // for the one system with a broken wprintf . . .
00617     {
00618         rtsa_char buff[1024], **src;
00619         int srcInd, destInd;
00620         Bool typeStart;
00621         // loop through the strings
00622         for (src = strings, loop = 0; loop < STRING_MAX; src++, loop++) {
00623             typeStart = FALSE;
00624             // loop through the characters in a string
00625             for (srcInd = destInd = 0; (*src)[srcInd] != 0;
00626             srcInd++, destInd++) { 
00627                 // check for a regular (single-byte) character string type
00628                 if (typeStart && ((*src)[srcInd] == 's')) {
00629                     // use MS's reverse X/Open non-ISO standard
00630                     buff[destInd] = 'S';
00631                     typeStart = FALSE;
00632                     continue;
00633                 }
00634                 // check for a wide character string type
00635                 else if (typeStart && ((*src)[srcInd] == 'l') &&
00636                 ((*src)[srcInd + 1] == 's')) {
00637                     // use MS's reverse ISO standard
00638                     buff[destInd] = 's';
00639                     // advance one more source character
00640                     srcInd++;
00641                     typeStart = FALSE;
00642                     continue;
00643                 }
00644                 // check for the start of a type
00645                 else if ((*src)[srcInd] == '%') {
00646                     // set the flag
00647                     typeStart = TRUE;
00648                 }
00649                 // assure that the character is not the field width or the
00650                 // positional paramter for formating
00651                 else if (((*src)[srcInd] != '$') &&
00652                 !iswdigit((*src)[srcInd])) {
00653                     // not a type start
00654                     typeStart = FALSE;
00655                 }
00656                 // copy the character
00657                 buff[destInd] = (*src)[srcInd];
00658             }
00659             // null terminate destination
00660             buff[destInd] = 0;
00661             // allocate memory for the converted string
00662             (*src) = malloc(sizeof(wchar_t) * (destInd + 1));
00663             // copy over the string
00664             memcpy(*src, buff, sizeof(wchar_t) * (destInd + 1));
00665         }
00666     }
00667     // for WIN32
00668     #endif
00669     // for Gettext
00670     #endif
00671     // success
00672     return TRUE;
00673 }
00674 
00675 Bool FontInit() {
00676     char path[128];
00677     int len, loop;
00678     const Uint16 space[] = { ' ', 0 };
00679 
00683     // clear out all the text items
00684     memset(textItems, 0, sizeof(textItems));
00685     // build a path to the data file from the current working directory
00686     strcpy(path, binPath);
00687     len = (int)strlen(path);
00688     strcpy(path + len, "font.ttf");
00689     // prepare the fonts for use
00690     if ((fonts[FONT_MESSAGE] = TTF_OpenFont(path, 32)) == NULL) {
00691         goto FontInit_noFont;
00692     }
00693     if ((fonts[FONT_SCORE] = TTF_OpenFont(path, 16)) == NULL) {
00694         goto FontInit_noFont;
00695     }
00696     if ((fonts[FONT_PLAYER] = TTF_OpenFont(path, 10)) == NULL) {
00697         goto FontInit_noFont;
00698     }
00699     // find the width of a space for each font
00700     for (loop = 0; loop < FONT_MAX; loop++) {
00701         TTF_SizeUNICODE(fonts[loop], space, &spaceWidth[loop], NULL);
00702         fontHeight[loop] = TTF_FontLineSkip(fonts[loop]);
00703     }
00704     return TRUE;
00705     // Handle not being able to open a font
00706     FontInit_noFont:
00707     // tell the user about the failure
00708     prnfile(stderr, strings[STRING_ERR_FNTOPEN], path);
00709     return FALSE;
00710 }
00711 
00729 static Bool TextSetup(int startStr, int startInd, int endInd, int font,
00730 SDL_Color color) {
00731     int loop, strInd;
00732     // render common messages for later use
00733     for (strInd = startStr, loop = startInd; loop < endInd;
00734     strInd++, loop++) {
00735         #ifdef USE_GETTEXT
00736         #ifndef WIN32
00737         // convert the string
00738         Uint16 destStr[96];
00739         char *src = (char*)strings[strInd], *dest = (char*)destStr;
00740         size_t srcLen = (wcslen((wchar_t*)src) + 1) * sizeof(rtsa_char);
00741         size_t destLen = sizeof(destStr);
00742         iconv(strconvdescr, &src, &srcLen, &dest, &destLen);
00743         *dest = 0;
00744         // render the message
00745         if ((textItems[loop].data = TTF_RenderUNICODE_Blended(fonts[font],
00746         destStr, color)) == NULL)
00747         #else
00748         // render the message
00749         if ((textItems[loop].data = TTF_RenderUNICODE_Blended(fonts[font],
00750         strings[strInd], color)) == NULL)
00751         #endif
00752         #else
00753         // render the message and check for error
00754         if ((textItems[loop].data = TTF_RenderText_Blended(fonts[font],
00755         strings[strInd], color)) == NULL)
00756         #endif
00757         {
00758             // error!
00759             return FALSE;
00760         }
00761         // setup the width and height of the item
00762         textItems[loop].loc.w = ((SDL_Surface*)textItems[loop].data)->w;
00763         textItems[loop].loc.h = ((SDL_Surface*)textItems[loop].data)->h;
00764         // set the render function
00765         textItems[loop].renderer = GenericSurfaceRenderer;
00766         // put the text in the text layer
00767         if (textItems[loop].parent == NULL) {
00768             AddRenderItem(&(textItems[loop]), LAYER_TEXT);
00769         }
00770     }
00771     return TRUE;
00772 }
00773 
00774 Bool TextSetupStateSplash()  {
00775     // render common messages for later use
00776     if (TextSetup(STRING_TITLE, TEXTITEM_TITLE, TEXTITEM_TITLE + 1,
00777     FONT_MESSAGE, colorFmtInd[COLOR_TEXT]) && TextSetup(STRING_AUTH,
00778     TEXTITEM_AUTH, TEXTITEM_AUTH + 1, FONT_SCORE,
00779     colorFmtInd[COLOR_TEXT]) && TextSetup(STRING_COPYRIGHT, TEXTITEM_COPYRIGHT,
00780     TEXTITEM_COPYRIGHT + 1, FONT_PLAYER, colorFmtInd[COLOR_TEXT]) &&
00781     TextRenderString(&textItems[TEXTITEM_GPL], FONT_PLAYER, 340,
00782     colorFmtInd[COLOR_TEXT], strings[STRING_GPL])) {
00783         // put the GPL in the text layer -- TextRenderString() doesn't do this
00784         if (textItems[TEXTITEM_GPL].parent == NULL) {
00785             AddRenderItem(&(textItems[TEXTITEM_GPL]), LAYER_TEXT);
00786         }
00787         // check for a translator
00788         #ifdef USE_GETTEXT
00789         if (wcscmp(L"translator", strings[STRING_TRANS]) != 0)
00790         #else
00791         if (strcmp("translator", strings[STRING_TRANS]) != 0)
00792         #endif
00793         {
00794             // render the translator credit & check for failure
00795             if (!TextRenderString(&textItems[TEXTITEM_TRANS], FONT_SCORE, 340,
00796             colorFmtInd[COLOR_TEXT], strings[STRING_TRANS])) {
00797                 // failure
00798                 return FALSE;
00799             }
00800             // assure it is in the text layer
00801             if (textItems[TEXTITEM_TRANS].parent == NULL) {
00802                 AddRenderItem(&(textItems[TEXTITEM_TRANS]), LAYER_TEXT);
00803             }
00804         }
00805         // success!
00806         return TRUE;
00807     }
00808     // failure
00809     return FALSE;
00810 }
00811 
00812 Bool TextSetupStateMenu()  {
00813     // render common messages for later use
00814     if (TextSetup(STRING_TITLE, TEXTITEM_TITLE, TEXTITEM_TITLE + 1,
00815     FONT_MESSAGE, colorFmtInd[COLOR_TEXT]) && TextSetup(STRING_CHOSETEAM,
00816     TEXTITEM_CHOSETEAM, TEXTITEM_FIREOPT + 1, FONT_SCORE,
00817     colorFmtInd[COLOR_TEXT])) {
00818         // success!
00819         return TRUE;
00820     }
00821     // failure
00822     return FALSE;
00823 }
00824 
00825 Bool TextSetupStatePlay()  {
00826     // render common messages for later use
00827     if (TextSetup(STRING_REDTEAM, TEXTITEM_REDTEAM, TEXTITEM_BLUETEAM + 1,
00828     FONT_SCORE, colorFmtInd[COLOR_TEXT]) && TextSetup(STRING_RESPAWN,
00829     TEXTITEM_RESPAWN, TEXTITEM_RESPAWN + 1, FONT_MESSAGE,
00830     colorFmtInd[COLOR_TEXT])) {
00831         // success!
00832         return TRUE;
00833     }
00834     // failure
00835     return FALSE;
00836 }
00837 
00838 void TextUnsetState()  {
00839     int loop;
00840     // loop through all the text items
00841     for (loop = 0; loop < TEXTITEM_MAX; loop++) {
00842         // if the item has a surface . . .
00843         if (textItems[loop].data) {
00844             // . . . free that surface
00845             SDL_FreeSurface(textItems[loop].data);
00846         }
00847         // if the item is a member of a layer . . .
00848         if (textItems[loop].parent != NULL) {
00849             // remove it from the layer
00850             RemoveRenderItem(&(textItems[loop]));
00851         }
00852     }
00853     // clear all data for extra good certainies today!
00854     memset(textItems, 0, sizeof(textItems));
00855 }
00856 
00857 void TextUninit()  {
00858     int loop;
00859     #ifdef USE_GETTEXT
00860     char *test = "Red team";
00861     #endif
00862     // assure the rendered text is gone
00863     TextUnsetState();
00864     // loop through all fonts
00865     for (loop = 0; loop < FONT_MAX; loop++) {
00866         // remove the font
00867         TTF_CloseFont(fonts[loop]);
00868     }
00869     #ifdef USE_GETTEXT
00870     // see if gettext couldn't load any strings
00871     test = gettext(test);
00872     if (strcmp(test, "Red team") == 0) {
00873         // deallocate all the converted strings
00874         for (loop = 0; loop < STRING_MAX; loop++) {
00875             free(strings[loop]);
00876         }
00877     }
00878     #ifndef WIN32
00879     iconv_close(strconvdescr);
00880     iconv_close(strconvntou);
00881     iconv_close(strconvuton);
00882     #endif
00883     #endif
00884 }
00885 
00886 int TextNativeToUTF16(Uint16 *dest, size_t destlen, rtsa_char *src,
00887 size_t srclen) {
00888     size_t len;
00889     // there must be enough room in the output buffer
00890     assert(destlen > srclen);
00891     // convert lengths to bytes
00892     srclen *= sizeof(rtsa_char);
00893     destlen <<= 1;
00894     #if defined(USE_GETTEXT) && !defined(WIN32)
00895     len = destlen;
00896     // convert!
00897     if (iconv(strconvntou, (char**)&src, &srclen, (char**)&dest, &len) < 0) {
00898         // error
00899         return -1;
00900     }
00901     // assure null termination
00902     *dest = 0;
00903     // send back the length, in shorts, of the converted string
00904     return (destlen - len) >> 1;
00905     #else
00906     #ifndef USE_GETTEXT
00907     srclen <<= 1;
00908     #endif
00909     // loop through all the characters
00910     for (len = 0; len < srclen; len += 2, src++) {
00911         // copy and check for null terminator
00912         #ifdef USE_GETTEXT
00913         ((Uint8*)(dest))[len]     = *src >> 8;
00914         #else
00915         ((Uint8*)(dest))[len]     = 0;
00916         #endif
00917         ((Uint8*)(dest))[len + 1] = *src & 0xFF;
00918         if (*src == 0) {
00919             // quit copying
00920             return (int)len >> 1;
00921         }
00922     }
00923     // assure null termination
00924     dest[srclen] = 0;
00925     // send back the length, in shorts, of the converted string
00926     return (int)len >> 1;
00927     #endif
00928 }
00929 
00930 int TextUTF16toNative(rtsa_char *dest, size_t destlen, Uint16 *src,
00931 size_t srclen) {
00932     size_t len;
00933     // there must be enough room in the output buffer
00934     assert(destlen > srclen);
00935     // convert lengths to bytes
00936     srclen <<= 1;
00937     destlen *= sizeof(rtsa_char);
00938     #if defined(USE_GETTEXT) && !defined(WIN32)
00939     len = destlen;
00940     // there must be at least twice as many bytes in the output buffer
00941     assert(destlen > (srclen << 1));
00942     if (iconv(strconvuton, (char**)&src, &srclen, (char**)&dest, &len) < 0) {
00943         // error
00944         return -1;
00945     }
00946     // assure null termination
00947     *dest = 0;
00948     // send back the length, in wchar_t's, of the converted string
00949     return (destlen - len) / sizeof(rtsa_char);
00950     #else
00951     //srclen /= sizeof(rtsa_char);
00952     // loop through all the characters
00953     for (len = 0; len < srclen; len += 2, dest++) {
00954         // copy and check for null terminator
00955         #ifdef USE_GETTEXT
00956         // copy from big endian source
00957         *dest = (((Uint8*)(src))[len] << 8) | ((Uint8*)(src))[len + 1];
00958         #else
00959         // character larger than a byte?
00960         if (((Uint8*)(src))[len] > 0) {
00961             // can't represent it in ASCII, but must maintain a string with the
00962             // same number of characters
00963             *dest = '?';
00964         }
00965         else {
00966             // can represent this one in ASCII
00967             *dest = ((Uint8*)(src))[len + 1];
00968         }
00969         #endif
00970         if (*dest == 0) {
00971             // quit copying
00972             return (int)len >> 1;
00973         }
00974     }
00975     // assure null termination
00976     *dest = 0;
00977     // send back the length, in shorts, of the converted string
00978     return (int)len >> 1;
00979     #endif
00980 }
00981 
00982 void TextSetWindowTitle() {
00991     #ifdef USE_GETTEXT
00992     // find the version of SDL in use
00993     const SDL_version * const ver = SDL_Linked_Version();
00994     // for version 1.2.10 and later, generate a UTF-8 string
00995     if ((ver->major >= 1) && (ver->minor >= 2) && (ver->patch >= 10)) {
00996         char buff[128], *buffPtr = buff, *inPtr = (char*)strings[STRING_TITLE];
00997         size_t res, inlen, outlen = 128;
00998         // converter from internal wchar_t to UTF-8
00999         iconv_t titleconv;
01000         // create the character encoding converter
01001         #ifdef WIN32
01002         titleconv = iconv_open("UTF-8", "UTF-16LE");
01003         #else
01004         titleconv = iconv_open("UTF-8", "wchar_t");
01005         #endif
01006         inlen = (rtsa_strlen(strings[STRING_TITLE]) + 1) * sizeof(rtsa_char);
01007         // convert the title string
01008         res = iconv(titleconv, &inPtr, &inlen, &buffPtr, &outlen);
01009         // no more need for the character encoding converter
01010         iconv_close(titleconv);
01011         // check for success
01012         if ((res >= 0) && (inlen == 0)) {
01013             // set the title
01014             SDL_WM_SetCaption(buff, NULL);
01015             // all done
01016             return;
01017         }
01018     }
01019     #endif
01020     // use an English title for English ony builds or if the title string
01021     // conversion fails
01022     SDL_WM_SetCaption("Retro Tank Super Attack", NULL);
01023 }
01024 
01025 Bool TextRenderString(RenderItem *text, int font, int maxwidth, SDL_Color color,
01026 const rtsa_char *format, ...) {
01027     va_list args;
01028     Bool res;
01029     // get the variable argument list
01030     va_start(args, format);
01031     // render
01032     res = TextRenderStringV(text, font, maxwidth, color, format, args);
01033     // done with variable args
01034     va_end(args);
01035     return res;
01036 }
01037 
01038 Bool TextRenderStringV(RenderItem *text, int font, int maxwidth,
01039 SDL_Color color, const rtsa_char *format, va_list args) {
01040     #if !defined(WIN32) && defined(USE_GETTEXT)
01041     rtsa_char wstring[512];
01042     #endif
01043     rtsa_outchar string[512];
01044     int len;
01045     assert(font < FONT_MAX);
01046     assert(text != NULL);
01047     text->renderer = NULL;
01048     // create the string
01049     #ifdef USE_GETTEXT
01050         #if defined(_MSC_VER)
01051             #if (_MSC_VER <= 1310)
01052                 // MS Visual Studio 2003
01053                 if ((len = _vsnwprintf(string, 511, format, args)) <= 0) {
01054                     return FALSE;
01055                 }
01056                 string[511] = 0;
01057             #else
01058                 // MS Visual Studio 2005
01059                 if ((len = _vswprintf_p(string, 512, format, args)) <= 0) {
01060                     return FALSE;
01061                 }
01062             #endif
01063         #else
01064             // ISO C with extension
01065             if ((len = vswprintf(wstring, 512, format, args)) > 0) {
01066                 size_t outsize = sizeof(string);
01067                 size_t inbytes = len * sizeof(rtsa_char);
01068                 rtsa_char *inbuff = wstring;
01069                 Uint16 *outbuff = string;
01070                 // convert from wide chars to double byte chars
01071                 if (iconv(strconvdescr, (char**)&inbuff, &inbytes,
01072                 (char**)&outbuff, &outsize) < 0) {
01073                     return FALSE;
01074                 }
01075                 *outbuff = 0;
01076             }
01077             else {
01078                 return FALSE;
01079             }
01080         #endif
01081     #else
01082         // ISO C for byte sized characters
01083         if ((len = vsprintf(string, format, args)) <= 0) {
01084             return FALSE;
01085         }
01086     #endif
01087     
01088     // the variable arguments are no longer needed
01089     va_end(args);
01090 
01091     // check for an already existing surface
01092     if (text->data != NULL) {
01093         // deallocate that surface
01094         SDL_FreeSurface(text->data);
01095     }
01096 
01097     // limited width for rendered string?
01098     if (maxwidth > 0) {
01099         SDL_Surface *lineSurf[TEXT_MAX_LINES], **surface;
01100         SDL_Rect dest;
01101         int start = 0, end = 0, pos = 0, greatestWidth = 0, lines = 0, width,
01102         newWidth, destind;
01103         // loop through the string
01104         while ((pos < len) && (lines < TEXT_MAX_LINES)) {
01105             // loop through a line
01106             width = 0;
01107             do {
01108                 // find the next space
01109                 for (pos = end + 1; (pos < len) && (string[pos] != ' '); pos++);
01110                 // found a space?
01111                 if (string[pos] == ' ') {
01112                     // yes, temporarily remove it
01113                     string[pos] = 0;
01114                 }
01115                 // compute the new width
01116                 if (SizeTTF(fonts[font], &string[start], &newWidth, NULL) < 0) {
01117                     // failure!
01118                     goto TRS_LinesFail;
01119                 }
01120                 // restore space
01121                 if (pos < len) {
01122                     string[pos] = ' ';
01123                 }
01124                 // does it fit, or is the only word?
01125                 if ((newWidth <= maxwidth) || (start == end)) {
01126                     // take it!
01127                     end = pos;
01128                     width = newWidth;
01129                 }
01130                 // render the next line
01131                 else {
01132                     break;
01133                 }
01134             } while ((pos < len) && (width < maxwidth));
01135             // terminate the line
01136             string[end] = 0;
01137             // render the line
01138             if ((lineSurf[lines++] =
01139             RenderTTF(fonts[font], &string[start], color)) == NULL) {
01140                 // failed to render the line
01141                 goto TRS_LinesFail;
01142             }
01143             // update the greatest width of any line
01144             if (lineSurf[lines-1]->w > greatestWidth) {
01145                 greatestWidth = lineSurf[lines-1]->w;
01146             }
01147             // prepare for the next line
01148             if (end < len) {
01149                 end++;
01150             }
01151             start = pos = end;  // = end + 1;
01152         }
01153         // no lines? nothing rendered?
01154         if (lines == 0) {
01155             return FALSE;
01156         }
01157         // quick special case -- one line only
01158         if (lines == 1) {
01159             // use the one surface
01160             text->data = lineSurf[0];
01161             goto TRS_End;
01162         }
01163         // create a new surface to contain all the text
01164         if ((text->data = SDL_CreateRGBSurface(SDL_SWSURFACE,
01165         text->loc.w = greatestWidth, text->loc.h = lines * fontHeight[font], 32,
01166         // 0xFF0000, 0xFF00, 0xFF000000, 0xFF
01167         lineSurf[0]->format->Rmask, lineSurf[0]->format->Gmask,
01168         lineSurf[0]->format->Bmask, lineSurf[0]->format->Amask
01169         )) == NULL) {
01170             // failed to create the final surface
01171             goto TRS_LinesFail;
01172         }
01173         // combine all the lines into a single surface
01174         dest.y = 0;
01175         destind = 0;
01176         for (surface = &lineSurf[0]; lines > 0; lines--, surface++) {
01177             int linecpy, srcind = 0;
01178             // center the text
01179             dest.x = (greatestWidth >> 1) - ((*surface)->w >> 1);
01180             // alter surface format so that the alpha channel will copy over
01181             // by making it look like blue  --  doesn't work
01182             /*
01183             (*surface)->format->Amask = 0xFF;
01184             (*surface)->format->Bmask = 0xFF000000;
01185             (*surface)->format->Ashift = 0;
01186             (*surface)->format->Bshift = 24;
01187             */
01188             // put it on the final surface  -- text includes alpha, if black it
01189             // is only alpha, and SDL's blit won't copy alpha, so doesn't work
01190             /*
01191             if (SDL_BlitSurface(*surface, NULL, text->data, &dest) < 0)
01192                 return FALSE;
01193             */
01194             // Try doing a simple blit that'll copy alpha and color. If I had
01195             // known it would come to this, I would have modified SDL_ttf.
01196             for (linecpy = fontHeight[font]; linecpy > 0; linecpy--, dest.y++) {
01197                 // copy one line of pixel data
01198                 memcpy(
01199                 ((int*)(((SDL_Surface*)(text->data))->pixels)) + dest.x + destind,
01200                 ((int*)((*surface)->pixels)) + srcind, (*surface)->w << 2);
01201                 // advance to the next line
01202                 srcind  += (*surface)->w;
01203                 destind += ((SDL_Surface*)(text->data))->w;
01204             }
01205             // deallocate the temp surface
01206             SDL_FreeSurface(*surface);
01207         }
01208         // swap the alpha and blue channels  --  doesn't work
01209         /*
01210         ((SDL_Surface*)(text->data))->format->Bmask = 0xFF;
01211         ((SDL_Surface*)(text->data))->format->Amask = 0xFF000000;
01212         ((SDL_Surface*)(text->data))->format->Bshift = 0;
01213         ((SDL_Surface*)(text->data))->format->Ashift = 24;
01214         */
01215         // set the rendering function
01216         text->renderer = GenericSurfaceRenderer;
01217         // all done!
01218         return TRUE;
01219         
01220         TRS_LinesFail:
01221         // eliminate any surfaces already rendered
01222         for (surface = &lineSurf[0]; lines > 0; lines--, surface++) {
01223             SDL_FreeSurface(*surface);
01224         }
01225         // send back the error code
01226         return FALSE;
01227     }
01228     
01229     // attempt to render the string
01230     if ((text->data = RenderTTF(fonts[font], string, color)) == NULL) {
01231         // error!
01232         return FALSE;
01233     }
01234     TRS_End:
01235     // setup the width and height of the item
01236     text->loc.w = ((SDL_Surface*)text->data)->w;
01237     text->loc.h = ((SDL_Surface*)text->data)->h;
01238     // set the render function
01239     text->renderer = GenericSurfaceRenderer;
01240     // worked
01241     return TRUE;
01242 }
01243 

Generated on Mon May 28 04:41:39 2007 for Retro Tank Super Attack by  doxygen 1.5.2