foxygit / doom Log in
commit 32803819a07859675b1d95b6aafd1674fe7835d8
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Sat Apr 12 16:31:31 2014 -0400
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Sat Apr 12 16:31:31 2014 -0400

    textscreen: Init screen at native bit depth.

    Always call SDL_SetVideoMode with bpp=0 to use the desktop's native
    bit depth, and instead draw into an intermediate 8-bit screenbuffer
    surface. This ensures that we do not encounter any palette mess-ups
    as on some systems true 8-bit screen modes are poorly supported.
---
 textscreen/txt_sdl.c | 37 +++++++++++++++++++++++++------------
 1 file changed, 25 insertions(+), 12 deletions(-)

diff --git a/textscreen/txt_sdl.c b/textscreen/txt_sdl.c
index 984a2e75..26b4a361 100644
--- a/textscreen/txt_sdl.c
+++ b/textscreen/txt_sdl.c
@@ -58,6 +58,7 @@ typedef struct
 #define BLINK_PERIOD 250

 static SDL_Surface *screen;
+static SDL_Surface *screenbuffer;
 static unsigned char *screendata;
 static int key_mapping = 1;

@@ -246,24 +247,29 @@ static void ChooseFont(void)

 int TXT_Init(void)
 {
-    int flags;
-
     if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
     {
         return 0;
     }

-    flags = SDL_SWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF;
-
     ChooseFont();

+    // Always create the screen at the native screen depth (bpp=0);
+    // some systems nowadays don't seem to support true 8-bit palettized
+    // screen modes very well and we end up with screwed up colors.
     screen = SDL_SetVideoMode(TXT_SCREEN_W * font->w,
-                              TXT_SCREEN_H * font->h, 8, flags);
+                              TXT_SCREEN_H * font->h, 0, 0);

     if (screen == NULL)
         return 0;

-    SDL_SetColors(screen, ega_colors, 0, 16);
+    // Instead, we draw everything into an intermediate 8-bit surface
+    // the same dimensions as the screen. SDL then takes care of all the
+    // 8->32 bit (or whatever depth) color conversions for us.
+    screenbuffer = SDL_CreateRGBSurface(0, TXT_SCREEN_W * font->w,
+                                        TXT_SCREEN_H * font->h,
+                                        8, 0, 0, 0, 0);
+    SDL_SetColors(screenbuffer, ega_colors, 0, 16);
     SDL_EnableUNICODE(1);

     screendata = malloc(TXT_SCREEN_W * TXT_SCREEN_H * 2);
@@ -285,6 +291,8 @@ void TXT_Shutdown(void)
 {
     free(screendata);
     screendata = NULL;
+    SDL_FreeSurface(screenbuffer);
+    screenbuffer = NULL;
     SDL_QuitSubSystem(SDL_INIT_VIDEO);
 }

@@ -324,8 +332,8 @@ static inline void UpdateCharacter(int x, int y)
     bytes = (font->w + 7) / 8;
     p = &font->data[character * font->h * bytes];

-    s = ((unsigned char *) screen->pixels)
-      + (y * font->h * screen->pitch)
+    s = ((unsigned char *) screenbuffer->pixels)
+      + (y * font->h * screenbuffer->pitch)
       + (x * font->w);

     for (y1=0; y1<font->h; ++y1)
@@ -357,7 +365,7 @@ static inline void UpdateCharacter(int x, int y)
             ++p;
         }

-        s += screen->pitch;
+        s += screenbuffer->pitch;
     }
 }

@@ -379,6 +387,7 @@ static int LimitToRange(int val, int min, int max)

 void TXT_UpdateScreenArea(int x, int y, int w, int h)
 {
+    SDL_Rect rect;
     int x1, y1;
     int x_end;
     int y_end;
@@ -396,9 +405,13 @@ void TXT_UpdateScreenArea(int x, int y, int w, int h)
         }
     }

-    SDL_UpdateRect(screen,
-                   x * font->w, y * font->h,
-                   (x_end - x) * font->w, (y_end - y) * font->h);
+    rect.x = x * font->w;
+    rect.y = y * font->h;
+    rect.w = (x_end - x) * font->w;
+    rect.h = (y_end - y) * font->h;
+
+    SDL_BlitSurface(screenbuffer, &rect, screen, &rect);
+    SDL_UpdateRects(screen, 1, &rect);
 }

 void TXT_UpdateScreen(void)