[Tux4kids-commits] r513 - tuxmath/trunk/src

cheezmeister-guest at alioth.debian.org cheezmeister-guest at alioth.debian.org
Thu Jun 12 00:07:51 UTC 2008


Author: cheezmeister-guest
Date: 2008-06-12 00:07:50 +0000 (Thu, 12 Jun 2008)
New Revision: 513

Modified:
   tuxmath/trunk/src/SDL_extras.c
   tuxmath/trunk/src/SDL_extras.h
   tuxmath/trunk/src/game.c
   tuxmath/trunk/src/highscore.c
   tuxmath/trunk/src/setup.c
   tuxmath/trunk/src/titlescreen.c
   tuxmath/trunk/src/titlescreen.h
   tuxmath/trunk/src/tuxmath.h
Log:
Added title screen and in-game support for extended fullscreen

tmdprintf(): works like printf(); only outputs when TUXMATH_DEBUG is 
defined

game_draw() separated into four functions for background, comets, 
igloos, and miscellaneous items like the score

Easter egg: when Tux's beak is clicked on the title screen, he eats
the cursor and temporarily turns it into an egg.



Modified: tuxmath/trunk/src/SDL_extras.c
===================================================================
--- tuxmath/trunk/src/SDL_extras.c	2008-06-11 21:26:58 UTC (rev 512)
+++ tuxmath/trunk/src/SDL_extras.c	2008-06-12 00:07:50 UTC (rev 513)
@@ -12,6 +12,7 @@
 
 #include "SDL_extras.h"
 #include "tuxmath.h"
+#include "pixels.h"
 
 #ifdef SDL_Pango
 #include "SDL_Pango.h"
@@ -29,7 +30,7 @@
   SDL_Surface* tmp_surf = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA,
                                           target_rect->w,
                                           target_rect->h,
-                                          32, 
+                                          32,
                                           rmask, gmask, bmask, amask);
   Uint32 color = SDL_MapRGBA(tmp_surf->format, r, g, b, a);
   SDL_FillRect(tmp_surf, NULL, color);
@@ -48,7 +49,7 @@
   Uint32* p = NULL;
   Uint32 alpha_mask;
   int bytes_per_pix;
-  
+
   if (!s)
     return;
   if (SDL_LockSurface(s) == -1)
@@ -69,8 +70,8 @@
 
   /* Now round off corners: */
   /* upper left:            */
-  for (y = 0; y < radius; y++) 
-  {  
+  for (y = 0; y < radius; y++)
+  {
     p = (Uint32*)(s->pixels + (y * s->pitch));
     x_dist = radius;
     y_dist = radius - y;
@@ -85,8 +86,8 @@
   }
 
   /* upper right:            */
-  for (y = 0; y < radius; y++) 
-  {  
+  for (y = 0; y < radius; y++)
+  {
     /* start at end of top row: */
     p = (Uint32*)(s->pixels + ((y + 1) * s->pitch) - bytes_per_pix);
 
@@ -103,8 +104,8 @@
   }
 
   /* bottom left:            */
-  for (y = (s->h - 1); y > (s->h - radius); y--) 
-  {  
+  for (y = (s->h - 1); y > (s->h - radius); y--)
+  {
     /* start at beginning of bottom row */
     p = (Uint32*)(s->pixels + (y * s->pitch));
     x_dist = radius;
@@ -120,8 +121,8 @@
   }
 
   /* bottom right:            */
-  for (y = (s->h - 1); y > (s->h - radius); y--) 
-  {  
+  for (y = (s->h - 1); y > (s->h - radius); y--)
+  {
     /* start at end of bottom row */
     p = (Uint32*)(s->pixels + ((y + 1) * s->pitch) - bytes_per_pix);
     x_dist = radius;
@@ -136,7 +137,7 @@
     }
   }
   SDL_UnlockSurface(s);
-} 
+}
 
 
 /**********************
@@ -144,8 +145,8 @@
    input: a SDL_Surface, x, y
    output: a copy of the SDL_Surface flipped via rules:
 
-     if x is a positive value, then flip horizontally
-     if y is a positive value, then flip vertically
+     if x is a nonzero value, then flip horizontally
+     if y is a nonzero value, then flip vertically
 
      note: you can have it flip both
 **********************/
@@ -323,8 +324,8 @@
 void init_SDLPango_Context()
 {
    context =  SDLPango_CreateContext_GivenFontDesc(DEFAULT_FONT_NAME);
-}  
-void free_SDLPango_Context() 
+}
+void free_SDLPango_Context()
 {
   if(context != NULL)
     SDLPango_FreeContext(context);
@@ -441,19 +442,17 @@
 void DarkenScreen(Uint8 bits)
 {
 #if PIXEL_BITS == 32
-  Uint32 rm = screen->format->Rmask;
-  Uint32 gm = screen->format->Gmask;
-  Uint32 bm = screen->format->Bmask;
-  Uint32* p; 
+  Uint32* p;
 #elif PIXEL_BITS == 16
-  Uint16 rm = screen->format->Rmask;
-  Uint16 gm = screen->format->Gmask;
-  Uint16 bm = screen->format->Bmask;
-  Uint16* p; 
+  Uint16* p;
 #else
   return;
 #endif
+  Uint32 rm = screen->format->Rmask;
+  Uint32 gm = screen->format->Gmask;
+  Uint32 bm = screen->format->Bmask;
 
+
   int x, y;
 
   /* (realistically, 1 and 2 are the only useful values) */
@@ -463,7 +462,7 @@
   p = screen->pixels;
 
   for (y = 0; y < RES_Y; y++)
-  { 
+  {
     for (x = 0; x < RES_X; x++)
     {
       *p = (((*p&rm)>>bits)&rm)
@@ -477,63 +476,430 @@
 
 void SwitchScreenMode(void)
 {
-  SDL_Surface *tmp;
-  SDL_Rect src, dst;
+  int window = (screen->flags & SDL_FULLSCREEN);
+  SDL_Surface* oldscreen = screen;
 
-  int window = 0;
-
-  src.x = 0;
-  src.y = 0;
-  src.w = RES_X;
-  src.h = RES_Y;
-  dst.x = 0;
-  dst.y = 0;
-
-  tmp = SDL_CreateRGBSurface(
-      SDL_SWSURFACE,
-      RES_X,
-      RES_Y,
-      PIXEL_BITS,
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-      0xff000000,
-      0x00ff0000,
-      0x0000ff00,
-      0x000000ff
-#else
-      0x000000ff,
-      0x0000ff00,
-      0x00ff0000,
-      0xff000000
-#endif
-      );
-
-  if (screen->flags & SDL_FULLSCREEN)
+  if (!window)
   {
-    window = 1;
+    screen = SDL_SetVideoMode(fs_res_x,
+                              fs_res_y,
+                              PIXEL_BITS,
+                              SDL_SWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN);
   }
-
-  SDL_BlitSurface(screen,&src,tmp,&dst);
-  SDL_UpdateRect(tmp, 0, 0, RES_X, RES_Y);
-  SDL_FreeSurface(screen);
-  screen = NULL;
-
-  if (window)
+  else
   {
     screen = SDL_SetVideoMode(RES_X,
                               RES_Y,
                               PIXEL_BITS,
                               SDL_SWSURFACE|SDL_HWPALETTE);
+
   }
+
+  if (screen == NULL)
+  {
+    fprintf(stderr,
+            "\nError: I could not switch to %s mode.\n"
+            "The Simple DirectMedia error that occured was:\n"
+            "%s\n\n",
+            window ? "windowed" : "fullscreen",
+            SDL_GetError());
+    screen = oldscreen;
+  }
   else
   {
-    screen = SDL_SetVideoMode(RES_X,
-                              RES_Y,
-                              PIXEL_BITS,
-                              SDL_SWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN);
+    SDL_FreeSurface(oldscreen);
+    oldscreen = NULL;
+    SDL_UpdateRect(screen, 0, 0, 0, 0);
   }
 
-  SDL_BlitSurface(tmp,&src,screen,&dst);
-  SDL_UpdateRect(tmp,0,0,RES_X,RES_Y);
-  SDL_FreeSurface(tmp);
 }
 
+//#if 0
+
+/* Swiped shamelessly from TuxPaint
+   Based on code from: http://www.codeproject.com/cs/media/imageprocessing4.asp
+   copyright 2002 Christian Graus */
+
+SDL_Surface *zoom(SDL_Surface * src, int new_w, int new_h)
+{
+  SDL_Surface * s;
+  void (*putpixel) (SDL_Surface *, int, int, Uint32);
+  Uint32(*getpixel) (SDL_Surface *, int, int) =
+    getpixels[src->format->BytesPerPixel];
+  float xscale, yscale;
+  int x, y;
+  float floor_x, ceil_x, floor_y, ceil_y, fraction_x, fraction_y,
+    one_minus_x, one_minus_y;
+  float n1, n2;
+  float r1, g1, b1, a1;
+  float r2, g2, b2, a2;
+  float r3, g3, b3, a3;
+  float r4, g4, b4, a4;
+  Uint8 r, g, b, a;
+
+
+  /* Create surface for zoom: */
+
+  s = SDL_CreateRGBSurface(src->flags,	/* SDL_SWSURFACE, */
+			   new_w, new_h, src->format->BitsPerPixel,
+                           src->format->Rmask,
+                           src->format->Gmask,
+                           src->format->Bmask,
+                           src->format->Amask);
+
+
+  if (s == NULL)
+  {
+    fprintf(stderr, "\nError: Can't build zoom surface\n"
+	    "The Simple DirectMedia Layer error that occurred was:\n"
+	    "%s\n\n", SDL_GetError());
+
+    cleanup();
+    exit(1);
+  }
+
+  putpixel = putpixels[s->format->BytesPerPixel];
+
+
+  SDL_LockSurface(src);
+  SDL_LockSurface(s);
+
+  xscale = (float) src->w / (float) new_w;
+  yscale = (float) src->h / (float) new_h;
+
+  for (x = 0; x < new_w; x++)
+  {
+    for (y = 0; y < new_h; y++)
+    {
+      floor_x = floor((float) x * xscale);
+      ceil_x = floor_x + 1;
+      if (ceil_x >= src->w)
+        ceil_x = floor_x;
+
+      floor_y = floor((float) y * yscale);
+      ceil_y = floor_y + 1;
+      if (ceil_y >= src->h)
+        ceil_y = floor_y;
+
+      fraction_x = x * xscale - floor_x;
+      fraction_y = y * yscale - floor_y;
+
+      one_minus_x = 1.0 - fraction_x;
+      one_minus_y = 1.0 - fraction_y;
+
+      SDL_GetRGBA(getpixel(src, floor_x, floor_y), src->format,
+                  &r1, &g1, &b1, &a1);
+      SDL_GetRGBA(getpixel(src, ceil_x,  floor_y), src->format,
+                  &r2, &g2, &b2, &a2);
+      SDL_GetRGBA(getpixel(src, floor_x, ceil_y),  src->format,
+                  &r3, &g3, &b3, &a3);
+      SDL_GetRGBA(getpixel(src, ceil_x,  ceil_y),  src->format,
+                  &r4, &g4, &b4, &a4);
+
+      n1 = (one_minus_x * r1 + fraction_x * r2);
+      n2 = (one_minus_x * r3 + fraction_x * r4);
+      r = (one_minus_y * n1 + fraction_y * n2);
+
+      n1 = (one_minus_x * g1 + fraction_x * g2);
+      n2 = (one_minus_x * g3 + fraction_x * g4);
+      g = (one_minus_y * n1 + fraction_y * n2);
+
+      n1 = (one_minus_x * b1 + fraction_x * b2);
+      n2 = (one_minus_x * b3 + fraction_x * b4);
+      b = (one_minus_y * n1 + fraction_y * n2);
+
+      n1 = (one_minus_x * a1 + fraction_x * a2);
+      n2 = (one_minus_x * a3 + fraction_x * a4);
+      a = (one_minus_y * n1 + fraction_y * n2);
+
+      putpixel(s, x, y, SDL_MapRGBA(s->format, r, g, b, a));
+    }
+  }
+
+  SDL_UnlockSurface(s);
+  SDL_UnlockSurface(src);
+
+  return s;
+
+}
+
+//FIXME: everything below is slightly modified code from pixels.c and would do
+//       better to be included as such.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+  pixels.c
+
+  For Tux Paint
+  Pixel read/write functions
+
+  Copyright (c) 2002-2006 by Bill Kendrick and others
+  bill at newbreedsoftware.com
+  http://www.newbreedsoftware.com/tuxpaint/
+
+  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
+  (See COPYING.txt)
+
+  June 14, 2002 - February 17, 2006
+  $Id: pixels.c,v 1.3 2006/08/27 21:00:55 wkendrick Exp $
+*/
+
+#include "pixels.h"
+//#include "compiler.h"
+//#include "debug.h"
+
+/* Draw a single pixel into the surface: */
+void putpixel8(SDL_Surface * surface, int x, int y, Uint32 pixel)
+{
+  Uint8 *p;
+
+  /* Assuming the X/Y values are within the bounds of this surface... */
+  if (
+      (((unsigned) x < (unsigned) surface->w)
+       && ((unsigned) y < (unsigned) surface->h)))
+  {
+    // Set a pointer to the exact location in memory of the pixel
+    p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start: beginning of RAM */
+		   (y * surface->pitch) +	/* Go down Y lines */
+		   x);		/* Go in X pixels */
+
+
+    /* Set the (correctly-sized) piece of data in the surface's RAM
+     *          to the pixel value sent in: */
+
+    *p = pixel;
+  }
+}
+
+/* Draw a single pixel into the surface: */
+void putpixel16(SDL_Surface * surface, int x, int y, Uint32 pixel)
+{
+  Uint8 *p;
+
+  /* Assuming the X/Y values are within the bounds of this surface... */
+  if (
+      (((unsigned) x < (unsigned) surface->w)
+       && ((unsigned) y < (unsigned) surface->h)))
+  {
+    // Set a pointer to the exact location in memory of the pixel
+    p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start: beginning of RAM */
+		   (y * surface->pitch) +	/* Go down Y lines */
+		   (x * 2));	/* Go in X pixels */
+
+
+    /* Set the (correctly-sized) piece of data in the surface's RAM
+     *          to the pixel value sent in: */
+
+    *(Uint16 *) p = pixel;
+  }
+}
+
+/* Draw a single pixel into the surface: */
+void putpixel24(SDL_Surface * surface, int x, int y, Uint32 pixel)
+{
+  Uint8 *p;
+
+  /* Assuming the X/Y values are within the bounds of this surface... */
+  if (
+      (((unsigned) x < (unsigned) surface->w)
+       && ((unsigned) y < (unsigned) surface->h)))
+  {
+    // Set a pointer to the exact location in memory of the pixel
+    p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start: beginning of RAM */
+		   (y * surface->pitch) +	/* Go down Y lines */
+		   (x * 3));	/* Go in X pixels */
+
+
+    /* Set the (correctly-sized) piece of data in the surface's RAM
+     *          to the pixel value sent in: */
+
+    if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
+    {
+      p[0] = (pixel >> 16) & 0xff;
+      p[1] = (pixel >> 8) & 0xff;
+      p[2] = pixel & 0xff;
+    }
+    else
+    {
+      p[0] = pixel & 0xff;
+      p[1] = (pixel >> 8) & 0xff;
+      p[2] = (pixel >> 16) & 0xff;
+    }
+
+  }
+}
+
+/* Draw a single pixel into the surface: */
+void putpixel32(SDL_Surface * surface, int x, int y, Uint32 pixel)
+{
+  Uint8 *p;
+
+  /* Assuming the X/Y values are within the bounds of this surface... */
+  if (
+      (((unsigned) x < (unsigned) surface->w)
+       && ((unsigned) y < (unsigned) surface->h)))
+  {
+    // Set a pointer to the exact location in memory of the pixel
+    p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start: beginning of RAM */
+		   (y * surface->pitch) +	/* Go down Y lines */
+		   (x * 4));	/* Go in X pixels */
+
+
+    /* Set the (correctly-sized) piece of data in the surface's RAM
+     *          to the pixel value sent in: */
+
+    *(Uint32 *) p = pixel;	// 32-bit display
+  }
+}
+
+/* Get a pixel: */
+Uint32 getpixel8(SDL_Surface * surface, int x, int y)
+{
+  Uint8 *p;
+
+  /* get the X/Y values within the bounds of this surface */
+  if ((unsigned) x < (unsigned) surface->w)
+    x = (x < 0) ? 0 : surface->w - 1;
+  if ((unsigned) y < (unsigned) surface->h)
+    y = (y < 0) ? 0 : surface->h - 1;
+
+  /* Set a pointer to the exact location in memory of the pixel
+     in question: */
+
+  p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start at top of RAM */
+		 (y * surface->pitch) +	/* Go down Y lines */
+		 x);		/* Go in X pixels */
+
+
+  /* Return the correctly-sized piece of data containing the
+   * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit
+   * RGB value) */
+
+  return (*p);
+}
+
+/* Get a pixel: */
+Uint32 getpixel16(SDL_Surface * surface, int x, int y)
+{
+  Uint8 *p;
+
+  /* get the X/Y values within the bounds of this surface */
+  if ((unsigned) x < (unsigned) surface->w)
+    x = (x < 0) ? 0 : surface->w - 1;
+  if ((unsigned) y < (unsigned) surface->h)
+    y = (y < 0) ? 0 : surface->h - 1;
+
+  /* Set a pointer to the exact location in memory of the pixel
+     in question: */
+
+  p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start at top of RAM */
+		 (y * surface->pitch) +	/* Go down Y lines */
+		 (x * 2));	/* Go in X pixels */
+
+
+  /* Return the correctly-sized piece of data containing the
+   * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit
+   * RGB value) */
+
+  return (*(Uint16 *) p);
+}
+
+/* Get a pixel: */
+Uint32 getpixel24(SDL_Surface * surface, int x, int y)
+{
+  Uint8 *p;
+  Uint32 pixel;
+
+  /* get the X/Y values within the bounds of this surface */
+  if ((unsigned) x < (unsigned) surface->w)
+    x = (x < 0) ? 0 : surface->w - 1;
+  if ((unsigned) y < (unsigned) surface->h)
+    y = (y < 0) ? 0 : surface->h - 1;
+
+  /* Set a pointer to the exact location in memory of the pixel
+     in question: */
+
+  p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start at top of RAM */
+		 (y * surface->pitch) +	/* Go down Y lines */
+		 (x * 3));	/* Go in X pixels */
+
+
+  /* Return the correctly-sized piece of data containing the
+   * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit
+   * RGB value) */
+
+  /* Depending on the byte-order, it could be stored RGB or BGR! */
+
+  if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
+    pixel = p[0] << 16 | p[1] << 8 | p[2];
+  else
+    pixel = p[0] | p[1] << 8 | p[2] << 16;
+
+  return pixel;
+}
+
+/* Get a pixel: */
+Uint32 getpixel32(SDL_Surface * surface, int x, int y)
+{
+  Uint8 *p;
+
+  /* get the X/Y values within the bounds of this surface */
+  if ((unsigned) x < (unsigned) surface->w)
+    x = (x < 0) ? 0 : surface->w - 1;
+  if ((unsigned) y < (unsigned) surface->h)
+    y = (y < 0) ? 0 : surface->h - 1;
+
+  /* Set a pointer to the exact location in memory of the pixel
+     in question: */
+
+  p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start at top of RAM */
+		 (y * surface->pitch) +	/* Go down Y lines */
+		 (x * 4));	/* Go in X pixels */
+
+
+  /* Return the correctly-sized piece of data containing the
+   * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit
+   * RGB value) */
+
+  return *(Uint32 *) p;		// 32-bit display
+}
+
+void (*putpixels[]) (SDL_Surface *, int, int, Uint32) =
+{
+putpixel8, putpixel8, putpixel16, putpixel24, putpixel32};
+
+
+Uint32(*getpixels[])(SDL_Surface *, int, int) =
+{
+getpixel8, getpixel8, getpixel16, getpixel24, getpixel32};
+
+//#endif

