X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fdrv%2Fvterm.c;h=ec5c1f5451779ed179d91373791ee129612f6f72;hb=311b8047c85b22302153740947694df50d2ce356;hp=805ce7b0e46f8ae270d393ae8b7d6cf6a0b4f718;hpb=63bd7149b4e48db1d236dff264a7dfe5286930fe;p=tpg%2Facess2.git diff --git a/Kernel/drv/vterm.c b/Kernel/drv/vterm.c index 805ce7b0..ec5c1f54 100644 --- a/Kernel/drv/vterm.c +++ b/Kernel/drv/vterm.c @@ -9,8 +9,9 @@ #include #include #include +#include -#define USE_CTRL_ALT 0 +#define USE_CTRL_ALT 1 // === CONSTANTS === #define VERSION ((0<<8)|(50)) @@ -30,7 +31,7 @@ #define VT_FLAG_HASFB 0x10 //!< Set if the VTerm has requested the Framebuffer enum eVT_InModes { - VT_INMODE_TEXT8, // UTF-8 Text Mode (VT100 Emulation) + VT_INMODE_TEXT8, // UTF-8 Text Mode (VT100/xterm Emulation) VT_INMODE_TEXT32, // UTF-32 Text Mode (Acess Native) NUM_VT_INMODES }; @@ -39,7 +40,6 @@ enum eVT_InModes { typedef struct { int Mode; //!< Current Mode (see ::eTplTerminal_Modes) int Flags; //!< Flags (see VT_FLAG_*) - short NewWidth; //!< Un-applied dimensions (Width) short NewHeight; //!< Un-applied dimensions (Height) @@ -52,9 +52,12 @@ typedef struct { int WritePos; //!< Write Buffer Offset (Text Only) Uint32 CurColour; //!< Current Text Colour + tMutex ReadingLock; //!< Lock the VTerm when a process is reading from it + tTID ReadingThread; //!< Owner of the lock int InputRead; //!< Input buffer read position int InputWrite; //!< Input buffer write position char InputBuffer[MAX_INPUT_CHARS8]; +// tSemaphore InputSemaphore; tVT_Char *Text; Uint32 *Buffer; @@ -64,14 +67,14 @@ typedef struct { } tVTerm; // === IMPORTS === -extern void Debug_SetKTerminal(char *File); +extern void Debug_SetKTerminal(const char *File); // === PROTOTYPES === int VT_Install(char **Arguments); void VT_InitOutput(void); void VT_InitInput(void); char *VT_ReadDir(tVFS_Node *Node, int Pos); -tVFS_Node *VT_FindDir(tVFS_Node *Node, char *Name); +tVFS_Node *VT_FindDir(tVFS_Node *Node, const char *Name); int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data); Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); @@ -81,6 +84,7 @@ void VT_SetMode(int Mode); void VT_SetTerminal(int ID); void VT_KBCallBack(Uint32 Codepoint); void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count); +void VT_int_ClearLine(tVTerm *Term, int Num); int VT_int_ParseEscape(tVTerm *Term, char *Buffer); void VT_int_PutChar(tVTerm *Term, Uint32 Ch); void VT_int_ScrollFramebuffer( tVTerm *Term ); @@ -139,21 +143,29 @@ int VT_Install(char **Arguments) // Scan Arguments if(Arguments) { - char **args = Arguments; - char *arg, *opt, *val; - for( ; (arg = *args); args++ ) + char **args; + const char *arg; + for(args = Arguments; (arg = *args); args++ ) { + char data[strlen(arg)+1]; + char *opt = data; + char *val; + + val = strchr(arg, '='); + strcpy(data, arg); + if( val ) { + data[ val - arg ] = '\0'; + val ++; + } Log_Debug("VTerm", "Argument '%s'", arg); - opt = arg; - val = arg + strpos(arg, '='); *val++ = '\0'; if( strcmp(opt, "Video") == 0 ) { - if(gsVT_OutputDevice) free(gsVT_OutputDevice); - gsVT_OutputDevice = strdup(val); + if( !gsVT_OutputDevice && Modules_InitialiseBuiltin( val ) == 0 ) + gsVT_OutputDevice = strdup(val); } else if( strcmp(opt, "Input") == 0 ) { - if(gsVT_InputDevice) free(gsVT_InputDevice); - gsVT_InputDevice = strdup(val); + if( !gsVT_InputDevice && Modules_InitialiseBuiltin( val ) == 0 ) + gsVT_InputDevice = strdup(val); } else if( strcmp(opt, "Width") == 0 ) { giVT_RealWidth = atoi( val ); @@ -168,8 +180,21 @@ int VT_Install(char **Arguments) } // Apply Defaults - if(!gsVT_OutputDevice) gsVT_OutputDevice = "/Devices/"DEFAULT_OUTPUT; - if(!gsVT_InputDevice) gsVT_InputDevice = "/Devices/"DEFAULT_INPUT; + if(!gsVT_OutputDevice) gsVT_OutputDevice = strdup(DEFAULT_OUTPUT); + if(!gsVT_InputDevice) gsVT_InputDevice = strdup(DEFAULT_INPUT); + + // Create paths + { + char *tmp; + tmp = malloc( 9 + strlen(gsVT_OutputDevice) + 1 ); + strcpy(tmp, "/Devices/"); + strcpy(&tmp[9], gsVT_OutputDevice); + gsVT_OutputDevice = tmp; + tmp = malloc( 9 + strlen(gsVT_InputDevice) + 1 ); + strcpy(tmp, "/Devices/"); + strcpy(&tmp[9], gsVT_InputDevice); + gsVT_InputDevice = tmp; + } Log_Log("VTerm", "Using '%s' as output", gsVT_OutputDevice); Log_Log("VTerm", "Using '%s' as input", gsVT_InputDevice); @@ -182,6 +207,7 @@ int VT_Install(char **Arguments) gVT_Terminals[i].CurColour = DEFAULT_COLOUR; gVT_Terminals[i].WritePos = 0; gVT_Terminals[i].ViewPos = 0; + gVT_Terminals[i].ReadingThread = -1; // Initialise VT_int_ChangeMode( &gVT_Terminals[i], @@ -196,6 +222,7 @@ int VT_Install(char **Arguments) gVT_Terminals[i].Node.Read = VT_Read; gVT_Terminals[i].Node.Write = VT_Write; gVT_Terminals[i].Node.IOCtl = VT_Terminal_IOCtl; +// Semaphore_Init(&gVT_Terminals[i].InputSemaphore, 0, MAX_INPUT_CHARS8, "VTerm", gVT_Terminals[i].Name); } // Add to DevFS @@ -218,11 +245,11 @@ int VT_Install(char **Arguments) void VT_InitOutput() { giVT_OutputDevHandle = VFS_Open(gsVT_OutputDevice, VFS_OPENFLAG_WRITE); - if(giVT_InputDevHandle == -1) { + if(giVT_OutputDevHandle == -1) { Log_Warning("VTerm", "Oh F**k, I can't open the video device '%s'", gsVT_OutputDevice); return ; } - VT_SetResolution(giVT_RealWidth, giVT_RealHeight); + VT_SetResolution( giVT_RealWidth, giVT_RealHeight ); VT_SetTerminal( 0 ); VT_SetMode( VIDEO_BUFFMT_TEXT ); } @@ -234,10 +261,76 @@ void VT_InitOutput() void VT_InitInput() { giVT_InputDevHandle = VFS_Open(gsVT_InputDevice, VFS_OPENFLAG_READ); - if(giVT_InputDevHandle == -1) return ; + if(giVT_InputDevHandle == -1) { + Log_Warning("VTerm", "Can't open the input device '%s'", gsVT_InputDevice); + return ; + } VFS_IOCtl(giVT_InputDevHandle, KB_IOCTL_SETCALLBACK, VT_KBCallBack); } +/** + * \brief Set the video resolution + * \param Width New screen width + * \param Height New screen height + */ +void VT_SetResolution(int Width, int Height) +{ + tVideo_IOCtl_Mode mode = {0}; + int tmp; + int i; + + // Create the video mode + mode.width = Width; + mode.height = Height; + mode.bpp = 32; + mode.flags = 0; + + // Set video mode + VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_FINDMODE, &mode ); + tmp = mode.id; + if( Width != mode.width || Height != mode.height ) + { + Log_Warning("VTerm", + "Selected resolution (%ix%i is not supported) by the device, using (%ix%i)", + giVT_RealWidth, giVT_RealHeight, + mode.width, mode.height + ); + } + VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_GETSETMODE, &tmp ); + + // Resize text terminals if needed + if( giVT_RealWidth != mode.width || giVT_RealHeight != mode.height ) + { + int newBufSize = (giVT_RealWidth/giVT_CharWidth) + *(giVT_RealHeight/giVT_CharHeight) + *(giVT_Scrollback+1); + //tVT_Char *tmp; + // Resize the text terminals + giVT_RealWidth = mode.width; + giVT_RealHeight = mode.height; + for( i = 0; i < NUM_VTS; i ++ ) + { + if( gVT_Terminals[i].Mode != TERM_MODE_TEXT ) continue; + + gVT_Terminals[i].TextWidth = giVT_RealWidth/giVT_CharWidth; + gVT_Terminals[i].TextHeight = giVT_RealHeight/giVT_CharHeight; + + gVT_Terminals[i].Text = realloc( + gVT_Terminals[i].Text, + newBufSize*sizeof(tVT_Char) + ); + } + } +} + +/** + * \brief Set video output buffer mode + */ +void VT_SetMode(int Mode) +{ + VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &Mode ); +} + /** * \fn char *VT_ReadDir(tVFS_Node *Node, int Pos) * \brief Read from the VTerm Directory @@ -250,10 +343,12 @@ char *VT_ReadDir(tVFS_Node *Node, int Pos) } /** - * \fn tVFS_Node *VT_FindDir(tVFS_Node *Node, char *Name) + * \fn tVFS_Node *VT_FindDir(tVFS_Node *Node, const char *Name) * \brief Find an item in the VTerm directory + * \param Node Root node + * \param Name Name (number) of the terminal */ -tVFS_Node *VT_FindDir(tVFS_Node *Node, char *Name) +tVFS_Node *VT_FindDir(tVFS_Node *Node, const char *Name) { int num; @@ -303,6 +398,8 @@ int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data) len = strlen(Data); + // TODO: Check if the string used is a heap string + free(gsVT_OutputDevice); gsVT_OutputDevice = malloc(len+1); @@ -324,16 +421,26 @@ int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data) Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) { int pos = 0; + int avail; tVTerm *term = &gVT_Terminals[ Node->Inode ]; + Mutex_Acquire( &term->ReadingLock ); + // Check current mode switch(term->Mode) { + // Text Mode (UTF-8) case TERM_MODE_TEXT: - while(pos < Length) + VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "VT_Read (UTF-8)"); + + avail = term->InputWrite - term->InputRead; + if(avail < 0) + avail += MAX_INPUT_CHARS8; + if(avail > Length - pos) + avail = Length - pos; + + while( avail -- ) { - while(term->InputRead == term->InputWrite) Threads_Yield(); - ((char*)Buffer)[pos] = term->InputBuffer[term->InputRead]; pos ++; term->InputRead ++; @@ -342,18 +449,37 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) break; //case TERM_MODE_FB: + // Other - UCS-4 default: - while(pos < Length) + VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "VT_Read (UCS-4)"); + + avail = term->InputWrite - term->InputRead; + if(avail < 0) + avail += MAX_INPUT_CHARS32; + if(avail > Length - pos) + avail = Length/4 - pos; + + + while( avail -- ) { - while(term->InputRead == term->InputWrite) Threads_Yield(); ((Uint32*)Buffer)[pos] = ((Uint32*)term->InputBuffer)[term->InputRead]; pos ++; term->InputRead ++; term->InputRead %= MAX_INPUT_CHARS32; } + pos *= 4; break; } - return 0; + + // Mark none avaliable if buffer empty + if( term->InputRead == term->InputWrite ) + VFS_MarkAvaliable(&term->Node, 0); + + term->ReadingThread = -1; + + Mutex_Release( &term->ReadingLock ); + + return pos; } /** @@ -368,29 +494,36 @@ Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) // Write switch( term->Mode ) { + // Print Text case TERM_MODE_TEXT: VT_int_PutString(term, Buffer, Length); break; + // Framebuffer :) case TERM_MODE_FB: + + // - Sanity Checking size = term->Width*term->Height*4; if( Offset > size ) { Log_Notice("VTerm", "VT_Write: Offset (0x%llx) > FBSize (0x%x)", Offset, size); return 0; } - if( Offset + Length > size ) { Log_Notice("VTerm", "VT_Write: Offset+Length (0x%llx) > FBSize (0x%x)", Offset+Length, size); Length = size - Offset; } + // Copy to the local cache memcpy( (void*)((Uint)term->Buffer + (Uint)Offset), Buffer, Length ); + // Update screen if needed if( Node->Inode == giVT_CurrentTerminal ) { + // Fill entire screen? if( giVT_RealWidth > term->Width || giVT_RealHeight > term->Height ) { + // No? :( Well, just center it int x, y, w, h; x = Offset/4; y = x / term->Width; x %= term->Width; w = Length/4+x; h = w / term->Width; w %= term->Width; @@ -414,6 +547,8 @@ Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) } } // Just pass on (for now) + // TODO: Handle locally too to ensure no information is lost on + // VT Switch (and to isolate terminals from each other) case TERM_MODE_2DACCEL: //case TERM_MODE_3DACCEL: if( Node->Inode == giVT_CurrentTerminal ) @@ -475,13 +610,17 @@ int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) || term->NewWidth || term->NewHeight) { + // Adjust for text mode if( *iData == TERM_MODE_TEXT ) { term->NewHeight *= giVT_CharHeight; term->NewWidth *= giVT_CharWidth; } + // Fill unchanged dimensions if(term->NewHeight == 0) term->NewHeight = term->Height; if(term->NewWidth == 0) term->NewWidth = term->Width; + // Set new mode VT_int_ChangeMode(term, *iData, term->NewWidth, term->NewHeight); + // Clear unapplied dimensions term->NewWidth = 0; term->NewHeight = 0; } @@ -523,7 +662,7 @@ int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) if( term->NewHeight ) ret = term->NewHeight; else if( term->Mode == TERM_MODE_TEXT ) - ret = term->TextHeight = *iData; + ret = term->TextHeight; else ret = term->Height; LEAVE('i', ret); @@ -540,58 +679,6 @@ int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) return -1; } -void VT_SetResolution(int Width, int Height) -{ - tVideo_IOCtl_Mode mode = {0}; - int tmp; - int i; - - // Create the video mode - mode.width = Width; - mode.height = Height; - mode.bpp = 32; - mode.flags = 0; - - // Set video mode - VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_FINDMODE, &mode ); - tmp = mode.id; - if( Width != mode.width || Height != mode.height ) - { - Log_Warning("VTerm", - "Selected resolution (%ix%i is not supported) by the device, using (%ix%i)", - giVT_RealWidth, giVT_RealHeight, - mode.width, mode.height - ); - } - VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_GETSETMODE, &tmp ); - - // Resize text terminals if needed - if( giVT_RealWidth != mode.width || giVT_RealHeight != mode.height ) - { - int newBufSize = (giVT_RealWidth/giVT_CharWidth) - *(giVT_RealHeight/giVT_CharHeight) - *(giVT_Scrollback+1); - //tVT_Char *tmp; - // Resize the text terminals - giVT_RealWidth = mode.width; - giVT_RealHeight = mode.height; - for( i = 0; i < NUM_VTS; i ++ ) - { - if( gVT_Terminals[i].Mode != TERM_MODE_TEXT ) continue; - - gVT_Terminals[i].Text = realloc( - gVT_Terminals[i].Text, - newBufSize*sizeof(tVT_Char) - ); - } - } -} - -void VT_SetMode(int Mode) -{ - VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &Mode ); -} - /** * \fn void VT_SetTerminal(int ID) * \brief Set the current terminal @@ -607,9 +694,10 @@ void VT_SetTerminal(int ID) if( gpVT_CurTerm->Mode == TERM_MODE_TEXT && !(gpVT_CurTerm->Flags & VT_FLAG_HIDECSR) ) { tVideo_IOCtl_Pos pos; - pos.x = gpVT_CurTerm->WritePos % gpVT_CurTerm->TextWidth; - pos.y = gpVT_CurTerm->WritePos / gpVT_CurTerm->TextWidth; - VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); + pos.x = (gpVT_CurTerm->WritePos - gpVT_CurTerm->ViewPos) % gpVT_CurTerm->TextWidth; + pos.y = (gpVT_CurTerm->WritePos - gpVT_CurTerm->ViewPos) / gpVT_CurTerm->TextWidth; + if( pos.x < gpVT_CurTerm->TextHeight ) + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); } if( gpVT_CurTerm->Mode == TERM_MODE_TEXT ) @@ -649,7 +737,7 @@ void VT_KBCallBack(Uint32 Codepoint) #else case KEY_LALT: gbVT_AltDown &= ~1; break; case KEY_RALT: gbVT_AltDown &= ~2; break; - case KEY_LCTRL: gbVT_CtrlDown &= ~1 break; + case KEY_LCTRL: gbVT_CtrlDown &= ~1; break; case KEY_RCTRL: gbVT_CtrlDown &= ~2; break; #endif } @@ -766,7 +854,6 @@ void VT_KBCallBack(Uint32 Codepoint) term->InputRead = term->InputWrite + 1; term->InputRead %= MAX_INPUT_CHARS8; } - } else { @@ -779,6 +866,13 @@ void VT_KBCallBack(Uint32 Codepoint) term->InputRead %= MAX_INPUT_CHARS32; } } + + VFS_MarkAvaliable(&term->Node, 1); + + // Wake up the thread waiting on us + //if( term->ReadingThread >= 0 ) { + // Threads_WakeTID(term->ReadingThread); + //} } /** @@ -789,7 +883,7 @@ void VT_int_ClearLine(tVTerm *Term, int Num) { int i; tVT_Char *cell = &Term->Text[ Num*Term->TextWidth ]; - if( Num < 0 || Num >= Term->TextHeight ) return ; + if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) ) return ; //ENTER("pTerm iNum", Term, Num); for( i = Term->TextWidth; i--; ) { @@ -829,17 +923,6 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) } while(c == ';'); } - /* - // Get string (what does this do?) - if(c == '"') { - c = Buffer[j++]; - while(c != '"') - c = Buffer[j++]; - } - */ - - //Log_Debug("VTerm", "argc = %i", argc); - // Get Command if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) { @@ -963,8 +1046,8 @@ void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count) if( Term == gpVT_CurTerm && !(Term->Flags & VT_FLAG_HIDECSR) ) { tVideo_IOCtl_Pos pos; - pos.x = Term->WritePos % Term->TextWidth; - pos.y = Term->WritePos / Term->TextWidth; + pos.x = (Term->WritePos - Term->ViewPos) % Term->TextWidth; + pos.y = (Term->WritePos - Term->ViewPos) / Term->TextWidth; VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); } } @@ -976,7 +1059,7 @@ void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count) void VT_int_PutChar(tVTerm *Term, Uint32 Ch) { int i; - + switch(Ch) { case '\0': return; // Ignore NULL byte @@ -1020,6 +1103,9 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) default: Term->Text[ Term->WritePos ].Ch = Ch; Term->Text[ Term->WritePos ].Colour = Term->CurColour; + // Update the line before wrapping + if( (Term->WritePos + 1) % Term->TextWidth == 0 ) + VT_int_UpdateScreen( Term, 0 ); Term->WritePos ++; break; } @@ -1028,9 +1114,7 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) // - Check if we need to scroll the entire scrollback buffer if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1)) { - int base, i; - - //Debug("Scrolling entire buffer"); + int base; // Move back by one Term->WritePos -= Term->TextWidth; @@ -1067,7 +1151,7 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) { //Debug("Term->WritePos (%i) >= %i", // Term->WritePos, - // Term->ViewPos + Term->Width*Term->Height + // Term->ViewPos + Term->TextWidth*Term->TextHeight // ); //Debug("Scrolling screen only"); @@ -1075,12 +1159,15 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) Term->WritePos -= Term->TextWidth; VT_int_UpdateScreen( Term, 0 ); Term->WritePos += Term->TextWidth; + VT_int_ClearLine(Term, Term->WritePos / Term->TextWidth); // Scroll Term->ViewPos += Term->TextWidth; //Debug("Term->ViewPos = %i", Term->ViewPos); VT_int_ScrollFramebuffer( Term ); VT_int_UpdateScreen( Term, 0 ); + + //VT_int_UpdateScreen( Term, 1 ); // HACK! } //LEAVE('-'); @@ -1271,34 +1358,113 @@ int giVT_CharHeight = FONT_HEIGHT; // === CODE === /** - * \fn void VT_Font_Render(Uint32 Codepoint, void *Buffer, int Pitch, Uint32 BGC, Uint32 FGC) * \brief Render a font character */ -void VT_Font_Render(Uint32 Codepoint, void *Buffer, int Pitch, Uint32 BGC, Uint32 FGC) +void VT_Font_Render(Uint32 Codepoint, void *Buffer, int Depth, int Pitch, Uint32 BGC, Uint32 FGC) { Uint8 *font; - Uint32 *buf = Buffer; int x, y; - font = VT_Font_GetChar(Codepoint); - - for(y = 0; y < FONT_HEIGHT; y ++) + // 8-bpp and below + if( Depth <= 8 ) { - for(x = 0; x < FONT_WIDTH; x ++) + Uint8 *buf = Buffer; + + font = VT_Font_GetChar(Codepoint); + + for(y = 0; y < FONT_HEIGHT; y ++) { - if(*font & (1 << (FONT_WIDTH-x-1))) - buf[x] = FGC; - else - buf[x] = BGC; + for(x = 0; x < FONT_WIDTH; x ++) + { + if(*font & (1 << (FONT_WIDTH-x-1))) + buf[x] = FGC; + else + buf[x] = BGC; + } + buf = (void*)( (tVAddr)buf + Pitch ); + font ++; + } + } + // 16-bpp and below + else if( Depth <= 16 ) + { + Uint16 *buf = Buffer; + + font = VT_Font_GetChar(Codepoint); + + for(y = 0; y < FONT_HEIGHT; y ++) + { + for(x = 0; x < FONT_WIDTH; x ++) + { + if(*font & (1 << (FONT_WIDTH-x-1))) + buf[x] = FGC; + else + buf[x] = BGC; + } + buf = (void*)( (tVAddr)buf + Pitch ); + font ++; + } + } + // 24-bpp colour + // - Special handling to not overwrite the next pixel + //TODO: Endian issues here + else if( Depth == 24 ) + { + Uint8 *buf = Buffer; + Uint8 bg_r = (BGC >> 16) & 0xFF; + Uint8 bg_g = (BGC >> 8) & 0xFF; + Uint8 bg_b = (BGC >> 0) & 0xFF; + Uint8 fg_r = (FGC >> 16) & 0xFF; + Uint8 fg_g = (FGC >> 8) & 0xFF; + Uint8 fg_b = (FGC >> 0) & 0xFF; + + font = VT_Font_GetChar(Codepoint); + + for(y = 0; y < FONT_HEIGHT; y ++) + { + for(x = 0; x < FONT_WIDTH; x ++) + { + Uint8 r, g, b; + + if(*font & (1 << (FONT_WIDTH-x-1))) { + r = fg_r; g = fg_g; b = fg_b; + } + else { + r = bg_r; g = bg_g; b = bg_b; + } + buf[x*3+0] = b; + buf[x*3+1] = g; + buf[x*3+2] = r; + } + buf = (void*)( (tVAddr)buf + Pitch ); + font ++; + } + } + // 32-bpp colour (nice and easy) + else if( Depth == 32 ) + { + Uint32 *buf = Buffer; + + font = VT_Font_GetChar(Codepoint); + + for(y = 0; y < FONT_HEIGHT; y ++) + { + for(x = 0; x < FONT_WIDTH; x ++) + { + if(*font & (1 << (FONT_WIDTH-x-1))) + buf[x] = FGC; + else + buf[x] = BGC; + } + buf = (Uint32*)( (tVAddr)buf + Pitch ); + font ++; } - buf += Pitch; - font ++; } } /** * \fn Uint32 VT_Colour12to24(Uint16 Col12) - * \brief Converts a + * \brief Converts a 12-bit colour into 24 bits */ Uint32 VT_Colour12to24(Uint16 Col12) { @@ -1312,6 +1478,68 @@ Uint32 VT_Colour12to24(Uint16 Col12) ret |= (tmp << 16) | (tmp << 20); return ret; } +/** + * \brief Converts a 12-bit colour into 15 bits + */ +Uint16 VT_Colour12to15(Uint16 Col12) +{ + Uint32 ret; + int tmp; + tmp = Col12 & 0xF; + ret = (tmp << 1) | (tmp & 1); + tmp = (Col12 & 0xF0) >> 4; + ret |= ( (tmp << 1) | (tmp & 1) ) << 5; + tmp = (Col12 & 0xF00) >> 8; + ret |= ( (tmp << 1) | (tmp & 1) ) << 10; + return ret; +} + +/** + * \brief Converts a 12-bit colour into any other depth + * \param Col12 12-bit source colour + * \param Depth Desired bit deptj + * \note Green then blue get the extra avaliable bits (16:5-6-5, 14:4-5-5) + */ +Uint32 VT_Colour12toN(Uint16 Col12, int Depth) +{ + Uint32 ret; + Uint32 r, g, b; + int rSize, gSize, bSize; + + // Fast returns + if( Depth == 24 ) return VT_Colour12to24(Col12); + if( Depth == 15 ) return VT_Colour12to15(Col12); + // - 32 is a special case, it's usually 24-bit colour with an unused byte + if( Depth == 32 ) return VT_Colour12to24(Col12); + + // Bounds checks + if( Depth < 8 ) return 0; + if( Depth > 32 ) return 0; + + r = Col12 & 0xF; + g = (Col12 & 0xF0) >> 4; + b = (Col12 & 0xF00) >> 8; + + rSize = gSize = bSize = Depth / 3; + if( rSize + gSize + bSize < Depth ) // Depth % 3 == 1 + gSize ++; + if( rSize + gSize + bSize < Depth ) // Depth % 3 == 2 + bSize ++; + + // Expand + r <<= rSize - 4; g <<= gSize - 4; b <<= bSize - 4; + // Fill with the lowest bit + if( Col12 & 0x001 ) r |= (1 << (rSize - 4)) - 1; + if( Col12 & 0x010 ) r |= (1 << (gSize - 4)) - 1; + if( Col12 & 0x100 ) r |= (1 << (bSize - 4)) - 1; + + // Create output + ret = r; + ret |= g << rSize; + ret |= b << (rSize + gSize); + + return ret; +} /** * \fn Uint8 *VT_Font_GetChar(Uint32 Codepoint)