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 30 static uint32 sPalette32[] = { 31 0xffffff, 32 0x0000ff, 33 0x00ff00, 34 0x00ffff, 35 0xff0000, 36 0xff00ff, 37 0xffff00, 38 0x000000, 39 }; 40 41 42 ViewBuffer::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 71 ViewBuffer::~ViewBuffer() 72 { 73 delete[] fGlyphGrid; 74 } 75 76 77 void 78 ViewBuffer::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 111 status_t 112 ViewBuffer::GetSize(int32 *width, int32 *height) 113 { 114 *width = fColumns; 115 *height = fRows; 116 return B_OK; 117 } 118 119 120 void 121 ViewBuffer::SetResizeCallback(resize_callback callback, void *data) 122 { 123 fResizeCallback = callback; 124 fResizeCallbackData = data; 125 } 126 127 128 uint8 129 ViewBuffer::ForegroundColor(uint8 attr) 130 { 131 return attr & 0x7; 132 } 133 134 135 uint8 136 ViewBuffer::BackgroundColor(uint8 attr) 137 { 138 return (attr >> 4) & 0x7; 139 } 140 141 142 rgb_color 143 ViewBuffer::GetPaletteEntry(uint8 index) 144 { 145 return fPalette[index]; 146 } 147 148 149 void 150 ViewBuffer::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 159 void 160 ViewBuffer::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 181 void 182 ViewBuffer::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 200 void 201 ViewBuffer::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 227 void 228 ViewBuffer::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 244 void 245 ViewBuffer::MoveCursor(int32 x, int32 y) 246 { 247 DrawCursor(fCursorX, fCursorY); 248 DrawCursor(x, y); 249 250 fCursorX = x; 251 fCursorY = y; 252 } 253 254 255 void 256 ViewBuffer::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 320 void 321 ViewBuffer::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 339 void 340 ViewBuffer::_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