Portability fixes.
[wine] / dlls / winedos / vga.c
1 /*
2  * VGA hardware emulation
3  * 
4  * Copyright 1998 Ove Kåven (with some help from Marcus Meissner)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <string.h>
22 #include "winbase.h"
23 #include "wingdi.h"
24 #include "winuser.h"
25 #include "wincon.h"
26 #include "miscemu.h"
27 #include "dosexe.h"
28 #include "vga.h"
29 #include "ddraw.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
33
34 static IDirectDraw *lpddraw = NULL;
35 static IDirectDrawSurface *lpddsurf;
36 static IDirectDrawPalette *lpddpal;
37 static DDSURFACEDESC sdesc;
38 static LONG vga_refresh;
39 static HANDLE poll_timer;
40
41 static int vga_width;
42 static int vga_height;
43 static int vga_depth;
44 static BYTE vga_text_attr;
45
46 static BOOL vga_mode_initialized = FALSE;
47
48 static CRITICAL_SECTION vga_lock = CRITICAL_SECTION_INIT("VGA");
49
50 typedef HRESULT (WINAPI *DirectDrawCreateProc)(LPGUID,LPDIRECTDRAW *,LPUNKNOWN);
51 static DirectDrawCreateProc pDirectDrawCreate;
52
53 static void CALLBACK VGA_Poll( LPVOID arg, DWORD low, DWORD high );
54
55 /*
56  * For simplicity, I'm creating a second palette.
57  * 16 color accesses will use these pointers and insert
58  * entries from the 64-color palette into the default
59  * palette.   --Robert 'Admiral' Coeyman
60  */
61
62 static char vga_16_palette[17]={
63   0x00,  /* 0 - Black         */
64   0x01,  /* 1 - Blue          */
65   0x02,  /* 2 - Green         */
66   0x03,  /* 3 - Cyan          */
67   0x04,  /* 4 - Red           */
68   0x05,  /* 5 - Magenta       */
69   0x14,  /* 6 - Brown         */
70   0x07,  /* 7 - Light gray    */
71   0x38,  /* 8 - Dark gray     */
72   0x39,  /* 9 - Light blue    */
73   0x3a,  /* A - Light green   */
74   0x3b,  /* B - Light cyan    */
75   0x3c,  /* C - Light red     */
76   0x3d,  /* D - Light magenta */
77   0x3e,  /* E - Yellow        */
78   0x3f,  /* F - White         */
79   0x00   /* Border Color      */
80 };
81
82 static PALETTEENTRY vga_def_palette[256]={
83 /* red  green  blue */
84   {0x00, 0x00, 0x00}, /* 0 - Black */
85   {0x00, 0x00, 0x80}, /* 1 - Blue */
86   {0x00, 0x80, 0x00}, /* 2 - Green */
87   {0x00, 0x80, 0x80}, /* 3 - Cyan */
88   {0x80, 0x00, 0x00}, /* 4 - Red */
89   {0x80, 0x00, 0x80}, /* 5 - Magenta */
90   {0x80, 0x80, 0x00}, /* 6 - Brown */
91   {0xC0, 0xC0, 0xC0}, /* 7 - Light gray */
92   {0x80, 0x80, 0x80}, /* 8 - Dark gray */
93   {0x00, 0x00, 0xFF}, /* 9 - Light blue */
94   {0x00, 0xFF, 0x00}, /* A - Light green */
95   {0x00, 0xFF, 0xFF}, /* B - Light cyan */
96   {0xFF, 0x00, 0x00}, /* C - Light red */
97   {0xFF, 0x00, 0xFF}, /* D - Light magenta */
98   {0xFF, 0xFF, 0x00}, /* E - Yellow */
99   {0xFF, 0xFF, 0xFF}, /* F - White */
100   {0,0,0} /* FIXME: a series of continuous rainbow hues should follow */
101 };
102
103 /* 
104  *   This palette is the dos default, converted from 18 bit color to 24. 
105  *      It contains only 64 entries of colors--all others are zeros.
106  *          --Robert 'Admiral' Coeyman
107  */
108 static PALETTEENTRY vga_def64_palette[256]={
109 /* red  green  blue */
110   {0x00, 0x00, 0x00}, /* 0x00      Black      */
111   {0x00, 0x00, 0xaa}, /* 0x01      Blue       */
112   {0x00, 0xaa, 0x00}, /* 0x02      Green      */
113   {0x00, 0xaa, 0xaa}, /* 0x03      Cyan       */
114   {0xaa, 0x00, 0x00}, /* 0x04      Red        */
115   {0xaa, 0x00, 0xaa}, /* 0x05      Magenta    */
116   {0xaa, 0xaa, 0x00}, /* 0x06      */
117   {0xaa, 0xaa, 0xaa}, /* 0x07      Light Gray */
118   {0x00, 0x00, 0x55}, /* 0x08      */
119   {0x00, 0x00, 0xff}, /* 0x09      */
120   {0x00, 0xaa, 0x55}, /* 0x0a      */
121   {0x00, 0xaa, 0xff}, /* 0x0b      */
122   {0xaa, 0x00, 0x55}, /* 0x0c      */
123   {0xaa, 0x00, 0xff}, /* 0x0d      */
124   {0xaa, 0xaa, 0x55}, /* 0x0e      */
125   {0xaa, 0xaa, 0xff}, /* 0x0f      */
126   {0x00, 0x55, 0x00}, /* 0x10      */
127   {0x00, 0x55, 0xaa}, /* 0x11      */
128   {0x00, 0xff, 0x00}, /* 0x12      */
129   {0x00, 0xff, 0xaa}, /* 0x13      */
130   {0xaa, 0x55, 0x00}, /* 0x14      Brown      */
131   {0xaa, 0x55, 0xaa}, /* 0x15      */
132   {0xaa, 0xff, 0x00}, /* 0x16      */
133   {0xaa, 0xff, 0xaa}, /* 0x17      */
134   {0x00, 0x55, 0x55}, /* 0x18      */
135   {0x00, 0x55, 0xff}, /* 0x19      */
136   {0x00, 0xff, 0x55}, /* 0x1a      */
137   {0x00, 0xff, 0xff}, /* 0x1b      */
138   {0xaa, 0x55, 0x55}, /* 0x1c      */
139   {0xaa, 0x55, 0xff}, /* 0x1d      */
140   {0xaa, 0xff, 0x55}, /* 0x1e      */
141   {0xaa, 0xff, 0xff}, /* 0x1f      */
142   {0x55, 0x00, 0x00}, /* 0x20      */
143   {0x55, 0x00, 0xaa}, /* 0x21      */
144   {0x55, 0xaa, 0x00}, /* 0x22      */
145   {0x55, 0xaa, 0xaa}, /* 0x23      */
146   {0xff, 0x00, 0x00}, /* 0x24      */
147   {0xff, 0x00, 0xaa}, /* 0x25      */
148   {0xff, 0xaa, 0x00}, /* 0x26      */
149   {0xff, 0xaa, 0xaa}, /* 0x27      */
150   {0x55, 0x00, 0x55}, /* 0x28      */
151   {0x55, 0x00, 0xff}, /* 0x29      */
152   {0x55, 0xaa, 0x55}, /* 0x2a      */
153   {0x55, 0xaa, 0xff}, /* 0x2b      */
154   {0xff, 0x00, 0x55}, /* 0x2c      */
155   {0xff, 0x00, 0xff}, /* 0x2d      */
156   {0xff, 0xaa, 0x55}, /* 0x2e      */
157   {0xff, 0xaa, 0xff}, /* 0x2f      */
158   {0x55, 0x55, 0x00}, /* 0x30      */
159   {0x55, 0x55, 0xaa}, /* 0x31      */
160   {0x55, 0xff, 0x00}, /* 0x32      */
161   {0x55, 0xff, 0xaa}, /* 0x33      */
162   {0xff, 0x55, 0x00}, /* 0x34      */
163   {0xff, 0x55, 0xaa}, /* 0x35      */
164   {0xff, 0xff, 0x00}, /* 0x36      */
165   {0xff, 0xff, 0xaa}, /* 0x37      */
166   {0x55, 0x55, 0x55}, /* 0x38      Dark Gray     */
167   {0x55, 0x55, 0xff}, /* 0x39      Light Blue    */
168   {0x55, 0xff, 0x55}, /* 0x3a      Light Green   */
169   {0x55, 0xff, 0xff}, /* 0x3b      Light Cyan    */
170   {0xff, 0x55, 0x55}, /* 0x3c      Light Red     */
171   {0xff, 0x55, 0xff}, /* 0x3d      Light Magenta */
172   {0xff, 0xff, 0x55}, /* 0x3e      Yellow        */
173   {0xff, 0xff, 0xff}, /* 0x3f      White         */
174   {0,0,0} /* The next 192 entries are all zeros  */
175 };
176
177 static HANDLE VGA_timer;
178 static HANDLE VGA_timer_thread;
179
180 /* set the timer rate; called in the polling thread context */
181 static void CALLBACK set_timer_rate( ULONG_PTR arg )
182 {
183     LARGE_INTEGER when;
184
185     when.s.LowPart = when.s.HighPart = 0;
186     SetWaitableTimer( VGA_timer, &when, arg, VGA_Poll, 0, FALSE );
187 }
188
189 static DWORD CALLBACK VGA_TimerThread( void *dummy )
190 {
191     for (;;) WaitForMultipleObjectsEx( 0, NULL, FALSE, INFINITE, TRUE );
192 }
193
194 static void VGA_DeinstallTimer(void)
195 {
196     if (VGA_timer_thread)
197     {
198         CancelWaitableTimer( VGA_timer );
199         CloseHandle( VGA_timer );
200         TerminateThread( VGA_timer_thread, 0 );
201         CloseHandle( VGA_timer_thread );
202         VGA_timer_thread = 0;
203     }
204 }
205
206 static void VGA_InstallTimer(unsigned Rate)
207 {
208     if (!VGA_timer_thread)
209     {
210         VGA_timer = CreateWaitableTimerA( NULL, FALSE, NULL );
211         VGA_timer_thread = CreateThread( NULL, 0, VGA_TimerThread, NULL, 0, NULL );
212     }
213     QueueUserAPC( set_timer_rate, VGA_timer_thread, (ULONG_PTR)Rate );
214 }
215
216 HANDLE VGA_AlphaConsole(void)
217 {
218     /* this assumes that no Win32 redirection has taken place, but then again,
219      * only 16-bit apps are likely to use this part of Wine... */
220     return GetStdHandle(STD_OUTPUT_HANDLE);
221 }
222
223 char*VGA_AlphaBuffer(void)
224 {
225     return DOSMEM_MapDosToLinear(0xb8000);
226 }
227
228 /*** GRAPHICS MODE ***/
229
230 typedef struct {
231   unsigned Xres, Yres, Depth;
232   int ret;
233 } ModeSet;
234
235 static void WINAPI VGA_DoExit(ULONG_PTR arg)
236 {
237     VGA_DeinstallTimer();
238     IDirectDrawSurface_SetPalette(lpddsurf,NULL);
239     IDirectDrawSurface_Release(lpddsurf);
240     lpddsurf=NULL;
241     IDirectDrawPalette_Release(lpddpal);
242     lpddpal=NULL;
243     IDirectDraw_Release(lpddraw);
244     lpddraw=NULL;
245 }
246
247 static void WINAPI VGA_DoSetMode(ULONG_PTR arg)
248 {
249     LRESULT     res;
250     HWND        hwnd;
251     ModeSet *par = (ModeSet *)arg;
252     par->ret=1;
253
254     if (lpddraw) VGA_DoExit(0);
255     if (!lpddraw) {
256         if (!pDirectDrawCreate)
257         {
258             HMODULE hmod = LoadLibraryA( "ddraw.dll" );
259             if (hmod) pDirectDrawCreate = (DirectDrawCreateProc)GetProcAddress( hmod, "DirectDrawCreate" );
260             if (!pDirectDrawCreate) {
261                 ERR("Can't lookup DirectDrawCreate from ddraw.dll.\n");
262                 return;
263             }
264         }
265         res = pDirectDrawCreate(NULL,&lpddraw,NULL);
266         if (!lpddraw) {
267             ERR("DirectDraw is not available (res = %lx)\n",res);
268             return;
269         }
270         hwnd = CreateWindowExA(0,"STATIC","WINEDOS VGA",WS_POPUP|WS_BORDER|WS_CAPTION|WS_SYSMENU,0,0,par->Xres,par->Yres,0,0,0,NULL);
271         if (!hwnd) {
272             ERR("Failed to create user window.\n");
273         }
274         if ((res=IDirectDraw_SetCooperativeLevel(lpddraw,hwnd,DDSCL_FULLSCREEN|DDSCL_EXCLUSIVE))) {
275             ERR("Could not set cooperative level to exclusive (%lx)\n",res);
276         }
277
278         if ((res=IDirectDraw_SetDisplayMode(lpddraw,par->Xres,par->Yres,par->Depth))) {
279             ERR("DirectDraw does not support requested display mode (%dx%dx%d), res = %lx!\n",par->Xres,par->Yres,par->Depth,res);
280             IDirectDraw_Release(lpddraw);
281             lpddraw=NULL;
282             return;
283         }
284
285         res=IDirectDraw_CreatePalette(lpddraw,DDPCAPS_8BIT,NULL,&lpddpal,NULL);
286         if (res) {
287             ERR("Could not create palette (res = %lx)\n",res);
288             IDirectDraw_Release(lpddraw);
289             lpddraw=NULL;
290             return;
291         }
292         if ((res=IDirectDrawPalette_SetEntries(lpddpal,0,0,256,vga_def_palette))) {
293             ERR("Could not set default palette entries (res = %lx)\n", res);
294         }
295
296         memset(&sdesc,0,sizeof(sdesc));
297         sdesc.dwSize=sizeof(sdesc);
298         sdesc.dwFlags = DDSD_CAPS;
299         sdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
300         if (IDirectDraw_CreateSurface(lpddraw,&sdesc,&lpddsurf,NULL)||(!lpddsurf)) {
301             ERR("DirectDraw surface is not available\n");
302             IDirectDraw_Release(lpddraw);
303             lpddraw=NULL;
304             return;
305         }
306         IDirectDrawSurface_SetPalette(lpddsurf,lpddpal);
307         vga_refresh=0;
308         /* poll every 20ms (50fps should provide adequate responsiveness) */
309         VGA_InstallTimer(20);
310     }
311     par->ret=0;
312     return;
313 }
314
315 int VGA_SetMode(unsigned Xres,unsigned Yres,unsigned Depth)
316 {
317     ModeSet par;
318
319     vga_width = Xres;
320     vga_height = Yres;
321     vga_depth = Depth;
322
323     if(Xres >= 640 || Yres >= 480) {
324       par.Xres = Xres;
325       par.Yres = Yres;
326     } else {
327       par.Xres = 640;
328       par.Yres = 480;
329     }
330
331     par.Depth = (Depth < 8) ? 8 : Depth;
332
333     vga_mode_initialized = TRUE;
334
335     MZ_RunInThread(VGA_DoSetMode, (ULONG_PTR)&par);
336     return par.ret;
337 }
338
339 int VGA_GetMode(unsigned*Height,unsigned*Width,unsigned*Depth)
340 {
341     if (!lpddraw) return 1;
342     if (!lpddsurf) return 1;
343     if (Height) *Height=sdesc.dwHeight;
344     if (Width) *Width=sdesc.dwWidth;
345     if (Depth) *Depth=sdesc.ddpfPixelFormat.u1.dwRGBBitCount;
346     return 0;
347 }
348
349 void VGA_Exit(void)
350 {
351     if (lpddraw) MZ_RunInThread(VGA_DoExit, 0);
352 }
353
354 void VGA_SetPalette(PALETTEENTRY*pal,int start,int len)
355 {
356     if (!lpddraw) return;
357     IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
358 }
359
360 /* set a single [char wide] color in 16 color mode. */
361 void VGA_SetColor16(int reg,int color)
362 {
363         PALETTEENTRY *pal;
364
365     if (!lpddraw) return;
366         pal= &vga_def64_palette[color];
367         IDirectDrawPalette_SetEntries(lpddpal,0,reg,1,pal);
368         vga_16_palette[reg]=(char)color;
369 }
370
371 /* Get a single [char wide] color in 16 color mode. */
372 char VGA_GetColor16(int reg)
373 {
374
375     if (!lpddraw) return 0;
376         return (char)vga_16_palette[reg];
377 }
378
379 /* set all 17 [char wide] colors at once in 16 color mode. */
380 void VGA_Set16Palette(char *Table) 
381 {
382         PALETTEENTRY *pal;
383         int c;
384
385     if (!lpddraw) return;         /* return if we're in text only mode */     
386         bcopy((void *)&vga_16_palette,(void *)Table,17);
387                                     /* copy the entries into the table */
388     for (c=0; c<17; c++) {                                /* 17 entries */
389         pal= &vga_def64_palette[(int)vga_16_palette[c]];  /* get color  */
390         IDirectDrawPalette_SetEntries(lpddpal,0,c,1,pal); /* set entry  */
391         TRACE("Palette register %d set to %d\n",c,(int)vga_16_palette[c]);
392    } /* end of the counting loop */
393 }
394
395 /* Get all 17 [ char wide ] colors at once in 16 color mode. */
396 void VGA_Get16Palette(char *Table) 
397 {
398
399     if (!lpddraw) return;         /* return if we're in text only mode */     
400         bcopy((void *)Table,(void *)&vga_16_palette,17);
401                                     /* copy the entries into the table */
402 }
403
404 void VGA_SetQuadPalette(RGBQUAD*color,int start,int len)
405 {
406     PALETTEENTRY pal[256];
407     int c;
408
409     if (!lpddraw) return;
410     for (c=0; c<len; c++) {
411         pal[c].peRed  =color[c].rgbRed;
412         pal[c].peGreen=color[c].rgbGreen;
413         pal[c].peBlue =color[c].rgbBlue;
414         pal[c].peFlags=0;
415     }
416     IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
417 }
418
419 LPSTR VGA_Lock(unsigned*Pitch,unsigned*Height,unsigned*Width,unsigned*Depth)
420 {
421     if (!lpddraw) return NULL;
422     if (!lpddsurf) return NULL;
423     if (IDirectDrawSurface_Lock(lpddsurf,NULL,&sdesc,0,0)) {
424         ERR("could not lock surface!\n");
425         return NULL;
426     }
427     if (Pitch) *Pitch=sdesc.u1.lPitch;
428     if (Height) *Height=sdesc.dwHeight;
429     if (Width) *Width=sdesc.dwWidth;
430     if (Depth) *Depth=sdesc.ddpfPixelFormat.u1.dwRGBBitCount;
431     return sdesc.lpSurface;
432 }
433
434 void VGA_Unlock(void)
435 {
436     IDirectDrawSurface_Unlock(lpddsurf,sdesc.lpSurface);
437 }
438
439 /*** TEXT MODE ***/
440
441 int VGA_SetAlphaMode(unsigned Xres,unsigned Yres)
442 {
443     COORD siz;
444
445     if (lpddraw) VGA_Exit();
446
447     /* FIXME: Where to initialize text attributes? */
448     VGA_SetTextAttribute(0xf);
449
450     /* the xterm is slow, so refresh only every 200ms (5fps) */
451     VGA_InstallTimer(200);
452
453     siz.X = Xres;
454     siz.Y = Yres;
455     SetConsoleScreenBufferSize(VGA_AlphaConsole(),siz);
456     return 0;
457 }
458
459 void VGA_GetAlphaMode(unsigned*Xres,unsigned*Yres)
460 {
461     CONSOLE_SCREEN_BUFFER_INFO info;
462     GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info);
463     if (Xres) *Xres=info.dwSize.X;
464     if (Yres) *Yres=info.dwSize.Y;
465 }
466
467 void VGA_SetCursorPos(unsigned X,unsigned Y)
468 {
469     COORD pos;
470
471     if (!poll_timer) VGA_SetAlphaMode(80, 25);
472     pos.X = X;
473     pos.Y = Y;
474     SetConsoleCursorPosition(VGA_AlphaConsole(),pos);
475 }
476
477 void VGA_GetCursorPos(unsigned*X,unsigned*Y)
478 {
479     CONSOLE_SCREEN_BUFFER_INFO info;
480     GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info);
481     if (X) *X=info.dwCursorPosition.X;
482     if (Y) *Y=info.dwCursorPosition.Y;
483 }
484
485 void VGA_WriteChars(unsigned X,unsigned Y,unsigned ch,int attr,int count)
486 {
487     CHAR_INFO info;
488     COORD siz, off;
489     SMALL_RECT dest;
490     unsigned XR, YR;
491     char *dat;
492
493     EnterCriticalSection(&vga_lock);
494
495     info.Char.AsciiChar = ch;
496     info.Attributes = (WORD)attr;
497     siz.X = 1;
498     siz.Y = 1;
499     off.X = 0;
500     off.Y = 0;
501     dest.Top=Y; 
502     dest.Bottom=Y;
503
504     VGA_GetAlphaMode(&XR, &YR);
505     dat = VGA_AlphaBuffer() + ((XR*Y + X) * 2);
506     while (count--) {
507         dest.Left = X + count;
508        dest.Right = X + count;
509
510         *dat++ = ch;
511         if (attr>=0) 
512          *dat = attr;
513        else
514          info.Attributes = *dat;
515         dat++;
516
517        WriteConsoleOutputA(VGA_AlphaConsole(), &info, siz, off, &dest);
518     }
519
520     LeaveCriticalSection(&vga_lock);
521 }
522
523 static void VGA_PutCharAt(BYTE ascii, unsigned x, unsigned y)
524 {
525     unsigned width, height;
526     char *dat;
527
528     VGA_GetAlphaMode(&width, &height);
529     dat = VGA_AlphaBuffer() + ((width*y + x) * 2);
530     dat[0] = ascii;
531     dat[1] = vga_text_attr;
532 }
533
534 void VGA_PutChar(BYTE ascii)
535 {
536     unsigned width, height, x, y, nx, ny;
537
538     EnterCriticalSection(&vga_lock);
539
540     VGA_GetAlphaMode(&width, &height);
541     VGA_GetCursorPos(&x, &y);
542   
543     switch(ascii) {
544     case '\b':
545         VGA_PutCharAt(' ', x, y);
546        x--;
547        break;
548
549     case '\t':
550        x += ((x + 8) & ~7) - x;
551        break;
552
553     case '\n':
554         y++;
555        x = 0;
556        break;
557   
558     case '\a':
559         break;
560
561     case '\r':
562         x = 0;
563        break;
564
565     default:
566         VGA_PutCharAt(ascii, x, y);
567        x++;
568     }
569
570     /*
571      * FIXME: add line wrapping and scrolling
572      */
573
574     WriteFile(VGA_AlphaConsole(), &ascii, 1, NULL, NULL);
575
576     /*
577      * The following is just a sanity check.
578      */
579     VGA_GetCursorPos(&nx, &ny);
580     if(nx != x || ny != y)
581       WARN("VGA emulator and text console have become unsynchronized.\n");
582
583     LeaveCriticalSection(&vga_lock);
584 }
585
586 void VGA_SetTextAttribute(BYTE attr)
587 {
588     vga_text_attr = attr;
589     SetConsoleTextAttribute(VGA_AlphaConsole(), attr);
590 }
591
592 void VGA_ClearText(unsigned row1, unsigned col1, 
593                   unsigned row2, unsigned col2,
594                   BYTE attr)
595 {
596     unsigned width, height, x, y;
597     COORD off;
598     char *dat = VGA_AlphaBuffer();
599     HANDLE con = VGA_AlphaConsole();
600     VGA_GetAlphaMode(&width, &height);
601
602     EnterCriticalSection(&vga_lock); 
603
604     for(y=row1; y<=row2; y++) {
605         off.X = col1;
606        off.Y = y;
607        FillConsoleOutputCharacterA(con, ' ', col2-col1+1, off, NULL);
608        FillConsoleOutputAttribute(con, attr, col2-col1+1, off, NULL);
609
610        for(x=col1; x<=col2; x++) {
611            char *ptr = dat + ((width*y + x) * 2);
612            ptr[0] = ' ';
613            ptr[1] = attr;
614        }
615     }
616
617     LeaveCriticalSection(&vga_lock);
618 }
619
620 void VGA_ScrollUpText(unsigned row1, unsigned col1, 
621                      unsigned row2, unsigned col2,
622                      unsigned lines, BYTE attr)
623 {
624     FIXME("not implemented\n");
625 }
626
627 void VGA_ScrollDownText(unsigned row1, unsigned col1, 
628                        unsigned row2, unsigned col2,
629                        unsigned lines, BYTE attr)
630 {
631     FIXME("not implemented\n");
632 }
633
634 void VGA_GetCharacterAtCursor(BYTE *ascii, BYTE *attr)
635 {
636     unsigned width, height, x, y;
637     char *dat;
638
639     VGA_GetAlphaMode(&width, &height);
640     VGA_GetCursorPos(&x, &y);
641     dat = VGA_AlphaBuffer() + ((width*y + x) * 2);
642
643     *ascii = dat[0];
644     *attr = dat[1];
645 }
646
647
648 /*** CONTROL ***/
649
650 static void VGA_Poll_Graphics(void)
651 {
652   unsigned int Pitch, Height, Width, X, Y;
653   char *surf;
654   char *dat = DOSMEM_MapDosToLinear(0xa0000);
655
656   surf = VGA_Lock(&Pitch,&Height,&Width,NULL);
657   if (!surf) return;
658
659   if(vga_width == 320 && vga_depth <= 4)
660     for (Y=0; Y<vga_height; Y++,surf+=Pitch*2,dat+=vga_width/8) {
661       for(X=0; X<vga_width; X+=8) {
662        int offset = X/8;
663        int Z;
664        for(Z=0; Z<8; Z++) {
665          int b0 =  (dat[offset] >> Z) & 0x1;
666          int index = 7-Z;
667          surf[(X+index)*2] = b0;
668          surf[(X+index)*2+1] = b0;
669          surf[(X+index)*2+Pitch] = b0;
670          surf[(X+index)*2+Pitch+1] = b0;
671        }
672       }
673     }
674
675   if(vga_width == 320 && vga_depth == 8)
676     for (Y=0; Y<vga_height; Y++,surf+=Pitch*2,dat+=vga_width) {
677       for(X=0; X<vga_width; X++) {
678        int b0 = dat[X];
679        surf[X*2] = b0;
680        surf[X*2+1] = b0;
681        surf[X*2+Pitch] = b0;
682        surf[X*2+Pitch+1] = b0;
683       }
684     }
685
686   if(vga_depth <= 4)
687     for (Y=0; Y<vga_height; Y++,surf+=Pitch,dat+=vga_width/8) {
688       for(X=0; X<vga_width; X+=8) {
689        int offset = X/8;
690        int Z;
691        for(Z=0; Z<8; Z++) {
692          int b0 =  (dat[offset] >> Z) & 0x1;
693          int index = 7-Z;
694          surf[X+index] = b0;
695        }
696       }
697     }
698
699   VGA_Unlock();
700 }
701
702 static void VGA_Poll_Text(void)
703 {
704     char *dat;
705     unsigned int Height,Width,Y,X;
706     CHAR_INFO ch[80];
707     COORD siz, off;
708     SMALL_RECT dest;
709     HANDLE con = VGA_AlphaConsole();
710
711     VGA_GetAlphaMode(&Width,&Height);
712     dat = VGA_AlphaBuffer();
713     siz.X = 80; siz.Y = 1;
714     off.X = 0; off.Y = 0;
715     /* copy from virtual VGA frame buffer to console */
716     for (Y=0; Y<Height; Y++) {
717         dest.Top=Y; dest.Bottom=Y;
718        for (X=0; X<Width; X++) {
719            ch[X].Char.AsciiChar = *dat++;
720            /* WriteConsoleOutputA doesn't like "dead" chars */
721            if (ch[X].Char.AsciiChar == '\0')
722                ch[X].Char.AsciiChar = ' ';
723            ch[X].Attributes = *dat++;
724        }
725        dest.Left=0; dest.Right=Width+1;
726        WriteConsoleOutputA(con, ch, siz, off, &dest);
727     }
728 }
729
730 static void CALLBACK VGA_Poll( LPVOID arg, DWORD low, DWORD high )
731 {
732     if(!TryEnterCriticalSection(&vga_lock))
733         return;
734
735     /* FIXME: optimize by doing this only if the data has actually changed
736      *        (in a way similar to DIBSection, perhaps) */
737     if (lpddraw) {
738         VGA_Poll_Graphics();
739     } else {
740         VGA_Poll_Text();
741     }
742
743     vga_refresh=1;
744     LeaveCriticalSection(&vga_lock);
745 }
746
747 static BYTE palreg,palcnt;
748 static PALETTEENTRY paldat;
749
750 void VGA_ioport_out( WORD port, BYTE val )
751 {
752     switch (port) {
753         case 0x3c8:
754             palreg=val; palcnt=0; break;
755         case 0x3c9:
756             ((BYTE*)&paldat)[palcnt++]=val << 2;
757             if (palcnt==3) {
758                 VGA_SetPalette(&paldat,palreg++,1);
759                 palcnt=0;
760             }
761             break;
762     }
763 }
764
765 BYTE VGA_ioport_in( WORD port )
766 {
767     BYTE ret;
768
769     switch (port) {
770         case 0x3da:
771             /* since we don't (yet?) serve DOS VM requests while VGA_Poll is running,
772                we need to fake the occurrence of the vertical refresh */
773             ret=vga_refresh?0x00:0x08;
774             if (vga_mode_initialized)
775                 vga_refresh=0;
776             else
777                 /* Also fake the occurence of the vertical refresh when no graphic
778                    mode has been set */
779                 vga_refresh=!vga_refresh;
780             break;
781         default:
782             ret=0xff;
783     }
784     return ret;
785 }
786
787 void VGA_Clean(void)
788 {
789     VGA_Exit();
790     VGA_DeinstallTimer();
791 }