Better toggle all relevant bits in VGA crt register.
[wine/wine-kai.git] / dlls / winedos / vga.c
blob207b240be185dd131e0aef85752382823d9e56ca
1 /*
2 * VGA hardware emulation
4 * Copyright 1998 Ove Kåven (with some help from Marcus Meissner)
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.
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.
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
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"
32 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
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;
41 static int vga_width;
42 static int vga_height;
43 static int vga_depth;
44 static BYTE vga_text_attr;
45 static char *textbuf_old = NULL;
47 static BOOL vga_mode_initialized = FALSE;
49 static CRITICAL_SECTION vga_lock = CRITICAL_SECTION_INIT("VGA");
51 typedef HRESULT (WINAPI *DirectDrawCreateProc)(LPGUID,LPDIRECTDRAW *,LPUNKNOWN);
52 static DirectDrawCreateProc pDirectDrawCreate;
54 static void CALLBACK VGA_Poll( LPVOID arg, DWORD low, DWORD high );
56 static HWND vga_hwnd = (HWND) NULL;
59 * For simplicity, I'm creating a second palette.
60 * 16 color accesses will use these pointers and insert
61 * entries from the 64-color palette into the default
62 * palette. --Robert 'Admiral' Coeyman
65 static char vga_16_palette[17]={
66 0x00, /* 0 - Black */
67 0x01, /* 1 - Blue */
68 0x02, /* 2 - Green */
69 0x03, /* 3 - Cyan */
70 0x04, /* 4 - Red */
71 0x05, /* 5 - Magenta */
72 0x14, /* 6 - Brown */
73 0x07, /* 7 - Light gray */
74 0x38, /* 8 - Dark gray */
75 0x39, /* 9 - Light blue */
76 0x3a, /* A - Light green */
77 0x3b, /* B - Light cyan */
78 0x3c, /* C - Light red */
79 0x3d, /* D - Light magenta */
80 0x3e, /* E - Yellow */
81 0x3f, /* F - White */
82 0x00 /* Border Color */
85 static PALETTEENTRY vga_def_palette[256]={
86 /* red green blue */
87 {0x00, 0x00, 0x00}, /* 0 - Black */
88 {0x00, 0x00, 0x80}, /* 1 - Blue */
89 {0x00, 0x80, 0x00}, /* 2 - Green */
90 {0x00, 0x80, 0x80}, /* 3 - Cyan */
91 {0x80, 0x00, 0x00}, /* 4 - Red */
92 {0x80, 0x00, 0x80}, /* 5 - Magenta */
93 {0x80, 0x80, 0x00}, /* 6 - Brown */
94 {0xC0, 0xC0, 0xC0}, /* 7 - Light gray */
95 {0x80, 0x80, 0x80}, /* 8 - Dark gray */
96 {0x00, 0x00, 0xFF}, /* 9 - Light blue */
97 {0x00, 0xFF, 0x00}, /* A - Light green */
98 {0x00, 0xFF, 0xFF}, /* B - Light cyan */
99 {0xFF, 0x00, 0x00}, /* C - Light red */
100 {0xFF, 0x00, 0xFF}, /* D - Light magenta */
101 {0xFF, 0xFF, 0x00}, /* E - Yellow */
102 {0xFF, 0xFF, 0xFF}, /* F - White */
103 {0,0,0} /* FIXME: a series of continuous rainbow hues should follow */
107 * This palette is the dos default, converted from 18 bit color to 24.
108 * It contains only 64 entries of colors--all others are zeros.
109 * --Robert 'Admiral' Coeyman
111 static PALETTEENTRY vga_def64_palette[256]={
112 /* red green blue */
113 {0x00, 0x00, 0x00}, /* 0x00 Black */
114 {0x00, 0x00, 0xaa}, /* 0x01 Blue */
115 {0x00, 0xaa, 0x00}, /* 0x02 Green */
116 {0x00, 0xaa, 0xaa}, /* 0x03 Cyan */
117 {0xaa, 0x00, 0x00}, /* 0x04 Red */
118 {0xaa, 0x00, 0xaa}, /* 0x05 Magenta */
119 {0xaa, 0xaa, 0x00}, /* 0x06 */
120 {0xaa, 0xaa, 0xaa}, /* 0x07 Light Gray */
121 {0x00, 0x00, 0x55}, /* 0x08 */
122 {0x00, 0x00, 0xff}, /* 0x09 */
123 {0x00, 0xaa, 0x55}, /* 0x0a */
124 {0x00, 0xaa, 0xff}, /* 0x0b */
125 {0xaa, 0x00, 0x55}, /* 0x0c */
126 {0xaa, 0x00, 0xff}, /* 0x0d */
127 {0xaa, 0xaa, 0x55}, /* 0x0e */
128 {0xaa, 0xaa, 0xff}, /* 0x0f */
129 {0x00, 0x55, 0x00}, /* 0x10 */
130 {0x00, 0x55, 0xaa}, /* 0x11 */
131 {0x00, 0xff, 0x00}, /* 0x12 */
132 {0x00, 0xff, 0xaa}, /* 0x13 */
133 {0xaa, 0x55, 0x00}, /* 0x14 Brown */
134 {0xaa, 0x55, 0xaa}, /* 0x15 */
135 {0xaa, 0xff, 0x00}, /* 0x16 */
136 {0xaa, 0xff, 0xaa}, /* 0x17 */
137 {0x00, 0x55, 0x55}, /* 0x18 */
138 {0x00, 0x55, 0xff}, /* 0x19 */
139 {0x00, 0xff, 0x55}, /* 0x1a */
140 {0x00, 0xff, 0xff}, /* 0x1b */
141 {0xaa, 0x55, 0x55}, /* 0x1c */
142 {0xaa, 0x55, 0xff}, /* 0x1d */
143 {0xaa, 0xff, 0x55}, /* 0x1e */
144 {0xaa, 0xff, 0xff}, /* 0x1f */
145 {0x55, 0x00, 0x00}, /* 0x20 */
146 {0x55, 0x00, 0xaa}, /* 0x21 */
147 {0x55, 0xaa, 0x00}, /* 0x22 */
148 {0x55, 0xaa, 0xaa}, /* 0x23 */
149 {0xff, 0x00, 0x00}, /* 0x24 */
150 {0xff, 0x00, 0xaa}, /* 0x25 */
151 {0xff, 0xaa, 0x00}, /* 0x26 */
152 {0xff, 0xaa, 0xaa}, /* 0x27 */
153 {0x55, 0x00, 0x55}, /* 0x28 */
154 {0x55, 0x00, 0xff}, /* 0x29 */
155 {0x55, 0xaa, 0x55}, /* 0x2a */
156 {0x55, 0xaa, 0xff}, /* 0x2b */
157 {0xff, 0x00, 0x55}, /* 0x2c */
158 {0xff, 0x00, 0xff}, /* 0x2d */
159 {0xff, 0xaa, 0x55}, /* 0x2e */
160 {0xff, 0xaa, 0xff}, /* 0x2f */
161 {0x55, 0x55, 0x00}, /* 0x30 */
162 {0x55, 0x55, 0xaa}, /* 0x31 */
163 {0x55, 0xff, 0x00}, /* 0x32 */
164 {0x55, 0xff, 0xaa}, /* 0x33 */
165 {0xff, 0x55, 0x00}, /* 0x34 */
166 {0xff, 0x55, 0xaa}, /* 0x35 */
167 {0xff, 0xff, 0x00}, /* 0x36 */
168 {0xff, 0xff, 0xaa}, /* 0x37 */
169 {0x55, 0x55, 0x55}, /* 0x38 Dark Gray */
170 {0x55, 0x55, 0xff}, /* 0x39 Light Blue */
171 {0x55, 0xff, 0x55}, /* 0x3a Light Green */
172 {0x55, 0xff, 0xff}, /* 0x3b Light Cyan */
173 {0xff, 0x55, 0x55}, /* 0x3c Light Red */
174 {0xff, 0x55, 0xff}, /* 0x3d Light Magenta */
175 {0xff, 0xff, 0x55}, /* 0x3e Yellow */
176 {0xff, 0xff, 0xff}, /* 0x3f White */
177 {0,0,0} /* The next 192 entries are all zeros */
180 static HANDLE VGA_timer;
181 static HANDLE VGA_timer_thread;
183 /* set the timer rate; called in the polling thread context */
184 static void CALLBACK set_timer_rate( ULONG_PTR arg )
186 LARGE_INTEGER when;
188 when.s.LowPart = when.s.HighPart = 0;
189 SetWaitableTimer( VGA_timer, &when, arg, VGA_Poll, 0, FALSE );
192 static DWORD CALLBACK VGA_TimerThread( void *dummy )
194 for (;;) WaitForMultipleObjectsEx( 0, NULL, FALSE, INFINITE, TRUE );
197 static void VGA_DeinstallTimer(void)
199 if (VGA_timer_thread)
201 CancelWaitableTimer( VGA_timer );
202 CloseHandle( VGA_timer );
203 TerminateThread( VGA_timer_thread, 0 );
204 CloseHandle( VGA_timer_thread );
205 VGA_timer_thread = 0;
209 static void VGA_InstallTimer(unsigned Rate)
211 if (!VGA_timer_thread)
213 VGA_timer = CreateWaitableTimerA( NULL, FALSE, NULL );
214 VGA_timer_thread = CreateThread( NULL, 0, VGA_TimerThread, NULL, 0, NULL );
216 QueueUserAPC( set_timer_rate, VGA_timer_thread, (ULONG_PTR)Rate );
219 HANDLE VGA_AlphaConsole(void)
221 /* this assumes that no Win32 redirection has taken place, but then again,
222 * only 16-bit apps are likely to use this part of Wine... */
223 return GetStdHandle(STD_OUTPUT_HANDLE);
226 char*VGA_AlphaBuffer(void)
228 return DOSMEM_MapDosToLinear(0xb8000);
231 /*** GRAPHICS MODE ***/
233 typedef struct {
234 unsigned Xres, Yres, Depth;
235 int ret;
236 } ModeSet;
238 static void WINAPI VGA_DoExit(ULONG_PTR arg)
240 VGA_DeinstallTimer();
241 IDirectDrawSurface_SetPalette(lpddsurf,NULL);
242 IDirectDrawSurface_Release(lpddsurf);
243 lpddsurf=NULL;
244 IDirectDrawPalette_Release(lpddpal);
245 lpddpal=NULL;
246 IDirectDraw_Release(lpddraw);
247 lpddraw=NULL;
250 static void WINAPI VGA_DoSetMode(ULONG_PTR arg)
252 LRESULT res;
253 ModeSet *par = (ModeSet *)arg;
254 par->ret=1;
256 if (lpddraw) VGA_DoExit(0);
257 if (!lpddraw) {
258 if (!pDirectDrawCreate)
260 HMODULE hmod = LoadLibraryA( "ddraw.dll" );
261 if (hmod) pDirectDrawCreate = (DirectDrawCreateProc)GetProcAddress( hmod, "DirectDrawCreate" );
262 if (!pDirectDrawCreate) {
263 ERR("Can't lookup DirectDrawCreate from ddraw.dll.\n");
264 return;
267 res = pDirectDrawCreate(NULL,&lpddraw,NULL);
268 if (!lpddraw) {
269 ERR("DirectDraw is not available (res = %lx)\n",res);
270 return;
272 if (!vga_hwnd) {
273 vga_hwnd = CreateWindowExA(0,"STATIC","WINEDOS VGA",WS_POPUP|WS_VISIBLE,0,0,par->Xres,par->Yres,0,0,0,NULL);
274 if (!vga_hwnd) {
275 ERR("Failed to create user window.\n");
276 IDirectDraw_Release(lpddraw);
277 lpddraw=NULL;
278 return;
281 else
282 SetWindowPos(vga_hwnd,0,0,0,par->Xres,par->Yres,SWP_NOMOVE|SWP_NOZORDER);
284 if ((res=IDirectDraw_SetCooperativeLevel(lpddraw,vga_hwnd,DDSCL_FULLSCREEN|DDSCL_EXCLUSIVE))) {
285 ERR("Could not set cooperative level to exclusive (%lx)\n",res);
288 if ((res=IDirectDraw_SetDisplayMode(lpddraw,par->Xres,par->Yres,par->Depth))) {
289 ERR("DirectDraw does not support requested display mode (%dx%dx%d), res = %lx!\n",par->Xres,par->Yres,par->Depth,res);
290 IDirectDraw_Release(lpddraw);
291 lpddraw=NULL;
292 return;
295 res=IDirectDraw_CreatePalette(lpddraw,DDPCAPS_8BIT,NULL,&lpddpal,NULL);
296 if (res) {
297 ERR("Could not create palette (res = %lx)\n",res);
298 IDirectDraw_Release(lpddraw);
299 lpddraw=NULL;
300 return;
302 if ((res=IDirectDrawPalette_SetEntries(lpddpal,0,0,256,vga_def_palette))) {
303 ERR("Could not set default palette entries (res = %lx)\n", res);
306 memset(&sdesc,0,sizeof(sdesc));
307 sdesc.dwSize=sizeof(sdesc);
308 sdesc.dwFlags = DDSD_CAPS;
309 sdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
310 if (IDirectDraw_CreateSurface(lpddraw,&sdesc,&lpddsurf,NULL)||(!lpddsurf)) {
311 ERR("DirectDraw surface is not available\n");
312 IDirectDraw_Release(lpddraw);
313 lpddraw=NULL;
314 return;
316 IDirectDrawSurface_SetPalette(lpddsurf,lpddpal);
317 vga_refresh=0;
318 /* poll every 20ms (50fps should provide adequate responsiveness) */
319 VGA_InstallTimer(20);
321 par->ret=0;
322 return;
325 int VGA_SetMode(unsigned Xres,unsigned Yres,unsigned Depth)
327 ModeSet par;
329 vga_width = Xres;
330 vga_height = Yres;
331 vga_depth = Depth;
333 if(Xres >= 640 || Yres >= 480) {
334 par.Xres = Xres;
335 par.Yres = Yres;
336 } else {
337 par.Xres = 640;
338 par.Yres = 480;
341 par.Depth = (Depth < 8) ? 8 : Depth;
343 vga_mode_initialized = TRUE;
345 MZ_RunInThread(VGA_DoSetMode, (ULONG_PTR)&par);
346 return par.ret;
349 int VGA_GetMode(unsigned*Height,unsigned*Width,unsigned*Depth)
351 if (!lpddraw) return 1;
352 if (!lpddsurf) return 1;
353 if (Height) *Height=sdesc.dwHeight;
354 if (Width) *Width=sdesc.dwWidth;
355 if (Depth) *Depth=sdesc.ddpfPixelFormat.u1.dwRGBBitCount;
356 return 0;
359 void VGA_Exit(void)
361 if (lpddraw) MZ_RunInThread(VGA_DoExit, 0);
364 void VGA_SetPalette(PALETTEENTRY*pal,int start,int len)
366 if (!lpddraw) return;
367 IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
370 /* set a single [char wide] color in 16 color mode. */
371 void VGA_SetColor16(int reg,int color)
373 PALETTEENTRY *pal;
375 if (!lpddraw) return;
376 pal= &vga_def64_palette[color];
377 IDirectDrawPalette_SetEntries(lpddpal,0,reg,1,pal);
378 vga_16_palette[reg]=(char)color;
381 /* Get a single [char wide] color in 16 color mode. */
382 char VGA_GetColor16(int reg)
385 if (!lpddraw) return 0;
386 return (char)vga_16_palette[reg];
389 /* set all 17 [char wide] colors at once in 16 color mode. */
390 void VGA_Set16Palette(char *Table)
392 PALETTEENTRY *pal;
393 int c;
395 if (!lpddraw) return; /* return if we're in text only mode */
396 bcopy((void *)&vga_16_palette,(void *)Table,17);
397 /* copy the entries into the table */
398 for (c=0; c<17; c++) { /* 17 entries */
399 pal= &vga_def64_palette[(int)vga_16_palette[c]]; /* get color */
400 IDirectDrawPalette_SetEntries(lpddpal,0,c,1,pal); /* set entry */
401 TRACE("Palette register %d set to %d\n",c,(int)vga_16_palette[c]);
402 } /* end of the counting loop */
405 /* Get all 17 [ char wide ] colors at once in 16 color mode. */
406 void VGA_Get16Palette(char *Table)
409 if (!lpddraw) return; /* return if we're in text only mode */
410 bcopy((void *)Table,(void *)&vga_16_palette,17);
411 /* copy the entries into the table */
414 void VGA_SetQuadPalette(RGBQUAD*color,int start,int len)
416 PALETTEENTRY pal[256];
417 int c;
419 if (!lpddraw) return;
420 for (c=0; c<len; c++) {
421 pal[c].peRed =color[c].rgbRed;
422 pal[c].peGreen=color[c].rgbGreen;
423 pal[c].peBlue =color[c].rgbBlue;
424 pal[c].peFlags=0;
426 IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
429 LPSTR VGA_Lock(unsigned*Pitch,unsigned*Height,unsigned*Width,unsigned*Depth)
431 if (!lpddraw) return NULL;
432 if (!lpddsurf) return NULL;
433 if (IDirectDrawSurface_Lock(lpddsurf,NULL,&sdesc,0,0)) {
434 ERR("could not lock surface!\n");
435 return NULL;
437 if (Pitch) *Pitch=sdesc.u1.lPitch;
438 if (Height) *Height=sdesc.dwHeight;
439 if (Width) *Width=sdesc.dwWidth;
440 if (Depth) *Depth=sdesc.ddpfPixelFormat.u1.dwRGBBitCount;
441 return sdesc.lpSurface;
444 void VGA_Unlock(void)
446 IDirectDrawSurface_Unlock(lpddsurf,sdesc.lpSurface);
449 /*** TEXT MODE ***/
451 /* prepare the text mode video memory copy that is used to only
452 * update the video memory line that did get updated. */
453 void VGA_PrepareVideoMemCopy(unsigned Xres, unsigned Yres)
455 char *p, *p2;
456 int i;
458 textbuf_old = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textbuf_old, Xres * Yres * 2); /* char + attr */
460 p = VGA_AlphaBuffer();
461 p2 = textbuf_old;
463 /* make sure the video mem copy contains the exact opposite of our
464 * actual text mode memory area to make sure the screen
465 * does get updated fully initially */
466 for (i=0; i < Xres*Yres*2; i++)
467 *p2++ ^= *p++; /* XOR it */
470 int VGA_SetAlphaMode(unsigned Xres,unsigned Yres)
472 COORD siz;
474 if (lpddraw) VGA_Exit();
476 /* FIXME: Where to initialize text attributes? */
477 VGA_SetTextAttribute(0xf);
479 VGA_PrepareVideoMemCopy(Xres, Yres);
481 /* poll every 30ms (33fps should provide adequate responsiveness) */
482 VGA_InstallTimer(30);
484 siz.X = Xres;
485 siz.Y = Yres;
486 SetConsoleScreenBufferSize(VGA_AlphaConsole(),siz);
487 return 0;
490 void VGA_GetAlphaMode(unsigned*Xres,unsigned*Yres)
492 CONSOLE_SCREEN_BUFFER_INFO info;
493 GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info);
494 if (Xres) *Xres=info.dwSize.X;
495 if (Yres) *Yres=info.dwSize.Y;
498 void VGA_SetCursorShape(unsigned char start_options, unsigned char end)
500 CONSOLE_CURSOR_INFO cci;
502 /* standard cursor settings:
503 * 0x0607 == CGA, 0x0b0c == monochrome, 0x0d0e == EGA/VGA */
505 /* calculate percentage from bottom - assuming VGA (bottom 0x0e) */
506 cci.dwSize = ((end & 0x1f) - (start_options & 0x1f))/0x0e * 100;
507 if (!cci.dwSize) cci.dwSize++; /* NULL cursor would make SCCI() fail ! */
508 cci.bVisible = ((start_options & 0x60) != 0x20); /* invisible ? */
510 SetConsoleCursorInfo(VGA_AlphaConsole(),&cci);
513 void VGA_SetCursorPos(unsigned X,unsigned Y)
515 COORD pos;
517 if (!poll_timer) VGA_SetAlphaMode(80, 25);
518 pos.X = X;
519 pos.Y = Y;
520 SetConsoleCursorPosition(VGA_AlphaConsole(),pos);
523 void VGA_GetCursorPos(unsigned*X,unsigned*Y)
525 CONSOLE_SCREEN_BUFFER_INFO info;
526 GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info);
527 if (X) *X=info.dwCursorPosition.X;
528 if (Y) *Y=info.dwCursorPosition.Y;
531 void VGA_WriteChars(unsigned X,unsigned Y,unsigned ch,int attr,int count)
533 CHAR_INFO info;
534 COORD siz, off;
535 SMALL_RECT dest;
536 unsigned XR, YR;
537 char *dat;
539 EnterCriticalSection(&vga_lock);
541 info.Char.AsciiChar = ch;
542 info.Attributes = (WORD)attr;
543 siz.X = 1;
544 siz.Y = 1;
545 off.X = 0;
546 off.Y = 0;
547 dest.Top=Y;
548 dest.Bottom=Y;
550 VGA_GetAlphaMode(&XR, &YR);
551 dat = VGA_AlphaBuffer() + ((XR*Y + X) * 2);
552 while (count--) {
553 dest.Left = X + count;
554 dest.Right = X + count;
556 *dat++ = ch;
557 if (attr>=0)
558 *dat = attr;
559 else
560 info.Attributes = *dat;
561 dat++;
563 WriteConsoleOutputA(VGA_AlphaConsole(), &info, siz, off, &dest);
566 LeaveCriticalSection(&vga_lock);
569 static void VGA_PutCharAt(BYTE ascii, unsigned x, unsigned y)
571 unsigned width, height;
572 char *dat;
574 VGA_GetAlphaMode(&width, &height);
575 dat = VGA_AlphaBuffer() + ((width*y + x) * 2);
576 dat[0] = ascii;
577 dat[1] = vga_text_attr;
580 void VGA_PutChar(BYTE ascii)
582 unsigned width, height, x, y, nx, ny;
584 EnterCriticalSection(&vga_lock);
586 VGA_GetAlphaMode(&width, &height);
587 VGA_GetCursorPos(&x, &y);
589 switch(ascii) {
590 case '\b':
591 VGA_PutCharAt(' ', x, y);
592 x--;
593 break;
595 case '\t':
596 x += ((x + 8) & ~7) - x;
597 break;
599 case '\n':
600 y++;
601 x = 0;
602 break;
604 case '\a':
605 break;
607 case '\r':
608 x = 0;
609 break;
611 default:
612 VGA_PutCharAt(ascii, x, y);
613 x++;
617 * FIXME: add line wrapping and scrolling
620 WriteFile(VGA_AlphaConsole(), &ascii, 1, NULL, NULL);
623 * The following is just a sanity check.
625 VGA_GetCursorPos(&nx, &ny);
626 if(nx != x || ny != y)
627 WARN("VGA emulator and text console have become unsynchronized.\n");
629 LeaveCriticalSection(&vga_lock);
632 void VGA_SetTextAttribute(BYTE attr)
634 vga_text_attr = attr;
635 SetConsoleTextAttribute(VGA_AlphaConsole(), attr);
638 void VGA_ClearText(unsigned row1, unsigned col1,
639 unsigned row2, unsigned col2,
640 BYTE attr)
642 unsigned width, height, x, y;
643 COORD off;
644 char *dat = VGA_AlphaBuffer();
645 HANDLE con = VGA_AlphaConsole();
646 VGA_GetAlphaMode(&width, &height);
648 EnterCriticalSection(&vga_lock);
650 for(y=row1; y<=row2; y++) {
651 off.X = col1;
652 off.Y = y;
653 FillConsoleOutputCharacterA(con, ' ', col2-col1+1, off, NULL);
654 FillConsoleOutputAttribute(con, attr, col2-col1+1, off, NULL);
656 for(x=col1; x<=col2; x++) {
657 char *ptr = dat + ((width*y + x) * 2);
658 ptr[0] = ' ';
659 ptr[1] = attr;
663 LeaveCriticalSection(&vga_lock);
666 void VGA_ScrollUpText(unsigned row1, unsigned col1,
667 unsigned row2, unsigned col2,
668 unsigned lines, BYTE attr)
670 FIXME("not implemented\n");
673 void VGA_ScrollDownText(unsigned row1, unsigned col1,
674 unsigned row2, unsigned col2,
675 unsigned lines, BYTE attr)
677 FIXME("not implemented\n");
680 void VGA_GetCharacterAtCursor(BYTE *ascii, BYTE *attr)
682 unsigned width, height, x, y;
683 char *dat;
685 VGA_GetAlphaMode(&width, &height);
686 VGA_GetCursorPos(&x, &y);
687 dat = VGA_AlphaBuffer() + ((width*y + x) * 2);
689 *ascii = dat[0];
690 *attr = dat[1];
694 /*** CONTROL ***/
696 /* FIXME: optimize by doing this only if the data has actually changed
697 * (in a way similar to DIBSection, perhaps) */
698 static void VGA_Poll_Graphics(void)
700 unsigned int Pitch, Height, Width, X, Y;
701 char *surf;
702 char *dat = DOSMEM_MapDosToLinear(0xa0000);
704 surf = VGA_Lock(&Pitch,&Height,&Width,NULL);
705 if (!surf) return;
707 if(vga_width == 320 && vga_depth <= 4)
708 for (Y=0; Y<vga_height; Y++,surf+=Pitch*2,dat+=vga_width/8) {
709 for(X=0; X<vga_width; X+=8) {
710 int offset = X/8;
711 int Z;
712 for(Z=0; Z<8; Z++) {
713 int b0 = (dat[offset] >> Z) & 0x1;
714 int index = 7-Z;
715 surf[(X+index)*2] = b0;
716 surf[(X+index)*2+1] = b0;
717 surf[(X+index)*2+Pitch] = b0;
718 surf[(X+index)*2+Pitch+1] = b0;
723 if(vga_width == 320 && vga_depth == 8)
724 for (Y=0; Y<vga_height; Y++,surf+=Pitch*2,dat+=vga_width) {
725 for(X=0; X<vga_width; X++) {
726 int b0 = dat[X];
727 surf[X*2] = b0;
728 surf[X*2+1] = b0;
729 surf[X*2+Pitch] = b0;
730 surf[X*2+Pitch+1] = b0;
734 if(vga_depth <= 4)
735 for (Y=0; Y<vga_height; Y++,surf+=Pitch,dat+=vga_width/8) {
736 for(X=0; X<vga_width; X+=8) {
737 int offset = X/8;
738 int Z;
739 for(Z=0; Z<8; Z++) {
740 int b0 = (dat[offset] >> Z) & 0x1;
741 int index = 7-Z;
742 surf[X+index] = b0;
747 VGA_Unlock();
750 static void VGA_Poll_Text(void)
752 char *dat, *old, *p_line;
753 unsigned int Height,Width,Y,X;
754 CHAR_INFO ch[256]; /* that should suffice for the largest text width */
755 COORD siz, off;
756 SMALL_RECT dest;
757 HANDLE con = VGA_AlphaConsole();
758 BOOL linechanged = FALSE; /* video memory area differs from stored copy ? */
760 VGA_GetAlphaMode(&Width,&Height);
761 dat = VGA_AlphaBuffer();
762 old = textbuf_old; /* pointer to stored video mem copy */
763 siz.X = Width; siz.Y = 1;
764 off.X = 0; off.Y = 0;
765 /* copy from virtual VGA frame buffer to console */
766 for (Y=0; Y<Height; Y++) {
767 linechanged = memcmp(dat, old, Width*2);
768 if (linechanged)
770 /*TRACE("line %d changed\n", Y);*/
771 p_line = dat;
772 for (X=0; X<Width; X++) {
773 ch[X].Char.AsciiChar = *p_line++;
774 /* WriteConsoleOutputA doesn't like "dead" chars */
775 if (ch[X].Char.AsciiChar == '\0')
776 ch[X].Char.AsciiChar = ' ';
777 ch[X].Attributes = *p_line++;
779 dest.Top=Y; dest.Bottom=Y;
780 dest.Left=0; dest.Right=Width+1;
781 WriteConsoleOutputA(con, ch, siz, off, &dest);
782 memcpy(old, dat, Width*2);
784 /* advance to next text line */
785 dat += Width*2;
786 old += Width*2;
790 static void CALLBACK VGA_Poll( LPVOID arg, DWORD low, DWORD high )
792 if(!TryEnterCriticalSection(&vga_lock))
793 return;
795 if (lpddraw) {
796 VGA_Poll_Graphics();
797 } else {
798 VGA_Poll_Text();
801 vga_refresh=1;
802 LeaveCriticalSection(&vga_lock);
805 static BYTE palreg,palcnt;
806 static PALETTEENTRY paldat;
808 void VGA_ioport_out( WORD port, BYTE val )
810 switch (port) {
811 case 0x3c8:
812 palreg=val; palcnt=0; break;
813 case 0x3c9:
814 ((BYTE*)&paldat)[palcnt++]=val << 2;
815 if (palcnt==3) {
816 VGA_SetPalette(&paldat,palreg++,1);
817 palcnt=0;
819 break;
820 default:
821 FIXME("Unsupported VGA register: 0x%04x (value 0x%02x)\n", port, val);
825 BYTE VGA_ioport_in( WORD port )
827 BYTE ret;
829 switch (port) {
830 case 0x3da:
831 /* since we don't (yet?) serve DOS VM requests while VGA_Poll is running,
832 we need to fake the occurrence of the vertical refresh */
833 ret=vga_refresh?0x00:0x0b; /* toggle video RAM and lightpen and VGA refresh bits ! */
834 if (vga_mode_initialized)
835 vga_refresh=0;
836 else
837 /* Also fake the occurence of the vertical refresh when no graphic
838 mode has been set */
839 vga_refresh=!vga_refresh;
840 break;
841 default:
842 ret=0xff;
843 FIXME("Unsupported VGA register: 0x%04x\n", port);
845 return ret;
848 void VGA_Clean(void)
850 VGA_Exit();
851 VGA_DeinstallTimer();