Modified: tuxmath/trunk/src/SDL_extras.h
===================================================================
--- tuxmath/trunk/src/SDL_extras.h	2008-06-11 21:26:58 UTC (rev 512)
+++ tuxmath/trunk/src/SDL_extras.h	2008-06-12 00:07:50 UTC (rev 513)
@@ -36,5 +36,7 @@
 void DarkenScreen(Uint8 bits);
 void SwitchScreenMode(void);
 SDL_Surface* Blend(SDL_Surface *S1, SDL_Surface *S2,float gamma);
+SDL_Surface *zoom(SDL_Surface * src, int new_w, int new_h);
 
+
 #endif

Modified: tuxmath/trunk/src/game.c
===================================================================
--- tuxmath/trunk/src/game.c	2008-06-11 21:26:58 UTC (rev 512)
+++ tuxmath/trunk/src/game.c	2008-06-12 00:07:50 UTC (rev 513)
@@ -11,7 +11,7 @@
 
   Part of "Tux4Kids" Project
   http://www.tux4kids.org/
-      
+
   August 26, 2001 - February 18, 2004
 
   Revised by David Bruce, Tim Holy and others
@@ -36,7 +36,7 @@
 #include "setup.h"
 #include "mathcards.h"
 #include "titlescreen.h"
-#include "options.h"  
+#include "options.h"
 #include "SDL_extras.h"
 
 #define FPS 15                     /* 15 frames per second */
@@ -152,6 +152,11 @@
 static void game_handle_steam(void);
 static void game_handle_extra_life(void);
 static void game_draw(void);
+static void game_draw_background(void);
+static void game_draw_comets(void);
+static void game_draw_cities(void);
+static void game_draw_misc(void);
+
 static int check_extra_life(void);
 static int check_exit_conditions(void);
 
@@ -179,6 +184,8 @@
 static void help_add_comet(int a,int oper,int b,int c);
 static int help_renderframe_exit(void);
 
+static void game_recalc_positions(void);
+
 #ifdef TUXMATH_DEBUG
 static void print_exit_conditions(void);
 static void print_status(void);
@@ -195,6 +202,13 @@
   fprintf(stderr, "Entering game():\n");
 #endif
 
+  //see if the option matches the actual screen
+  if (Opts_Fullscreen() == !(screen->flags & SDL_FULLSCREEN) )
+    {
+    SwitchScreenMode();
+    }
+
+
    /* most code moved into smaller functions (game_*()): */
   if (!game_initialize())
   {
@@ -203,7 +217,7 @@
     /* player simply has all operations deselected */
     free_on_exit();
     return 0;
-  } 
+  }
 
   if (Opts_HelpMode()) {
     game_handle_help();
@@ -211,7 +225,9 @@
     return 0;
   }
 
-  /* --- MAIN GAME LOOP: --- */ 
+
+
+  /* --- MAIN GAME LOOP: --- */
   do
   {
     /* reset or increment various things with each loop: */
@@ -223,11 +239,11 @@
     if (laser.alive > 0)
     {
       laser.alive--;
-    }   
+    }
 
     /* Most code now in smaller functions: */
     game_handle_user_events();
-    game_handle_demo(); 
+    game_handle_demo();
     game_handle_answer();
     game_countdown();
     game_handle_tux();
@@ -238,28 +254,28 @@
     game_handle_extra_life();
     game_draw();
     /* figure out if we should leave loop: */
-    game_status = check_exit_conditions(); 
+    game_status = check_exit_conditions();
 
-   
+
     /* If we're in "PAUSE" mode, pause! */
     if (paused)
     {
       pause_game();
       paused = 0;
     }
-      
+
       /* Keep playing music: */
-      
+
 #ifndef NOSOUND
     if (Opts_UsingSound())
     {
       if (!Mix_PlayingMusic())
       {
 	    Mix_PlayMusic(musics[MUS_GAME + (rand() % 3)], 0);
-      }  
+      }
     }
 #endif
- 
+
     /* Pause (keep frame-rate event) */
     now_time = SDL_GetTicks();
     if (now_time < last_time + MS_PER_FRAME)
@@ -313,7 +329,7 @@
             || event.type == SDL_MOUSEBUTTONDOWN)
           {
             looping = 0;
-          }   
+          }
         }
 
         if (bkgd)
@@ -352,7 +368,7 @@
         SDL_BlitSurface(images[tux_img], NULL, screen, &dest_tux);
 
 /*        draw_console_image(tux_img);*/
-	
+
         SDL_Flip(screen);
 
         now_time = SDL_GetTicks();
@@ -370,7 +386,7 @@
       printf("\ngame() exiting with error");
 #endif
     }
-    case GAME_OVER_LOST: 
+    case GAME_OVER_LOST:
     case GAME_OVER_OTHER:
     {
       int looping = 1;
@@ -393,7 +409,7 @@
             || event.type == SDL_MOUSEBUTTONDOWN)
           {
             looping = 0;
-          }   
+          }
         }
 
         SDL_BlitSurface(images[IMG_GAMEOVER], NULL, screen, &dest_message);
@@ -402,7 +418,7 @@
         now_time = SDL_GetTicks();
 
         if (now_time < last_time + MS_PER_FRAME)
-	  SDL_Delay(last_time + MS_PER_FRAME - now_time);     
+	  SDL_Delay(last_time + MS_PER_FRAME - now_time);
       }
       while (looping);
 
@@ -419,7 +435,7 @@
       break;
     }
 
-  } 
+  }
 
   game_cleanup();
 
@@ -427,13 +443,13 @@
   if (Opts_SaveSummary())
   {
     write_postgame_summary();
-  }  
+  }
 
   /* Save score in case needed for high score table: */
   Opts_SetLastScore(score);
 
   /* Return the chosen command: */
-  if (GAME_OVER_WINDOW_CLOSE == game_status) 
+  if (GAME_OVER_WINDOW_CLOSE == game_status)
   {
     /* program exits: */
     cleanup();
@@ -452,11 +468,11 @@
 {
   int i,img;
   /* Clear window: */
-  
+
   SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
   SDL_Flip(screen);
 
-  game_status = GAME_IN_PROGRESS;  
+  game_status = GAME_IN_PROGRESS;
   gameover_counter = -1;
   SDL_quit_received = 0;
   escape_received = 0;
@@ -499,8 +515,8 @@
 #endif
     fprintf(stderr, "\nMC_StartGame() failed!");
     return 0;
-  }  
-  
+  }
+
   /* Write pre-game info to game summary file: */
   if (Opts_SaveSummary())
   {
@@ -514,7 +530,7 @@
   comet_feedback_number = 0;
   comet_feedback_height = 0;
   danger_level = Opts_DangerLevel();
-  
+
   wave = 1;
   num_attackers = 2;
   prev_wave_comets = Opts_StartingComets();
@@ -524,9 +540,9 @@
   demo_countdown = 2000;
   level_start_wait = LEVEL_START_WAIT_START;
   neg_answer_picked = 0;
- 
+
   /* (Create and position cities) */
-  
+
   if (Opts_UseIgloos())
     img = IMG_IGLOO_INTACT;
   else
@@ -538,7 +554,7 @@
     cities[i].counter = 0;
     cities[i].threatened = 0;
     cities[i].layer = 0;
-     
+
     /* Left vs. Right - makes room for Tux and the console */
     if (i < NUM_CITIES / 2)
     {
@@ -581,13 +597,13 @@
 
   /* (Clear laser) */
   laser.alive = 0;
-  
+
   /* Reset remaining stuff: */
- 
+
   bkgd = NULL;
   last_bkgd = -1;
   reset_level();
-  reset_comets();  
+  reset_comets();
 
   frame = 0;
   paused = 0;
@@ -668,10 +684,10 @@
     if (!Mix_PlayingMusic())
     {
       Mix_PlayMusic(musics[MUS_GAME], 0);
-    }  
+    }
   }
 #endif
- 
+
   // Wait 2 seconds while rendering frames
   while (frame < 2*FPS && !(quit_help = help_renderframe_exit()));
   if (quit_help)
@@ -717,7 +733,7 @@
   help_controls.laser_enabled = 0;
   frame_start = frame;
   while (frame-frame_start < 3*FPS && !(quit_help = help_renderframe_exit()));  // wait 3 secs
-  
+
   speed = 2;
   game_set_message(&s1,_("If an igloo gets hit by a comet,"),left_edge,100);
   game_set_message(&s2,_("it melts. But don't worry: the"),left_edge,135);
@@ -730,7 +746,7 @@
   if (quit_help)
     return;
   game_clear_message(&s5);
-  
+
   help_add_comet(3,MC_OPER_MULT,3,9);
   comets[0].y = 2*(screen->h)/3;   // start it low down
   while (!(comets[0].expl) && !(quit_help = help_renderframe_exit()));  // wait 3 secs
@@ -765,7 +781,7 @@
   while ((frame-frame_start < 3*FPS) && !(quit_help = help_renderframe_exit()));
   if (quit_help)
     return;
-  
+
   help_controls.laser_enabled = 1;
   game_set_message(&s1,_("You can fix the igloos"),left_edge,100);
   game_set_message(&s2,_("by stopping bonus comets."),left_edge,135);
@@ -979,7 +995,7 @@
         answer_digit = 2;
     }
   }
-  
+
   /* Add a digit: */
   if (picked_comet != -1 && (frame % 5) == 0 && (rand() % 10) < 8)
   {
@@ -1002,7 +1018,7 @@
       {
         digits[2] = (demo_answer % 10);
       }
-	    
+
       answer_digit++;
     }
     else
@@ -1040,8 +1056,8 @@
   if (neg_answer_picked)
   {
     num = -num;
-  }	
-	
+  }
+
   /*  Pick the lowest comet which has the right answer: */
   /*  FIXME: do we want it to prefer bonus comets to regular comets? */
   lowest_y = 0;
@@ -1050,7 +1066,7 @@
   for (i = 0; i < MAX_COMETS; i++)
   {
     if (comets[i].alive &&
-        comets[i].expl < COMET_EXPL_END && 
+        comets[i].expl < COMET_EXPL_END &&
         comets[i].answer == num &&
         comets[i].y > lowest_y)
     {
@@ -1058,7 +1074,7 @@
       lowest_y = comets[i].y;
     }
   }
-	
+
   /* If there was an comet with this answer, destroy it! */
   if (lowest != -1)  /* -1 means no comet had this answer */
   {
@@ -1070,8 +1086,8 @@
     if (ctime > comets[lowest].time_started) {
       MC_AddTimeToList((float)(ctime - comets[lowest].time_started)/1000);
     }
-    
 
+
     /* Destroy comet: */
     comets[lowest].expl = COMET_EXPL_START;
     comets[lowest].zapped = 1;
@@ -1095,7 +1111,7 @@
 #endif
     }
 
-	    
+
     /* FIXME maybe should move this into game_handle_tux() */
     /* 50% of the time.. */
     if ((rand() % 10) < 5)
@@ -1126,13 +1142,13 @@
     laser.y2 = 0;
     playsound(SND_LASER);
     playsound(SND_BUZZ);
-	    
+
     if ((rand() % 10) < 5)
       tux_img = IMG_TUX_DRAT;
     else
       tux_img = IMG_TUX_YIPE;
   }
-	
+
   /* Clear digits: */
   digits[0] = 0;
   digits[1] = 0;
