/* * 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 #include "ViewBuffer.h" #define CHAR_WIDTH 7 #define CHAR_HEIGHT 13 // Palette is (black and white are swapt like in normal BeOS Terminal) // 0 - black, // 1 - blue, // 2 - green, // 3 - cyan, // 4 - red, // 5 - magenta, // 6 - yellow, // 7 - white // 8-15 - same but bright (we're ignoring those) 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), // initially, the cursor is hidden fCursorX(-1), fCursorY(-1) { SetFont(be_fixed_font); // initialize private palette 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; } // initialize glyph grid 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; // resize glyph grid uint16* oldGlyphGrid = fGlyphGrid; uint32 size = fRows * fColumns; if (size > 0) { fGlyphGrid = new uint16[size]; memset(fGlyphGrid, 0, size * sizeof(uint16)); } else fGlyphGrid = NULL; // transfer old glyph grid into new one 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(); } // remember the glyph in the grid 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) { // blit inside the glyph grid if (fGlyphGrid) { int32 xOffset = destx - srcx; int32 yOffset = desty - srcy; int32 xIncrement; int32 yIncrement; uint16* src = fGlyphGrid + srcy * fColumns + srcx; if (xOffset > 0) { // copy from right to left xIncrement = -1; src += width - 1; } else { // copy from left to right xIncrement = 1; } if (yOffset > 0) { // copy from bottom to top yIncrement = -fColumns; src += (height - 1) * fColumns; } else { // copy from top to bottom 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); }