mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Added a text buffer that works with graphical linear frame buffers.
This commit is contained in:
parent
ce43f9c306
commit
cb5a242dfc
3 changed files with 449 additions and 0 deletions
|
@ -114,6 +114,7 @@ textterminal.o \
|
|||
serialterminal.o \
|
||||
textbuffer.o \
|
||||
vgatextbuffer.o \
|
||||
lfbtextbuffer.o \
|
||||
descriptors.o \
|
||||
device.o \
|
||||
refcount.o \
|
||||
|
|
334
sortix/lfbtextbuffer.cpp
Normal file
334
sortix/lfbtextbuffer.cpp
Normal file
|
@ -0,0 +1,334 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
lfbtextbuffer.cpp
|
||||
An indexable text buffer rendered to a graphical linear frame buffer.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/textbuffer.h>
|
||||
#include <sortix/vga.h>
|
||||
#include <libmaxsi/memory.h>
|
||||
#include "vga.h"
|
||||
#include "lfbtextbuffer.h"
|
||||
|
||||
using namespace Maxsi;
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
static uint32_t ColorFromRGB(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
union { struct { uint8_t b, g, r, a; }; uint32_t color; } ret;
|
||||
ret.r = r;
|
||||
ret.g = g;
|
||||
ret.b = b;
|
||||
ret.a = 255;
|
||||
return ret.color;
|
||||
}
|
||||
|
||||
LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat,
|
||||
size_t xres, size_t yres, size_t scansize)
|
||||
{
|
||||
size_t columns = xres / (VGA_FONT_WIDTH + 1);
|
||||
size_t rows = yres / VGA_FONT_HEIGHT;
|
||||
size_t fontsize = VGA_FONT_CHARSIZE * VGA_FONT_NUMCHARS;
|
||||
uint8_t* font;
|
||||
uint16_t* chars;
|
||||
uint16_t* attrs;
|
||||
LFBTextBuffer* ret;
|
||||
|
||||
if ( !(font = new uint8_t[fontsize]) )
|
||||
goto cleanup_done;
|
||||
if ( !(chars = new uint16_t[columns * rows]) )
|
||||
goto cleanup_font;
|
||||
if ( !(attrs = new uint16_t[columns * rows]) )
|
||||
goto cleanup_chars;
|
||||
if ( !(ret = new LFBTextBuffer) )
|
||||
goto cleanup_attrs;
|
||||
|
||||
Memory::Copy(font, VGA::GetFont(), fontsize);
|
||||
ret->lfb = lfb;
|
||||
ret->lfbformat = lfbformat;
|
||||
ret->pixelsx = xres;
|
||||
ret->pixelsy = yres;
|
||||
ret->scansize = scansize;
|
||||
ret->columns = columns;
|
||||
ret->rows = rows;
|
||||
ret->font = font;
|
||||
Memory::Set(chars, 0, sizeof(uint16_t) * columns * rows);
|
||||
ret->chars = chars;
|
||||
Memory::Set(attrs, 0, sizeof(uint16_t) * columns * rows);
|
||||
ret->attrs = attrs;
|
||||
ret->cursorcolor = ColorFromRGB(200, 200, 200);
|
||||
for ( size_t i = 0; i < 16UL; i++ )
|
||||
{
|
||||
uint8_t r = i & 0b0100 ? (i & 0b1000 ? 255 : 191) : 0;
|
||||
uint8_t g = i & 0b0010 ? (i & 0b1000 ? 255 : 191) : 0;
|
||||
uint8_t b = i & 0b0001 ? (i & 0b1000 ? 255 : 191) : 0;
|
||||
ret->colors[i] = ColorFromRGB(r, g, b);
|
||||
}
|
||||
ret->cursorenabled = true;
|
||||
ret->cursorpos = TextPos(0, 0);
|
||||
for ( size_t y = 0; y < yres; y++ )
|
||||
Memory::Set(lfb + scansize * y, 0, lfbformat/8UL * xres);
|
||||
return ret;
|
||||
|
||||
cleanup_attrs:
|
||||
delete[] attrs;
|
||||
cleanup_chars:
|
||||
delete[] chars;
|
||||
cleanup_font:
|
||||
delete[] font;
|
||||
cleanup_done:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// TODO: Those are also in vgatextbuffer.cpp. Move them to a shared location and
|
||||
// give them better names.
|
||||
static TextChar EntryToTextChar(uint16_t entry)
|
||||
{
|
||||
char c = entry & 0x00FF;
|
||||
uint8_t vgacolor = entry >> 8U;
|
||||
return TextChar{c, vgacolor};
|
||||
}
|
||||
|
||||
static uint16_t CharToTextEntry(TextChar c)
|
||||
{
|
||||
unsigned char uc = c.c;
|
||||
return (uint16_t) uc | (uint16_t) c.vgacolor << 8U;
|
||||
}
|
||||
|
||||
LFBTextBuffer::LFBTextBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
LFBTextBuffer::~LFBTextBuffer()
|
||||
{
|
||||
delete[] font;
|
||||
delete[] chars;
|
||||
delete[] attrs;
|
||||
}
|
||||
|
||||
size_t LFBTextBuffer::Width() const
|
||||
{
|
||||
return columns;
|
||||
}
|
||||
|
||||
size_t LFBTextBuffer::Height() const
|
||||
{
|
||||
return rows;
|
||||
}
|
||||
|
||||
bool LFBTextBuffer::UsablePosition(TextPos pos) const
|
||||
{
|
||||
return pos.x < columns && pos.y < rows;
|
||||
}
|
||||
|
||||
TextPos LFBTextBuffer::CropPosition(TextPos pos) const
|
||||
{
|
||||
if ( columns <= pos.x )
|
||||
pos.x = columns - 1;
|
||||
if ( rows <= pos.y )
|
||||
pos.y = rows -1;
|
||||
return pos;
|
||||
}
|
||||
|
||||
TextPos LFBTextBuffer::AddToPosition(TextPos pos, size_t count)
|
||||
{
|
||||
size_t index = pos.y * columns + pos.x + count;
|
||||
TextPos ret(index % columns, index / columns);
|
||||
return CropPosition(ret);
|
||||
}
|
||||
|
||||
void LFBTextBuffer::RenderChar(uint16_t vgachar, size_t posx, size_t posy)
|
||||
{
|
||||
if ( columns <= posx || rows <= posy )
|
||||
return;
|
||||
// TODO: Support other font sizes and resolutions.
|
||||
if ( lfbformat != 32 || VGA_FONT_WIDTH != 8UL )
|
||||
return;
|
||||
bool drawcursor = cursorenabled && posx == cursorpos.x && posy == cursorpos.y;
|
||||
uint8_t c = vgachar >> 0 & 0xFF;
|
||||
uint8_t fgcoloridx = vgachar >> 8 & 0x0F;
|
||||
uint8_t bgcoloridx = vgachar >> 12 & 0x0F;
|
||||
uint32_t fgcolor = colors[fgcoloridx];
|
||||
uint32_t bgcolor = colors[bgcoloridx];
|
||||
for ( size_t y = 0; y < VGA_FONT_HEIGHT; y++ )
|
||||
{
|
||||
size_t pixely = posy * VGA_FONT_HEIGHT + y;
|
||||
uint8_t linebitmap = font[c * VGA_FONT_CHARSIZE + y];
|
||||
for ( size_t x = 0; x < VGA_FONT_WIDTH+1; x++ )
|
||||
{
|
||||
uint32_t* line = (uint32_t*) (lfb + pixely * scansize);
|
||||
size_t pixelx = posx * (VGA_FONT_WIDTH+1) + x;
|
||||
bool fg = x != VGA_FONT_WIDTH && linebitmap & 1U << (7-x);
|
||||
line[pixelx] = fg ? fgcolor : bgcolor;
|
||||
}
|
||||
}
|
||||
if ( likely(!drawcursor) )
|
||||
return;
|
||||
for ( size_t y = VGA_FONT_HEIGHT - 2; y < VGA_FONT_HEIGHT; y++ )
|
||||
{
|
||||
size_t pixely = posy * VGA_FONT_HEIGHT + y;
|
||||
for ( size_t x = 0; x < VGA_FONT_WIDTH+1; x++ )
|
||||
{
|
||||
uint32_t* line = (uint32_t*) (lfb + pixely * scansize);
|
||||
size_t pixelx = posx * (VGA_FONT_WIDTH+1) + x;
|
||||
line[pixelx] = cursorcolor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LFBTextBuffer::RenderCharAt(TextPos pos)
|
||||
{
|
||||
RenderChar(chars[pos.y * columns + pos.x], pos.x, pos.y);
|
||||
}
|
||||
|
||||
void LFBTextBuffer::RenderRegion(size_t c1, size_t r1, size_t c2, size_t r2)
|
||||
{
|
||||
for ( size_t y = r1; y <= r2; y++ )
|
||||
for ( size_t x = c1; x <= c2; x++ )
|
||||
RenderChar(chars[y * columns + x], x, y);
|
||||
}
|
||||
|
||||
void LFBTextBuffer::RenderRange(TextPos from, TextPos to)
|
||||
{
|
||||
from = CropPosition(from);
|
||||
to = CropPosition(to);
|
||||
TextPos i = from;
|
||||
RenderChar(chars[i.y * columns + i.x], i.x, i.y);
|
||||
do
|
||||
{
|
||||
i = AddToPosition(i, 1);
|
||||
RenderChar(chars[i.y * columns + i.x], i.x, i.y);
|
||||
} while ( !(i.x==to.x && i.y==to.y) );
|
||||
}
|
||||
|
||||
TextChar LFBTextBuffer::GetChar(TextPos pos) const
|
||||
{
|
||||
if ( UsablePosition(pos) )
|
||||
return EntryToTextChar(chars[pos.y * columns + pos.x]);
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
void LFBTextBuffer::SetChar(TextPos pos, TextChar c)
|
||||
{
|
||||
if ( !UsablePosition(pos) )
|
||||
return;
|
||||
chars[pos.y * columns + pos.x] = CharToTextEntry(c);
|
||||
RenderRegion(pos.x, pos.y, pos.x, pos.y);
|
||||
}
|
||||
|
||||
uint16_t LFBTextBuffer::GetCharAttr(TextPos pos) const
|
||||
{
|
||||
if ( UsablePosition(pos) )
|
||||
return attrs[pos.y * columns + pos.x];
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LFBTextBuffer::SetCharAttr(TextPos pos, uint16_t attrval)
|
||||
{
|
||||
if ( UsablePosition(pos) )
|
||||
attrs[pos.y * columns + pos.x] = attrval;
|
||||
}
|
||||
|
||||
bool LFBTextBuffer::GetCursorEnabled() const
|
||||
{
|
||||
return cursorenabled;
|
||||
}
|
||||
|
||||
void LFBTextBuffer::SetCursorEnabled(bool enablecursor)
|
||||
{
|
||||
bool updatecursor = cursorenabled != enablecursor;
|
||||
cursorenabled = enablecursor;
|
||||
if ( updatecursor )
|
||||
RenderCharAt(cursorpos);
|
||||
}
|
||||
|
||||
TextPos LFBTextBuffer::GetCursorPos() const
|
||||
{
|
||||
return cursorpos;
|
||||
}
|
||||
|
||||
void LFBTextBuffer::SetCursorPos(TextPos newcursorpos)
|
||||
{
|
||||
TextPos oldcursorpos = cursorpos;
|
||||
cursorpos = newcursorpos;
|
||||
RenderCharAt(oldcursorpos);
|
||||
RenderCharAt(newcursorpos);
|
||||
}
|
||||
|
||||
size_t LFBTextBuffer::OffsetOfPos(TextPos pos) const
|
||||
{
|
||||
return pos.y * columns + pos.x;
|
||||
}
|
||||
|
||||
void LFBTextBuffer::Scroll(ssize_t off, TextChar fillwith)
|
||||
{
|
||||
if ( !off )
|
||||
return;
|
||||
bool neg = 0 < off;
|
||||
size_t absoff = off < 0 ? -off : off;
|
||||
if ( rows < absoff )
|
||||
absoff = rows;
|
||||
TextPos scrollfrom = neg ? TextPos{0, absoff} : TextPos{0, 0};
|
||||
TextPos scrollto = neg ? TextPos{0, 0} : TextPos{0, absoff};
|
||||
TextPos fillfrom = neg ? TextPos{0, rows-absoff} : TextPos{0, 0};
|
||||
TextPos fillto = neg ? TextPos{columns-1, rows-1} : TextPos{columns-1, absoff-1};
|
||||
size_t scrollchars = columns * (rows-absoff);
|
||||
Move(scrollto, scrollfrom, scrollchars);
|
||||
Fill(fillfrom, fillto, fillwith, 0);
|
||||
}
|
||||
|
||||
void LFBTextBuffer::Move(TextPos to, TextPos from, size_t numchars)
|
||||
{
|
||||
to = CropPosition(to);
|
||||
from = CropPosition(from);
|
||||
size_t dest = OffsetOfPos(to);
|
||||
size_t src = OffsetOfPos(from);
|
||||
if ( dest < src )
|
||||
for ( size_t i = 0; i < numchars; i++ )
|
||||
chars[dest + i] = chars[src + i],
|
||||
attrs[dest + i] = attrs[src + i];
|
||||
else if ( src < dest )
|
||||
for ( size_t i = 0; i < numchars; i++ )
|
||||
chars[dest + numchars-1 - i] = chars[src + numchars-1 - i],
|
||||
attrs[dest + numchars-1 - i] = attrs[src + numchars-1 - i];
|
||||
TextPos toend = AddToPosition(to, numchars);
|
||||
RenderRange(to, toend);
|
||||
}
|
||||
|
||||
void LFBTextBuffer::Fill(TextPos from, TextPos to, TextChar fillwith,
|
||||
uint16_t fillattr)
|
||||
{
|
||||
from = CropPosition(from);
|
||||
to = CropPosition(to);
|
||||
size_t start = OffsetOfPos(from);
|
||||
size_t end = OffsetOfPos(to);
|
||||
size_t entry = CharToTextEntry(fillwith);
|
||||
for ( size_t i = start; i <= end; i++ )
|
||||
chars[i] = entry,
|
||||
attrs[i] = fillattr;
|
||||
RenderRange(from, to);
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
114
sortix/lfbtextbuffer.h
Normal file
114
sortix/lfbtextbuffer.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
lfbtextbuffer.h
|
||||
An indexable text buffer rendered to a graphical linear frame buffer.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_LFBTEXTBUFFER_H
|
||||
#define SORTIX_LFBTEXTBUFFER_H
|
||||
|
||||
#include <sortix/kernel/textbuffer.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
// Needed information:
|
||||
// Linear frame bufer
|
||||
// - Pointer
|
||||
// - Format (bit depth)
|
||||
// - X resolution, Y resolution, scanline size
|
||||
// Font
|
||||
// - Pointer to our copy of the font.
|
||||
// Color table for each VGA color in <sortix/vga.h>
|
||||
// Number of columns and rows.
|
||||
// Table of characters and attributes.
|
||||
|
||||
struct LFBTextBufferInfo
|
||||
{
|
||||
uint8_t* lfb;
|
||||
size_t lfbformat;
|
||||
size_t xres;
|
||||
size_t yres;
|
||||
size_t columns;
|
||||
size_t rows;
|
||||
uint16_t* chars;
|
||||
uint16_t* attrs;
|
||||
uint8_t* vgafont;
|
||||
};
|
||||
|
||||
class LFBTextBuffer : public TextBuffer
|
||||
{
|
||||
friend LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat,
|
||||
size_t xres, size_t yres,
|
||||
size_t scansize);
|
||||
private:
|
||||
LFBTextBuffer();
|
||||
|
||||
public:
|
||||
virtual ~LFBTextBuffer();
|
||||
virtual size_t Width() const;
|
||||
virtual size_t Height() const;
|
||||
virtual TextChar GetChar(TextPos pos) const;
|
||||
virtual void SetChar(TextPos pos, TextChar c);
|
||||
virtual uint16_t GetCharAttr(TextPos pos) const;
|
||||
virtual void SetCharAttr(TextPos pos, uint16_t attrval);
|
||||
virtual void Scroll(ssize_t off, TextChar fillwith);
|
||||
virtual void Move(TextPos to, TextPos from, size_t numchars);
|
||||
virtual void Fill(TextPos from, TextPos to, TextChar fillwith,
|
||||
uint16_t fillattr);
|
||||
virtual bool GetCursorEnabled() const;
|
||||
virtual void SetCursorEnabled(bool enablecursor);
|
||||
virtual TextPos GetCursorPos() const;
|
||||
virtual void SetCursorPos(TextPos newcursorpos);
|
||||
|
||||
private:
|
||||
void RenderChar(uint16_t vgachar, size_t posx, size_t posy);
|
||||
void RenderCharAt(TextPos pos);
|
||||
void RenderRegion(size_t c1, size_t r1, size_t c2, size_t r2);
|
||||
void RenderRange(TextPos from, TextPos to);
|
||||
bool UsablePosition(TextPos pos) const;
|
||||
size_t OffsetOfPos(TextPos pos) const;
|
||||
TextPos CropPosition(TextPos pos) const;
|
||||
TextPos AddToPosition(TextPos pos, size_t count);
|
||||
|
||||
private:
|
||||
uint8_t* lfb;
|
||||
uint8_t* font;
|
||||
uint16_t* chars;
|
||||
uint16_t* attrs;
|
||||
size_t columns;
|
||||
size_t rows;
|
||||
size_t pixelsx;
|
||||
size_t pixelsy;
|
||||
size_t scansize;
|
||||
uint32_t colors[16UL];
|
||||
uint32_t cursorcolor;
|
||||
uint32_t lfbformat;
|
||||
bool cursorenabled;
|
||||
TextPos cursorpos;
|
||||
|
||||
};
|
||||
|
||||
LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat,
|
||||
size_t xres, size_t yres, size_t scansize);
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue