foxygit / doom Log in
commit ced40ce2c44caca11be2b33060f8283c12ef0d7b
Author:     Simon Howard <fraggle@soulsphere.org>
AuthorDate: Sun May 22 17:34:17 2016 +0200
Commit:     Simon Howard <fraggle@soulsphere.org>
CommitDate: Sun May 22 17:34:17 2016 +0200

    Refactor loading disk icon code.

    Only draw the disk icon just before doing the SDL blit to the screen,
    and restore the background to I_VideoBuffer immediately after doing
    so. This avoids the possibility of the disk remaining in the video
    buffer and fixes #668.

    Also centralize most loading disk code inside v_diskicon.c.
---
 src/doom/d_main.c   |  2 +-
 src/i_video.c       | 23 ++++------------
 src/strife/d_main.c |  2 +-
 src/v_diskicon.c    | 76 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/v_diskicon.h    | 15 +++--------
 src/w_wad.c         |  4 +--
 6 files changed, 81 insertions(+), 41 deletions(-)

diff --git a/src/doom/d_main.c b/src/doom/d_main.c
index aef3f308..9b4fb4b9 100644
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@ -214,7 +214,7 @@ void D_Display (void)
 	    break;
 	if (automapactive)
 	    AM_Drawer ();
-	if (wipe || (viewheight != SCREENHEIGHT && fullscreen) || disk_indicator == disk_dirty)
+	if (wipe || (viewheight != SCREENHEIGHT && fullscreen))
 	    redrawsbar = true;
 	if (inhelpscreensstate && !inhelpscreens)
 	    redrawsbar = true;              // just put away the help screen
diff --git a/src/i_video.c b/src/i_video.c
index b98c3667..dd3166dd 100644
--- a/src/i_video.c
+++ b/src/i_video.c
@@ -175,12 +175,6 @@ int png_screenshots = 0;

 int show_diskicon = 1;

-// Only display the disk icon if more then this much bytes have been read
-// during the previous tic.
-
-static const int diskicon_threshold = 20*1024;
-int diskicon_readbytes = 0;
-
 // if true, I_VideoBuffer is screen->pixels

 static boolean native_surface;
@@ -965,18 +959,8 @@ void I_FinishUpdate (void)
 	    I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0;
     }

-    if (show_diskicon && disk_indicator == disk_on)
-    {
-	if (diskicon_readbytes >= diskicon_threshold)
-	{
-	    V_BeginRead();
-	}
-    }
-    else if (disk_indicator == disk_dirty)
-    {
-	disk_indicator = disk_off;
-    }
-    diskicon_readbytes = 0;
+    // Draw disk icon before blit, if necessary.
+    V_DrawDiskIcon();

     // draw to screen

@@ -1012,6 +996,9 @@ void I_FinishUpdate (void)
     }

     SDL_Flip(screen);
+
+    // Restore background and undo the disk indicator, if it was drawn.
+    V_RestoreDiskBackground();
 }