@@ -1152,7 +1168,7 @@
     tux_img = IMG_TUX_RELAX2;
   else
     tux_img = IMG_TUX_SIT;
-	  
+
   if (level_start_wait == LEVEL_START_WAIT_START / 4)
   {
     playsound(SND_ALARM);
@@ -1174,7 +1190,7 @@
 
     playsound(SND_CLICK);
   }
- 
+
   /* If Tux is being animated, show the animation: */
   if (tux_anim != -1)
   {
@@ -1198,6 +1214,8 @@
     tux_same_counter = 0;
 }
 
+//FIXME might be simpler to store vertical position (and speed) in terms of time
+//rather than absolute position, and determine the latter in game_draw_comets()
 void game_handle_comets(void)
 {
   /* Handle comets. Since the comets also are the things that trigger
@@ -1223,11 +1241,13 @@
       /* Make bonus comet move faster at chosen ratio: */
       if (comets[i].bonus)
       {
-	comets[i].y += speed * Opts_BonusSpeedRatio();
+	comets[i].y += speed * Opts_BonusSpeedRatio() *
+	               city_expl_height / (RES_Y - images[IMG_CITY_BLUE]->h);
       }
       else /* Regular comet: */
       {
-        comets[i].y += speed;
+        comets[i].y += speed *
+                       city_expl_height / (RES_Y - images[IMG_CITY_BLUE]->h);
       }
 
       /* Does it threaten a city? */
@@ -1260,7 +1280,7 @@
                   1.0 + Opts_CityExplHandicap());
 #endif
  	}
- 
+
         /* Disable shields/destroy city/create steam cloud: */
         if (cities[this_city].hits_left)
 	{
@@ -1282,8 +1302,8 @@
 	    }
 	  }
 	  cities[this_city].hits_left--;
-	}	    
-	      
+	}
+
 	/* If this was a bonus comet, restart the counter */
 	if (comets[i].bonus)
 	  bonus_comet_counter = Opts_BonusCometInterval()+1;
@@ -1433,7 +1453,7 @@
       /* Change image to appropriate color: */
       cities[i].img = cities[i].img + ((wave % MAX_CITY_COLORS) *
 		   (IMG_CITY_GREEN - IMG_CITY_BLUE));
-      
+
     }
   }
 }
@@ -1681,116 +1701,211 @@
 /* FIXME consider splitting this into smaller functions e.g. draw_comets(), etc. */
 void game_draw(void)
 {
-  int i,j, img, current_layer, max_layer,offset;
-  SDL_Rect src, dest;
-  SDL_Surface *this_image;
-  char str[64];
-  char* comet_str;
+  SDL_Rect dest;
 
   /* Clear screen: */
-  if (bkgd == NULL)
+  game_draw_background();
+
+  /* Draw miscellaneous informational items */
+  game_draw_misc();
+
+  /* Draw cities/igloos and (if applicable) penguins: */
+  game_draw_cities();
+
+  /* Draw normal comets first, then bonus comets */
+  game_draw_comets();
+
+
+  /* Draw laser: */
+  if (laser.alive)
   {
+    draw_line(laser.x1, laser.y1, laser.x2, laser.y2,
+		  255 / ((LASER_START + 1) - laser.alive),
+		  192 / ((LASER_START + 1) - laser.alive),
+		  64);
+  }
+
+  /* Draw numeric keypad: */
+  if (Opts_UseKeypad())
+  {
+    /* pick image to draw: */
+    int keypad_image;
+    if (MC_AllowNegatives())
+    {
+      /* draw regular keypad */
+      keypad_image = IMG_KEYPAD;
+    }
+    else
+    {
+      /* draw keypad with with grayed-out '+' and '-' */
+      keypad_image = IMG_KEYPAD_NO_NEG;
+    }
+
+    /* now draw it: */
+    dest.x = (screen->w - images[keypad_image]->w) / 2;
+    dest.y = (screen->h - images[keypad_image]->h) / 2;
+    dest.w = images[keypad_image]->w;
+    dest.h = images[keypad_image]->h;
+    SDL_BlitSurface(images[keypad_image], NULL, screen, &dest);
+  }
+
+  /* Draw console, LED numbers, & tux: */
+  draw_led_console();
+  draw_console_image(tux_img);
+
+  /* Draw any messages on the screen (used for the help mode) */
+  game_write_messages();
+
+  /* Swap buffers: */
+  SDL_Flip(screen);
+}
+
+void game_draw_background(void)
+{
+  static int old_wave = 0; //update wave immediately
+  static Uint32 bgcolor, fgcolor = 0;
+  SDL_Rect dest;
+
+  if (fgcolor == 0)
+    fgcolor = SDL_MapRGB(screen->format, 64, 96, 64);
+  if (old_wave != wave)
+  {
+    tmdprintf("Wave %d\n", wave);
+    old_wave = wave;
+    bgcolor = SDL_MapRGB(screen->format,
+                         64,
+                         64 + ((wave * 32) % 192),
+                         128 - ((wave * 16) % 128) );
+    tmdprintf("Filling screen with color %d\n", bgcolor);
+  }
+
+  if (bkgd == NULL || screen->flags & SDL_FULLSCREEN)
+  {
     dest.x = 0;
     dest.y = 0;
     dest.w = screen->w;
     dest.h = ((screen->h) / 4) * 3;
 
-    SDL_FillRect(screen, &dest, 
-                 SDL_MapRGB(screen->format,
-                                    64,
-		                    64 + ((wave * 32) % 192),
-		                    128 - ((wave * 16) % 128)));
+    SDL_FillRect(screen, &dest, bgcolor);
 
-    dest.x = 0;
+
     dest.y = ((screen->h) / 4) * 3;
-    dest.w = screen->w;
     dest.h = (screen->h) / 4;
 
-    SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 64, 96, 64));
+    SDL_FillRect(screen, &dest, fgcolor);
   }
-  else
+
+  if (bkgd)
   {
-    SDL_BlitSurface(bkgd, NULL, screen, NULL);
+    dest.x = (screen->w - bkgd->w) / 2;
+    dest.y = (screen->h - bkgd->h) / 2;
+    SDL_BlitSurface(bkgd, NULL, screen, &dest);
   }
+}
 
-  /* Draw "Demo" */
-  if (Opts_DemoMode())
+/* Draw comets: */
+/* NOTE bonus comets split into separate pass to make them */
+/* draw last (i.e. in front), as they can overlap          */
+void game_draw_comets(void)
+{
+
+  int i,j, img, max_layer,offset;
+  SDL_Rect dest;
+  char* comet_str;
+
+   /* First draw regular comets: */
+  for (i = 0; i < MAX_COMETS; i++)
   {
-    dest.x = (screen->w - images[IMG_DEMO]->w) / 2;
-    dest.y = (screen->h - images[IMG_DEMO]->h) / 2;
-    dest.w = images[IMG_DEMO]->w;
-    dest.h = images[IMG_DEMO]->h;
+    if (comets[i].alive && !comets[i].bonus)
+    {
+      if (comets[i].expl < COMET_EXPL_END)
+      {
+        /* Decide which image to display: */
+        img = IMG_COMET1 + ((frame + i) % 3);
+        /* Display the formula (flashing, in the bottom half
+		   of the screen) */
+        if (comets[i].y < screen->h / 2 || frame % 8 < 6)
+        {
+          comet_str = comets[i].flashcard.formula_string;
+        }
+        else
+        {
+          comet_str = NULL;
+        }
+      }
+      else
+      {
+        img = comets[i].expl;
+        comet_str = comets[i].flashcard.answer_string;
+      }
 
-    SDL_BlitSurface(images[IMG_DEMO], NULL, screen, &dest);
+      /* Draw it! */
+      dest.x = comets[i].x - (images[img]->w / 2);
+      dest.y = comets[i].y - images[img]->h;
+      dest.w = images[img]->w;
+      dest.h = images[img]->h;
+
+      SDL_BlitSurface(images[img], NULL, screen, &dest);
+      if (comet_str != NULL)
+      {
+        draw_nums(comet_str, comets[i].x, comets[i].y);
+      }
+    }
   }
 
-  /* If we are playing through a defined list of questions */
-  /* without "recycling", display number of remaining questions: */
-  if (MC_PlayThroughList())
+  /* Now draw any bonus comets: */
+  for (i = 0; i < MAX_COMETS; i++)
   {
-    draw_question_counter();
-  }
+    if (comets[i].alive && comets[i].bonus)
+    {
+      if (comets[i].expl < COMET_EXPL_END)
+      {
+        /* Decide which image to display: */
+        img = IMG_COMET1 + ((frame + i) % 3);
+        /* Display the formula (flashing, in the bottom half
+		   of the screen) */
+        if (comets[i].y < screen->h / 2 || frame % 8 < 6)
+        {
+          comet_str = comets[i].flashcard.formula_string;
+        }
+        else
+        {
+          comet_str = NULL;
+        }
+      }
+      else
+      {
+        img = comets[i].expl;
+        comet_str = comets[i].flashcard.answer_string;
+      }
 
-  if (extra_life_earned) {
-    /* Draw extra life earned icon */
-    dest.x = 0;
-    dest.y = 0;
-    dest.w = images[IMG_EXTRA_LIFE]->w;
-    dest.h = images[IMG_EXTRA_LIFE]->h;
-    SDL_BlitSurface(images[IMG_EXTRA_LIFE], NULL, screen, &dest);
-  } else if (bonus_comet_counter) {
-    /* Draw extra life progress bar */
-    dest.x = 0;
-    dest.y = images[IMG_EXTRA_LIFE]->h/4;
-    dest.h = images[IMG_EXTRA_LIFE]->h/2;
-    dest.w = ((Opts_BonusCometInterval() + 1 - bonus_comet_counter)
-	      * images[IMG_EXTRA_LIFE]->w) / Opts_BonusCometInterval();
-    SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 0, 255, 0));
-  }
+      /* Move images[] index to bonus range: */
+      img += IMG_BONUS_COMET1 - IMG_COMET1;
 
-  /* Draw wave: */
-  if (Opts_BonusCometInterval())
-    offset = images[IMG_EXTRA_LIFE]->w + 5;
-  else
-    offset = 0;
+      /* Draw it! */
+      dest.x = comets[i].x - (images[img]->w / 2);
+      dest.y = comets[i].y - images[img]->h;
+      dest.w = images[img]->w;
+      dest.h = images[img]->h;
 
-  dest.x = offset;
-  dest.y = 0;
-  dest.w = images[IMG_WAVE]->w;
-  dest.h = images[IMG_WAVE]->h;
+      SDL_BlitSurface(images[img], NULL, screen, &dest);
+      if (comet_str != NULL)
+      {
+        draw_nums(comet_str, comets[i].x, comets[i].y);
+      }
+    }
+  }
 
-  SDL_BlitSurface(images[IMG_WAVE], NULL, screen, &dest);
 
-  sprintf(str, "%d", wave);
-  draw_numbers(str, offset+images[IMG_WAVE]->w + (images[IMG_NUMBERS]->w / 10), 0);
 
-  /* Draw "score" label: */
-  dest.x = (screen->w - ((images[IMG_NUMBERS]->w / 10) * 7) -
-	        images[IMG_SCORE]->w -
-                images[IMG_STOP]->w - 5);
-  dest.y = 0;
-  dest.w = images[IMG_SCORE]->w;
-  dest.h = images[IMG_SCORE]->h;
+}
 
-  SDL_BlitSurface(images[IMG_SCORE], NULL, screen, &dest);
-        
-  /* Draw score numbers: */
-  sprintf(str, "%.6d", score);
-  draw_numbers(str,
-               screen->w - ((images[IMG_NUMBERS]->w / 10) * 6) - images[IMG_STOP]->w - 5,
-               0);
+void game_draw_cities(void)
+{
+  int i, j, current_layer, max_layer;
+  SDL_Rect src, dest;
+  SDL_Surface* this_image;
 
-  /* Draw stop button: */
-  if (!help_controls.x_is_blinking || (frame % 10 < 5)) {
-    dest.x = (screen->w - images[IMG_STOP]->w);
-    dest.y = 0;
-    dest.w = images[IMG_STOP]->w;
-    dest.h = images[IMG_STOP]->h;
-    
-    SDL_BlitSurface(images[IMG_STOP], NULL, screen, &dest);
-  }
-   
-  /* Draw cities/igloos and (if applicable) penguins: */
   if (Opts_UseIgloos()) {
     /* We have to draw respecting layering */
     current_layer = 0;
@@ -1859,7 +1974,7 @@
 	  dest.w = (this_image->w);
 	  dest.h = (this_image->h);
 	  SDL_BlitSurface(this_image, NULL, screen, &dest);
-	}	  
+	}
       }
       current_layer++;
     } while (current_layer <= max_layer);
@@ -1915,138 +2030,89 @@
   }
 
 
-   /* Draw comets: */
-   /* NOTE bonus comets split into separate pass to make them */
-   /* draw last (i.e. in front), as they can overlap          */
+}
+void game_draw_misc(void)
+{
+  int offset;
+  SDL_Rect dest;
+  char str[64];
 
-   /* First draw regular comets: */
-  for (i = 0; i < MAX_COMETS; i++)
+  /* Draw "Demo" */
+  if (Opts_DemoMode())
   {
-    if (comets[i].alive && !comets[i].bonus)
-    { 
-      if (comets[i].expl < COMET_EXPL_END)
-      {
-        /* Decide which image to display: */
-        img = IMG_COMET1 + ((frame + i) % 3);
-        /* Display the formula (flashing, in the bottom half
-		   of the screen) */
-        if (comets[i].y < screen->h / 2 || frame % 8 < 6)
-        {
-          comet_str = comets[i].flashcard.formula_string;
-        }
-        else 
-        {
-          comet_str = NULL;
-        }
-      }
-      else
-      {
-        img = comets[i].expl;
-        comet_str = comets[i].flashcard.answer_string;
-      }
+    dest.x = (screen->w - images[IMG_DEMO]->w) / 2;
+    dest.y = (screen->h - images[IMG_DEMO]->h) / 2;
+    dest.w = images[IMG_DEMO]->w;
+    dest.h = images[IMG_DEMO]->h;
 
-      /* Draw it! */
-      dest.x = comets[i].x - (images[img]->w / 2);
-      dest.y = comets[i].y - images[img]->h;
-      dest.w = images[img]->w;
-      dest.h = images[img]->h;
-	      
-      SDL_BlitSurface(images[img], NULL, screen, &dest);
-      if (comet_str != NULL)
-      {
-        draw_nums(comet_str, comets[i].x, comets[i].y);
-      }
-    }
+    SDL_BlitSurface(images[IMG_DEMO], NULL, screen, &dest);
   }
 
-  /* Now draw any bonus comets: */
-  for (i = 0; i < MAX_COMETS; i++)
+  /* If we are playing through a defined list of questions */
+  /* without "recycling", display number of remaining questions: */
+  if (MC_PlayThroughList())
   {
-    if (comets[i].alive && comets[i].bonus)
-    { 
-      if (comets[i].expl < COMET_EXPL_END)
-      {
-        /* Decide which image to display: */
-        img = IMG_COMET1 + ((frame + i) % 3);
-        /* Display the formula (flashing, in the bottom half
-		   of the screen) */
-        if (comets[i].y < screen->h / 2 || frame % 8 < 6)
-        {
-          comet_str = comets[i].flashcard.formula_string;
-        }
-        else 
-        {
-          comet_str = NULL;
-        }
-      }
-      else
-      {
-        img = comets[i].expl;
-        comet_str = comets[i].flashcard.answer_string;
-      }
+    draw_question_counter();
+  }
 
-      /* Move images[] index to bonus range: */
-      img += IMG_BONUS_COMET1 - IMG_COMET1;
-	      
-      /* Draw it! */
-      dest.x = comets[i].x - (images[img]->w / 2);
-      dest.y = comets[i].y - images[img]->h;
-      dest.w = images[img]->w;
-      dest.h = images[img]->h;
-	      
-      SDL_BlitSurface(images[img], NULL, screen, &dest);
-      if (comet_str != NULL)
-      {
-        draw_nums(comet_str, comets[i].x, comets[i].y);
-      }
-    }
+  if (extra_life_earned) {
+    /* Draw extra life earned icon */
+    dest.x = 0;
+    dest.y = 0;
+    dest.w = images[IMG_EXTRA_LIFE]->w;
+    dest.h = images[IMG_EXTRA_LIFE]->h;
+    SDL_BlitSurface(images[IMG_EXTRA_LIFE], NULL, screen, &dest);
+  } else if (bonus_comet_counter) {
+    /* Draw extra life progress bar */
+    dest.x = 0;
+    dest.y = images[IMG_EXTRA_LIFE]->h/4;
+    dest.h = images[IMG_EXTRA_LIFE]->h/2;
+    dest.w = ((Opts_BonusCometInterval() + 1 - bonus_comet_counter)
+	      * images[IMG_EXTRA_LIFE]->w) / Opts_BonusCometInterval();
+    SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 0, 255, 0));
   }
 
