More DOS text mode fixes

Jukka Heinonen jhei at iki.fi
Sat Apr 6 15:54:31 CST 2002


After this patch, DOS NetHack console output seems to work.
Some fixing would still be needed, since parts of the
screen are not erased properly.

Changelog:
  Writes to stdout and VGA_WriteChars routine
  now update both VGA buffers and Windows console.
  Added routine for changing current console attributes.
  Moved text mode handling from VGA_Poll into new routine and
  changed locking primitive into critical section.


Index: int10.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/int10.c,v
retrieving revision 1.4
diff -u -r1.4 int10.c
--- int10.c     3 Apr 2002 02:34:45 -0000       1.4
+++ int10.c     6 Apr 2002 21:36:11 -0000
@@ -840,9 +840,7 @@
 
   TRACE("char: 0x%02x\n", ascii);
 
-  // FIXME: Update VGA text buffers here...
-  WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), &ascii, 1, NULL, NULL);
-
+  VGA_PutChar(ascii);
   VGA_GetCursorPos(&xpos, &ypos);
   BIOS_SetCursorPos(data, 0, xpos, ypos);
 }



Index: vga.h
===================================================================
RCS file: /home/wine/wine/dlls/winedos/vga.h,v
retrieving revision 1.4
diff -u -r1.4 vga.h
--- vga.h       23 Mar 2002 18:48:53 -0000      1.4
+++ vga.h       6 Apr 2002 21:36:25 -0000
@@ -40,6 +40,8 @@
 void VGA_SetCursorPos(unsigned X,unsigned Y);
 void VGA_GetCursorPos(unsigned*X,unsigned*Y);
 void VGA_WriteChars(unsigned X,unsigned Y,unsigned ch,int attr,int count);
+void VGA_PutChar(BYTE ascii);
+void VGA_SetTextAttribute(BYTE attr);
 
 /* control */
 void VGA_ioport_out(WORD port, BYTE val);



Index: vga.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/vga.c,v
retrieving revision 1.6
diff -u -r1.6 vga.c
--- vga.c       23 Mar 2002 18:48:53 -0000      1.6
+++ vga.c       6 Apr 2002 21:36:40 -0000
@@ -35,12 +35,15 @@
 static IDirectDrawSurface *lpddsurf;
 static IDirectDrawPalette *lpddpal;
 static DDSURFACEDESC sdesc;
-static LONG vga_polling,vga_refresh;
+static LONG vga_refresh;
 static HANDLE poll_timer;
 
 static int vga_width;
 static int vga_height;
 static int vga_depth;
+static BYTE vga_text_attr;
+
+static CRITICAL_SECTION vga_lock = CRITICAL_SECTION_INIT("VGA");
 
 typedef HRESULT (WINAPI *DirectDrawCreateProc)(LPGUID,LPDIRECTDRAW *,LPUNKNOWN);
 static DirectDrawCreateProc pDirectDrawCreate;
@@ -404,6 +407,9 @@
 
     if (lpddraw) VGA_Exit();
 
+    /* FIXME: Where to initialize text attributes? */
+    VGA_SetTextAttribute(0xf);
+
     /* the xterm is slow, so refresh only every 200ms (5fps) */
     VGA_InstallTimer(200);
 
@@ -441,17 +447,109 @@
 
 void VGA_WriteChars(unsigned X,unsigned Y,unsigned ch,int attr,int count)
 {
+    CHAR_INFO info;
+    COORD siz, off;
+    SMALL_RECT dest;
     unsigned XR, YR;
-    char*dat;
+    char *dat;
+
+    EnterCriticalSection(&vga_lock);
+
+    info.Char.AsciiChar = ch;
+    info.Attributes = (WORD)attr;
+    siz.X = 1;
+    siz.Y = 1;
+    off.X = 0;
+    off.Y = 0;
+    dest.Top=Y; 
+    dest.Bottom=Y;
 
     VGA_GetAlphaMode(&XR, &YR);
     dat = VGA_AlphaBuffer() + ((XR*Y + X) * 2);
-    /* FIXME: also call WriteConsoleOutputA, for better responsiveness */
     while (count--) {
+        dest.Left = X + count;
+       dest.Right = X + count;
+
         *dat++ = ch;
-        if (attr>=0) *dat = attr;
+        if (attr>=0) 
+         *dat = attr;
+       else
+         info.Attributes = *dat;
         dat++;
+
+       WriteConsoleOutputA(VGA_AlphaConsole(), &info, siz, off, &dest);
     }
+
+    LeaveCriticalSection(&vga_lock);
+}
+
+static void VGA_PutCharAt(BYTE ascii, unsigned x, unsigned y)
+{
+    unsigned width, height;
+    char *dat;
+
+    VGA_GetAlphaMode(&width, &height);
+    dat = VGA_AlphaBuffer() + ((width*y + x) * 2);
+    dat[0] = ascii;
+    dat[1] = vga_text_attr;
+}
+
+void VGA_PutChar(BYTE ascii)
+{
+    unsigned width, height, x, y, nx, ny;
+
+    EnterCriticalSection(&vga_lock);
+
+    VGA_GetAlphaMode(&width, &height);
+    VGA_GetCursorPos(&x, &y);
+  
+    switch(ascii) {
+    case '\b':
+        VGA_PutCharAt(' ', x, y);
+       x--;
+       break;
+
+    case '\t':
+       x += ((x + 8) & ~7) - x;
+       break;
+
+    case '\n':
+        y++;
+       x = 0;
+       break;
+  
+    case '\a':
+        break;
+
+    case '\r':
+        x = 0;
+       break;
+
+    default:
+        VGA_PutCharAt(ascii, x, y);
+       x++;
+    }
+
+    /*
+     * FIXME: add line wrapping and scrolling
+     */
+
+    WriteFile(VGA_AlphaConsole(), &ascii, 1, NULL, NULL);
+
+    /*
+     * The following is just a sanity check.
+     */
+    VGA_GetCursorPos(&nx, &ny);
+    if(nx != x || ny != y)
+      WARN("VGA emulator and text console have become unsynchronized.\n");
+
+    LeaveCriticalSection(&vga_lock);
+}
+
+void VGA_SetTextAttribute(BYTE attr)
+{
+    vga_text_attr = attr;
+    SetConsoleTextAttribute(VGA_AlphaConsole(), attr);
 }
 
 /*** CONTROL ***/