diff --git a/src/strife/d_main.c b/src/strife/d_main.c
index ddfbd7a9..dcc06832 100644
--- a/src/strife/d_main.c
+++ b/src/strife/d_main.c
@@ -301,7 +301,7 @@ void D_Display (void)
     // see if the border needs to be updated to the screen
     if (gamestate == GS_LEVEL && !automapactive && scaledviewwidth != 320)
     {
-        if (menuactive || menuactivestate || !viewactivestate || disk_indicator == disk_dirty)
+        if (menuactive || menuactivestate || !viewactivestate)
         {
             borderdrawcount = 3;
             popupactivestate = false;
diff --git a/src/v_diskicon.c b/src/v_diskicon.c
index 92d1eea1..6b097026 100644
--- a/src/v_diskicon.c
+++ b/src/v_diskicon.c
@@ -18,6 +18,8 @@

 #include "doomtype.h"
 #include "deh_str.h"
+#include "i_swap.h"
+#include "i_video.h"
 #include "m_argv.h"
 #include "v_video.h"
 #include "w_wad.h"
@@ -25,14 +27,22 @@

 #include "v_diskicon.h"

+// Only display the disk icon if more then this much bytes have been read
+// during the previous tic.
+
+static const int diskicon_threshold = 20*1024;
+
 // disk image patch (either STDISK or STCDROM)

 static patch_t *disk;
+static byte *saved_background;

 static int loading_disk_xoffs = 0;
 static int loading_disk_yoffs = 0;

-disk_indicator_e disk_indicator = disk_off;
+// Number of bytes read since the last call to V_DrawDiskIcon().
+static size_t recent_bytes_read = 0;
+static boolean disk_drawn;

 void V_EnableLoadingDisk(int xoffs, int yoffs)
 {
@@ -47,15 +57,67 @@ void V_EnableLoadingDisk(int xoffs, int yoffs)
         disk_name = DEH_String("STDISK");

     disk = W_CacheLumpName(disk_name, PU_STATIC);
+    saved_background = Z_Malloc(SHORT(disk->width) * SHORT(disk->height),
+                                PU_STATIC, NULL);
+}
+
+void V_BeginRead(size_t nbytes)
+{
+    recent_bytes_read += nbytes;
+}
+
+static void CopyRegion(byte *dest, int dest_pitch,
+                       byte *src, int src_pitch,
+                       int w, int h)
+{
+    byte *s, *d;
+    int y;
+
+    s = src; d = dest;
+    for (y = 0; y < h; ++y)
+    {
+        memcpy(d, s, w);
+        s += src_pitch;
+        d += dest_pitch;
+    }
 }

-void V_BeginRead(void)
+static byte *DiskRegionPointer(void)
 {
-    if (disk == NULL)
-        return;
+    int x, y;

-    // Draw the disk to the screen
-    V_DrawPatch(loading_disk_xoffs, loading_disk_yoffs, disk);
+    x = loading_disk_xoffs + SHORT(disk->leftoffset);
+    y = loading_disk_yoffs + SHORT(disk->topoffset);
+    return I_VideoBuffer + y * SCREENWIDTH + x;
+}
+
+void V_DrawDiskIcon(void)
+{
+    if (disk != NULL && recent_bytes_read > diskicon_threshold)
+    {
+        // Save the background behind the disk before we draw it.
+        CopyRegion(saved_background, SHORT(disk->width),
+                   DiskRegionPointer(), SCREENWIDTH,
+                   SHORT(disk->width), SHORT(disk->height));

-    disk_indicator = disk_dirty;
+        // Draw the disk to the screen
+        V_DrawPatch(loading_disk_xoffs, loading_disk_yoffs, disk);
+        disk_drawn = true;
+    }
+
+    recent_bytes_read = 0;
 }
+
+void V_RestoreDiskBackground(void)
+{
+    if (disk_drawn)
+    {
+        // Restore the background.
+        CopyRegion(DiskRegionPointer(), SCREENWIDTH,
+                   saved_background, SHORT(disk->width),
+                   SHORT(disk->width), SHORT(disk->height));
+
+        disk_drawn = false;
+    }
+}
+
diff --git a/src/v_diskicon.h b/src/v_diskicon.h
index 860c203c..240812a7 100644
--- a/src/v_diskicon.h
+++ b/src/v_diskicon.h
@@ -24,16 +24,9 @@
 #define LOADING_DISK_W 16
 #define LOADING_DISK_H 16

-typedef enum
-{
-    disk_off,
-    disk_on,
-    disk_dirty
-} disk_indicator_e;
-
-extern disk_indicator_e disk_indicator;
-
-extern void V_EnableLoadingDisk (int xoffs, int yoffs);
-extern void V_BeginRead (void);
+extern void V_EnableLoadingDisk(int xoffs, int yoffs);
+extern void V_BeginRead(size_t nbytes);
+extern void V_DrawDiskIcon(void);
+extern void V_RestoreDiskBackground(void);

 #endif
diff --git a/src/w_wad.c b/src/w_wad.c
index c26fb0f7..6f0bc58f 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -348,9 +348,7 @@ void W_ReadLump(lumpindex_t lump, void *dest)

     l = lumpinfo[lump];

-    diskicon_readbytes += l->size;
-
-    disk_indicator = disk_on;
+    V_BeginRead(l->size);

     c = W_Read(l->wad_file, l->position, dest, l->size);