* ViewBuffer - Mimicing a frame buffer output - but using a BView.
* Based on frame_buffer_console.
*
* Copyright 2005 Michael Lotz. All rights reserved.
* Distributed under the Haiku License.
*
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <string.h>
#include "ViewBuffer.h"
#define CHAR_WIDTH 7
#define CHAR_HEIGHT 13
static uint32 sPalette32[] = {
0xffffff,
0x0000ff,
0x00ff00,
0x00ffff,
0xff0000,
0xff00ff,
0xffff00,
0x000000,
};
ViewBuffer::ViewBuffer(BRect frame)
: BView(frame, "ViewBuffer", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS),
fColumns(frame.IntegerWidth() / CHAR_WIDTH),
fRows(frame.IntegerHeight() / CHAR_HEIGHT),
fGlyphGrid(NULL),
fResizeCallback(NULL),
fCursorX(-1),
fCursorY(-1)
{
SetFont(be_fixed_font);
for (int i = 0; i < 8; i++) {
fPalette[i].red = (sPalette32[i] >> 16) & 0xff;
fPalette[i].green = (sPalette32[i] >> 8) & 0xff;
fPalette[i].blue = (sPalette32[i] >> 0) & 0xff;
fPalette[i].alpha = 0xff;
}
uint32 size = fRows * fColumns;
if (size > 0) {
fGlyphGrid = new uint16[size];
memset(fGlyphGrid, 0, size * sizeof(uint16));
}
}
ViewBuffer::~ViewBuffer()
{
delete[] fGlyphGrid;
}
void
ViewBuffer::FrameResized(float width, float height)
{
int32 oldColumns = fColumns;
int32 oldRows = fRows;
fColumns = (int32)width / CHAR_WIDTH;
fRows = (int32)height / CHAR_HEIGHT;
uint16* oldGlyphGrid = fGlyphGrid;
uint32 size = fRows * fColumns;
if (size > 0) {
fGlyphGrid = new uint16[size];
memset(fGlyphGrid, 0, size * sizeof(uint16));
} else
fGlyphGrid = NULL;
if (oldGlyphGrid && fGlyphGrid) {
int32 columns = min_c(oldColumns, fColumns);
int32 rows = min_c(oldRows, fRows);
for (int32 y = 0; y < rows; y++) {
for (int32 x = 0; x < columns; x++) {
fGlyphGrid[y * fColumns + x] = oldGlyphGrid[y * oldColumns + x];
}
}
}
delete[] oldGlyphGrid;
if (fResizeCallback)
fResizeCallback(fColumns, fRows, fResizeCallbackData);
}
status_t
ViewBuffer::GetSize(int32 *width, int32 *height)
{
*width = fColumns;
*height = fRows;
return B_OK;
}
void
ViewBuffer::SetResizeCallback(resize_callback callback, void *data)
{
fResizeCallback = callback;
fResizeCallbackData = data;
}
uint8
ViewBuffer::ForegroundColor(uint8 attr)
{
return attr & 0x7;
}
uint8
ViewBuffer::BackgroundColor(uint8 attr)
{
return (attr >> 4) & 0x7;
}
rgb_color
ViewBuffer::GetPaletteEntry(uint8 index)
{
return fPalette[index];
}
void
ViewBuffer::PutGlyph(int32 x, int32 y, uint8 glyph, uint8 attr)
{
if (x >= fColumns || y >= fRows)
return;
RenderGlyph(x, y, glyph, attr);
}
void
ViewBuffer::FillGlyph(int32 x, int32 y, int32 width, int32 height, uint8 glyph, uint8 attr)
{
if (x >= fColumns || y >= fRows)
return;
int32 left = x + width;
if (left > fColumns)
left = fColumns;
int32 bottom = y + height;
if (bottom > fRows)
bottom = fRows;
for (; y < bottom; y++) {
for (int32 x2 = x; x2 < left; x2++) {
RenderGlyph(x2, y, glyph, attr);
}
}
}
void
ViewBuffer::RenderGlyph(int32 x, int32 y, uint8 glyph, uint8 attr)
{
char string[2];
string[0] = glyph;
string[1] = 0;
if (LockLooper()) {
_RenderGlyph(x, y, string, attr);
Sync();
UnlockLooper();
}
if (fGlyphGrid) {
fGlyphGrid[y * fColumns + x] = (glyph << 8) | attr;
}
}
void
ViewBuffer::Draw(BRect updateRect)
{
if (fGlyphGrid) {
int32 startX = max_c(0, (int32)(updateRect.left / CHAR_WIDTH));
int32 endX = min_c(fColumns - 1, (int32)(updateRect.right / CHAR_WIDTH) + 1);
int32 startY = max_c(0, (int32)(updateRect.top / CHAR_HEIGHT));
int32 endY = min_c(fRows - 1, (int32)(updateRect.bottom / CHAR_HEIGHT) + 1);
char string[2];
string[1] = 0;
for (int32 y = startY; y <= endY; y++) {
for (int32 x = startX; x <= endX; x++) {
uint16 grid = fGlyphGrid[y * fColumns + x];
uint8 glyph = grid >> 8;
uint8 attr = grid & 0x00ff;
string[0] = glyph;
_RenderGlyph(x, y, string, attr, false);
}
}
}
DrawCursor(fCursorX, fCursorY);
}
void
ViewBuffer::DrawCursor(int32 x, int32 y)
{
if (x < 0 || y < 0)
return;
x *= CHAR_WIDTH;
y *= CHAR_HEIGHT;
if (LockLooper()) {
InvertRect(BRect(x, y, x + CHAR_WIDTH, y + CHAR_HEIGHT));
Sync();
UnlockLooper();
}
}
void
ViewBuffer::MoveCursor(int32 x, int32 y)
{
DrawCursor(fCursorX, fCursorY);
DrawCursor(x, y);
fCursorX = x;
fCursorY = y;
}
void
ViewBuffer::Blit(int32 srcx, int32 srcy, int32 width, int32 height, int32 destx, int32 desty)
{
if (fGlyphGrid) {
int32 xOffset = destx - srcx;
int32 yOffset = desty - srcy;
int32 xIncrement;
int32 yIncrement;
uint16* src = fGlyphGrid + srcy * fColumns + srcx;
if (xOffset > 0) {
xIncrement = -1;
src += width - 1;
} else {
xIncrement = 1;
}
if (yOffset > 0) {
yIncrement = -fColumns;
src += (height - 1) * fColumns;
} else {
yIncrement = fColumns;
}
uint16* dst = src + yOffset * fColumns + xOffset;
for (int32 y = 0; y < height; y++) {
uint16* srcHandle = src;
uint16* dstHandle = dst;
for (int32 x = 0; x < width; x++) {
*dstHandle = *srcHandle;
srcHandle += xIncrement;
dstHandle += xIncrement;
}
src += yIncrement;
dst += yIncrement;
}
}
height *= CHAR_HEIGHT;
width *= CHAR_WIDTH;
srcx *= CHAR_WIDTH;
srcy *= CHAR_HEIGHT;
BRect source(srcx, srcy, srcx + width, srcy + height);
destx *= CHAR_WIDTH;
desty *= CHAR_HEIGHT;
BRect dest(destx, desty, destx + width, desty + height);
if (LockLooper()) {
CopyBits(source, dest);
Sync();
UnlockLooper();
}
}
void
ViewBuffer::Clear(uint8 attr)
{
if (LockLooper()) {
SetLowColor(GetPaletteEntry(BackgroundColor(attr)));
SetViewColor(LowColor());
FillRect(Frame(), B_SOLID_LOW);
Sync();
UnlockLooper();
}
fCursorX = -1;
fCursorY = -1;
if (fGlyphGrid)
memset(fGlyphGrid, 0, fRows * fColumns * sizeof(uint16));
}
void
ViewBuffer::_RenderGlyph(int32 x, int32 y, const char* string, uint8 attr, bool fill)
{
BPoint where(x * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT - 3);
SetHighColor(GetPaletteEntry(ForegroundColor(attr)));
if (fill) {
SetLowColor(GetPaletteEntry(BackgroundColor(attr)));
FillRect(BRect(x * CHAR_WIDTH, y * CHAR_HEIGHT,
(x + 1) * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT),
B_SOLID_LOW);
}
DrawString(string, where);
}