3 * Video BIOS Extensions (Vesa) Driver
\r
6 #define VERSION 0x100
\r
10 #include <api_drv_video.h>
\r
11 #include <fs_devfs.h>
\r
12 #include <modules.h>
\r
17 // === CONSTANTS ===
\r
18 #define FLAG_LFB 0x1
\r
19 #define FLAG_POPULATED 0x2
\r
20 #define FLAG_VALID 0x4
\r
21 #define VESA_DEFAULT_FRAMEBUFFER (KERNEL_BASE|0xA0000)
\r
22 #define BLINKING_CURSOR 0
\r
24 # define VESA_CURSOR_PERIOD 1000
\r
27 // === PROTOTYPES ===
\r
28 int Vesa_Install(char **Arguments);
\r
29 int VBE_int_GetModeList(void);
\r
30 size_t Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags);
\r
31 int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data);
\r
32 int Vesa_Int_SetMode(int Mode);
\r
33 int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data);
\r
34 int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data);
\r
35 void Vesa_int_HideCursor(void);
\r
36 void Vesa_int_ShowCursor(void);
\r
37 void Vesa_FlipCursor(void *Arg);
\r
38 Uint16 VBE_int_GetWord(const tVT_Char *Char);
\r
39 void VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
\r
40 void VBE_int_Text_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
\r
43 MODULE_DEFINE(0, VERSION, Vesa, Vesa_Install, NULL, "PCI", "VM8086", NULL);
\r
44 tVFS_NodeType gVesa_NodeType = {
\r
45 .Write = Vesa_Write,
\r
48 tDevFS_Driver gVesa_DriverStruct = {
\r
50 {.Type = &gVesa_NodeType}
\r
53 tVM8086 *gpVesa_BiosState;
\r
54 int giVesaDriverId = -1;
\r
55 // --- Video Modes ---
\r
56 int giVesaCurrentMode = 0;
\r
57 tVesa_Mode gVesa_BootMode = {0x03, 80*8, 25*16, 80*8*2, 12, FLAG_POPULATED, 80*25*2, 0xB8000};
\r
58 tVesa_Mode *gVesa_Modes;
\r
59 tVesa_Mode *gpVesaCurMode;
\r
60 int giVesaModeCount = 0;
\r
61 int gbVesaModesChecked;
\r
62 // --- Framebuffer ---
\r
63 char *gpVesa_Framebuffer = (void*)VESA_DEFAULT_FRAMEBUFFER;
\r
64 int giVesaPageCount = 0; //!< Framebuffer size in pages
\r
65 // --- Cursor Control ---
\r
66 int giVesaCursorX = -1;
\r
67 int giVesaCursorY = -1;
\r
69 tTimer *gpVesaCursorTimer;
\r
71 int gbVesa_CursorVisible = 0;
\r
72 // --- 2D Video Stream Handlers ---
\r
73 tDrvUtil_Video_BufInfo gVesa_BufInfo;
\r
74 tDrvUtil_Video_2DHandlers gVBE_Text2DFunctions = {
\r
76 VBE_int_Text_2D_Fill,
\r
77 VBE_int_Text_2D_Blit
\r
80 bool gbVesa_DisableBIOSCalls; // Disables calls to the BIOS
\r
81 // int gbVesa_DisableFBCache; // Disables the main-memory framebuffer cache
\r
84 int Vesa_Install(char **Arguments)
\r
88 for( int i = 0; Arguments && Arguments[i]; i ++ )
\r
90 if( strcmp(Arguments[i], "nobios") == 0 )
\r
91 gbVesa_DisableBIOSCalls = 1;
\r
92 //else if( strcmp(Arguments[i], "nocache") == 0 )
\r
93 // gbVesa_DisableFBCache = 1;
\r
95 Log_Notice("VBE", "Unknown argument '%s'", Arguments[i]);
\r
99 if( !gbVesa_DisableBIOSCalls )
\r
101 gpVesa_BiosState = VM8086_Init();
\r
103 if( (rv = VBE_int_GetModeList()) )
\r
107 #if BLINKING_CURSOR
\r
108 // Create blink timer
\r
109 gpVesaCursorTimer = Time_AllocateTimer( Vesa_FlipCursor, NULL );
\r
113 giVesaDriverId = DevFS_AddDevice( &gVesa_DriverStruct );
\r
114 if(giVesaDriverId == -1) return MODULE_ERR_MISC;
\r
116 return MODULE_ERR_OK;
\r
119 int VBE_int_GetModeList(void)
\r
121 tVesa_CallInfo *info;
\r
125 // Allocate Info Block
\r
126 info = VM8086_Allocate(gpVesa_BiosState, 512, &infoPtr.seg, &infoPtr.ofs);
\r
127 // Set Requested Version
\r
128 memcpy(info->signature, "VBE2", 4);
\r
130 gpVesa_BiosState->AX = 0x4F00;
\r
131 gpVesa_BiosState->ES = infoPtr.seg; gpVesa_BiosState->DI = infoPtr.ofs;
\r
133 VM8086_Int(gpVesa_BiosState, 0x10);
\r
134 if(gpVesa_BiosState->AX != 0x004F) {
\r
135 Log_Warning("VBE", "Vesa_Install - VESA/VBE Unsupported (AX = 0x%x)", gpVesa_BiosState->AX);
\r
136 return MODULE_ERR_NOTNEEDED;
\r
139 modes = (Uint16 *) VM8086_GetPointer(gpVesa_BiosState, info->VideoModes.seg, info->VideoModes.ofs);
\r
140 LOG("Virtual addres of mode list from %04x:%04x is %p",
\r
141 info->VideoModes.seg, info->VideoModes.ofs, modes);
\r
142 // VM8086_Deallocate( gpVesa_BiosState, info );
\r
145 for( giVesaModeCount = 0; modes[giVesaModeCount] != 0xFFFF; giVesaModeCount++ )
\r
147 gVesa_Modes = (tVesa_Mode *)malloc( giVesaModeCount * sizeof(tVesa_Mode) );
\r
149 Log_Debug("VBE", "%i Modes", giVesaModeCount);
\r
151 // Insert Text Mode
\r
153 for( int i = 0; i < giVesaModeCount; i++ )
\r
155 gVesa_Modes[i].code = modes[i];
\r
161 int VBE_int_GetModeInfo(Uint16 Code, tFarPtr *BufPtr)
\r
164 gpVesa_BiosState->AX = 0x4F01;
\r
165 gpVesa_BiosState->CX = Code;
\r
166 gpVesa_BiosState->ES = BufPtr->seg;
\r
167 gpVesa_BiosState->DI = BufPtr->ofs;
\r
168 VM8086_Int(gpVesa_BiosState, 0x10);
\r
170 if( gpVesa_BiosState->AX != 0x004F ) {
\r
171 Log_Error("VBE", "Getting info on mode 0x%x failed (AX=0x%x)",
\r
172 Code, gpVesa_BiosState->AX);
\r
179 void VBE_int_FillMode_Int(tVesa_Mode *Mode, const tVesa_CallModeInfo *vbeinfo)
\r
182 #define S_LOG(s, fld, fmt) LOG(" ."#fld" = "fmt, (s).fld)
\r
183 LOG("vbeinfo[0x%x] = {", Mode->code);
\r
184 S_LOG(*vbeinfo, attributes, "0x%02x");
\r
185 S_LOG(*vbeinfo, winA, "0x%02x");
\r
186 S_LOG(*vbeinfo, winB, "0x%02x");
\r
187 S_LOG(*vbeinfo, granularity, "0x%04x");
\r
188 S_LOG(*vbeinfo, winsize, "0x%04x");
\r
189 S_LOG(*vbeinfo, segmentA, "0x%04x");
\r
190 S_LOG(*vbeinfo, segmentB, "0x%04x");
\r
191 LOG(" .realFctPtr = %04x:%04x", vbeinfo->realFctPtr.seg, vbeinfo->realFctPtr.ofs);
\r
192 S_LOG(*vbeinfo, pitch, "0x%04x");
\r
195 S_LOG(*vbeinfo, Xres, "%i");
\r
196 S_LOG(*vbeinfo, Yres, "%i");
\r
197 S_LOG(*vbeinfo, Wchar, "%i");
\r
198 S_LOG(*vbeinfo, Ychar, "%i");
\r
199 S_LOG(*vbeinfo, planes, "%i");
\r
200 S_LOG(*vbeinfo, bpp, "%i");
\r
201 S_LOG(*vbeinfo, banks, "%i");
\r
202 S_LOG(*vbeinfo, memory_model, "%i");
\r
203 S_LOG(*vbeinfo, bank_size, "%i");
\r
204 S_LOG(*vbeinfo, image_pages, "%i");
\r
206 LOG(" Red = %i bits at %i", vbeinfo->red_mask, vbeinfo->red_position );
\r
207 LOG(" Green = %i bits at %i", vbeinfo->green_mask, vbeinfo->green_position);
\r
208 LOG(" Blue = %i bits at %i", vbeinfo->blue_mask, vbeinfo->blue_position );
\r
210 Uint8 rsv_mask, rsv_position;
\r
211 Uint8 directcolor_attributes;
\r
214 S_LOG(*vbeinfo, physbase, "0x%08x");
\r
215 S_LOG(*vbeinfo, offscreen_ptr, "0x%08x");
\r
216 S_LOG(*vbeinfo, offscreen_size_kb, "0x%04x");
\r
218 S_LOG(*vbeinfo, lfb_pitch, "0x%04x");
\r
219 S_LOG(*vbeinfo, image_count_banked, "%i");
\r
220 S_LOG(*vbeinfo, image_count_lfb, "%i");
\r
224 Mode->flags = FLAG_POPULATED;
\r
225 if( !(vbeinfo->attributes & 1) )
\r
228 Log_Log("VBE", "0x%x - not supported", Mode->code);
\r
237 Mode->flags |= FLAG_VALID;
\r
238 switch( vbeinfo->attributes & 0x90 ) // LFB, Graphics
\r
240 case 0x00: // Banked, Text
\r
241 case 0x10: // Banked, Graphics
\r
242 case 0x80: // Linear, Text (?)
\r
248 Mode->flags |= FLAG_LFB;
\r
249 Mode->framebuffer = vbeinfo->physbase;
\r
250 Mode->fbSize = vbeinfo->Yres*vbeinfo->pitch;
\r
254 Mode->pitch = vbeinfo->pitch;
\r
255 Mode->width = vbeinfo->Xres;
\r
256 Mode->height = vbeinfo->Yres;
\r
257 Mode->bpp = vbeinfo->bpp;
\r
260 Log_Log("VBE", "0x%x - %ix%ix%i (%x)",
\r
261 Mode->code, Mode->width, Mode->height, Mode->bpp, Mode->flags);
\r
266 void VBE_int_SetBootMode(Uint16 ModeID, const void *ModeInfo)
\r
268 gVesa_BootMode.code = ModeID;
\r
269 VBE_int_FillMode_Int(&gVesa_BootMode, ModeInfo);
\r
272 void Vesa_int_FillModeList(void)
\r
274 if( !gbVesaModesChecked && !gbVesa_DisableBIOSCalls )
\r
276 tVesa_CallModeInfo *modeinfo;
\r
277 tFarPtr modeinfoPtr;
\r
279 modeinfo = VM8086_Allocate(gpVesa_BiosState, 256, &modeinfoPtr.seg, &modeinfoPtr.ofs);
\r
280 for( int i = 0; i < giVesaModeCount; i ++ )
\r
282 if( VBE_int_GetModeInfo(gVesa_Modes[i].code, &modeinfoPtr) == 0 )
\r
284 VBE_int_FillMode_Int( &gVesa_Modes[i], modeinfo );
\r
287 // VM8086_Deallocate( gpVesa_BiosState, modeinfo );
\r
289 gbVesaModesChecked = 1;
\r
294 * \brief Write to the framebuffer
\r
296 size_t Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
\r
298 // Framebuffer modes - just pass on
\r
299 if( gpVesaCurMode->flags & FLAG_LFB )
\r
300 return DrvUtil_Video_WriteLFB(&gVesa_BufInfo, Offset, Length, Buffer);
\r
302 // EGA text mode translation
\r
303 switch( gVesa_BufInfo.BufferFormat )
\r
305 case VIDEO_BUFFMT_TEXT: {
\r
306 int num = Length / sizeof(tVT_Char);
\r
307 int ofs = Offset / sizeof(tVT_Char);
\r
309 const tVT_Char *chars = Buffer;
\r
312 for( ; num--; i ++, ofs ++)
\r
314 word = VBE_int_GetWord( &chars[i] );
\r
315 ((Uint16*)gVesa_BufInfo.Framebuffer)[ ofs ] = word;
\r
319 case VIDEO_BUFFMT_2DSTREAM:
\r
320 return DrvUtil_Video_2DStream(NULL, Buffer, Length,
\r
321 &gVBE_Text2DFunctions, sizeof(gVBE_Text2DFunctions));
\r
323 Log_Warning("VBE", "TODO: Alternate modes in EGA text mode");
\r
329 const char *csaVESA_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};
\r
331 * \brief Handle messages to the device
\r
333 int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data)
\r
338 BASE_IOCTLS(DRV_TYPE_VIDEO, "VBE", VERSION, csaVESA_IOCtls);
\r
340 case VIDEO_IOCTL_GETSETMODE:
\r
341 if( !Data ) return giVesaCurrentMode;
\r
342 return Vesa_Int_SetMode( *(int*)Data );
\r
344 case VIDEO_IOCTL_FINDMODE:
\r
345 return Vesa_Int_FindMode((tVideo_IOCtl_Mode*)Data);
\r
346 case VIDEO_IOCTL_MODEINFO:
\r
347 return Vesa_Int_ModeInfo((tVideo_IOCtl_Mode*)Data);
\r
349 case VIDEO_IOCTL_SETBUFFORMAT:
\r
350 Vesa_int_HideCursor();
\r
351 ret = gVesa_BufInfo.BufferFormat;
\r
352 if(Data) gVesa_BufInfo.BufferFormat = *(int*)Data;
\r
353 if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
\r
354 DrvUtil_Video_SetCursor( &gVesa_BufInfo, &gDrvUtil_TextModeCursor );
\r
355 Vesa_int_ShowCursor();
\r
358 case VIDEO_IOCTL_SETCURSOR: // Set cursor position
\r
359 Vesa_int_HideCursor();
\r
360 giVesaCursorX = ((tVideo_IOCtl_Pos*)Data)->x;
\r
361 giVesaCursorY = ((tVideo_IOCtl_Pos*)Data)->y;
\r
362 Vesa_int_ShowCursor();
\r
365 case VIDEO_IOCTL_SETCURSORBITMAP:
\r
366 DrvUtil_Video_SetCursor( &gVesa_BufInfo, Data );
\r
373 * \brief Updates the video mode
\r
375 int Vesa_Int_SetMode(int mode)
\r
377 tVesa_Mode *modeptr;
\r
378 // Check for fast return
\r
379 if(mode == giVesaCurrentMode) return 1;
\r
381 // Special case: Boot mode
\r
383 modeptr = &gVesa_BootMode;
\r
384 else if( 0 <= mode && mode < giVesaModeCount )
\r
385 modeptr = &gVesa_Modes[mode];
\r
389 Vesa_int_FillModeList();
\r
391 #if BLINKING_CURSOR
\r
392 Time_RemoveTimer(gpVesaCursorTimer);
\r
395 Mutex_Acquire( &glVesa_Lock );
\r
397 if( gbVesa_DisableBIOSCalls )
\r
399 ASSERT(mode == -1);
\r
403 gpVesa_BiosState->AX = 0x4F02;
\r
404 gpVesa_BiosState->BX = modeptr->code;
\r
405 if(modeptr->flags & FLAG_LFB) {
\r
406 gpVesa_BiosState->BX |= 1 << 14; // Use LFB
\r
408 LOG("In : AX=%04x/BX=%04x", gpVesa_BiosState->AX, gpVesa_BiosState->BX);
\r
411 VM8086_Int(gpVesa_BiosState, 0x10);
\r
413 LOG("Out: AX = %04x", gpVesa_BiosState->AX);
\r
417 if( gpVesaCurMode )
\r
419 if( gpVesaCurMode->framebuffer < 1024*1024 )
\r
422 MM_UnmapHWPages((tVAddr)gpVesa_Framebuffer, giVesaPageCount);
\r
424 giVesaPageCount = (modeptr->fbSize + 0xFFF) >> 12;
\r
425 if( modeptr->framebuffer < 1024*1024 )
\r
426 gpVesa_Framebuffer = (void*)(KERNEL_BASE|modeptr->framebuffer);
\r
428 gpVesa_Framebuffer = (void*)MM_MapHWPages(modeptr->framebuffer, giVesaPageCount);
\r
430 Log_Log("VBE", "Setting mode to %i 0x%x (%ix%i %ibpp) %p[0x%x] maps %P",
\r
431 mode, modeptr->code,
\r
432 modeptr->width, modeptr->height,
\r
434 gpVesa_Framebuffer, giVesaPageCount << 12, modeptr->framebuffer
\r
438 giVesaCurrentMode = mode;
\r
439 gpVesaCurMode = modeptr;
\r
441 Mutex_Release( &glVesa_Lock );
\r
443 // TODO: Disableable backbuffer
\r
444 gVesa_BufInfo.BackBuffer = realloc(gVesa_BufInfo.BackBuffer,
\r
445 modeptr->height * modeptr->pitch);
\r
446 gVesa_BufInfo.Framebuffer = gpVesa_Framebuffer;
\r
447 gVesa_BufInfo.Pitch = modeptr->pitch;
\r
448 gVesa_BufInfo.Width = modeptr->width;
\r
449 gVesa_BufInfo.Height = modeptr->height;
\r
450 gVesa_BufInfo.Depth = modeptr->bpp;
\r
455 int VBE_int_MatchModes(tVideo_IOCtl_Mode *ReqMode, tVesa_Mode *ThisMode)
\r
457 LOG("Matching %ix%i %ibpp", ThisMode->width, ThisMode->height, ThisMode->bpp);
\r
458 if(ThisMode->width == ReqMode->width && ThisMode->height == ReqMode->height)
\r
460 //if( (data->bpp == 32 || data->bpp == 24)
\r
461 // && (gVesa_Modes[i].bpp == 32 || gVesa_Modes[i].bpp == 24) )
\r
462 if( ReqMode->bpp == ThisMode->bpp )
\r
469 int tmp = ThisMode->width * ThisMode->height - ReqMode->width * ReqMode->height;
\r
470 tmp = tmp < 0 ? -tmp : tmp;
\r
471 unsigned int factor = (Uint64)tmp * 1000 / (ReqMode->width * ReqMode->height);
\r
472 if( ThisMode->bpp > ReqMode->bpp )
\r
473 factor += ThisMode->bpp - ReqMode->bpp;
\r
475 factor += ReqMode->bpp - ThisMode->bpp;
\r
477 if( ReqMode->bpp == ThisMode->bpp )
\r
481 if( ReqMode->bpp == 8 && ThisMode->bpp != 8 ) factor *= 4;
\r
482 if( ReqMode->bpp == 16 && ThisMode->bpp != 16 ) factor *= 4;
\r
484 if( (ReqMode->bpp == 32 || ReqMode->bpp == 24)
\r
485 && (ThisMode->bpp == 32 || ThisMode->bpp == 24) )
\r
490 if( ReqMode->bpp < ThisMode->bpp )
\r
491 factor *= ThisMode->bpp / ReqMode->bpp + 1;
\r
493 factor *= ReqMode->bpp / ThisMode->bpp + 1;
\r
500 int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data)
\r
504 ENTER("idata->width idata->height idata->bpp", data->width, data->height, data->bpp);
\r
506 Vesa_int_FillModeList();
\r
508 int bestFactor = VBE_int_MatchModes(data, &gVesa_BootMode);
\r
509 tVesa_Mode *bestPtr = &gVesa_BootMode;
\r
511 for(int i = 0; bestFactor > 0 && i < giVesaModeCount; i ++)
\r
513 LOG("Mode %i (%ix%ix%i)", i, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp);
\r
515 int factor = VBE_int_MatchModes(data, &gVesa_Modes[i]);
\r
517 LOG("factor = %i, bestFactor = %i", factor, bestFactor);
\r
519 if(factor < bestFactor)
\r
521 bestFactor = factor;
\r
523 bestPtr = &gVesa_Modes[i];
\r
527 data->width = bestPtr->width;
\r
528 data->height = bestPtr->height;
\r
529 data->bpp = bestPtr->bpp;
\r
534 int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data)
\r
536 tVesa_Mode *modeptr;
\r
537 if( data->id == -1 )
\r
538 modeptr = &gVesa_BootMode;
\r
539 else if( 0 <= data->id && data->id < giVesaModeCount)
\r
540 modeptr = &gVesa_Modes[data->id];
\r
544 Vesa_int_FillModeList();
\r
546 data->width = modeptr->width;
\r
547 data->height = modeptr->height;
\r
548 data->bpp = modeptr->bpp;
\r
552 void Vesa_int_HideCursor(void)
\r
554 if( gpVesaCurMode->flags & FLAG_LFB )
\r
556 DrvUtil_Video_RemoveCursor( &gVesa_BufInfo );
\r
557 #if BLINKING_CURSOR
\r
558 if(gpVesaCursorTimer) {
\r
559 Time_RemoveTimer(gpVesaCursorTimer);
\r
565 void Vesa_int_ShowCursor(void)
\r
567 if( gpVesaCurMode->flags & FLAG_LFB )
\r
569 gbVesa_CursorVisible = (giVesaCursorX >= 0);
\r
570 if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
\r
572 DrvUtil_Video_DrawCursor(
\r
574 giVesaCursorX*giVT_CharWidth,
\r
575 giVesaCursorY*giVT_CharHeight
\r
577 #if BLINKING_CURSOR
\r
578 Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD );
\r
582 DrvUtil_Video_DrawCursor(
\r
591 * \brief Swaps the text cursor on/off
\r
593 void Vesa_FlipCursor(void *Arg)
\r
595 if( gVesa_BufInfo.BufferFormat != VIDEO_BUFFMT_TEXT )
\r
598 if( gpVesaCurMode->flags & FLAG_LFB )
\r
600 if( gbVesa_CursorVisible )
\r
601 DrvUtil_Video_RemoveCursor(&gVesa_BufInfo);
\r
603 DrvUtil_Video_DrawCursor(&gVesa_BufInfo,
\r
604 giVesaCursorX*giVT_CharWidth,
\r
605 giVesaCursorY*giVT_CharHeight
\r
607 gbVesa_CursorVisible = !gbVesa_CursorVisible;
\r
609 #if BLINKING_CURSOR
\r
610 Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD );
\r
616 // Helpers for text mode
\r
620 * \fn Uint8 VGA_int_GetColourNibble(Uint16 col)
\r
621 * \brief Converts a 12-bit colour into a VGA 4-bit colour
\r
623 Uint8 VBE_int_GetColourNibble(Uint16 col)
\r
629 col = ((col>>2)&3) | ((col>>4)&0xC) | ((col>>6)&0x30);
\r
630 bright = ( (col & 2 ? 1 : 0) + (col & 8 ? 1 : 0) + (col & 32 ? 1 : 0) ) / 2;
\r
635 case 0x00: ret = 0x0; break;
\r
637 case 0x15: ret = 0x8; break;
\r
640 case 0x02: ret = 0x1; break;
\r
641 case 0x03: ret = 0x9; break;
\r
644 case 0x08: ret = 0x2; break;
\r
645 case 0x0C: ret = 0xA; break;
\r
648 case 0x20: ret = 0x4; break;
\r
649 case 0x30: ret = 0xC; break;
\r
651 case 0x2A: ret = 0x7; break;
\r
653 case 0x3F: ret = 0xF; break;
\r
656 ret |= (col & 0x03 ? 1 : 0);
\r
657 ret |= (col & 0x0C ? 2 : 0);
\r
658 ret |= (col & 0x30 ? 4 : 0);
\r
659 ret |= (bright ? 8 : 0);
\r
666 * \brief Convers a character structure to a VGA character word
\r
668 Uint16 VBE_int_GetWord(const tVT_Char *Char)
\r
679 default: ret = 0; break;
\r
683 col = VBE_int_GetColourNibble(Char->BGCol);
\r
686 col = VBE_int_GetColourNibble(Char->FGCol);
\r
692 void VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
\r
694 const int charw = 8;
\r
695 const int charh = 16;
\r
696 const int tw = gpVesaCurMode->width / charw;
\r
697 const int th = gpVesaCurMode->height / charh;
\r
706 ch.BGCol = (Colour & 0x0F0000) >> (16-8);
\r
707 ch.BGCol |= (Colour & 0x000F00) >> (8-4);
\r
708 ch.BGCol |= (Colour & 0x00000F);
\r
710 Uint16 word = VBE_int_GetWord(&ch);
\r
712 Log("Fill (%i,%i) %ix%i with 0x%x", X, Y, W, H, word);
\r
714 if( X >= tw || Y >= th ) return ;
\r
715 if( X + W > tw ) W = tw - X;
\r
716 if( Y + H > th ) H = th - Y;
\r
718 Uint16 *buf = (Uint16*)gpVesa_Framebuffer + Y*tw + X;
\r
722 for( int i = 0; i < W; i ++ )
\r
728 void VBE_int_Text_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
\r
730 const int charw = 8;
\r
731 const int charh = 16;
\r
732 const int tw = gpVesaCurMode->width / charw;
\r
733 const int th = gpVesaCurMode->height / charh;
\r
743 // Log("(%i,%i) from (%i,%i) %ix%i", DstX, DstY, SrcX, SrcY, W, H);
\r
745 if( SrcX >= tw || SrcY >= th ) return ;
\r
746 if( SrcX + W > tw ) W = tw - SrcX;
\r
747 if( SrcY + H > th ) H = th - SrcY;
\r
748 if( DstX >= tw || DstY >= th ) return ;
\r
749 if( DstX + W > tw ) W = tw - DstX;
\r
750 if( DstY + H > th ) H = th - DstY;
\r
753 Uint16 *src = (Uint16*)gpVesa_Framebuffer + SrcY*tw + SrcX;
\r
754 Uint16 *dst = (Uint16*)gpVesa_Framebuffer + DstY*tw + DstX;
\r
760 memcpy(dst, src, W*2);
\r
772 for( int i = W; i --; ) *--dst = *--src;
\r