1160bd2ffSMichael Lotz /*
2160bd2ffSMichael Lotz * ViewBuffer - Mimicing a frame buffer output - but using a BView.
3160bd2ffSMichael Lotz * Based on frame_buffer_console.
4160bd2ffSMichael Lotz *
5160bd2ffSMichael Lotz * Copyright 2005 Michael Lotz. All rights reserved.
6*47a21c5cSAugustin Cavalier * Distributed under the MIT License.
7160bd2ffSMichael Lotz *
8160bd2ffSMichael Lotz * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
9160bd2ffSMichael Lotz * Distributed under the terms of the MIT License.
10160bd2ffSMichael Lotz */
11160bd2ffSMichael Lotz
128b0aee9fSStephan Aßmus #include <string.h>
138b0aee9fSStephan Aßmus
14160bd2ffSMichael Lotz #include "ViewBuffer.h"
15160bd2ffSMichael Lotz
16160bd2ffSMichael Lotz #define CHAR_WIDTH 7
1752e1c3c0SMichael Lotz #define CHAR_HEIGHT 13
18160bd2ffSMichael Lotz
19160bd2ffSMichael Lotz // Palette is (black and white are swapt like in normal BeOS Terminal)
20160bd2ffSMichael Lotz // 0 - black,
21160bd2ffSMichael Lotz // 1 - blue,
22160bd2ffSMichael Lotz // 2 - green,
23160bd2ffSMichael Lotz // 3 - cyan,
24160bd2ffSMichael Lotz // 4 - red,
25160bd2ffSMichael Lotz // 5 - magenta,
26160bd2ffSMichael Lotz // 6 - yellow,
27160bd2ffSMichael Lotz // 7 - white
28160bd2ffSMichael Lotz // 8-15 - same but bright (we're ignoring those)
29160bd2ffSMichael Lotz
30160bd2ffSMichael Lotz static uint32 sPalette32[] = {
31160bd2ffSMichael Lotz 0xffffff,
32160bd2ffSMichael Lotz 0x0000ff,
33160bd2ffSMichael Lotz 0x00ff00,
34160bd2ffSMichael Lotz 0x00ffff,
35160bd2ffSMichael Lotz 0xff0000,
36160bd2ffSMichael Lotz 0xff00ff,
37160bd2ffSMichael Lotz 0xffff00,
38160bd2ffSMichael Lotz 0x000000,
39160bd2ffSMichael Lotz };
40160bd2ffSMichael Lotz
41160bd2ffSMichael Lotz
ViewBuffer(BRect frame)42160bd2ffSMichael Lotz ViewBuffer::ViewBuffer(BRect frame)
438b0aee9fSStephan Aßmus : BView(frame, "ViewBuffer", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS),
448b0aee9fSStephan Aßmus fColumns(frame.IntegerWidth() / CHAR_WIDTH),
458b0aee9fSStephan Aßmus fRows(frame.IntegerHeight() / CHAR_HEIGHT),
468b0aee9fSStephan Aßmus fGlyphGrid(NULL),
478b0aee9fSStephan Aßmus fResizeCallback(NULL),
488b0aee9fSStephan Aßmus // initially, the cursor is hidden
498b0aee9fSStephan Aßmus fCursorX(-1),
508b0aee9fSStephan Aßmus fCursorY(-1)
51160bd2ffSMichael Lotz {
52160bd2ffSMichael Lotz SetFont(be_fixed_font);
53160bd2ffSMichael Lotz
54160bd2ffSMichael Lotz // initialize private palette
55160bd2ffSMichael Lotz for (int i = 0; i < 8; i++) {
56160bd2ffSMichael Lotz fPalette[i].red = (sPalette32[i] >> 16) & 0xff;
57160bd2ffSMichael Lotz fPalette[i].green = (sPalette32[i] >> 8) & 0xff;
58160bd2ffSMichael Lotz fPalette[i].blue = (sPalette32[i] >> 0) & 0xff;
59160bd2ffSMichael Lotz fPalette[i].alpha = 0xff;
60160bd2ffSMichael Lotz }
618b0aee9fSStephan Aßmus
628b0aee9fSStephan Aßmus // initialize glyph grid
638b0aee9fSStephan Aßmus uint32 size = fRows * fColumns;
648b0aee9fSStephan Aßmus if (size > 0) {
658b0aee9fSStephan Aßmus fGlyphGrid = new uint16[size];
668b0aee9fSStephan Aßmus memset(fGlyphGrid, 0, size * sizeof(uint16));
678b0aee9fSStephan Aßmus }
68160bd2ffSMichael Lotz }
69160bd2ffSMichael Lotz
70160bd2ffSMichael Lotz
~ViewBuffer()71160bd2ffSMichael Lotz ViewBuffer::~ViewBuffer()
72160bd2ffSMichael Lotz {
738b0aee9fSStephan Aßmus delete[] fGlyphGrid;
74160bd2ffSMichael Lotz }
75160bd2ffSMichael Lotz
76160bd2ffSMichael Lotz
77160bd2ffSMichael Lotz void
FrameResized(float width,float height)78160bd2ffSMichael Lotz ViewBuffer::FrameResized(float width, float height)
79160bd2ffSMichael Lotz {
808b0aee9fSStephan Aßmus int32 oldColumns = fColumns;
818b0aee9fSStephan Aßmus int32 oldRows = fRows;
828b0aee9fSStephan Aßmus
83160bd2ffSMichael Lotz fColumns = (int32)width / CHAR_WIDTH;
84160bd2ffSMichael Lotz fRows = (int32)height / CHAR_HEIGHT;
85160bd2ffSMichael Lotz
868b0aee9fSStephan Aßmus // resize glyph grid
878b0aee9fSStephan Aßmus uint16* oldGlyphGrid = fGlyphGrid;
888b0aee9fSStephan Aßmus uint32 size = fRows * fColumns;
898b0aee9fSStephan Aßmus if (size > 0) {
908b0aee9fSStephan Aßmus fGlyphGrid = new uint16[size];
918b0aee9fSStephan Aßmus memset(fGlyphGrid, 0, size * sizeof(uint16));
928b0aee9fSStephan Aßmus } else
938b0aee9fSStephan Aßmus fGlyphGrid = NULL;
948b0aee9fSStephan Aßmus // transfer old glyph grid into new one
958b0aee9fSStephan Aßmus if (oldGlyphGrid && fGlyphGrid) {
968b0aee9fSStephan Aßmus int32 columns = min_c(oldColumns, fColumns);
978b0aee9fSStephan Aßmus int32 rows = min_c(oldRows, fRows);
988b0aee9fSStephan Aßmus for (int32 y = 0; y < rows; y++) {
998b0aee9fSStephan Aßmus for (int32 x = 0; x < columns; x++) {
1008b0aee9fSStephan Aßmus fGlyphGrid[y * fColumns + x] = oldGlyphGrid[y * oldColumns + x];
1018b0aee9fSStephan Aßmus }
1028b0aee9fSStephan Aßmus }
1038b0aee9fSStephan Aßmus }
1048b0aee9fSStephan Aßmus delete[] oldGlyphGrid;
1058b0aee9fSStephan Aßmus
106160bd2ffSMichael Lotz if (fResizeCallback)
107160bd2ffSMichael Lotz fResizeCallback(fColumns, fRows, fResizeCallbackData);
108160bd2ffSMichael Lotz }
109160bd2ffSMichael Lotz
110160bd2ffSMichael Lotz
111160bd2ffSMichael Lotz status_t
GetSize(int32 * width,int32 * height)112160bd2ffSMichael Lotz ViewBuffer::GetSize(int32 *width, int32 *height)
113160bd2ffSMichael Lotz {
114160bd2ffSMichael Lotz *width = fColumns;
115160bd2ffSMichael Lotz *height = fRows;
116160bd2ffSMichael Lotz return B_OK;
117160bd2ffSMichael Lotz }
118160bd2ffSMichael Lotz
119160bd2ffSMichael Lotz
120160bd2ffSMichael Lotz void
SetResizeCallback(resize_callback callback,void * data)121160bd2ffSMichael Lotz ViewBuffer::SetResizeCallback(resize_callback callback, void *data)
122160bd2ffSMichael Lotz {
123160bd2ffSMichael Lotz fResizeCallback = callback;
124160bd2ffSMichael Lotz fResizeCallbackData = data;
125160bd2ffSMichael Lotz }
126160bd2ffSMichael Lotz
127160bd2ffSMichael Lotz
128160bd2ffSMichael Lotz uint8
ForegroundColor(uint8 attr)129160bd2ffSMichael Lotz ViewBuffer::ForegroundColor(uint8 attr)
130160bd2ffSMichael Lotz {
131160bd2ffSMichael Lotz return attr & 0x7;
132160bd2ffSMichael Lotz }
133160bd2ffSMichael Lotz
134160bd2ffSMichael Lotz
135160bd2ffSMichael Lotz uint8
BackgroundColor(uint8 attr)136160bd2ffSMichael Lotz ViewBuffer::BackgroundColor(uint8 attr)
137160bd2ffSMichael Lotz {
138160bd2ffSMichael Lotz return (attr >> 4) & 0x7;
139160bd2ffSMichael Lotz }
140160bd2ffSMichael Lotz
141160bd2ffSMichael Lotz
142160bd2ffSMichael Lotz rgb_color
GetPaletteEntry(uint8 index)143160bd2ffSMichael Lotz ViewBuffer::GetPaletteEntry(uint8 index)
144160bd2ffSMichael Lotz {
145160bd2ffSMichael Lotz return fPalette[index];
146160bd2ffSMichael Lotz }
147160bd2ffSMichael Lotz
148160bd2ffSMichael Lotz
149160bd2ffSMichael Lotz void
PutGlyph(int32 x,int32 y,uint8 glyph,uint8 attr)150160bd2ffSMichael Lotz ViewBuffer::PutGlyph(int32 x, int32 y, uint8 glyph, uint8 attr)
151160bd2ffSMichael Lotz {
152160bd2ffSMichael Lotz if (x >= fColumns || y >= fRows)
153160bd2ffSMichael Lotz return;
154160bd2ffSMichael Lotz
155160bd2ffSMichael Lotz RenderGlyph(x, y, glyph, attr);
156160bd2ffSMichael Lotz }
157160bd2ffSMichael Lotz
158160bd2ffSMichael Lotz
159160bd2ffSMichael Lotz void
FillGlyph(int32 x,int32 y,int32 width,int32 height,uint8 glyph,uint8 attr)160160bd2ffSMichael Lotz ViewBuffer::FillGlyph(int32 x, int32 y, int32 width, int32 height, uint8 glyph, uint8 attr)
161160bd2ffSMichael Lotz {
162160bd2ffSMichael Lotz if (x >= fColumns || y >= fRows)
163160bd2ffSMichael Lotz return;
164160bd2ffSMichael Lotz
165160bd2ffSMichael Lotz int32 left = x + width;
166160bd2ffSMichael Lotz if (left > fColumns)
167160bd2ffSMichael Lotz left = fColumns;
168160bd2ffSMichael Lotz
169160bd2ffSMichael Lotz int32 bottom = y + height;
170160bd2ffSMichael Lotz if (bottom > fRows)
171160bd2ffSMichael Lotz bottom = fRows;
172160bd2ffSMichael Lotz
173160bd2ffSMichael Lotz for (; y < bottom; y++) {
174160bd2ffSMichael Lotz for (int32 x2 = x; x2 < left; x2++) {
175160bd2ffSMichael Lotz RenderGlyph(x2, y, glyph, attr);
176160bd2ffSMichael Lotz }
177160bd2ffSMichael Lotz }
178160bd2ffSMichael Lotz }
179160bd2ffSMichael Lotz
180160bd2ffSMichael Lotz
181160bd2ffSMichael Lotz void
RenderGlyph(int32 x,int32 y,uint8 glyph,uint8 attr)182160bd2ffSMichael Lotz ViewBuffer::RenderGlyph(int32 x, int32 y, uint8 glyph, uint8 attr)
183160bd2ffSMichael Lotz {
184160bd2ffSMichael Lotz char string[2];
185160bd2ffSMichael Lotz string[0] = glyph;
186160bd2ffSMichael Lotz string[1] = 0;
187160bd2ffSMichael Lotz
188160bd2ffSMichael Lotz if (LockLooper()) {
1898b0aee9fSStephan Aßmus _RenderGlyph(x, y, string, attr);
190160bd2ffSMichael Lotz Sync();
191160bd2ffSMichael Lotz UnlockLooper();
192160bd2ffSMichael Lotz }
1938b0aee9fSStephan Aßmus // remember the glyph in the grid
1948b0aee9fSStephan Aßmus if (fGlyphGrid) {
1958b0aee9fSStephan Aßmus fGlyphGrid[y * fColumns + x] = (glyph << 8) | attr;
1968b0aee9fSStephan Aßmus }
1978b0aee9fSStephan Aßmus }
1988b0aee9fSStephan Aßmus
1998b0aee9fSStephan Aßmus
2008b0aee9fSStephan Aßmus void
Draw(BRect updateRect)2018b0aee9fSStephan Aßmus ViewBuffer::Draw(BRect updateRect)
2028b0aee9fSStephan Aßmus {
2038b0aee9fSStephan Aßmus if (fGlyphGrid) {
2048b0aee9fSStephan Aßmus int32 startX = max_c(0, (int32)(updateRect.left / CHAR_WIDTH));
2058b0aee9fSStephan Aßmus int32 endX = min_c(fColumns - 1, (int32)(updateRect.right / CHAR_WIDTH) + 1);
2068b0aee9fSStephan Aßmus int32 startY = max_c(0, (int32)(updateRect.top / CHAR_HEIGHT));
2078b0aee9fSStephan Aßmus int32 endY = min_c(fRows - 1, (int32)(updateRect.bottom / CHAR_HEIGHT) + 1);
2088b0aee9fSStephan Aßmus
2098b0aee9fSStephan Aßmus char string[2];
2108b0aee9fSStephan Aßmus string[1] = 0;
2118b0aee9fSStephan Aßmus
2128b0aee9fSStephan Aßmus for (int32 y = startY; y <= endY; y++) {
2138b0aee9fSStephan Aßmus for (int32 x = startX; x <= endX; x++) {
2148b0aee9fSStephan Aßmus uint16 grid = fGlyphGrid[y * fColumns + x];
2158b0aee9fSStephan Aßmus uint8 glyph = grid >> 8;
2168b0aee9fSStephan Aßmus uint8 attr = grid & 0x00ff;
2178b0aee9fSStephan Aßmus string[0] = glyph;
2188b0aee9fSStephan Aßmus _RenderGlyph(x, y, string, attr, false);
2198b0aee9fSStephan Aßmus }
2208b0aee9fSStephan Aßmus }
2218b0aee9fSStephan Aßmus }
2228b0aee9fSStephan Aßmus
2238b0aee9fSStephan Aßmus DrawCursor(fCursorX, fCursorY);
224160bd2ffSMichael Lotz }
225160bd2ffSMichael Lotz
226160bd2ffSMichael Lotz
227160bd2ffSMichael Lotz void
DrawCursor(int32 x,int32 y)228160bd2ffSMichael Lotz ViewBuffer::DrawCursor(int32 x, int32 y)
229160bd2ffSMichael Lotz {
230160bd2ffSMichael Lotz if (x < 0 || y < 0)
231160bd2ffSMichael Lotz return;
232160bd2ffSMichael Lotz
233160bd2ffSMichael Lotz x *= CHAR_WIDTH;
234160bd2ffSMichael Lotz y *= CHAR_HEIGHT;
235160bd2ffSMichael Lotz
236160bd2ffSMichael Lotz if (LockLooper()) {
237160bd2ffSMichael Lotz InvertRect(BRect(x, y, x + CHAR_WIDTH, y + CHAR_HEIGHT));
238160bd2ffSMichael Lotz Sync();
239160bd2ffSMichael Lotz UnlockLooper();
240160bd2ffSMichael Lotz }
241160bd2ffSMichael Lotz }
242160bd2ffSMichael Lotz
243160bd2ffSMichael Lotz
244160bd2ffSMichael Lotz void
MoveCursor(int32 x,int32 y)245160bd2ffSMichael Lotz ViewBuffer::MoveCursor(int32 x, int32 y)
246160bd2ffSMichael Lotz {
247160bd2ffSMichael Lotz DrawCursor(fCursorX, fCursorY);
248160bd2ffSMichael Lotz DrawCursor(x, y);
249160bd2ffSMichael Lotz
250160bd2ffSMichael Lotz fCursorX = x;
251160bd2ffSMichael Lotz fCursorY = y;
252160bd2ffSMichael Lotz }
253160bd2ffSMichael Lotz
254160bd2ffSMichael Lotz
255160bd2ffSMichael Lotz void
Blit(int32 srcx,int32 srcy,int32 width,int32 height,int32 destx,int32 desty)256160bd2ffSMichael Lotz ViewBuffer::Blit(int32 srcx, int32 srcy, int32 width, int32 height, int32 destx, int32 desty)
257160bd2ffSMichael Lotz {
2588b0aee9fSStephan Aßmus // blit inside the glyph grid
2598b0aee9fSStephan Aßmus if (fGlyphGrid) {
2608b0aee9fSStephan Aßmus int32 xOffset = destx - srcx;
2618b0aee9fSStephan Aßmus int32 yOffset = desty - srcy;
2628b0aee9fSStephan Aßmus
2638b0aee9fSStephan Aßmus int32 xIncrement;
2648b0aee9fSStephan Aßmus int32 yIncrement;
2658b0aee9fSStephan Aßmus
2668b0aee9fSStephan Aßmus uint16* src = fGlyphGrid + srcy * fColumns + srcx;
2678b0aee9fSStephan Aßmus
2688b0aee9fSStephan Aßmus if (xOffset > 0) {
2698b0aee9fSStephan Aßmus // copy from right to left
2708b0aee9fSStephan Aßmus xIncrement = -1;
2718b0aee9fSStephan Aßmus src += width - 1;
2728b0aee9fSStephan Aßmus } else {
2738b0aee9fSStephan Aßmus // copy from left to right
2748b0aee9fSStephan Aßmus xIncrement = 1;
2758b0aee9fSStephan Aßmus }
2768b0aee9fSStephan Aßmus
2778b0aee9fSStephan Aßmus if (yOffset > 0) {
2788b0aee9fSStephan Aßmus // copy from bottom to top
2798b0aee9fSStephan Aßmus yIncrement = -fColumns;
2808b0aee9fSStephan Aßmus src += (height - 1) * fColumns;
2818b0aee9fSStephan Aßmus } else {
2828b0aee9fSStephan Aßmus // copy from top to bottom
2838b0aee9fSStephan Aßmus yIncrement = fColumns;
2848b0aee9fSStephan Aßmus }
2858b0aee9fSStephan Aßmus
2868b0aee9fSStephan Aßmus uint16* dst = src + yOffset * fColumns + xOffset;
2878b0aee9fSStephan Aßmus
2888b0aee9fSStephan Aßmus for (int32 y = 0; y < height; y++) {
2898b0aee9fSStephan Aßmus uint16* srcHandle = src;
2908b0aee9fSStephan Aßmus uint16* dstHandle = dst;
2918b0aee9fSStephan Aßmus for (int32 x = 0; x < width; x++) {
2928b0aee9fSStephan Aßmus *dstHandle = *srcHandle;
2938b0aee9fSStephan Aßmus srcHandle += xIncrement;
2948b0aee9fSStephan Aßmus dstHandle += xIncrement;
2958b0aee9fSStephan Aßmus }
2968b0aee9fSStephan Aßmus src += yIncrement;
2978b0aee9fSStephan Aßmus dst += yIncrement;
2988b0aee9fSStephan Aßmus }
2998b0aee9fSStephan Aßmus }
3008b0aee9fSStephan Aßmus
301160bd2ffSMichael Lotz height *= CHAR_HEIGHT;
302160bd2ffSMichael Lotz width *= CHAR_WIDTH;
303160bd2ffSMichael Lotz
304160bd2ffSMichael Lotz srcx *= CHAR_WIDTH;
305160bd2ffSMichael Lotz srcy *= CHAR_HEIGHT;
306160bd2ffSMichael Lotz BRect source(srcx, srcy, srcx + width, srcy + height);
307160bd2ffSMichael Lotz
308160bd2ffSMichael Lotz destx *= CHAR_WIDTH;
309160bd2ffSMichael Lotz desty *= CHAR_HEIGHT;
310160bd2ffSMichael Lotz BRect dest(destx, desty, destx + width, desty + height);
311160bd2ffSMichael Lotz
312160bd2ffSMichael Lotz if (LockLooper()) {
313160bd2ffSMichael Lotz CopyBits(source, dest);
314160bd2ffSMichael Lotz Sync();
315160bd2ffSMichael Lotz UnlockLooper();
316160bd2ffSMichael Lotz }
317160bd2ffSMichael Lotz }
318160bd2ffSMichael Lotz
319160bd2ffSMichael Lotz
320160bd2ffSMichael Lotz void
Clear(uint8 attr)321160bd2ffSMichael Lotz ViewBuffer::Clear(uint8 attr)
322160bd2ffSMichael Lotz {
323160bd2ffSMichael Lotz if (LockLooper()) {
324160bd2ffSMichael Lotz SetLowColor(GetPaletteEntry(BackgroundColor(attr)));
325160bd2ffSMichael Lotz SetViewColor(LowColor());
326160bd2ffSMichael Lotz FillRect(Frame(), B_SOLID_LOW);
327160bd2ffSMichael Lotz Sync();
328160bd2ffSMichael Lotz UnlockLooper();
329160bd2ffSMichael Lotz }
330160bd2ffSMichael Lotz
331160bd2ffSMichael Lotz fCursorX = -1;
332160bd2ffSMichael Lotz fCursorY = -1;
3338b0aee9fSStephan Aßmus
3348b0aee9fSStephan Aßmus if (fGlyphGrid)
3358b0aee9fSStephan Aßmus memset(fGlyphGrid, 0, fRows * fColumns * sizeof(uint16));
336160bd2ffSMichael Lotz }
3378b0aee9fSStephan Aßmus
3388b0aee9fSStephan Aßmus
3398b0aee9fSStephan Aßmus void
_RenderGlyph(int32 x,int32 y,const char * string,uint8 attr,bool fill)3408b0aee9fSStephan Aßmus ViewBuffer::_RenderGlyph(int32 x, int32 y, const char* string, uint8 attr, bool fill)
3418b0aee9fSStephan Aßmus {
3428b0aee9fSStephan Aßmus BPoint where(x * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT - 3);
3438b0aee9fSStephan Aßmus
3448b0aee9fSStephan Aßmus SetHighColor(GetPaletteEntry(ForegroundColor(attr)));
3458b0aee9fSStephan Aßmus if (fill) {
3468b0aee9fSStephan Aßmus SetLowColor(GetPaletteEntry(BackgroundColor(attr)));
3478b0aee9fSStephan Aßmus FillRect(BRect(x * CHAR_WIDTH, y * CHAR_HEIGHT,
3488b0aee9fSStephan Aßmus (x + 1) * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT),
3498b0aee9fSStephan Aßmus B_SOLID_LOW);
3508b0aee9fSStephan Aßmus }
3518b0aee9fSStephan Aßmus DrawString(string, where);
3528b0aee9fSStephan Aßmus }
3538b0aee9fSStephan Aßmus
354