+  /* Draw wave: */
+  if (Opts_BonusCometInterval())
+    offset = images[IMG_EXTRA_LIFE]->w + 5;
+  else
+    offset = 0;
 
+  dest.x = offset;
+  dest.y = 0;
+  dest.w = images[IMG_WAVE]->w;
+  dest.h = images[IMG_WAVE]->h;
 
+  SDL_BlitSurface(images[IMG_WAVE], NULL, screen, &dest);
 
-  /* Draw laser: */
-  if (laser.alive)
-  {
-    draw_line(laser.x1, laser.y1, laser.x2, laser.y2,
-		  255 / ((LASER_START + 1) - laser.alive),
-		  192 / ((LASER_START + 1) - laser.alive),
-		  64);
-  }
+  sprintf(str, "%d", wave);
+  draw_numbers(str, offset+images[IMG_WAVE]->w + (images[IMG_NUMBERS]->w / 10), 0);
 
-  /* Draw numeric keypad: */
-  if (Opts_UseKeypad())
-  {
-    /* pick image to draw: */
-    int keypad_image;
-    if (MC_AllowNegatives())
-    {
-      /* draw regular keypad */
-      keypad_image = IMG_KEYPAD;
-    }
-    else
-    {
-      /* draw keypad with with grayed-out '+' and '-' */
-      keypad_image = IMG_KEYPAD_NO_NEG;
-    }
+  /* Draw "score" label: */
+  dest.x = (screen->w - ((images[IMG_NUMBERS]->w / 10) * 7) -
+	        images[IMG_SCORE]->w -
+                images[IMG_STOP]->w - 5);
+  dest.y = 0;
+  dest.w = images[IMG_SCORE]->w;
+  dest.h = images[IMG_SCORE]->h;
 
-    /* now draw it: */ 
-    dest.x = (screen->w - images[keypad_image]->w) / 2;
-    dest.y = (screen->h - images[keypad_image]->h) / 2;
-    dest.w = images[keypad_image]->w;
-    dest.h = images[keypad_image]->h;
-    SDL_BlitSurface(images[keypad_image], NULL, screen, &dest);
-  }
+  SDL_BlitSurface(images[IMG_SCORE], NULL, screen, &dest);
 
-  /* Draw console, LED numbers, & tux: */
-  draw_led_console();
-  draw_console_image(tux_img);
+  /* Draw score numbers: */
+  sprintf(str, "%.6d", score);
+  draw_numbers(str,
+               screen->w - ((images[IMG_NUMBERS]->w / 10) * 6) - images[IMG_STOP]->w - 5,
+               0);
 
-  /* Draw any messages on the screen (used for the help mode) */
-  game_write_messages();
- 
-  /* Swap buffers: */
-  SDL_Flip(screen);
+  /* Draw stop button: */
+  if (!help_controls.x_is_blinking || (frame % 10 < 5)) {
+    dest.x = (screen->w - images[IMG_STOP]->w);
+    dest.y = 0;
+    dest.w = images[IMG_STOP]->w;
+    dest.h = images[IMG_STOP]->h;
+
+    SDL_BlitSurface(images[IMG_STOP], NULL, screen, &dest);
+  }
 }
 
 int check_exit_conditions(void)
@@ -2070,7 +2136,7 @@
     if (gameover_counter == 0)
       return GAME_OVER_LOST;
   }
-  
+
   /* determine if game won (i.e. all questions in mission answered correctly): */
   if (MC_MissionAccomplished())
   {
@@ -2092,11 +2158,11 @@
     #ifdef TUXMATH_DEBUG
     printf("\nListQuestionsLeft() = %d", MC_ListQuestionsLeft());
     printf("\nnum_comets_alive = %d", num_comets_alive);
-    #endif 
+    #endif
     return GAME_OVER_ERROR;
   }
-  
-  /* If using demo mode, see if counter has run out: */ 
+
+  /* If using demo mode, see if counter has run out: */
   if (Opts_DemoMode())
   {
     if (demo_countdown <= 0 )
@@ -2163,14 +2229,14 @@
 void reset_level(void)
 {
   char fname[1024];
-  int i;    
+  int i;
   int next_wave_comets;
   int use_feedback;
   float comet_avg_height,height_differential;
-  
-  
+
+
   /* Clear all comets: */
-  
+
   for (i = 0; i < MAX_COMETS; i++)
   {
     comets[i].alive = 0;
@@ -2178,7 +2244,7 @@
   num_comets_alive = 0;
 
   /* Clear LED digits: */
-  
+
   digits[0] = 0;
   digits[1] = 0;
   digits[2] = 0;
@@ -2186,13 +2252,14 @@
 
 
 
-  /* Load random background image: */
-  do
-  {
-    /* Don't pick the same one as last time... */
-    i = rand() % NUM_BKGDS;
-  }
-  while (i == last_bkgd);
+  /* Load random background image, but ensure it's different from this one: */
+  for (i = last_bkgd; i == last_bkgd; i = rand() % NUM_BKGDS);
+//  do
+//  {
+//    /* Don't pick the same one as last time... */
+//    i = rand() % NUM_BKGDS;
+//  }
+//  while (i == last_bkgd);
 
   last_bkgd = i;
 
@@ -2245,17 +2312,17 @@
       {
         next_wave_comets = Opts_MaxComets();
       }
-      
+
       use_feedback = Opts_UseFeedback();
 
-      if (use_feedback) 
+      if (use_feedback)
       {
 	#ifdef FEEDBACK_DEBUG
 	printf("Evaluating feedback...\n  old danger level = %g,",danger_level);
         #endif
-	
+
         /* Update our danger level, i.e., the target height */
-	danger_level = 1 - (1-danger_level) / 
+	danger_level = 1 - (1-danger_level) /
 	                   Opts_DangerLevelSpeedup();
 	if (danger_level > Opts_DangerLevelMax())
 	  danger_level = Opts_DangerLevelMax();
@@ -2273,7 +2340,7 @@
 	  printf("No feedback data available, aborting.\n\n");
 	  #endif
 	}
-	else 
+	else
         {
 	  /* Compute the average height of comet destruction. */
 	  comet_avg_height = comet_feedback_height/comet_feedback_number;
@@ -2285,7 +2352,7 @@
 	  /* height. That makes the changes a bit more conservative. */
 
 	  #ifdef FEEDBACK_DEBUG
-	  printf("  comet average height = %g, height differential = %g.\n", 
+	  printf("  comet average height = %g, height differential = %g.\n",
                  comet_avg_height, height_differential);
 	  printf("  old speed = %g,",speed);
 	  #endif
@@ -2354,19 +2421,19 @@
       found = i;
     }
   }
-  
+
   if (-1 == found)
   {
     /* free comet slot not found - no comet added: */
     return 0;
   }
 
-  
+
   /* Get math question for new comet - the following function fills in */
   /* the flashcard struct that is part of the comet struct:            */
   if (!MC_NextQuestion(&(comets[found].flashcard)))
   {
-    /* no more questions available - cannot create comet.  */ 
+    /* no more questions available - cannot create comet.  */
     return 0;
   }
 
@@ -2399,20 +2466,20 @@
 
 
   comets[found].alive = 1;
-  num_comets_alive++;      
+  num_comets_alive++;
 
   /* Pick a city to attack that was not attacked last time */
   /* (so formulas are less likely to overlap). */
-  do 
+  do
   {
     i = rand() % NUM_CITIES;
   }
   while (i == prev_city);
 
   prev_city = i;
-     
+
   /* Set in to attack that city: */
-  comets[found].city = i; 
+  comets[found].city = i;
   /* Start at the top, above the city in question: */
   comets[found].x = cities[i].x;
   comets[found].y = 0;
@@ -2455,7 +2522,7 @@
   str_length = strlen(str);
   /* IMG_NUMS now consists of 10 digit graphics, NUM_OPERS (i.e. 4) */
   /* operation symbols, and the '=' and '?' symbols, all side by side. */
-  /* char_width is the width of a single symbol.                     */ 
+  /* char_width is the width of a single symbol.                     */
   char_width = (images[IMG_NUMS]->w / (16));
   /* Calculate image_length, taking into account that the string will */
   /* usually have four empty spaces that are only half as wide:       */
@@ -2473,20 +2540,20 @@
 
 
   /* Draw each character: */
-  
+
   for (i = 0; i < str_length; i++)
   {
     c = -1;
 
 
     /* Determine which character to display: */
-      
+
     if (str[i] >= '0' && str[i] <= '9')
     {
       c = str[i] - '0';
     }
     else if ('=' == str[i])
-    {   
+    {
       c = 14;  /* determined by layout of nums.png image */
     }
     else if ('?' == str[i])
@@ -2503,7 +2570,7 @@
 	}
       }
     }
-      
+
     /* Display this character! */
     if (c != -1)
     {
@@ -2511,12 +2578,12 @@
       src.y = 0;
       src.w = char_width;
       src.h = images[IMG_NUMS]->h;
-	  
+
       dest.x = cur_x;
       dest.y = y - images[IMG_NUMS]->h;
       dest.w = src.w;
       dest.h = src.h;
-	  
+
       SDL_BlitSurface(images[IMG_NUMS], &src,
 			  screen, &dest);
       /* Move the 'cursor' one character width: */
@@ -2543,32 +2610,32 @@
 
 
   /* Draw each character: */
-  
+
   for (i = 0; i < strlen(str); i++)
     {
       c = -1;
 
 
       /* Determine which character to display: */
-      
+
       if (str[i] >= '0' && str[i] <= '9')
 	c = str[i] - '0';
-      
 
+
       /* Display this character! */
-      
+
       if (c != -1)
 	{
 	  src.x = c * (images[IMG_NUMBERS]->w / 10);
 	  src.y = 0;
 	  src.w = (images[IMG_NUMBERS]->w / 10);
 	  src.h = images[IMG_NUMBERS]->h;
-	  
+
 	  dest.x = cur_x;
 	  dest.y = y;
 	  dest.w = src.w;
 	  dest.h = src.h;
-	  
+
 	  SDL_BlitSurface(images[IMG_NUMBERS], &src,
 			  screen, &dest);
 
@@ -2597,7 +2664,7 @@
     fprintf(stderr, "Pause requested but not allowed by Opts!\n");
     return 0;
   }
- 
+
   pause_done = 0;
   pause_quit = 0;
 
@@ -2615,8 +2682,8 @@
   if (Opts_UsingSound())
     Mix_PauseMusic();
 #endif
-  
-  
+
+
   do
   {
     while (SDL_PollEvent(&event))
@@ -2641,7 +2708,7 @@
 #endif
 
   return (pause_quit);
-}  
+}
 
 
 
@@ -2653,14 +2720,14 @@
   float m, b;
   Uint32 pixel;
   SDL_Rect dest;
- 
+
   pixel = SDL_MapRGB(screen->format, red, grn, blu);
 
   dx = x2 - x1;
   dy = y2 - y1;
 
   putpixel(screen, x1, y1, pixel);
-  
+
   if (dx != 0)
   {
     m = ((float) dy) / ((float) dx);
@@ -2675,7 +2742,7 @@
     {
       x1 = x1 + dx;
       y1 = m * x1 + b;
-      
+
       putpixel(screen, x1, y1, pixel);
     }
   }
@@ -2687,7 +2754,7 @@
       y1 = y2;
       y2 = tmp;
     }
-    
+
     dest.x = x1;
     dest.y = y1;
     dest.w = 3;
@@ -2705,27 +2772,27 @@
 #ifdef PUTPIXEL_RAW
   int bpp;
   Uint8* p;
-  
+
   /* Determine bytes-per-pixel for the surface in question: */
-  
+
   bpp = surface->format->BytesPerPixel;
-  
-  
+
+
   /* Set a pointer to the exact location in memory of the pixel
      in question: */
-  
+
   p = (Uint8 *) (surface->pixels +       /* Start at beginning of RAM */
                  (y * surface->pitch) +  /* Go down Y lines */
                  (x * bpp));             /* Go in X pixels */
-  
-  
+
+
   /* Assuming the X/Y values are within the bounds of this surface... */
-  
+
   if (x >= 0 && y >= 0 && x < surface->w && y < surface->h)
     {
       /* Set the (correctly-sized) piece of data in the surface's RAM
          to the pixel value sent in: */
-      
+
       if (bpp == 1)
         *p = pixel;
       else if (bpp == 2)
@@ -2787,7 +2854,7 @@
   int comet_x;
 
   char str[64];
-  SDL_Rect dest;  
+  SDL_Rect dest;
 
   /* Calculate placement based on image widths: */
   nums_width = (images[IMG_NUMBERS]->w / 10) * 4; /* displaying 4 digits */
@@ -2803,7 +2870,7 @@
   dest.y = 0;
   dest.w = comet_width;
   dest.h = images[comet_img]->h;
-	      
+
   SDL_BlitSurface(images[comet_img], NULL, screen, &dest);
 
   /* draw number of remaining questions: */
@@ -2824,7 +2891,7 @@
   /* set y to draw LED numbers into Tux's "monitor": */
   y = (screen->h
      - images[IMG_CONSOLE_LED]->h
-     + 4);  /* "monitor" has 4 pixel margin */       
+     + 4);  /* "monitor" has 4 pixel margin */
 
   /* begin drawing so as to center display depending on whether minus */
   /* sign needed (4 digit slots) or not (3 digit slots) DSB */
@@ -2835,7 +2902,7 @@
 
   for (i = -1; i < 3; i++)  /* -1 is special case to allow minus sign */
                               /* with minimal modification of existing code DSB */
-  { 
+  {
     if (-1 == i)
     {
       if (MC_AllowNegatives())
@@ -2848,11 +2915,11 @@
         src.y = 0;
         src.w = (images[IMG_LED_NEG_SIGN]->w) / 2;
         src.h = images[IMG_LED_NEG_SIGN]->h;
-	  
+
         dest.y = y;
         dest.w = src.w;
         dest.h = src.h;
-	  
+
         SDL_BlitSurface(images[IMG_LED_NEG_SIGN], &src, screen, &dest);
         /* move "cursor" */
         dest.x += src.w;
@@ -2864,12 +2931,12 @@
       src.y = 0;
       src.w = (images[IMG_LEDNUMS]->w) / 10;
       src.h = images[IMG_LEDNUMS]->h;
-	  
+
       /* dest.x already set */
       dest.y = y;
       dest.w = src.w;
       dest.h = src.h;
-	  
+
       SDL_BlitSurface(images[IMG_LEDNUMS], &src, screen, &dest);
       /* move "cursor" */
       dest.x += src.w;
@@ -2895,10 +2962,10 @@
     key = SDLK_ESCAPE;
     game_key_event(key);
     return;
-  } 
+  }
 
   /* get out unless we really are using keypad */
-  if ( level_start_wait 
+  if ( level_start_wait
     || Opts_DemoMode()
     || !Opts_UseKeypad())
   {
@@ -2929,7 +2996,7 @@
       keypad_h = images[IMG_KEYPAD]->h;
     }
   }
- 
+
   if (!keypad_w || !keypad_h)
   {
     return;
@@ -2941,7 +3008,7 @@
         (screen->w / 2) - (keypad_w / 2) &&
         event.button.x <=
         (screen->w / 2) + (keypad_w / 2) &&
-        event.button.y >= 
+        event.button.y >=
         (screen->h / 2) - (keypad_h / 2) &&
         event.button.y <=
         (screen->h / 2) + (keypad_h / 2))))
@@ -2949,12 +3016,12 @@
   {
     return;
   }
-  
-  else /* click was within keypad */ 
+
+  else /* click was within keypad */
   {
     x = (event.button.x - ((screen->w / 2) - (keypad_w / 2)));
     y = (event.button.y - ((screen->h / 2) - (keypad_h / 2)));
- 
+
   /* Now determine what onscreen key was pressed */
   /*                                             */
   /* The on-screen keypad has a 4 x 4 layout:    */
@@ -3006,7 +3073,7 @@
         key = SDLK_9;
       if (3 == column)
         key = SDLK_MINUS;
-    } 
+    }
     if (1 == row)
     {
       if (0 == column)
@@ -3017,7 +3084,7 @@
         key = SDLK_6;
       if (3 == column)
         key = SDLK_PLUS;
-    }     
+    }
     if (2 == row)
     {
       if (0 == column)
@@ -3028,7 +3095,7 @@
         key = SDLK_3;
       if (3 == column)
         key = SDLK_PLUS;
-    } 
+    }
     if (3 == row)
     {
       if (0 == column)
@@ -3039,7 +3106,7 @@
         key = SDLK_RETURN;
       if (3 == column)
         key = SDLK_RETURN;
-    }     
+    }
 
     if (key == SDLK_UNKNOWN)
     {
@@ -3095,7 +3162,9 @@
   /* Toggle screen mode: */
   else if (key == SDLK_F10)
   {
+    Opts_SetFullscreen(!Opts_Fullscreen() );
     SwitchScreenMode();
+    game_recalc_positions();
   }
 
   /* Toggle music: */
@@ -3107,7 +3176,7 @@
       if (Mix_PlayingMusic())
       {
         Mix_HaltMusic();
-      }  
+      }
       else
       {
         Mix_PlayMusic(musics[MUS_GAME + (rand() % 3)], 0);
@@ -3116,7 +3185,7 @@
   }
 #endif
 
