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
ViewBuffer(BRect frame)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
~ViewBuffer()71 ViewBuffer::~ViewBuffer()
72 {
73 delete[] fGlyphGrid;
74 }
75
76
77 void
FrameResized(float width,float height)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
GetSize(int32 * width,int32 * height)112 ViewBuffer::GetSize(int32 *width, int32 *height)
113 {
114 *width = fColumns;
115 *height = fRows;
116 return B_OK;
117 }
118
119
120 void
SetResizeCallback(resize_callback callback,void * data)121 ViewBuffer::SetResizeCallback(resize_callback callback, void *data)
122 {
123 fResizeCallback = callback;
124 fResizeCallbackData = data;
125 }
126
127
128 uint8
ForegroundColor(uint8 attr)129 ViewBuffer::ForegroundColor(uint8 attr)
130 {
131 return attr & 0x7;
132 }
133
134
135 uint8
BackgroundColor(uint8 attr)136 ViewBuffer::BackgroundColor(uint8 attr)
137 {
138 return (attr >> 4) & 0x7;
139 }
140
141
142 rgb_color
GetPaletteEntry(uint8 index)143 ViewBuffer::GetPaletteEntry(uint8 index)
144 {
145 return fPalette[index];
146 }
147
148
149 void
PutGlyph(int32 x,int32 y,uint8 glyph,uint8 attr)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
FillGlyph(int32 x,int32 y,int32 width,int32 height,uint8 glyph,uint8 attr)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
RenderGlyph(int32 x,int32 y,uint8 glyph,uint8 attr)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
Draw(BRect updateRect)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
DrawCursor(int32 x,int32 y)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
MoveCursor(int32 x,int32 y)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
Blit(int32 srcx,int32 srcy,int32 width,int32 height,int32 destx,int32 desty)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
Clear(uint8 attr)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
_RenderGlyph(int32 x,int32 y,const char * string,uint8 attr,bool fill)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