Many changes:
[Marmot.git] / video.c
blob6e24f7b048d0d55d70010bcbe90db471337c2448
1 /*
2 * video.c --
4 * Video interface.
5 */
7 #include <marmot.h>
10 struct FontTable {
11 /* glyph is the 32 bit address of the glyph */
12 uint32 glyph;
13 /* width and height of the glyph in pixels */
14 uint16 w;
15 uint16 h;
16 } __attribute__((packed));
18 extern struct FontTable fontTable[];
20 extern uint8 *frameBuffer;
21 extern uint64 frameBufferSize;
23 extern uint32 physBasePtr;
24 extern uint8 bitsPerPixel;
25 extern uint16 xResolution;
26 extern uint16 yResolution;
27 extern uint8 redMaskSize;
28 extern uint8 redFieldPosition;
29 extern uint8 greenMaskSize;
30 extern uint8 greenFieldPosition;
31 extern uint8 blueMaskSize;
32 extern uint8 blueFieldPosition;
33 extern uint8 rsvdMaskSize;
34 extern uint8 rsvdFieldPosition;
36 static uint64 rMask;
37 static uint64 gMask;
38 static uint64 bMask;
39 static uint64 aMask;
43 * SetPixel --
45 * Set the pixel at x,y to the specified ARGB color.
48 void
49 SetPixel(Color color, Point p)
51 uint32 pixelValue = 0;
52 int bytesPerPixel = 1;
53 uint8 *pixel;
56 /* Convert color into local colorspace. */
58 switch (bitsPerPixel) {
59 case 32:
60 case 24:
61 bytesPerPixel = 4;
62 pixelValue = (uint32)color;
63 break;
64 case 16:
65 case 15:
66 /* 5:6:5 */
67 /* 1:5:5:5 */
68 pixelValue = (uint32)(((color >> redFieldPosition) & rMask) |
69 ((color >> greenFieldPosition) & gMask) |
70 ((color >> blueFieldPosition) & bMask) |
71 ((color >> rsvdFieldPosition) & aMask));
72 bytesPerPixel = 2;
73 break;
74 case 8:
75 case 4:
76 UNIMPLEMENTED("8 or 4 bits per pixel");
77 pixelValue = 0x80;
78 bytesPerPixel = 1;
81 /* Find pixel address */
82 pixel = frameBuffer + bytesPerPixel * (p.x + p.y * xResolution);
84 switch (bytesPerPixel) {
85 case 4:
86 *((uint32 *)pixel) = pixelValue;
87 break;
88 case 2:
89 *((uint16 *)pixel) = (uint16)pixelValue;
90 break;
91 case 1:
92 *((uint8 *)pixel) = (uint8)pixelValue;
93 break;
98 Color
99 GetPixel(Point p)
101 Color c = COLOR_BLACK;
102 uint16 pix16;
103 uint8 *pixel;
105 switch (bitsPerPixel) {
106 case 32:
107 case 24:
108 pixel = frameBuffer + 4 * (p.x + p.y * xResolution);
109 c = *((uint32 *)pixel);
110 break;
111 case 16:
112 case 15:
113 pixel = frameBuffer + 2 * (p.x + p.y * xResolution);
114 pix16 = *((uint16 *)pixel);
115 c = (((pix16 & rMask) << redFieldPosition) |
116 ((pix16 & gMask) << greenFieldPosition) |
117 ((pix16 & bMask) << blueFieldPosition) |
118 ((pix16 & aMask) << rsvdFieldPosition));
119 break;
120 case 8:
121 case 4:
122 UNIMPLEMENTED("8 or 4 bits per pixel");
123 break;
126 return c;
131 * ColorRectangle --
133 * Set a rectangular area to be the specified color.
136 void
137 ColorRectangle(Color color, Point c0, Point c1)
139 uint64 xLow, xHigh, yLow, yHigh, x, y;
141 if (c0.x == c1.x || c0.y == c1.y) {
142 return;
145 if (c0.x < c1.x) {
146 xLow = c0.x;
147 xHigh = c1.x;
148 } else {
149 xLow = c1.x;
150 xHigh = c0.x;
152 if (c0.y < c1.y) {
153 yLow = c0.y;
154 yHigh = c1.y;
155 } else {
156 yLow = c1.y;
157 yHigh = c0.y;
160 for (x = xLow; x <= xHigh; x++) {
161 for (y = yLow; y <= yHigh; y++) {
162 Point p;
164 p.x = x;
165 p.y = y;
167 SetPixel(color, p);
172 void
173 ColorCircle(Color color, Point c, Length r)
175 uint64 xl, xr, yt, yb;
176 Point p;
178 if (r == 0) {
179 return;
182 /* correct borders */
183 if (r > c.x) {
184 xl = r - c.x;
185 } else {
186 xl = 0;
188 if (c.x + r > xResolution - 1) {
189 xr = xResolution - 1;
190 } else {
191 xr = c.x + r;
193 if (r > c.y) {
194 yt = r - c.y;
195 } else {
196 yt = 0;
198 if (c.y + r > yResolution - 1) {
199 yb = yResolution - 1;
200 } else {
201 yb = c.y + r;
204 for (p.x = xl; p.x <=xr; p.x++) {
205 for (p.y = yt; p.y <= yb; p.y++) {
206 uint64 xx, yy;
208 /* limit x and y to quadrant 4 */
209 if (p.x < c.x) {
210 xx = c.x - p.x;
211 } else {
212 xx = p.x - c.x;
214 if (p.y < c.y) {
215 yy = c.y - p.y;
216 } else {
217 yy = p.y - c.y;
220 if (xx * xx + yy * yy < r * r) {
221 SetPixel(color, p);
229 * SetBootBackground --
231 * Set the screen background to the default boot color.
234 void
235 SetBootBackground(void)
237 Point p;
239 for (p.x = 0; p.x < xResolution; p.x++) {
240 for (p.y = 0; p.y < yResolution; p.y++) {
241 SetPixel(BOOT_BACKGROUND_COLOR, p);
248 * VideoInit --
250 * Calculate frame buffer size and map it into the virtual
251 * address space.
254 void
255 VideoInit(void)
257 uint64 bytesPerPixel = 0;
260 * Identity map the frame buffer.
263 frameBuffer = (uint8 *)(VA)physBasePtr;
265 switch (bitsPerPixel) {
266 case 32:
267 case 24:
268 bytesPerPixel = 4;
269 break;
270 case 16:
271 case 15:
272 bytesPerPixel = 2;
273 break;
274 default:
275 bytesPerPixel = 1;
278 frameBufferSize = xResolution * yResolution * bytesPerPixel;
280 MapIORegion((PA)frameBuffer,
281 (PA)(frameBuffer + frameBufferSize),
282 "frameBuffer");
286 * Init pixel masks.
289 rMask = ((1ULL << redMaskSize) - 1) << redFieldPosition;
290 gMask = ((1ULL << greenMaskSize) - 1) << greenFieldPosition;
291 bMask = ((1ULL << blueMaskSize) - 1) << blueFieldPosition;
292 aMask = (rsvdMaskSize ? (1ULL << rsvdMaskSize) - 1 : 0) << rsvdFieldPosition;
296 * Set a pleasing background color.
299 SetBootBackground();
303 #define PIXEL_VALUE(glyph,p) ((((glyph)[(p) >> 3]) & \
304 (1 << (7 - ((p) % 8)) )) >> \
305 (7 - ((p) % 8)))
308 * PrintMessage --
310 * Display msg at pixel coordinates x,y.
313 void
314 PrintMessage(Color color, Point where, char *msg)
316 int c;
317 uint64 xOff = 0; /* offset from start of message */
319 for (c = 0; msg[c]; c++) {
320 uint8 *glyph;
321 uint64 xp, yp;
322 int p, ch;
324 ch = msg[c];
326 glyph = (uint8 *)((VA)fontTable[ch].glyph);
327 xp = yp = 0;
329 /* loop over pixels */
330 for (p = 0; p < fontTable[ch].w * fontTable[ch].h; p++) {
332 if (PIXEL_VALUE(glyph, p) == 1) {
333 Point p;
335 p.x = where.x + xOff + xp;
336 p.y = where.y + yp;
338 SetPixel(color, p);
341 xp++;
342 if ((xp % fontTable[ch].w) == 0) {
343 xp = 0;
344 yp++;
348 xOff += fontTable[ch].w;
353 * Cursor handling.
355 * Register a callback with irq12 (will be a deferred function call).
356 * When the cursor moves, the old cursor spot is replaced with its
357 * saved spot, then the new cursor spot is saved and the cursor is
358 * drawn.
362 #include "cursor.xbm"
364 static Color savedCursor[cursor_width][cursor_height];
365 static struct {
366 int32 x;
367 int32 y;
368 int32 z;
369 unsigned int button1:1;
370 unsigned int button2:1;
371 unsigned int button3:1;
372 unsigned int button4:1;
373 unsigned int button5:1;
374 } cursorInfo;
377 static CbID cursorCbId;
379 void
380 RestoreCursorArea(void)
382 int32 x, y, sx, sy;
383 Point p;
385 for (x = 0; x < cursor_width; x++) {
386 for (y = 0; y < cursor_height; y++) {
387 sx = cursorInfo.x - cursor_x_hot + x;
388 sy = cursorInfo.y - cursor_y_hot + y;
390 if (sx < 0 || sy < 0 || sx > xResolution || sy > yResolution) {
391 continue;
394 p.x = sx;
395 p.y = sy;
396 SetPixel(savedCursor[x][y], p);
402 void
403 SaveCursorArea(void)
405 int32 x, y, sx, sy;
406 Point p;
408 for (x = 0; x < cursor_width; x++) {
409 for (y = 0; y < cursor_height; y++) {
410 sx = cursorInfo.x - cursor_x_hot + x;
411 sy = cursorInfo.y - cursor_y_hot + y;
413 if (sx < 0 || sy < 0 || sx > xResolution || sy > yResolution) {
414 continue;
417 p.x = sx;
418 p.y = sy;
419 savedCursor[x][y] = GetPixel(p);
425 /* assume 16x16 */
426 #define CURSOR_ISSET(x,y) ((cursor_bits[(x)] >> y) & 1)
428 void
429 DisplayCursor(void)
431 int32 x, y, sx, sy;
432 Point p;
434 for (x = 0; x < cursor_width; x++) {
435 for (y = 0; y < cursor_height; y++) {
436 sx = cursorInfo.x - cursor_x_hot + x;
437 sy = cursorInfo.y - cursor_y_hot + y;
439 if (sx < 0 || sy < 0 || sx > xResolution || sy > yResolution) {
440 continue;
443 p.x = sx;
444 p.y = sy;
446 if (!CURSOR_ISSET(x,y)) {
447 continue;
450 SetPixel(COLOR_BLACK, p);
456 void
457 DoButtons(int b1, int b2, int b3)
459 Point p;
460 Length r;
462 p.x = 520;
463 p.y = 25;
464 r = 20;
466 if (b1) {
467 ColorCircle(COLOR_BLUE, p, r);
468 } else {
469 ColorCircle(COLOR_PLEASING_GREEN, p, r);
471 p.x += 40;
472 if (b2) {
473 ColorCircle(COLOR_ROBINs_PURPLE, p, r);
474 } else {
475 ColorCircle(COLOR_PLEASING_GREEN, p, r);
477 p.x += 40;
478 if (b3) {
479 ColorCircle(COLOR_RED, p, r);
480 } else {
481 ColorCircle(COLOR_PLEASING_GREEN, p, r);
486 void
487 DoCursor(uint8 *packet, uint64 N)
489 int32 xd = 0, yd = 0;
491 RestoreCursorArea();
493 /* update coordinates */
495 * N == 3
497 * Byte 1: Yof Xof Ys Xs 1 b1 b2 b0
498 * Byte 2: Xmove
499 * Byte 3: Ymove
501 * N == 4
503 * Byte 1: Yof Xof Ys Xs 1 b1 b2 b0
504 * Byte 2: Xmove
505 * Byte 3: Ymove
506 * Byte 4: Zmove
509 xd |= packet[1];
510 if (packet[0] & 0x10) {
511 xd |= 0xffffff00;
513 yd |= packet[2];
514 if (packet[0] & 0x20) {
515 yd |= 0xffffff00;
518 /* XXX do Z */
520 cursorInfo.x += xd;
521 cursorInfo.y -= yd;
523 if (cursorInfo.x < 0) {
524 cursorInfo.x = 0;
525 } else if (cursorInfo.x > xResolution) {
526 cursorInfo.x = xResolution;
528 if (cursorInfo.y < 0) {
529 cursorInfo.y = 0;
530 } else if (cursorInfo.y > yResolution) {
531 cursorInfo.y = yResolution;
534 cursorInfo.button1 = packet[0] & 1;
535 cursorInfo.button2 = (packet[0] >> 2) & 1;
536 cursorInfo.button3 = (packet[0] >> 1) & 1;
538 /* draw some small circles */
539 DoButtons(cursorInfo.button1, cursorInfo.button2, cursorInfo.button3);
541 SaveCursorArea();
542 DisplayCursor();
546 void
547 CursorInit(void)
549 cursorInfo.x = xResolution / 2;
550 cursorInfo.y = yResolution / 2;
551 cursorInfo.z = 0;
552 cursorInfo.button1 = 0;
553 cursorInfo.button2 = 0;
554 cursorInfo.button3 = 0;
555 cursorInfo.button4 = 0;
556 cursorInfo.button5 = 0;
558 SaveCursorArea();
559 DisplayCursor();
561 cursorCbId = InstallMouseCB(DoCursor);