-    
+
   if (level_start_wait > 0 || Opts_DemoMode() || !help_controls.laser_enabled)
   {
     /* Eat other keys until level start wait has passed,
@@ -3126,7 +3195,7 @@
 
 
   /* The rest of the keys control the numeric answer console: */
-	      
+
   if (key >= SDLK_0 && key <= SDLK_9)
   {
     /* [0]-[9]: Add a new digit: */
@@ -3197,8 +3266,8 @@
     comets[i].x = 0;
     comets[i].y = 0;
     comets[i].answer = 0;
-    strncpy(comets[i].flashcard.formula_string, " ", MC_FORMULA_LEN); 
-    strncpy(comets[i].flashcard.answer_string, " ", MC_ANSWER_LEN); 
+    strncpy(comets[i].flashcard.formula_string, " ", MC_FORMULA_LEN);
+    strncpy(comets[i].flashcard.answer_string, " ", MC_ANSWER_LEN);
     comets[i].bonus = 0;
   }
 }
@@ -3233,3 +3302,55 @@
   free(penguins);
   free(steam);
 }
+
+/* Recalculate on-screen city & comet locations when screen dimensions change */
+void game_recalc_positions(void)
+{
+  int i, img;
+  int old_city_expl_height = city_expl_height;
+
+  tmdprintf("Recalculating positions\n");
+
+  if (Opts_UseIgloos())
+    img = IMG_IGLOO_INTACT;
+  else
+    img = IMG_CITY_BLUE;
+
+  for (i = 0; i < NUM_CITIES; ++i)
+  {
+    /* Left vs. Right - makes room for Tux and the console */
+    if (i < NUM_CITIES / 2)
+    {
+      cities[i].x = (((screen->w / (NUM_CITIES + 1)) * i) +
+                     ((images[img] -> w) / 2));
+      tmdprintf("%d,", cities[i].x);
+    }
+    else
+    {
+      cities[i].x = screen->w -
+                   (screen->w / (NUM_CITIES + 1) *
+                   (i - NUM_CITIES / 2) +
+                    images[img]->w / 2);
+      tmdprintf("%d,", cities[i].x);
+    }
+
+    penguins[i].x = cities[i].x;
+  }
+
+  city_expl_height = screen->h - images[IMG_CITY_BLUE]->h;
+  //move comets to a location 'equivalent' to where they were
+  //i.e. with the same amount of time left before impact
+  for (i = 0; i < MAX_COMETS; ++i)
+  {
+    if (!comets[i].alive)
+      continue;
+
+    comets[i].x = cities[comets[i].city].x;
+    //if (Opts_Fullscreen() )
+      comets[i].y = comets[i].y * city_expl_height / old_city_expl_height;
+    //else
+    //  comets[i].y = comets[i].y * RES_Y / screen->h;
+  }
+
+
+}

Modified: tuxmath/trunk/src/highscore.c
===================================================================
--- tuxmath/trunk/src/highscore.c	2008-06-11 21:26:58 UTC (rev 512)
+++ tuxmath/trunk/src/highscore.c	2008-06-12 00:07:50 UTC (rev 513)
@@ -426,7 +426,7 @@
                                   default_font, &white);
     if (s)
     {
-      loc.x = 320 - (s->w/2);
+      loc.x = (screen->w/2) - (s->w/2);
       loc.y = 110;
       SDL_BlitSurface(s, NULL, screen, &loc);
       SDL_FreeSurface(s);
@@ -436,7 +436,7 @@
                      default_font, &white);
     if (s)
     {
-      loc.x = 320 - (s->w/2);
+      loc.x = (screen->w/2) - (s->w/2);
       loc.y = 140;
       SDL_BlitSurface(s, NULL, screen, &loc);
       SDL_FreeSurface(s);
@@ -537,7 +537,7 @@
             if (s)
             {
               /* set up loc and blit: */
-              loc.x = 320 - (s->w/2);
+              loc.x = (screen->w/2) - (s->w/2);
               loc.y = 200;
               SDL_BlitSurface(s, NULL, screen, &loc);
 

Modified: tuxmath/trunk/src/setup.c
===================================================================
--- tuxmath/trunk/src/setup.c	2008-06-11 21:26:58 UTC (rev 512)
+++ tuxmath/trunk/src/setup.c	2008-06-12 00:07:50 UTC (rev 513)
@@ -18,7 +18,7 @@
   Subversion repository:
   https://svn.debian.alioth.org/tux4kids/tuxmath/
 
- 
+
   August 26, 2001 - Sept 18, 2007.
 */
 
@@ -51,6 +51,11 @@
 
 /* Global data used in setup.c:              */
 /* (These are now 'extern'd in "tuxmath.h") */
+
+int fs_res_x = RES_X;
+int fs_res_y = RES_Y;
+
+
 SDL_Surface* screen;
 SDL_Surface* images[NUM_IMAGES];
 /* Need special handling to generate flipped versions of images. This
@@ -70,6 +75,7 @@
   IMG_PENGUIN_WALK_OFF3
 };
 
+
 #ifndef NOSOUND
 Mix_Chunk* sounds[NUM_SOUNDS];
 Mix_Music* musics[NUM_MUSICS];
@@ -152,7 +158,7 @@
 /* from titlescreen, to allow for user-login to occur.         */
 void initialize_options_user(void)
 {
-  /* Read in user-specific settings, if desired.  By    */  
+  /* Read in user-specific settings, if desired.  By    */
   /* default, this restores settings from the player's last */
   /* game:                                                  */
   if (Opts_PerUserConfig())
@@ -184,7 +190,7 @@
   }
 
 #ifdef TUXMATH_DEBUG
-  print_high_scores(stdout);  
+  print_high_scores(stdout);
 #endif
 }
 
@@ -249,7 +255,7 @@
 	);
 
       printf("\n");
-    
+
       cleanup_on_error();
       exit(0);
     }
@@ -274,7 +280,7 @@
 	     strcmp(argv[i], "-u") == 0)
     {
       /* Display (happy) usage: */
-	    
+
       usage(0, argv[0]);
     }
     else if (0 == strcmp(argv[i], "--homedir"))
@@ -305,7 +311,7 @@
       }
       else /* try to read file named in following arg: */
       {
-        if (!read_named_config_file(argv[i + 1])) 
+        if (!read_named_config_file(argv[i + 1]))
         {
           fprintf(stderr, "Could not read config file: %s\n", argv[i + 1]);
         }
@@ -456,7 +462,7 @@
   /* Init SDL Audio: */
   Opts_SetSoundHWAvailable(0);  // By default no sound HW
   if (Opts_UseSound())
-  { 
+  {
     if (SDL_Init(SDL_INIT_AUDIO) < 0)
     {
       fprintf(stderr,
@@ -466,18 +472,21 @@
     }
     else {
       //if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 2048) < 0)
-      if (Mix_OpenAudio(22050, AUDIO_S16SYS, 2, 2048) < 0)
+      if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, AUDIO_S16SYS, 2, 2048) < 0)
       {
 	fprintf(stderr,
 		"\nWarning: I could not set up audio for 44100 Hz "
 		"16-bit stereo.\n"
 		"The Simple DirectMedia error that occured was:\n"
 		"%s\n\n", SDL_GetError());
+
       }
     }
     n_timesopened = Mix_QuerySpec(&frequency,&format,&channels);
     if (n_timesopened > 0)
       Opts_SetSoundHWAvailable(1);
+    else
+      frequency = format = channels = 0; //more helpful than garbage
     #ifdef TUXMATH_DEBUG
     fprintf(stderr, "Sound mixer: frequency = %d, "
                     "format = %x, "
@@ -486,7 +495,7 @@
                     frequency,format,channels,n_timesopened);
     #endif
   }
-  
+
   #endif
   {
     SDL_VideoInfo *videoInfo;
@@ -495,21 +504,32 @@
     if (videoInfo->hw_available)
     {
       surfaceMode = SDL_HWSURFACE;
-#ifdef TUXMATH_DEBUG    
+#ifdef TUXMATH_DEBUG
       printf("HW mode\n");
 #endif
     }
     else
     {
       surfaceMode = SDL_SWSURFACE;
-#ifdef TUXMATH_DEBUG    
+#ifdef TUXMATH_DEBUG
       printf("SW mode\n");
 #endif
     }
 
+    //determine the best fullscreen resolution
+    int i;
+    SDL_Rect** modes = SDL_ListModes(videoInfo->vfmt, SDL_FULLSCREEN | surfaceMode);
+    if (modes != 0 && modes != -1) //if there _is_ a "best" resolution
+      {
+      fs_res_x = modes[0]->w;
+      fs_res_y = modes[0]->h;
+      tmdprintf("Optimal resolution is %dx%d\n", RES_X, RES_Y);
+      }
+
+
     if (Opts_Fullscreen())
     {
-      screen = SDL_SetVideoMode(RES_X, RES_Y, PIXEL_BITS, SDL_FULLSCREEN | surfaceMode);
+      screen = SDL_SetVideoMode(fs_res_x, fs_res_y, PIXEL_BITS, SDL_FULLSCREEN | surfaceMode);
       if (screen == NULL)
       {
         fprintf(stderr,
@@ -583,7 +603,6 @@
   }
 }
 
-
 /* Created images that are blends of two other images to smooth out
    the transitions. */
 void generate_blended_images(void)
@@ -712,7 +731,7 @@
     Mix_CloseAudio();
     n_timesopened--;
   }
-  
+
 #ifdef SDL_Pango
    free_SDLPango_Context();
 #endif
@@ -736,8 +755,8 @@
   int masklen;
   Uint8* mask;
   SDL_Surface* icon;
-  
-  
+
+
   /* Load icon into a surface: */
   icon = IMG_Load(DATA_PREFIX "/images/icons/icon.png");
   if (icon == NULL)
@@ -748,23 +767,23 @@
             "%s\n\n", DATA_PREFIX "/images/icons/icon.png", SDL_GetError());
     return;
   }
-  
-  
+
+
   /* Create mask: */
   masklen = (((icon -> w) + 7) / 8) * (icon -> h);
   mask = malloc(masklen * sizeof(Uint8));
   memset(mask, 0xFF, masklen);
-  
-  
+
+
   /* Set icon: */
   SDL_WM_SetIcon(icon, mask);
-  
-  
+
+
   /* Free icon surface & mask: */
   free(mask);
   SDL_FreeSurface(icon);
-  
-  
+
+
   /* Seed random-number generator: */
   srand(SDL_GetTicks());
 }

Modified: tuxmath/trunk/src/titlescreen.c
===================================================================
--- tuxmath/trunk/src/titlescreen.c	2008-06-11 21:26:58 UTC (rev 512)
+++ tuxmath/trunk/src/titlescreen.c	2008-06-12 00:07:50 UTC (rev 513)
@@ -1,6 +1,6 @@
 /***************************************************************************
  -  file: titlescreen.c
- -  description: splash, title and menu screen functionality 
+ -  description: splash, title and menu screen functionality
                             ------------------
     begin                : Thur May 4 2000
     copyright            : (C) 2000 by Sam Hart
@@ -103,7 +103,7 @@
   "trophy",
   "credits"
 };
-   
+
 sprite **sprite_list = NULL;
 
 /* reg and sel are used to create the translucent button backgrounds. */
@@ -118,8 +118,16 @@
 	 Tuxdest,
 	 Titledest,
          stopRect,
+         Backrect, //location of the background
+         Tuxback,  //the portion of the background actually covered by Tux
+         Titleback,//and that covered by the title
 	 cursor;
 
+/* The background image scaled to fullscreen dimensions */
+SDL_Surface* scaled_bkgd = NULL;
+/* Set to scaled_bkgd if scaling fullscreen, images[IMG_MENU_BKG] otherwise */
+SDL_Surface* current_bkg = NULL; //DON'T SDL_Free()!
+
 /* Local function prototypes: */
 void TitleScreen_load_menu(void);
 void TitleScreen_unload_menu(void);
@@ -131,7 +139,12 @@
 void AddRect(SDL_Rect* src, SDL_Rect* dst);
 void InitEngine(void);
 void ShowMessage(char* str1, char* str2, char* str3, char* str4);
-void set_buttons_max_width(SDL_Rect *,int);
+void RecalcTitlePositions();
+void RecalcMenuPositions(int*, int, menu_options*, void (*)(menu_options*),
+                         SDL_Rect**, SDL_Rect**, SDL_Rect**,
+                         SDL_Rect**, SDL_Rect**, SDL_Rect**,
+                         SDL_Rect*, SDL_Rect*);
+void set_buttons_max_width(SDL_Rect *, SDL_Rect *, int);
 int run_main_menu(void);
 int run_arcade_menu(void);
 int run_custom_menu(void);
@@ -140,7 +153,6 @@
 
 
 
