1/* 2 * ViewBuffer - Mimicing a frame buffer output - but using a BView. 3 * Based on frame_buffer_console. 4 * 5 * Copyright 2005 Michael Lotz. All rights reserved. 6 * Distributed under the MIT License. 7 * 8 * Copyright 2005, Axel D��rfler, axeld@pinc-software.de. All rights reserved. 9 * Distributed under the terms of the MIT License. 10 */ 11 12#include <string.h> 13 14#include "ViewBuffer.h" 15 16#define CHAR_WIDTH 7 17#define CHAR_HEIGHT 13 18 19// Palette is (black and white are swapt like in normal BeOS Terminal) 20// 0 - black, 21// 1 - blue, 22// 2 - green, 23// 3 - cyan, 24// 4 - red, 25// 5 - magenta, 26// 6 - yellow, 27// 7 - white 28// 8-15 - same but bright (we're ignoring those) 29 30static uint32 sPalette32[] = { 31 0xffffff, 32 0x0000ff, 33 0x00ff00, 34 0x00ffff, 35 0xff0000, 36 0xff00ff, 37 0xffff00, 38 0x000000, 39}; 40 41 42ViewBuffer::ViewBuffer(BRect frame) 43 : BView(frame, "ViewBuffer", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS), 44 fColumns(frame.IntegerWidth() / CHAR_WIDTH), 45 fRows(frame.IntegerHeight() / CHAR_HEIGHT), 46 fGlyphGrid(NULL), 47 fResizeCallback(NULL), 48 // initially, the cursor is hidden 49 fCursorX(-1), 50 fCursorY(-1) 51{ 52 SetFont(be_fixed_font); 53 54 // initialize private palette 55 for (int i = 0; i < 8; i++) { 56 fPalette[i].red = (sPalette32[i] >> 16) & 0xff; 57 fPalette[i].green = (sPalette32[i] >> 8) & 0xff; 58 fPalette[i].blue = (sPalette32[i] >> 0) & 0xff; 59 fPalette[i].alpha = 0xff; 60 } 61 62 // initialize glyph grid 63 uint32 size = fRows * fColumns; 64 if (size > 0) { 65 fGlyphGrid = new uint16[size]; 66 memset(fGlyphGrid, 0, size * sizeof(uint16)); 67 } 68} 69 70 71ViewBuffer::~ViewBuffer() 72{ 73 delete[] fGlyphGrid; 74} 75 76 77void 78ViewBuffer::FrameResized(float width, float height) 79{ 80 int32 oldColumns = fColumns; 81 int32 oldRows = fRows; 82 83 fColumns = (int32)width / CHAR_WIDTH; 84 fRows = (int32)height / CHAR_HEIGHT; 85 86 // resize glyph grid 87 uint16* oldGlyphGrid = fGlyphGrid; 88 uint32 size = fRows * fColumns; 89 if (size > 0) { 90 fGlyphGrid = new uint16[size]; 91 memset(fGlyphGrid, 0, size * sizeof(uint16)); 92 } else 93 fGlyphGrid = NULL; 94 // transfer old glyph grid into new one 95 if (oldGlyphGrid && fGlyphGrid) { 96 int32 columns = min_c(oldColumns, fColumns); 97 int32 rows = min_c(oldRows, fRows); 98 for (int32 y = 0; y < rows; y++) { 99 for (int32 x = 0; x < columns; x++) { 100 fGlyphGrid[y * fColumns + x] = oldGlyphGrid[y * oldColumns + x]; 101 } 102 } 103 } 104 delete[] oldGlyphGrid; 105 106 if (fResizeCallback) 107 fResizeCallback(fColumns, fRows, fResizeCallbackData); 108} 109 110 111status_t 112ViewBuffer::GetSize(int32 *width, int32 *height) 113{ 114 *width = fColumns; 115 *height = fRows; 116 return B_OK; 117} 118 119 120void 121ViewBuffer::SetResizeCallback(resize_callback callback, void *data) 122{ 123 fResizeCallback = callback; 124 fResizeCallbackData = data; 125} 126 127 128uint8 129ViewBuffer::ForegroundColor(uint8 attr) 130{ 131 return attr & 0x7; 132} 133 134 135uint8 136ViewBuffer::BackgroundColor(uint8 attr) 137{ 138 return (attr >> 4) & 0x7; 139} 140 141 142rgb_color 143ViewBuffer::GetPaletteEntry(uint8 index) 144{ 145 return fPalette[index]; 146} 147 148 149void 150ViewBuffer::PutGlyph(int32 x, int32 y, uint8 glyph, uint8 attr) 151{ 152 if (x >= fColumns || y >= fRows) 153 return; 154 155 RenderGlyph(x, y, glyph, attr); 156} 157 158 159void 160ViewBuffer::FillGlyph(int32 x, int32 y, int32 width, int32 height, uint8 glyph, uint8 attr) 161{ 162 if (x >= fColumns || y >= fRows) 163 return; 164 165 int32 left = x + width; 166 if (left > fColumns) 167 left = fColumns; 168 169 int32 bottom = y + height; 170 if (bottom > fRows) 171 bottom = fRows; 172 173 for (; y < bottom; y++) { 174 for (int32 x2 = x; x2 < left; x2++) { 175 RenderGlyph(x2, y, glyph, attr); 176 } 177 } 178} 179 180 181void 182ViewBuffer::RenderGlyph(int32 x, int32 y, uint8 glyph, uint8 attr) 183{ 184 char string[2]; 185 string[0] = glyph; 186 string[1] = 0; 187 188 if (LockLooper()) { 189 _RenderGlyph(x, y, string, attr); 190 Sync(); 191 UnlockLooper(); 192 } 193 // remember the glyph in the grid 194 if (fGlyphGrid) { 195 fGlyphGrid[y * fColumns + x] = (glyph << 8) | attr; 196 } 197} 198 199 200void 201ViewBuffer::Draw(BRect updateRect) 202{ 203 if (fGlyphGrid) { 204 int32 startX = max_c(0, (int32)(updateRect.left / CHAR_WIDTH)); 205 int32 endX = min_c(fColumns - 1, (int32)(updateRect.right / CHAR_WIDTH) + 1); 206 int32 startY = max_c(0, (int32)(updateRect.top / CHAR_HEIGHT)); 207 int32 endY = min_c(fRows - 1, (int32)(updateRect.bottom / CHAR_HEIGHT) + 1); 208 209 char string[2]; 210 string[1] = 0; 211 212 for (int32 y = startY; y <= endY; y++) { 213 for (int32 x = startX; x <= endX; x++) { 214 uint16 grid = fGlyphGrid[y * fColumns + x]; 215 uint8 glyph = grid >> 8; 216 uint8 attr = grid & 0x00ff; 217 string[0] = glyph; 218 _RenderGlyph(x, y, string, attr, false); 219 } 220 } 221 } 222 223 DrawCursor(fCursorX, fCursorY); 224} 225 226 227void 228ViewBuffer::DrawCursor(int32 x, int32 y) 229{ 230 if (x < 0 || y < 0) 231 return; 232 233 x *= CHAR_WIDTH; 234 y *= CHAR_HEIGHT; 235 236 if (LockLooper()) { 237 InvertRect(BRect(x, y, x + CHAR_WIDTH, y + CHAR_HEIGHT)); 238 Sync(); 239 UnlockLooper(); 240 } 241} 242 243 244void 245ViewBuffer::MoveCursor(int32 x, int32 y) 246{ 247 DrawCursor(fCursorX, fCursorY); 248 DrawCursor(x, y); 249 250 fCursorX = x; 251 fCursorY = y; 252} 253 254 255void 256ViewBuffer::Blit(int32 srcx, int32 srcy, int32 width, int32 height, int32 destx, int32 desty) 257{ 258 // blit inside the glyph grid 259 if (fGlyphGrid) { 260 int32 xOffset = destx - srcx; 261 int32 yOffset = desty - srcy; 262 263 int32 xIncrement; 264 int32 yIncrement; 265 266 uint16* src = fGlyphGrid + srcy * fColumns + srcx; 267 268 if (xOffset > 0) { 269 // copy from right to left 270 xIncrement = -1; 271 src += width - 1; 272 } else { 273 // copy from left to right 274 xIncrement = 1; 275 } 276 277 if (yOffset > 0) { 278 // copy from bottom to top 279 yIncrement = -fColumns; 280 src += (height - 1) * fColumns; 281 } else { 282 // copy from top to bottom 283 yIncrement = fColumns; 284 } 285 286 uint16* dst = src + yOffset * fColumns + xOffset; 287 288 for (int32 y = 0; y < height; y++) { 289 uint16* srcHandle = src; 290 uint16* dstHandle = dst; 291 for (int32 x = 0; x < width; x++) { 292 *dstHandle = *srcHandle; 293 srcHandle += xIncrement; 294 dstHandle += xIncrement; 295 } 296 src += yIncrement; 297 dst += yIncrement; 298 } 299 } 300 301 height *= CHAR_HEIGHT; 302 width *= CHAR_WIDTH; 303 304 srcx *= CHAR_WIDTH; 305 srcy *= CHAR_HEIGHT; 306 BRect source(srcx, srcy, srcx + width, srcy + height); 307 308 destx *= CHAR_WIDTH; 309 desty *= CHAR_HEIGHT; 310 BRect dest(destx, desty, destx + width, desty + height); 311 312 if (LockLooper()) { 313 CopyBits(source, dest); 314 Sync(); 315 UnlockLooper(); 316 } 317} 318 319 320void 321ViewBuffer::Clear(uint8 attr) 322{ 323 if (LockLooper()) { 324 SetLowColor(GetPaletteEntry(BackgroundColor(attr))); 325 SetViewColor(LowColor()); 326 FillRect(Frame(), B_SOLID_LOW); 327 Sync(); 328 UnlockLooper(); 329 } 330 331 fCursorX = -1; 332 fCursorY = -1; 333 334 if (fGlyphGrid) 335 memset(fGlyphGrid, 0, fRows * fColumns * sizeof(uint16)); 336} 337 338 339void 340ViewBuffer::_RenderGlyph(int32 x, int32 y, const char* string, uint8 attr, bool fill) 341{ 342 BPoint where(x * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT - 3); 343 344 SetHighColor(GetPaletteEntry(ForegroundColor(attr))); 345 if (fill) { 346 SetLowColor(GetPaletteEntry(BackgroundColor(attr))); 347 FillRect(BRect(x * CHAR_WIDTH, y * CHAR_HEIGHT, 348 (x + 1) * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT), 349 B_SOLID_LOW); 350 } 351 DrawString(string, where); 352} 353 354