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
19 #define VESA_DEFAULT_FRAMEBUFFER (KERNEL_BASE|0xA0000)
\r
20 #define BLINKING_CURSOR 0
\r
22 # define VESA_CURSOR_PERIOD 1000
\r
25 // === PROTOTYPES ===
\r
26 int Vesa_Install(char **Arguments);
\r
27 int VBE_int_GetModeList(void);
\r
28 size_t Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags);
\r
29 int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data);
\r
30 int Vesa_Int_SetMode(int Mode);
\r
31 int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data);
\r
32 int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data);
\r
33 void Vesa_int_HideCursor(void);
\r
34 void Vesa_int_ShowCursor(void);
\r
35 void Vesa_FlipCursor(void *Arg);
\r
36 Uint16 VBE_int_GetWord(const tVT_Char *Char);
\r
37 void VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
\r
38 void VBE_int_Text_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
\r
41 MODULE_DEFINE(0, VERSION, Vesa, Vesa_Install, NULL, "PCI", "VM8086", NULL);
\r
42 tVFS_NodeType gVesa_NodeType = {
\r
43 .Write = Vesa_Write,
\r
46 tDevFS_Driver gVesa_DriverStruct = {
\r
48 {.Type = &gVesa_NodeType}
\r
51 tVM8086 *gpVesa_BiosState;
\r
52 int giVesaDriverId = -1;
\r
53 // --- Video Modes ---
\r
54 int giVesaCurrentMode = 0;
\r
55 tVesa_Mode gVesa_BootMode = {0x03, 80*8, 25*16, 80*8*2, 12, FLAG_POPULATED, 80*25*2, 0xB8000};
\r
56 tVesa_Mode *gVesa_Modes;
\r
57 tVesa_Mode *gpVesaCurMode;
\r
58 int giVesaModeCount = 0;
\r
59 int gbVesaModesChecked;
\r
60 // --- Framebuffer ---
\r
61 char *gpVesa_Framebuffer = (void*)VESA_DEFAULT_FRAMEBUFFER;
\r
62 int giVesaPageCount = 0; //!< Framebuffer size in pages
\r
63 // --- Cursor Control ---
\r
64 int giVesaCursorX = -1;
\r
65 int giVesaCursorY = -1;
\r
67 tTimer *gpVesaCursorTimer;
\r
69 int gbVesa_CursorVisible = 0;
\r
70 // --- 2D Video Stream Handlers ---
\r
71 tDrvUtil_Video_BufInfo gVesa_BufInfo;
\r
72 tDrvUtil_Video_2DHandlers gVBE_Text2DFunctions = {
\r
74 VBE_int_Text_2D_Fill,
\r
75 VBE_int_Text_2D_Blit
\r
78 bool gbVesa_DisableBIOSCalls; // Disables calls to the BIOS
\r
79 // int gbVesa_DisableFBCache; // Disables the main-memory framebuffer cache
\r
82 int Vesa_Install(char **Arguments)
\r
84 for( int i = 0; Arguments && Arguments[i]; i ++ )
\r
86 if( strcmp(Arguments[i], "nobios") == 0 )
\r
87 gbVesa_DisableBIOSCalls = 1;
\r
88 //else if( strcmp(Arguments[i], "nocache") == 0 )
\r
89 // gbVesa_DisableFBCache = 1;
\r
91 Log_Notice("VBE", "Unknown argument '%s'", Arguments[i]);
\r
96 if( !gbVesa_DisableBIOSCalls )
\r
98 gpVesa_BiosState = VM8086_Init();
\r
100 int rv = VBE_int_GetModeList();
\r
105 #if BLINKING_CURSOR
\r
106 // Create blink timer
\r
107 gpVesaCursorTimer = Time_AllocateTimer( Vesa_FlipCursor, NULL );
\r
111 giVesaDriverId = DevFS_AddDevice( &gVesa_DriverStruct );
\r
112 if(giVesaDriverId == -1) return MODULE_ERR_MISC;
\r
114 return MODULE_ERR_OK;
\r
118 int VBE_int_GetModeList(void)
\r
120 tVesa_CallInfo *info;
\r
124 // Allocate Info Block
\r
125 info = VM8086_Allocate(gpVesa_BiosState, 512, &infoPtr.seg, &infoPtr.ofs);
\r
126 // Set Requested Version
\r
127 memcpy(info->signature, "VBE2", 4);
\r
129 gpVesa_BiosState->AX = 0x4F00;
\r
130 gpVesa_BiosState->ES = infoPtr.seg; gpVesa_BiosState->DI = infoPtr.ofs;
\r
132 VM8086_Int(gpVesa_BiosState, 0x10);
\r
133 if(gpVesa_BiosState->AX != 0x004F) {
\r
134 Log_Warning("VBE", "Vesa_Install - VESA/VBE Unsupported (AX = 0x%x)", gpVesa_BiosState->AX);
\r
135 return MODULE_ERR_NOTNEEDED;
\r
138 modes = (Uint16 *) VM8086_GetPointer(gpVesa_BiosState, info->VideoModes.seg, info->VideoModes.ofs);
\r
139 LOG("Virtual addres of mode list from %04x:%04x is %p",
\r
140 info->VideoModes.seg, info->VideoModes.ofs, modes);
\r
141 // VM8086_Deallocate( gpVesa_BiosState, info );
\r
144 for( giVesaModeCount = 0; modes[giVesaModeCount] != 0xFFFF; giVesaModeCount++ )
\r
146 gVesa_Modes = (tVesa_Mode *)malloc( giVesaModeCount * sizeof(tVesa_Mode) );
\r
148 Log_Debug("VBE", "%i Modes", giVesaModeCount);
\r
150 // Insert Text Mode
\r
152 for( int i = 0; i < giVesaModeCount; i++ )
\r
154 gVesa_Modes[i].code = modes[i];
\r
160 int VBE_int_GetModeInfo(Uint16 Code, tFarPtr *BufPtr)
\r
163 gpVesa_BiosState->AX = 0x4F01;
\r
164 gpVesa_BiosState->CX = Code;
\r
165 gpVesa_BiosState->ES = BufPtr->seg;
\r
166 gpVesa_BiosState->DI = BufPtr->ofs;
\r
167 VM8086_Int(gpVesa_BiosState, 0x10);
\r
169 if( gpVesa_BiosState->AX != 0x004F ) {
\r
170 Log_Error("VBE", "Getting info on mode 0x%x failed (AX=0x%x)",
\r
171 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 // Check if this mode is supported by hardware
\r
226 if( !(vbeinfo->attributes & 1) )
\r
229 Log_Log("VBE", "0x%x - not supported", Mode->code);
\r
238 Mode->flags |= FLAG_VALID;
\r
239 switch( vbeinfo->attributes & 0x90 ) // LFB, Graphics
\r
241 case 0x00: // Banked, Text
\r
242 case 0x10: // Banked, Graphics
\r
243 case 0x80: // Linear, Text (?)
\r
249 Mode->flags |= FLAG_LFB|FLAG_GRAPHICS;
\r
250 Mode->framebuffer = vbeinfo->physbase;
\r
251 Mode->fbSize = vbeinfo->Yres*vbeinfo->pitch;
\r
255 Mode->pitch = vbeinfo->pitch;
\r
256 Mode->width = vbeinfo->Xres;
\r
257 Mode->height = vbeinfo->Yres;
\r
258 Mode->bpp = vbeinfo->bpp;
\r
261 Log_Log("VBE", "0x%x - %ix%ix%i (%x)",
\r
262 Mode->code, Mode->width, Mode->height, Mode->bpp, Mode->flags);
\r
267 void VBE_int_SetBootMode(Uint16 ModeID, const void *ModeInfo)
\r
269 gVesa_BootMode.code = ModeID;
\r
270 VBE_int_FillMode_Int(&gVesa_BootMode, ModeInfo);
\r
273 void Vesa_int_FillModeList(void)
\r
276 if( !gbVesaModesChecked && !gbVesa_DisableBIOSCalls )
\r
278 tVesa_CallModeInfo *modeinfo;
\r
279 tFarPtr modeinfoPtr;
\r
281 modeinfo = VM8086_Allocate(gpVesa_BiosState, 256, &modeinfoPtr.seg, &modeinfoPtr.ofs);
\r
282 for( int i = 0; i < giVesaModeCount; i ++ )
\r
284 if( VBE_int_GetModeInfo(gVesa_Modes[i].code, &modeinfoPtr) == 0 )
\r
286 VBE_int_FillMode_Int( &gVesa_Modes[i], modeinfo );
\r
289 // VM8086_Deallocate( gpVesa_BiosState, modeinfo );
\r
291 gbVesaModesChecked = 1;
\r
297 * \brief Write to the framebuffer
\r
299 size_t Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
\r
301 switch( gpVesaCurMode->flags & (FLAG_LFB|FLAG_GRAPHICS) )
\r
304 // EGA text mode translation
\r
305 switch( gVesa_BufInfo.BufferFormat )
\r
307 case VIDEO_BUFFMT_TEXT: {
\r
308 int num = Length / sizeof(tVT_Char);
\r
309 int ofs = Offset / sizeof(tVT_Char);
\r
311 const tVT_Char *chars = Buffer;
\r
313 for( ; num--; i ++, ofs ++)
\r
315 Uint16 word = VBE_int_GetWord( &chars[i] );
\r
316 ((Uint16*)gVesa_BufInfo.Framebuffer)[ ofs ] = word;
\r
320 case VIDEO_BUFFMT_2DSTREAM:
\r
321 return DrvUtil_Video_2DStream(NULL, Buffer, Length,
\r
322 &gVBE_Text2DFunctions, sizeof(gVBE_Text2DFunctions));
\r
324 Log_Warning("VBE", "TODO: Alternate modes in EGA text mode");
\r
328 case FLAG_LFB|FLAG_GRAPHICS:
\r
329 // Framebuffer modes - use DrvUtil Video
\r
330 return DrvUtil_Video_WriteLFB(&gVesa_BufInfo, Offset, Length, Buffer);
\r
332 Log_Warning("VBE", "TODO: _Write %s%s",
\r
333 (gpVesaCurMode->flags & FLAG_LFB ? "FLAG_LFB" : ""),
\r
334 (gpVesaCurMode->flags & FLAG_GRAPHICS ? "FLAG_GRAPHICS" : "")
\r
340 const char *csaVESA_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};
\r
342 * \brief Handle messages to the device
\r
344 int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data)
\r
349 BASE_IOCTLS(DRV_TYPE_VIDEO, "VBE", VERSION, csaVESA_IOCtls);
\r
351 case VIDEO_IOCTL_GETSETMODE:
\r
352 if( !Data ) return giVesaCurrentMode;
\r
353 return Vesa_Int_SetMode( *(int*)Data );
\r
355 case VIDEO_IOCTL_FINDMODE:
\r
356 return Vesa_Int_FindMode((tVideo_IOCtl_Mode*)Data);
\r
357 case VIDEO_IOCTL_MODEINFO:
\r
358 return Vesa_Int_ModeInfo((tVideo_IOCtl_Mode*)Data);
\r
360 case VIDEO_IOCTL_SETBUFFORMAT:
\r
361 Vesa_int_HideCursor();
\r
362 ret = gVesa_BufInfo.BufferFormat;
\r
363 if(Data) gVesa_BufInfo.BufferFormat = *(int*)Data;
\r
364 if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
\r
365 DrvUtil_Video_SetCursor( &gVesa_BufInfo, &gDrvUtil_TextModeCursor );
\r
366 Vesa_int_ShowCursor();
\r
369 case VIDEO_IOCTL_SETCURSOR: // Set cursor position
\r
370 Vesa_int_HideCursor();
\r
371 giVesaCursorX = ((tVideo_IOCtl_Pos*)Data)->x;
\r
372 giVesaCursorY = ((tVideo_IOCtl_Pos*)Data)->y;
\r
373 Vesa_int_ShowCursor();
\r
376 case VIDEO_IOCTL_SETCURSORBITMAP:
\r
377 if( gpVesaCurMode->flags & FLAG_LFB )
\r
378 DrvUtil_Video_SetCursor( &gVesa_BufInfo, Data );
\r
385 * \brief Updates the video mode
\r
387 int Vesa_Int_SetMode(int mode)
\r
389 tVesa_Mode *modeptr;
\r
390 // Check for fast return
\r
391 if(mode == giVesaCurrentMode) return 1;
\r
393 // Special case: Boot mode
\r
395 modeptr = &gVesa_BootMode;
\r
396 else if( 0 <= mode && mode < giVesaModeCount )
\r
397 modeptr = &gVesa_Modes[mode];
\r
401 Vesa_int_FillModeList();
\r
403 #if BLINKING_CURSOR
\r
404 Time_RemoveTimer(gpVesaCursorTimer);
\r
407 Mutex_Acquire( &glVesa_Lock );
\r
410 if( gbVesa_DisableBIOSCalls )
\r
412 ASSERT(mode == -1);
\r
416 gpVesa_BiosState->AX = 0x4F02;
\r
417 gpVesa_BiosState->BX = modeptr->code;
\r
418 if(modeptr->flags & FLAG_LFB) {
\r
419 gpVesa_BiosState->BX |= 1 << 14; // Use LFB
\r
421 LOG("In : AX=%04x/BX=%04x", gpVesa_BiosState->AX, gpVesa_BiosState->BX);
\r
424 VM8086_Int(gpVesa_BiosState, 0x10);
\r
426 LOG("Out: AX = %04x", gpVesa_BiosState->AX);
\r
429 ASSERT(mode == -1);
\r
433 if( gpVesaCurMode )
\r
435 if( gpVesaCurMode->framebuffer < 1024*1024 )
\r
438 MM_UnmapHWPages((tVAddr)gpVesa_Framebuffer, giVesaPageCount);
\r
440 giVesaPageCount = (modeptr->fbSize + 0xFFF) >> 12;
\r
441 if( modeptr->framebuffer < 1024*1024 )
\r
442 gpVesa_Framebuffer = (void*)(KERNEL_BASE|modeptr->framebuffer);
\r
444 gpVesa_Framebuffer = (void*)MM_MapHWPages(modeptr->framebuffer, giVesaPageCount);
\r
446 Log_Log("VBE", "Setting mode to %i 0x%x (%ix%i %ibpp) %p[0x%x] maps %P",
\r
447 mode, modeptr->code,
\r
448 modeptr->width, modeptr->height,
\r
450 gpVesa_Framebuffer, giVesaPageCount << 12, modeptr->framebuffer
\r
454 giVesaCurrentMode = mode;
\r
455 gpVesaCurMode = modeptr;
\r
457 Mutex_Release( &glVesa_Lock );
\r
459 // TODO: Disableable backbuffer
\r
460 gVesa_BufInfo.BackBuffer = realloc(gVesa_BufInfo.BackBuffer,
\r
461 modeptr->height * modeptr->pitch);
\r
462 gVesa_BufInfo.Framebuffer = gpVesa_Framebuffer;
\r
463 gVesa_BufInfo.Pitch = modeptr->pitch;
\r
464 gVesa_BufInfo.Width = modeptr->width;
\r
465 gVesa_BufInfo.Height = modeptr->height;
\r
466 gVesa_BufInfo.Depth = modeptr->bpp;
\r
471 int VBE_int_MatchModes(tVideo_IOCtl_Mode *ReqMode, tVesa_Mode *ThisMode)
\r
473 LOG("Matching %ix%i %ibpp", ThisMode->width, ThisMode->height, ThisMode->bpp);
\r
474 if(ThisMode->width == ReqMode->width && ThisMode->height == ReqMode->height)
\r
476 //if( (data->bpp == 32 || data->bpp == 24)
\r
477 // && (gVesa_Modes[i].bpp == 32 || gVesa_Modes[i].bpp == 24) )
\r
478 if( ReqMode->bpp == ThisMode->bpp )
\r
485 int tmp = ThisMode->width * ThisMode->height - ReqMode->width * ReqMode->height;
\r
486 tmp = tmp < 0 ? -tmp : tmp;
\r
487 unsigned int factor = (Uint64)tmp * 1000 / (ReqMode->width * ReqMode->height);
\r
488 if( ThisMode->bpp > ReqMode->bpp )
\r
489 factor += ThisMode->bpp - ReqMode->bpp;
\r
491 factor += ReqMode->bpp - ThisMode->bpp;
\r
493 if( ReqMode->bpp == ThisMode->bpp )
\r
497 if( ReqMode->bpp == 8 && ThisMode->bpp != 8 ) factor *= 4;
\r
498 if( ReqMode->bpp == 16 && ThisMode->bpp != 16 ) factor *= 4;
\r
500 if( (ReqMode->bpp == 32 || ReqMode->bpp == 24)
\r
501 && (ThisMode->bpp == 32 || ThisMode->bpp == 24) )
\r
506 if( ReqMode->bpp < ThisMode->bpp )
\r
507 factor *= ThisMode->bpp / ReqMode->bpp + 1;
\r
509 factor *= ReqMode->bpp / ThisMode->bpp + 1;
\r
516 int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data)
\r
520 ENTER("idata->width idata->height idata->bpp", data->width, data->height, data->bpp);
\r
522 Vesa_int_FillModeList();
\r
524 int bestFactor = VBE_int_MatchModes(data, &gVesa_BootMode);
\r
525 tVesa_Mode *bestPtr = &gVesa_BootMode;
\r
527 for(int i = 0; bestFactor > 0 && i < giVesaModeCount; i ++)
\r
529 LOG("Mode %i (%ix%ix%i)", i, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp);
\r
531 int factor = VBE_int_MatchModes(data, &gVesa_Modes[i]);
\r
533 LOG("factor = %i, bestFactor = %i", factor, bestFactor);
\r
535 if(factor < bestFactor)
\r
537 bestFactor = factor;
\r
539 bestPtr = &gVesa_Modes[i];
\r
543 data->width = bestPtr->width;
\r
544 data->height = bestPtr->height;
\r
545 data->bpp = bestPtr->bpp;
\r
550 int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data)
\r
552 tVesa_Mode *modeptr;
\r
553 if( data->id == -1 )
\r
554 modeptr = &gVesa_BootMode;
\r
555 else if( 0 <= data->id && data->id < giVesaModeCount)
\r
556 modeptr = &gVesa_Modes[data->id];
\r
560 Vesa_int_FillModeList();
\r
562 data->width = modeptr->width;
\r
563 data->height = modeptr->height;
\r
564 data->bpp = modeptr->bpp;
\r
568 void Vesa_int_HideCursor(void)
\r
570 DrvUtil_Video_RemoveCursor( &gVesa_BufInfo );
\r
571 if( gpVesaCurMode->flags & FLAG_LFB )
\r
573 #if BLINKING_CURSOR
\r
574 if(gpVesaCursorTimer) {
\r
575 Time_RemoveTimer(gpVesaCursorTimer);
\r
581 void Vesa_int_ShowCursor(void)
\r
583 if( gpVesaCurMode->flags & FLAG_LFB )
\r
585 gbVesa_CursorVisible = (giVesaCursorX >= 0);
\r
586 if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
\r
588 DrvUtil_Video_DrawCursor(
\r
590 giVesaCursorX*giVT_CharWidth,
\r
591 giVesaCursorY*giVT_CharHeight
\r
593 #if BLINKING_CURSOR
\r
594 Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD );
\r
598 DrvUtil_Video_DrawCursor(
\r
606 DrvUtil_Video_RemoveCursor( &gVesa_BufInfo );
\r
611 * \brief Swaps the text cursor on/off
\r
613 void Vesa_FlipCursor(void *Arg)
\r
615 if( gVesa_BufInfo.BufferFormat != VIDEO_BUFFMT_TEXT )
\r
618 if( gpVesaCurMode->flags & FLAG_LFB )
\r
620 if( gbVesa_CursorVisible )
\r
621 DrvUtil_Video_RemoveCursor(&gVesa_BufInfo);
\r
623 DrvUtil_Video_DrawCursor(&gVesa_BufInfo,
\r
624 giVesaCursorX*giVT_CharWidth,
\r
625 giVesaCursorY*giVT_CharHeight
\r
627 gbVesa_CursorVisible = !gbVesa_CursorVisible;
\r
629 #if BLINKING_CURSOR
\r
630 Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD );
\r
636 // Helpers for text mode
\r
640 * \fn Uint8 VGA_int_GetColourNibble(Uint16 col)
\r
641 * \brief Converts a 12-bit colour into a VGA 4-bit colour
\r
643 Uint8 VBE_int_GetColourNibble(Uint16 col)
\r
649 col = ((col>>2)&3) | ((col>>4)&0xC) | ((col>>6)&0x30);
\r
650 bright = ( (col & 2 ? 1 : 0) + (col & 8 ? 1 : 0) + (col & 32 ? 1 : 0) ) / 2;
\r
655 case 0x00: ret = 0x0; break;
\r
657 case 0x15: ret = 0x8; break;
\r
660 case 0x02: ret = 0x1; break;
\r
661 case 0x03: ret = 0x9; break;
\r
664 case 0x08: ret = 0x2; break;
\r
665 case 0x0C: ret = 0xA; break;
\r
668 case 0x20: ret = 0x4; break;
\r
669 case 0x30: ret = 0xC; break;
\r
671 case 0x2A: ret = 0x7; break;
\r
673 case 0x3F: ret = 0xF; break;
\r
676 ret |= (col & 0x03 ? 1 : 0);
\r
677 ret |= (col & 0x0C ? 2 : 0);
\r
678 ret |= (col & 0x30 ? 4 : 0);
\r
679 ret |= (bright ? 8 : 0);
\r
686 * \brief Convers a character structure to a VGA character word
\r
688 Uint16 VBE_int_GetWord(const tVT_Char *Char)
\r
699 default: ret = 0; break;
\r
703 col = VBE_int_GetColourNibble(Char->BGCol);
\r
706 col = VBE_int_GetColourNibble(Char->FGCol);
\r
712 void VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
\r
714 const int charw = 8;
\r
715 const int charh = 16;
\r
716 const int tw = gpVesaCurMode->width / charw;
\r
717 const int th = gpVesaCurMode->height / charh;
\r
726 ch.BGCol = (Colour & 0x0F0000) >> (16-8);
\r
727 ch.BGCol |= (Colour & 0x000F00) >> (8-4);
\r
728 ch.BGCol |= (Colour & 0x00000F);
\r
730 Uint16 word = VBE_int_GetWord(&ch);
\r
732 Log("Fill (%i,%i) %ix%i with 0x%x", X, Y, W, H, word);
\r
734 if( X >= tw || Y >= th ) return ;
\r
735 if( X + W > tw ) W = tw - X;
\r
736 if( Y + H > th ) H = th - Y;
\r
738 Uint16 *buf = (Uint16*)gpVesa_Framebuffer + Y*tw + X;
\r
742 for( int i = 0; i < W; i ++ )
\r
748 void VBE_int_Text_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
\r
750 const int charw = 8;
\r
751 const int charh = 16;
\r
752 const int tw = gpVesaCurMode->width / charw;
\r
753 const int th = gpVesaCurMode->height / charh;
\r
763 // Log("(%i,%i) from (%i,%i) %ix%i", DstX, DstY, SrcX, SrcY, W, H);
\r
765 if( SrcX >= tw || SrcY >= th ) return ;
\r
766 if( SrcX + W > tw ) W = tw - SrcX;
\r
767 if( SrcY + H > th ) H = th - SrcY;
\r
768 if( DstX >= tw || DstY >= th ) return ;
\r
769 if( DstX + W > tw ) W = tw - DstX;
\r
770 if( DstY + H > th ) H = th - DstY;
\r
773 Uint16 *src = (Uint16*)gpVesa_Framebuffer + SrcY*tw + SrcX;
\r
774 Uint16 *dst = (Uint16*)gpVesa_Framebuffer + DstY*tw + DstX;
\r
780 memcpy(dst, src, W*2);
\r
792 for( int i = W; i --; ) *--dst = *--src;
\r