-
 /***********************************************************/
 /*                                                         */
 /*       "Public functions" (callable throughout program)  */
@@ -160,7 +172,7 @@
 
   Uint32 start = 0;
 
-  int i; 
+  int i;
   int n_subdirs;
   char **subdir_names;
 
@@ -178,10 +190,10 @@
   /* --- setup colors we use --- */
   black.r       = 0x00; black.g       = 0x00; black.b       = 0x00;
   gray.r        = 0x80; gray.g        = 0x80; gray.b        = 0x80;
-  dark_blue.r   = 0x00; dark_blue.g   = 0x00; dark_blue.b   = 0x60; 
+  dark_blue.r   = 0x00; dark_blue.g   = 0x00; dark_blue.b   = 0x60;
   red.r         = 0xff; red.g         = 0x00; red.b         = 0x00;
   white.r       = 0xff; white.g       = 0xff; white.b       = 0xff;
-  yellow.r      = 0xff; yellow.g      = 0xff; yellow.b      = 0x00; 
+  yellow.r      = 0xff; yellow.g      = 0xff; yellow.b      = 0x00;
 
 
   start = SDL_GetTicks();
@@ -189,7 +201,7 @@
 
   /* StandbyScreen: Display the Standby screen: */
   if (images[IMG_STANDBY])
-  {  
+  {
     // Center horizontally
     dest.x = ((screen->w) / 2) - (images[IMG_STANDBY]->w) / 2;
     // Center vertically
@@ -201,8 +213,8 @@
     SDL_BlitSurface(images[IMG_STANDBY], NULL, screen, &dest);
     SDL_UpdateRect(screen, 0, 0, 0, 0);
   }
- 
 
+
   /* --- wait  --- */
 
   while ((SDL_GetTicks() - start) < 2000)
@@ -213,7 +225,7 @@
      && event.key.keysym.sym == SDLK_ESCAPE)
     {
       return;
-    } 
+    }
     SDL_Delay(50);
   }
 
@@ -236,15 +248,23 @@
     return;
   }
 
+//  if (screen->flags & SDL_FULLSCREEN)
+//    current_bkg = scaled_bkgd;
+//  else
+    current_bkg = images[IMG_MENU_BKG];
   /* Draw background, if it loaded OK: */
-  if (images[IMG_MENU_BKG])
+  if (current_bkg)
   {
+    Backrect.x = (screen->w - current_bkg->w) / 2;
+    Backrect.y = (screen->h - current_bkg->h) / 2;
+    Backrect.w = current_bkg->w;
+    Backrect.h = current_bkg->h;
     /* FIXME not sure TransWipe() works in Windows: */
-    TransWipe(images[IMG_MENU_BKG], RANDOM_WIPE, 10, 20);
+    TransWipe(current_bkg, RANDOM_WIPE, 10, 20);
     /* Make sure background gets drawn (since TransWipe() doesn't */
     /* seem to work reliably as of yet):                          */
-    SDL_BlitSurface(images[IMG_MENU_BKG], NULL, screen, NULL);
- 
+    SDL_BlitSurface(current_bkg, NULL, screen, &Backrect);
+
   }
   /* Red "Stop" circle in upper right corner to go back to main menu: */
   if (images[IMG_STOP])
@@ -260,41 +280,68 @@
   /* --- Pull tux & logo onscreen --- */
   /* NOTE we wind up with Tuxdest.y == (screen->h)  - (Tux->frame[0]->h), */
   /* and Titledest.x == 0.                                                */