@@ -508,45 +606,49 @@
   VGA_Unlock();
 }
 
-
-static void CALLBACK VGA_Poll( LPVOID arg, DWORD low, DWORD high )
+static void VGA_Poll_Text(void)
 {
     char *dat;
     unsigned int Height,Width,Y,X;
+    CHAR_INFO ch[80];
+    COORD siz, off;
+    SMALL_RECT dest;
+    HANDLE con = VGA_AlphaConsole();
+
+    VGA_GetAlphaMode(&Width,&Height);
+    dat = VGA_AlphaBuffer();
+    siz.X = 80; siz.Y = 1;
+    off.X = 0; off.Y = 0;
+    /* copy from virtual VGA frame buffer to console */
+    for (Y=0; Y<Height; Y++) {
+        dest.Top=Y; dest.Bottom=Y;
+       for (X=0; X<Width; X++) {
+           ch[X].Char.AsciiChar = *dat++;
+           /* WriteConsoleOutputA doesn't like "dead" chars */
+           if (ch[X].Char.AsciiChar == '\0')
+               ch[X].Char.AsciiChar = ' ';
+           ch[X].Attributes = *dat++;
+       }
+       dest.Left=0; dest.Right=Width+1;
+       WriteConsoleOutputA(con, ch, siz, off, &dest);
+    }
+}
 
-    if (!InterlockedExchangeAdd(&vga_polling, 1)) {
-        /* FIXME: optimize by doing this only if the data has actually changed
-         *        (in a way similar to DIBSection, perhaps) */
-        if (lpddraw) {
-         VGA_Poll_Graphics();
-        } else {
-          /* text mode */
-          CHAR_INFO ch[80];
-          COORD siz, off;
-          SMALL_RECT dest;
-          HANDLE con = VGA_AlphaConsole();
-
-          VGA_GetAlphaMode(&Width,&Height);
-          dat = VGA_AlphaBuffer();
-          siz.X = 80; siz.Y = 1;
-          off.X = 0; off.Y = 0;
-          /* copy from virtual VGA frame buffer to console */
-          for (Y=0; Y<Height; Y++) {
-              dest.Top=Y; dest.Bottom=Y;
-              for (X=0; X<Width; X++) {
-                  ch[X].Char.AsciiChar = *dat++;
-                 /* WriteConsoleOutputA doesn't like "dead" chars */
-                 if (ch[X].Char.AsciiChar == '\0')
-                     ch[X].Char.AsciiChar = ' ';
-                  ch[X].Attributes = *dat++;
-              }
-              dest.Left=0; dest.Right=Width+1;
-              WriteConsoleOutputA(con, ch, siz, off, &dest);
-          }
-        }
-        vga_refresh=1;
+static void CALLBACK VGA_Poll( LPVOID arg, DWORD low, DWORD high )
+{
+    if(!TryEnterCriticalSection(&vga_lock))
+        return;
+
+    /* FIXME: optimize by doing this only if the data has actually changed
+     *        (in a way similar to DIBSection, perhaps) */
+    if (lpddraw) {
+        VGA_Poll_Graphics();
+    } else {
+        VGA_Poll_Text();
     }
-    InterlockedDecrement(&vga_polling);
+
+    vga_refresh=1;
+    LeaveCriticalSection(&vga_lock);
 }
 
 static BYTE palreg,palcnt;




-- 
Jukka Heinonen <http://www.iki.fi/jhei/>



More information about the wine-patches mailing list