-  if (images[IMG_MENU_BKG]
+  if (current_bkg
    && images[IMG_MENU_TITLE]
    && images[IMG_STOP]
    && Tux && Tux->frame[0])
   {
+
     Tuxdest.x = 0;
     Tuxdest.y = screen->h;
-    Tuxdest.w = Tux->frame[0]->w;
-    Tuxdest.h = Tux->frame[0]->h;
+    Tuxback.x = Tuxdest.x - Backrect.x;
+    Tuxback.y = Tuxdest.y - Backrect.y;
+    Tuxdest.w = Tuxback.w = Tux->frame[0]->w;
+    Tuxdest.h = Tuxback.h = Tux->frame[0]->h;
 
+
     Titledest.x = screen->w;
     Titledest.y = 10;
-    Titledest.w = images[IMG_MENU_TITLE]->w;
-    Titledest.h = images[IMG_MENU_TITLE]->h;
+    Titleback.x = Titledest.x - Backrect.x;
+    Titleback.y = Titledest.y - Backrect.y;
+    Titledest.w = Titleback.w = images[IMG_MENU_TITLE]->w;
+    Titledest.h = Titleback.h = images[IMG_MENU_TITLE]->h;
 
 
     for (i = 0; i < (PRE_ANIM_FRAMES * PRE_FRAME_MULT); i++)
     {
       start = SDL_GetTicks();
-      SDL_BlitSurface(images[IMG_MENU_BKG], &Tuxdest, screen, &Tuxdest);
-      SDL_BlitSurface(images[IMG_MENU_BKG], &Titledest, screen, &Titledest);
 
+      /*
+      if (inRect(Backrect, Tuxdest.x, Tuxdest.y) &&
+          inRect(Backrect, Tuxdest.x + Tuxdest.w, Tuxdest.y) &&
+          inRect(Backrect, Tuxdest.x, Tuxdest.y + Tuxdest.h) &&
+          inRect(Backrect, Tuxdest.x + Tuxdest.w, Tuxdest.y + Tuxdest.h) )
+        SDL_BlitSurface(images[IMG_MENU_BKG], &Tuxback, screen, &Tuxdest);
+      else
+        SDL_FillRect(screen, &Tuxdest, 0);
+      if (inRect(Backrect, Titledest.x, Titledest.y) &&
+          inRect(Backrect, Titledest.x + Titledest.w, Titledest.y) &&
+          inRect(Backrect, Titledest.x, Titledest.y + Titledest.h) &&
+          inRect(Backrect, Titledest.x + Titledest.w, Titledest.y + Titledest.h) )
+        SDL_BlitSurface(images[IMG_MENU_BKG], &Titleback, screen, &Titledest);
+      else
+        SDL_FillRect(screen, &Titledest, 0);
+      */
+
+      //just draw to the whole screen. Less error prone than the above at the cost of efficiency
+      SDL_FillRect(screen, &screen->clip_rect, 0);
+      SDL_BlitSurface(current_bkg, NULL, screen, &Backrect);
+
       Tuxdest.y -= Tux->frame[0]->h / (PRE_ANIM_FRAMES * PRE_FRAME_MULT);
+      Tuxback.y -= Tux->frame[0]->h / (PRE_ANIM_FRAMES * PRE_FRAME_MULT);
       Titledest.x -= (screen->w) / (PRE_ANIM_FRAMES * PRE_FRAME_MULT);
+      Titleback.y -= (screen->w) / (PRE_ANIM_FRAMES * PRE_FRAME_MULT);
 
       SDL_BlitSurface(Tux->frame[0], NULL, screen, &Tuxdest);
       SDL_BlitSurface(images[IMG_MENU_TITLE], NULL, screen, &Titledest);
       SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
- 
+
       SDL_UpdateRect(screen, Tuxdest.x, Tuxdest.y, Tuxdest.w, Tuxdest.h);
       SDL_UpdateRect(screen, Titledest.x, Titledest.y, Titledest.w + 40,
                      Titledest.h);
       SDL_UpdateRect(screen, stopRect.x, stopRect.y, stopRect.w, stopRect.h);
 
-      while ((SDL_GetTicks() - start) < 33) 
+      while ((SDL_GetTicks() - start) < 33)
       {
         SDL_Delay(2);
       }
@@ -367,12 +414,13 @@
   sprite_list = (sprite**) malloc(N_SPRITES*sizeof(sprite*));
   if (sprite_list == NULL)
     return 0;
-    
+
   for (i = 0; i < N_SPRITES; i++) {
     /* --- load animated icon for menu item --- */
     sprintf(fn, "sprites/%s", menu_sprite_files[i]);
     sprite_list[i] = LoadSprite(fn, IMG_ALPHA);
   }
+  scaled_bkgd = zoom(images[IMG_MENU_BKG], fs_res_x, fs_res_y);
   return 1;
 }
 
@@ -396,6 +444,7 @@
   FreeSprite(Tux);
   Tux = NULL;
   TitleScreen_unload_menu();
+  SDL_FreeSurface(scaled_bkgd);
 }
 
 
@@ -452,7 +501,7 @@
 //     TTF_CloseFont(english_font);
 //     useEnglish = 0;
 //   }
-//   else 
+//   else
 //   {
 //     s4 = black_outline( "tuxmath-devel at lists.sourceforge.net", default_font, &white);
 //   }
@@ -463,7 +512,7 @@
 
   /* Redraw background: */
   if (images[IMG_MENU_BKG])
-    SDL_BlitSurface( images[IMG_MENU_BKG], NULL, screen, NULL );
+    SDL_BlitSurface( current_bkg, NULL, screen, &Backrect );
 
   /* Red "Stop" circle in upper right corner to go back to main menu: */
   if (images[IMG_STOP])
@@ -483,24 +532,24 @@
   /* Draw lines of text (do after drawing Tux so text is in front): */
   if (s1)
   {
-    loc.x = 320 - (s1->w/2); loc.y = 10;
+    loc.x = (screen->w / 2) - (s1->w/2); loc.y = 10;
     SDL_BlitSurface( s1, NULL, screen, &loc);
   }
   if (s2)
   {
-    loc.x = 320 - (s2->w/2); loc.y = 60;
+    loc.x = (screen->w / 2) - (s2->w/2); loc.y = 60;
     SDL_BlitSurface( s2, NULL, screen, &loc);
   }
   if (s3)
   {
     //loc.x = 320 - (s3->w/2); loc.y = 300;
-    loc.x = 320 - (s3->w/2); loc.y = 110;
+    loc.x = (screen->w / 2) - (s3->w/2); loc.y = 110;
     SDL_BlitSurface( s3, NULL, screen, &loc);
   }
   if (s4)
   {
     //loc.x = 320 - (s4->w/2); loc.y = 340;
-    loc.x = 320 - (s4->w/2); loc.y = 200;
+    loc.x = (screen->w / 2) - (s4->w/2); loc.y = 200;
     SDL_BlitSurface( s4, NULL, screen, &loc);
   }
 
@@ -511,7 +560,7 @@
   {
     start = SDL_GetTicks();
 
-    while (SDL_PollEvent(&event)) 
+    while (SDL_PollEvent(&event))
     {
       switch (event.type)
       {
@@ -522,7 +571,7 @@
 
         case SDL_MOUSEBUTTONDOWN:
         /* "Stop" button - go to main menu: */
-        { 
+        {
           if (inRect(stopRect, event.button.x, event.button.y ))
           {
             finished = 1;
@@ -544,7 +593,7 @@
       case 0:    tux_frame = 1; break;
       case TUX1: tux_frame = 2; break;
       case TUX2: tux_frame = 3; break;
-      case TUX3: tux_frame = 4; break;			
+      case TUX3: tux_frame = 4; break;
       case TUX4: tux_frame = 3; break;
       case TUX5: tux_frame = 2; break;
       default: tux_frame = 0;
@@ -572,6 +621,10 @@
 }
 
 
+void main_scmo(menu_options* mo) //set custum menu opts for main
+{
+  mo->ygap = 15;
+}
 int run_main_menu(void)
 {
   const unsigned char* menu_text[6] =
@@ -594,14 +647,15 @@
   sprites[4] = sprite_list[SPRITE_OPTIONS];
   sprites[5] = sprite_list[SPRITE_QUIT];
 
-  set_default_menu_options(&menu_opts);
-  menu_opts.ytop = 100;
-  menu_opts.ygap = 15;
 
+  //set_default_menu_options(&menu_opts);
+  //menu_opts.ytop = 100;
+  //menu_opts.ygap = 15;
+
   //This function takes care of all the drawing and receives
   //user input:
-  choice = choose_menu_item(menu_text,sprites,6,menu_opts);
-  
+  choice = choose_menu_item(menu_text,sprites,6,NULL,main_scmo);
+
   while (choice >= 0) {
     switch (choice) {
       case 0: {
@@ -642,7 +696,7 @@
       }
     }
     menu_opts.starting_entry = choice;
-    choice = choose_menu_item(menu_text,sprites,6,menu_opts);
+    choice = choose_menu_item(menu_text,sprites,6,NULL,main_scmo);
   }
   return 0;
 }
@@ -673,12 +727,12 @@
   sprites[4] = sprite_list[SPRITE_TROPHY];
   sprites[5] = sprite_list[SPRITE_MAIN];
 
-  set_default_menu_options(&menu_opts);
-  menu_opts.ytop = 100;
+//  set_default_menu_options(&menu_opts);
+//  menu_opts.ytop = 100;
 
   //This function takes care of all the drawing and receives
   //user input:
-  choice = choose_menu_item(menu_text,sprites,6,menu_opts);
+  choice = choose_menu_item(menu_text,sprites,6,NULL,NULL);
 
   while (choice >= 0) {
     if (choice < 4) {
@@ -687,6 +741,7 @@
       {
 	audioMusicUnload();
 	game();
+	RecalcTitlePositions();
 	if (Opts_MenuMusic()) {
 	  audioMusicLoad( "tuxi.ogg", -1 );
 	}
@@ -694,9 +749,9 @@
 	read_high_scores();  /* Update, in case other users have added to it */
 	hs_table = arcade_high_score_tables[choice];
 	if (check_score_place(hs_table, Opts_LastScore()) < HIGH_SCORES_SAVED){
-          
+
 	  unsigned char player_name[HIGH_SCORE_NAME_LENGTH * 3];
-	  
+
 	  /* Get name from player: */
 	  HighScoreNameEntry(&player_name[0]);
 	  insert_score(player_name, hs_table, Opts_LastScore());
@@ -707,10 +762,10 @@
 	  /* save to disk: */
 	  /* See "On File Locking" in fileops.c */
 	  append_high_score(choice,Opts_LastScore(),&player_name[0]);
-	  
+
 #ifdef TUXMATH_DEBUG
 	  print_high_scores(stderr);
-#endif 
+#endif
 	}
       } else {
 	fprintf(stderr, "\nCould not find %s config file\n",arcade_config_files[choice]);
@@ -724,9 +779,9 @@
       // Return to main menu
       return 0;
     }
-
+    set_default_menu_options(&menu_opts);
     menu_opts.starting_entry = choice;
-    choice = choose_menu_item(menu_text,sprites,6,menu_opts);
+    choice = choose_menu_item(menu_text,sprites,6,NULL, NULL);
   }
 
   return 0;
@@ -786,12 +841,12 @@
   sprites[2] = sprite_list[SPRITE_CREDITS];
   sprites[3] = sprite_list[SPRITE_MAIN];
 
-  set_default_menu_options(&menu_opts);
-  menu_opts.ytop = 100;
+  //set_default_menu_options(&menu_opts);
+  //menu_opts.ytop = 100;
 
   //This function takes care of all the drawing and receives
   //user input:
-  choice = choose_menu_item(menu_text,sprites,n_menu_entries,menu_opts);
+  choice = choose_menu_item(menu_text,sprites,n_menu_entries,NULL,NULL);
 
   while (choice >= 0) {
     switch (choice) {
@@ -838,14 +893,19 @@
     }
     }
 
+    set_default_menu_options(&menu_opts);
     menu_opts.starting_entry = choice;
-    choice = choose_menu_item(menu_text,sprites,n_menu_entries,menu_opts);
+    choice = choose_menu_item(menu_text,sprites,n_menu_entries,NULL,NULL);
   }
 
   return 0;
 }
 
 
+void lessons_scmo(menu_options* mo)
+{
+mo->ytop = 30;
+}
 /* Display a list of tuxmath config files in the missions directory   */
 /* and allow the player to pick one (AKA "Lessons").                  */
 
@@ -871,28 +931,30 @@
         star_sprites[i] = sprite_list[SPRITE_NO_GOLDSTAR];
     }
   }
-  set_default_menu_options(&menu_opts);
+//  set_default_menu_options(&menu_opts);
+//  ytop = 30;
 
   //This function takes care of all the drawing and receives
   //user input:
-  chosen_lesson = choose_menu_item((const unsigned char**)lesson_list_titles, star_sprites, num_lessons, menu_opts);
+  chosen_lesson = choose_menu_item((const unsigned char**)lesson_list_titles, star_sprites, num_lessons, NULL, &lessons_scmo);
 
-  while (chosen_lesson >= 0) 
+  while (chosen_lesson >= 0)
   {
     if (Opts_MenuSound())
       playsound(SND_POP);
-    
+
     /* Re-read global settings first in case any settings were */
     /* clobbered by other lesson or arcade games this session: */
     read_global_config_file();
-    
-    /* Now read the selected file and play the "mission": */ 
+    /* Now read the selected file and play the "mission": */
     if (read_named_config_file(lesson_list_filenames[chosen_lesson]))
     {
       if (Opts_MenuMusic())  //Turn menu music off for game
         {audioMusicUnload();}
 
+
       game();
+      RecalcTitlePositions();
 
       /* If successful, display Gold Star for this lesson! */
       if (MC_MissionAccomplished())
@@ -913,8 +975,9 @@
     }
     // Let the user choose another lesson; start with the screen and
     // selection that we ended with
+    set_default_menu_options(&menu_opts);
     menu_opts.starting_entry = chosen_lesson;
-    chosen_lesson = choose_menu_item((const unsigned char**)lesson_list_titles, star_sprites, num_lessons, menu_opts);
+    chosen_lesson = choose_menu_item((const unsigned char**)lesson_list_titles, star_sprites, num_lessons, &menu_opts, &lessons_scmo);
   }
   if (star_sprites)
   {
@@ -951,7 +1014,7 @@
 
   // Check for & read user_menu_entries file
   n_users = read_user_menu_entries(&user_names);
-  
+
   if (n_users == 0)
     return 0;   // a quick exit, there's only one user
 
@@ -967,7 +1030,7 @@
 
   while (n_users) {
     // Get the user choice
-    chosen_login = choose_menu_item(user_names, NULL, n_users, menu_opts);
+    chosen_login = choose_menu_item(user_names, NULL, n_users, &menu_opts, NULL);
     // Determine whether there were any modifier (CTRL) keys pressed
     mod = SDL_GetModState();
     if (chosen_login == -1 || chosen_login == n_users) {
@@ -1037,7 +1100,7 @@
 /* (the function returns the index for the selected menu item)  */
 /* -1 indicates that the user pressed escape                    */
 /****************************************************************/
-int choose_menu_item(const unsigned char **menu_text, sprite **menu_sprites, int n_menu_entries, menu_options menu_opts)
+int choose_menu_item(const unsigned char **menu_text, sprite **menu_sprites, int n_menu_entries, menu_options* custom_mo, void (*set_custom_menu_opts)(menu_options*) )
 {
   // Pixel renderings of menu text choices
   SDL_Surface **menu_item_unselected = NULL;
@@ -1049,10 +1112,17 @@
   // Menu sprite locations
   SDL_Rect *menu_sprite_rect = NULL;
 
+  // The section of the background that the menu rects actually cover
+  SDL_Rect *back_text_rect = NULL,
+           *back_button_rect = NULL,
+           *back_sprite_rect = NULL;
   SDL_Rect left_arrow_rect, right_arrow_rect;
+  SDL_Rect temp_rect; //temporary copy of a dest rect that may be written to by SDL_BlitSurface
 
+  menu_options menu_opts;
+
   Uint32 frame_counter = 0;
-  Uint32 frame_start = 0;       //For keeping frame rate constant 
+  Uint32 frame_start = 0;       //For keeping frame rate constant
   Uint32 frame_now = 0;
   int stop = 0;
   int loc = 0;                  //The currently selected menu item
@@ -1081,6 +1151,14 @@
     fprintf(stderr,"%s\n",menu_text[i]);
 #endif
 
+  if (custom_mo == NULL)
+    set_default_menu_options(&menu_opts);
+  else
+    menu_opts = *custom_mo;
+  if (set_custom_menu_opts != NULL)
+    set_custom_menu_opts(&menu_opts);
+
+  tmdprintf("Allocating memory\n");
   /**** Memory allocation for menu text  ****/
   title_offset = 0;
   if (menu_opts.title != NULL)
@@ -1115,6 +1193,8 @@
   // the total entries including the title & trailer
   n_menu_entries += title_offset+have_trailer;
 
+//  recalcMenuPositions();
+
   /**** Calculate the menu item heights and the number of     ****/
   /**** entries per screen                                    ****/
   if (menu_opts.buttonheight <= 0) {
@@ -1139,15 +1219,22 @@
   /**** Memory allocation for current screen rects  ****/
   menu_text_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
   menu_button_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
-  if (menu_text_rect == NULL || menu_button_rect == NULL) {
+  back_text_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
+  back_button_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
+  if (menu_text_rect == NULL || menu_button_rect == NULL ||
+      back_text_rect == NULL || back_button_rect == NULL) {
     free(menu_text_rect);
     free(menu_button_rect);
+    free(back_text_rect);
+    free(back_button_rect);
     return -2;
   }
   if (menu_sprites != NULL) {
     menu_sprite_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
-    if (menu_sprite_rect == NULL) {
+    back_sprite_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
+    if (menu_sprite_rect == NULL || back_sprite_rect == NULL) {
       free(menu_sprite_rect);
+      free(back_sprite_rect);
       return -2;
     }
   }
@@ -1188,7 +1275,7 @@
     loc_screen_start = 0;  // in case starting_entry was -1 (or wasn't set)
   imod = loc-loc_screen_start;
   for (i = 0; i < n_entries_per_screen; i++)
-  { 
+  {
     menu_button_rect[i].x = menu_opts.xleft;
     menu_text_rect[i].x = menu_opts.xleft + 15;  // 15 is left gap
     if (menu_sprites != NULL)
@@ -1212,12 +1299,28 @@
       menu_sprite_rect[i].h = 50;
     }
   }
+
   if (menu_opts.button_same_width)
-    set_buttons_max_width(menu_button_rect,n_entries_per_screen);
+    set_buttons_max_width(menu_button_rect,back_button_rect,n_entries_per_screen);
 
+  for (i = 0; i < n_entries_per_screen; ++i)
+  {
+    back_button_rect[i] = menu_button_rect[i];
+    back_button_rect[i].x -= Backrect.x;
+    back_button_rect[i].y -= Backrect.y;
+
+    back_text_rect[i] = menu_text_rect[i];
+    back_text_rect[i].x -= Backrect.x;
+    back_text_rect[i].y -= Backrect.y;
+
+    back_sprite_rect[i] = menu_sprite_rect[i];
+    back_sprite_rect[i].x -= Backrect.x;
+    back_sprite_rect[i].y -= Backrect.y;
+  }
+
   /**** Draw background, title, and Tux:                            ****/
-  if (images[IMG_MENU_BKG])
-    SDL_BlitSurface(images[IMG_MENU_BKG], NULL, screen, NULL);
+  if (current_bkg)
+    SDL_BlitSurface(current_bkg, NULL, screen, &Backrect);
   if (images[IMG_MENU_TITLE])
     SDL_BlitSurface(images[IMG_MENU_TITLE], NULL, screen, &Titledest);
   if (Tux && Tux->frame[0])
@@ -1249,7 +1352,7 @@
           //exit(0);
           break;
         }
- 
+
         case SDL_MOUSEMOTION:
         {
 	  loc = -1;  // By default, don't be in any entry
@@ -1258,7 +1361,7 @@
             if (inRect(menu_button_rect[i], event.motion.x, event.motion.y))
             {
               // Play sound if loc is being changed:
-              if (Opts_MenuSound() && (old_loc != loc_screen_start + i)) 
+              if (Opts_MenuSound() && (old_loc != loc_screen_start + i))
               {
                 playsound(SND_TOCK);
               }
@@ -1319,7 +1422,7 @@
 	      break;
             }
           }
-        
+
           /* "Left" button - go to previous page: */
           if (inRect(left_arrow_rect, event.button.x, event.button.y))
           {
@@ -1368,7 +1471,7 @@
           switch (event.key.keysym.sym)
           {
             case SDLK_ESCAPE:
-            { 
+            {
               stop = 2;
               break;
             }
@@ -1410,7 +1513,7 @@
 		loc = -1;
 	      }
               //  {loc = (loc_screen_start + n_entries_per_screen);}
-              break; 
+              break;
             }
 
             /* Go up one entry, if present: */
@@ -1446,14 +1549,29 @@
 		loc = loc_screen_start;
 	      if (loc != old_loc)
 		warp_mouse = 1;
-              break; 
+              break;
            }
 
 
             /* Toggle screen mode: */
-            case SDLK_F10: 
+            case SDLK_F10:
             {
               SwitchScreenMode();
+              RecalcTitlePositions();
+              RecalcMenuPositions(&n_entries_per_screen,
+                                  n_menu_entries,
+                                  &menu_opts,
+                                  set_custom_menu_opts,
+                                  &menu_button_rect,
+                                  &menu_sprite_rect,
+                                  &menu_text_rect,
+                                  &back_button_rect,
+                                  &back_sprite_rect,
+                                  &back_text_rect,
+                                  &left_arrow_rect,
+                                  &right_arrow_rect);
+              //we're unsure how the entries might shuffle, so return to start
+              loc_screen_start = 0;
               redraw = 1;
               break;
             }
@@ -1493,21 +1611,23 @@
     /* Redraw screen: */
     if (loc >= 0)
       loc_screen_start = loc - (loc % n_entries_per_screen);
-    if (old_loc_screen_start != loc_screen_start) 
+    if (old_loc_screen_start != loc_screen_start)
       redraw = 1;
     if (redraw)
     {
+      tmdprintf("Updating entire screen\n");
       /* This is a full-screen redraw */
       /* Redraw background, title, stop button, and Tux: */
-      if (images[IMG_MENU_BKG])
-        SDL_BlitSurface(images[IMG_MENU_BKG], NULL, screen, NULL); 
+      if (!current_bkg || Opts_Fullscreen() )
+        SDL_FillRect(screen, &screen->clip_rect, 0); //clear to black
+      if (current_bkg)
+        SDL_BlitSurface(current_bkg, NULL, screen, &Backrect);
       if (images[IMG_MENU_TITLE])
         SDL_BlitSurface(images[IMG_MENU_TITLE], NULL, screen, &Titledest);
       if (images[IMG_STOP])
         SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
       if (Tux->frame[0])
 	SDL_BlitSurface(Tux->frame[0], NULL, screen, &Tuxdest);
-
       /* Redraw the menu entries */
       for (imod = 0; imod < n_entries_per_screen; imod++)
 	menu_button_rect[imod].w = 0;  // so undrawn buttons don't affect width
@@ -1521,11 +1641,10 @@
       }
 
       if (menu_opts.button_same_width)
-	set_buttons_max_width(menu_button_rect,n_entries_per_screen);
+	set_buttons_max_width(menu_button_rect,back_button_rect,n_entries_per_screen);
       // Make sure the menu title mouse button didn't get turned on
       if (loc_screen_start == 0 && title_offset)
 	menu_button_rect[0].w = 0;
-
       for (i = loc_screen_start, imod = 0; i < loc_screen_start+n_entries_per_screen && i < n_menu_entries; i++, imod++) {
 	if (i == loc) {  //Draw text in yellow
 	  DrawButton(&menu_button_rect[imod], 10, SEL_RGBA);
@@ -1560,36 +1679,44 @@
 	  SDL_BlitSurface(images[IMG_RIGHT_GRAY], NULL, screen, &right_arrow_rect);
 	}
       }
-      SDL_UpdateRect(screen, 0, 0, 0 ,0);
+      SDL_Flip(screen);//SDL_UpdateRect(screen, 0, 0, 0 ,0);
     } else if (old_loc != loc) {
       // This is not a full redraw, but the selected entry did change.
       // By just redrawing the old and new selections, we avoid flickering.
       if (old_loc >= 0) {
 	imod = old_loc-loc_screen_start;
 	use_sprite = (menu_sprites != NULL && old_loc >= title_offset && menu_sprites[old_loc-title_offset] != NULL);
-	SDL_BlitSurface(images[IMG_MENU_BKG], &menu_button_rect[imod], screen, &menu_button_rect[imod]);   // redraw background
+        temp_rect = menu_button_rect[imod];
+        SDL_FillRect(screen, &temp_rect, 0);
+	SDL_BlitSurface(current_bkg, &back_button_rect[imod], screen, &temp_rect);   // redraw background
 	if (use_sprite) {
 	  // Some of the sprites extend beyond the menu button, so we
 	  // have to make sure we redraw in the sprite rects, too
-	  SDL_BlitSurface(images[IMG_MENU_BKG], &menu_sprite_rect[imod], screen, &menu_sprite_rect[imod]);
+	  SDL_BlitSurface(current_bkg, &back_sprite_rect[imod], screen, &temp_rect);
 	}
 	DrawButton(&menu_button_rect[imod], 10, REG_RGBA);  // draw button
+	//temp_rect = menu_text_rect[imod];
 	SDL_BlitSurface(menu_item_unselected[old_loc], NULL, screen, &menu_text_rect[imod]);  // draw text
 	if (use_sprite) {
-	  SDL_BlitSurface(menu_sprites[old_loc-title_offset]->default_img, NULL, screen, &menu_sprite_rect[imod]);
+	  temp_rect = menu_sprite_rect[imod];
+	  tmdprintf("Sprite %d at (%d %d)\n",  imod, temp_rect.x, temp_rect.y);
+	  SDL_BlitSurface(menu_sprites[old_loc-title_offset]->default_img, NULL, screen, &temp_rect);
 	  // Also update the sprite rect (in some cases the sprite
 	  // extends beyond the menu button)
 	  SDL_UpdateRect(screen, menu_sprite_rect[imod].x, menu_sprite_rect[imod].y, menu_sprite_rect[imod].w, menu_sprite_rect[imod].h);
 	}
 	SDL_UpdateRect(screen, menu_button_rect[imod].x, menu_button_rect[imod].y, menu_button_rect[imod].w, menu_button_rect[imod].h);
       }
-
       if (loc >= 0) {
 	imod = loc-loc_screen_start;
 	use_sprite = (menu_sprites != NULL && loc >= title_offset && menu_sprites[loc] != NULL);
-	SDL_BlitSurface(images[IMG_MENU_BKG], &menu_button_rect[imod], screen, &menu_button_rect[imod]);
+	temp_rect = menu_button_rect[imod];
+	SDL_BlitSurface(current_bkg, &back_button_rect[imod], screen, &temp_rect);
 	if (use_sprite)
-	  SDL_BlitSurface(images[IMG_MENU_BKG], &menu_sprite_rect[imod], screen, &menu_sprite_rect[imod]);
+	{
+	  temp_rect = menu_sprite_rect[imod];
+	  SDL_BlitSurface(current_bkg, &back_sprite_rect[imod], screen, &temp_rect);
+	}
 	DrawButton(&menu_button_rect[imod], 10, SEL_RGBA);
 	SDL_BlitSurface(menu_item_selected[loc], NULL, screen, &menu_text_rect[imod]);
 	if (use_sprite) {
@@ -1599,14 +1726,16 @@
 	  next_frame(menu_sprites[loc-title_offset]);
 	}
 	SDL_UpdateRect(screen, menu_button_rect[imod].x, menu_button_rect[imod].y, menu_button_rect[imod].w, menu_button_rect[imod].h);
+	tmdprintf("Updating rect: %d %d %d %d\n", menu_button_rect[imod].x, menu_button_rect[imod].y, menu_button_rect[imod].w, menu_button_rect[imod].h);
       }
     } else if (frame_counter % 5 == 0 && loc >= 0) {
       // No user input changed anything, but check to see if we need to
       // animate the sprite
       if (menu_sprites != NULL && loc >= title_offset && menu_sprites[loc-title_offset] != NULL) {
 	imod = loc-loc_screen_start;
-	//SDL_BlitSurface(images[IMG_MENU_BKG], &menu_button_rect[imod], screen, &menu_button_rect[imod]);
-	SDL_BlitSurface(images[IMG_MENU_BKG], &menu_sprite_rect[imod], screen, &menu_sprite_rect[imod]);
+	//SDL_BlitSurface(current_bkg, &menu_button_rect[imod], screen, &menu_button_rect[imod]);
+	temp_rect = menu_sprite_rect[imod];
+	SDL_BlitSurface(current_bkg, &back_sprite_rect[imod], screen, &temp_rect);
 	DrawButton(&menu_button_rect[imod], 10, SEL_RGBA);
 	//SDL_BlitSurface(menu_item_selected[loc], NULL, screen, &menu_text_rect[imod]);
 	// Note: even though the whole button was redrawn, we don't
@@ -1634,13 +1763,15 @@
     old_loc = loc;
     old_loc_screen_start = loc_screen_start;
 
+
+
     /* --- make Tux blink --- */
     switch (frame_counter % TUX6)
     {
       case 0:    tux_frame = 1; break;
       case TUX1: tux_frame = 2; break;
       case TUX2: tux_frame = 3; break;
-      case TUX3: tux_frame = 4; break;			
+      case TUX3: tux_frame = 4; break;
       case TUX4: tux_frame = 3; break;
       case TUX5: tux_frame = 2; break;
       default: tux_frame = 0;
@@ -1649,7 +1780,7 @@
     if (Tux && tux_frame)
     {
       /* Redraw background to keep edges anti-aliased properly: */
-      SDL_BlitSurface(images[IMG_MENU_BKG],&Tuxdest, screen, &Tuxdest);
+      SDL_BlitSurface(current_bkg,&Tuxdest, screen, &Tuxdest);
       SDL_BlitSurface(Tux->frame[tux_frame - 1], NULL, screen, &Tuxdest);
       SDL_UpdateRect(screen, Tuxdest.x, Tuxdest.y, Tuxdest.w, Tuxdest.h);
       //SDL_UpdateRect(screen, 0, 0, 0, 0);
@@ -1668,7 +1799,7 @@
 
   /***** User made a choice, clean up and return the choice.   ******/
 
-  /* --- clear graphics before leaving function --- */ 
+  /* --- clear graphics before leaving function --- */
   for (i = 0; i < n_menu_entries; i++)
   {
     SDL_FreeSurface(menu_item_unselected[i]);
@@ -1689,7 +1820,8 @@
 
 
 
-void set_buttons_max_width(SDL_Rect *menu_button_rect,int n)
+void set_buttons_max_width(SDL_Rect *menu_button_rect,
+                           SDL_Rect *back_button_rect, int n)
 {
   int i,max;
 
@@ -1699,7 +1831,9 @@
       max = menu_button_rect[i].w;
 
   for (i = 0; i < n; i++)
-    menu_button_rect[i].w = max;
+    menu_button_rect[i].w = back_button_rect[i].w = max;
+
+  tmdprintf("All buttons at width %d\n", max);
 }
 
 // Was in playgame.c in tuxtype:
@@ -1752,10 +1886,10 @@
                    var2 is how many frames animation should take */
                 if( var1 < 1 ) var1 = 1;
                 if( var2 < 1 ) var2 = 1;
-                step1 = screen->w / var1; 
+                step1 = screen->w / var1;
                 step2 = step1 / var2;
 
-                for(i = 0; i <= var2; i++) 
+                for(i = 0; i <= var2; i++)
                 {
                     for(j = 0; j <= var1; j++)
                     {
@@ -1904,20 +2038,20 @@
 
 	/* -- First erase everything we need to -- */
 	for (i = 0; i < numupdates; i++)
-		if (blits[i].type == 'E') 
+		if (blits[i].type == 'E')
 			SDL_LowerBlit(blits[i].src, blits[i].srcrect, screen, blits[i].dstrect);
 //	SNOW_erase();
 
-	/* -- then draw -- */ 
+	/* -- then draw -- */
 	for (i = 0; i < numupdates; i++)
-		if (blits[i].type == 'D') 
+		if (blits[i].type == 'D')
 			SDL_BlitSurface(blits[i].src, blits[i].srcrect, screen, blits[i].dstrect);
 //	SNOW_draw();
 
 	/* -- update the screen only where we need to! -- */
-//	if (SNOW_on) 
+//	if (SNOW_on)
 //		SDL_UpdateRects(screen, SNOW_add( (SDL_Rect*)&dstupdate, numupdates ), SNOW_rects);
-//	else 
+//	else
 		SDL_UpdateRects(screen, numupdates, dstupdate);
 
 	numupdates = 0;
@@ -1937,7 +2071,7 @@
 
     if (!src || !dst)
     {
-#ifdef TUXMATH_DEBUG 
+#ifdef TUXMATH_DEBUG
      fprintf(stderr, "AddRect(): src or dst invalid!\n");
 #endif
       return;
@@ -1963,7 +2097,7 @@
     int i;
 
     /* --- Set up the update rectangle pointers --- */
-	
+
     for (i = 0; i < MAX_UPDATES; ++i) {
         blits[i].srcrect = &srcupdate[i];
         blits[i].dstrect = &dstupdate[i];
@@ -1974,8 +2108,8 @@
 void set_default_menu_options(menu_options *menu_opts)
 {
   menu_opts->starting_entry = 0;
-  menu_opts->xleft = 240;
-  menu_opts->ytop = 30;
+  menu_opts->xleft = screen->w / 2 - 60;
+  menu_opts->ytop = (screen->h - current_bkg->h) / 2 + 100;
   // Leave room for arrows at the bottom:
   menu_opts->ybottom = screen->h - images[IMG_LEFT]->h - 20;
   menu_opts->buttonheight = -1;
@@ -1984,3 +2118,148 @@
   menu_opts->title = NULL;
   menu_opts->trailer = NULL;
 }
+
+/* Recalculate on-screen locations for title screen elements */
+void RecalcTitlePositions()
+{
+//  if (screen->flags & SDL_FULLSCREEN)
+//    current_bkg = scaled_bkgd;
+//  else
+    current_bkg = images[IMG_MENU_BKG];
+  Backrect = current_bkg->clip_rect;
+  Backrect.x = (screen->w - Backrect.w) / 2;
+  Backrect.y = (screen->h - Backrect.h) / 2;
+  Titledest.x = 0;
+  Titledest.y = 0;
+  Tuxdest.x = 0;
+  Tuxdest.y = screen->h - Tuxdest.h;
+  stopRect.x = screen->w - stopRect.w;
+  stopRect.y = 0;
+}
+
+/* Recalculate on-screen locations for menus when screen dimensions change */
+/* Perhaps consider generalizing this for use in initial menu calculations? */
+void RecalcMenuPositions(int* numentries,
+                         int totalentries,
+                         menu_options* mo,
+                         void (*set_custom_menu_opts)(menu_options*),
+                         SDL_Rect** menu_button_rect,
+                         SDL_Rect** menu_sprite_rect,
+                         SDL_Rect** menu_text_rect,
+                         SDL_Rect** back_button_rect,
+                         SDL_Rect** back_sprite_rect,
+                         SDL_Rect** back_text_rect,
+                         SDL_Rect* left_arrow_rect,
+                         SDL_Rect* right_arrow_rect)
+{
+  int i, imod;
+  SDL_Rect* old_mbr = *menu_button_rect;
+  SDL_Rect* old_msr = *menu_sprite_rect;
+  SDL_Rect* old_mtr = *menu_text_rect;
+  SDL_Rect* old_bbr = *back_button_rect;
+  SDL_Rect* old_bsr = *back_sprite_rect;
+  SDL_Rect* old_btr = *back_text_rect;
+
+  int old_ne = *numentries;
+  int buttonheight = old_mbr->h; //height shouldn't change
+  int textwidth = old_mtr->w; //neither should width =P
+
+  right_arrow_rect->x = screen->w - images[IMG_RIGHT]->w - 20;
+  right_arrow_rect->y = screen->h - images[IMG_RIGHT]->h - 20;
+  left_arrow_rect->x = right_arrow_rect->x - 10 - images[IMG_LEFT]->w;
+  left_arrow_rect->y = screen->h - images[IMG_LEFT]->h - 20;
+
+  set_default_menu_options(mo);
+  if (set_custom_menu_opts != NULL)
+    set_custom_menu_opts(mo);
+
+  *numentries     = (int)(screen->h - mo->ytop+mo->ygap)/(buttonheight + mo->ygap);
+  if (*numentries < totalentries)
+    *numentries = (int)(mo->ybottom - mo->ytop+mo->ygap)/(buttonheight + mo->ygap);
+  if (*numentries > totalentries)
+    *numentries = totalentries;
+
+
+
+
+  /**** Memory allocation for new screen rects  ****/
+  *menu_text_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
+  *menu_button_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
+  *menu_sprite_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
+  *back_text_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
+  *back_button_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
+  *back_sprite_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
+  if (*menu_text_rect == NULL ||
+      *back_text_rect == NULL ||
+      *menu_button_rect == NULL ||
+      *back_button_rect == NULL ||
+      *menu_sprite_rect == NULL ||
+      *back_sprite_rect == NULL) {
+    free(*menu_text_rect);
+    free(*menu_button_rect);
+    free(*menu_sprite_rect);
+    free(*back_text_rect);
+    free(*back_button_rect);
+    free(*back_sprite_rect);
+    *menu_text_rect = old_mtr;
+    *menu_button_rect = old_mbr;
+    *menu_sprite_rect = old_msr;
+    *numentries = old_ne;
+    return;
+  }
+  else {
+    free(old_mtr);
+    free(old_mbr);
+    free(old_msr);
+    free(old_btr);
+    free(old_bbr);
+    free(old_bsr);
+  }
+
+
+  //note: the [0] notation is merely to avoid typing out (*menu_xxx_rect)[i]
+  for (i = 0; i < *numentries; i++)
+  {
+    menu_button_rect[0][i].x = mo->xleft;
+    menu_text_rect[0][i].x = mo->xleft + 15;  // 15 is left gap
+    menu_text_rect[0][i].x += 60;  // for now, assume we have a sprite
+    if (i > 0)
+      menu_text_rect[0][i].y = menu_text_rect[0][i - 1].y + buttonheight + mo->ygap;
+    else
+      menu_text_rect[0][i].y = mo->ytop;
+
+    menu_button_rect[0][i].y = menu_text_rect[0][i].y - 5;
+    menu_text_rect[0][i].h = buttonheight - 10;
+    menu_button_rect[0][i].h = buttonheight;
+
+    menu_text_rect[0][i].w = textwidth;
+    menu_button_rect[0][i].w = menu_text_rect[0][i].w + 30;
+
+    if (menu_sprite_rect != NULL) {
+      menu_sprite_rect[0][i].x = menu_button_rect[0][i].x + 3;
+      menu_sprite_rect[0][i].y = menu_button_rect[0][i].y + 3;
+      menu_sprite_rect[0][i].w = 40;
+      menu_sprite_rect[0][i].h = 50;
+    }
+    tmdprintf("***Rects[%d]****\n", i);
+    tmdprintf("%3d %3d %3d %3d\n", menu_button_rect[0][i].x, menu_button_rect[0][i].y, menu_button_rect[0][i].w, menu_button_rect[0][i].h);
+    tmdprintf("%3d %3d %3d %3d\n", menu_text_rect[0][i].x, menu_text_rect[0][i].y, menu_text_rect[0][i].w, menu_text_rect[0][i].h);
+    tmdprintf("%3d %3d %3d %3d\n", menu_sprite_rect[0][i].x, menu_sprite_rect[0][i].y, menu_sprite_rect[0][i].w, menu_sprite_rect[0][i].h);
+    tmdprintf("***************\n");
+  }
+  for (i = 0; i < *numentries; ++i)
+  {
+    back_button_rect[0][i] = menu_button_rect[0][i];
+    back_button_rect[0][i].x -= Backrect.x;
+    back_button_rect[0][i].y -= Backrect.y;
+
+    back_text_rect[0][i] = menu_text_rect[0][i];
+    back_text_rect[0][i].x -= Backrect.x;
+    back_text_rect[0][i].y -= Backrect.y;
+
+    back_sprite_rect[0][i] = menu_sprite_rect[0][i];
+    back_sprite_rect[0][i].x -= Backrect.x;
+    back_sprite_rect[0][i].y -= Backrect.y;
+  }
+
+}

Modified: tuxmath/trunk/src/titlescreen.h
===================================================================
--- tuxmath/trunk/src/titlescreen.h	2008-06-11 21:26:58 UTC (rev 512)
+++ tuxmath/trunk/src/titlescreen.h	2008-06-12 00:07:50 UTC (rev 513)
@@ -76,7 +76,7 @@
 #define menu_font  "AndikaDesRevA.ttf"  /*  "GenAI102.ttf" */
 #define menu_font_size	18
 
-#define ttf_font  "AndikaDesRevA.ttf"  /*   "GenAI102.ttf" */ 
+#define ttf_font  "AndikaDesRevA.ttf"  /*   "GenAI102.ttf" */
 #define ttf_font_size	18
 
 #define MAX_LESSONS 100
@@ -109,11 +109,10 @@
 
 
 
-extern SDL_Surface *screen;
+//extern SDL_Surface *screen;
 //extern TTF_Font  *font;
 extern SDL_Event  event;
 
-
 extern SDL_Surface *bkg;
 
 #define MUSIC_FADE_OUT_MS	80
@@ -157,7 +156,7 @@
 /*In titlescreen.c */
 void TitleScreen(void);
 int ChooseMission(void);  //FIXME really should be in fileops.c
-int choose_menu_item(const unsigned char**, sprite**, int, menu_options);
+int choose_menu_item(const unsigned char**, sprite**, int, menu_options* menu_opts, void (*)(menu_options*) );
 void set_default_menu_options(menu_options *);
 
 

Modified: tuxmath/trunk/src/tuxmath.h
===================================================================
--- tuxmath/trunk/src/tuxmath.h	2008-06-11 21:26:58 UTC (rev 512)
+++ tuxmath/trunk/src/tuxmath.h	2008-06-12 00:07:50 UTC (rev 513)
@@ -45,6 +45,12 @@
 //#define TUXMATH_DEBUG
 /* for Tim's feedback speed control code           */
 //#define FEEDBACK_DEBUG
++/* nice inline debugging macro */
+#ifdef TUXMATH_DEBUG
+#define tmdprintf(...) printf(__VA_ARGS__)
+#else
+#define tmdprintf(...) 0
+#endif
 
 /* Maximum length of file path: */
 #define PATH_MAX 4096
@@ -125,6 +131,9 @@
 
 
 /* Global data gets 'externed' here: */
+extern int fs_res_x;
+extern int fs_res_y;
+
 extern SDL_Color black;
 extern SDL_Color gray;
 extern SDL_Color dark_blue;




More information about the Tux4kids-commits mailing list