2c8485a2e41309402405ef5d21312660308487d7
9 #include "chargen-4x8.h"
11 /* preliminary attempt at handling display */
12 /* currently keeps display state in buffer, and just updates a PNM file on each screen update */
14 #define DISPLAY_BASE 0x8000
15 #define DISPLAY_END 0x8179
16 #define DISPLAY_CELL_MAP 0x8180
17 #define DISPLAY_MISC 0x8280
29 /* total display is 160 pixels by 128 pixels */
30 /* active display is 32x12 cells (each 4x8 pixels), surrounded by 16 pixel border */
31 /* cells are rendered from cell map, which is bitmap of two words, defining four eight-bit columns */
39 struct dcpu16_display_
{
41 struct pixel_
*pixbuf
;
45 struct pixel_
pcolor_(unsigned int c
) {
46 struct pixel_ p
= { 0, 0, 0 };
49 case 0x1: p
.r
=0x00, p
.g
=0x00, p
.b
=0xaa; break; /* dark blue */
50 case 0x2: p
.r
=0x00, p
.g
=0xaa, p
.b
=0x00; break; /* green */
51 case 0x3: p
.r
=0x00, p
.g
=0xaa, p
.b
=0xaa; break; /* cyan */
52 case 0x4: p
.r
=0xaa, p
.g
=0x00, p
.b
=0x00; break; /* red */
53 case 0x5: p
.r
=0xaa, p
.g
=0x00, p
.b
=0xaa; break; /* magenta */
54 case 0x6: p
.r
=0xaa, p
.g
=0xaa, p
.b
=0x55; break; /* yellow [] */
55 case 0x7: p
.r
=0xaa, p
.g
=0xaa, p
.b
=0xff; break; /* pale blue */
56 case 0x8: p
.r
=0x55, p
.g
=0x55, p
.b
=0x55; break; /* grey */
57 case 0x9: p
.r
=0x55, p
.g
=0x55, p
.b
=0xff; break; /* also blue */
58 case 0xa: p
.r
=0x55, p
.g
=0xff, p
.b
=0x55; break; /* light green */
59 case 0xb: p
.r
=0x55, p
.g
=0xff, p
.b
=0xff; break; /* light cyan */
60 case 0xc: p
.r
=0xff, p
.g
=0x55, p
.b
=0x55; break; /* light red */
61 case 0xd: p
.r
=0xff, p
.g
=0x55, p
.b
=0xff; break; /* light magenta */
62 case 0xe: p
.r
=0xff, p
.g
=0xff, p
.b
=0x55; break; /* light yellow */
63 case 0xf: p
.r
=0xff, p
.g
=0xff, p
.b
=0xff; break; /* white */
64 default: p
.r
=0x00, p
.g
=0x00, p
.b
=0x00; /* black */
70 /* should this just flood-fill entire display? */
72 void display_draw_border(struct pixel_
*pixbuf
, struct pixel_ color
) {
77 for (y
= 0; y
< PIX_BORDER
; y
++) {
78 for (x
= 0; x
< PIX_X
; x
++) {
81 i
= ((PIX_Y
- y
) * PIX_X
) + x
;
87 for (y
= PIX_BORDER
; y
< (PIX_Y
- PIX_BORDER
+ 1); y
++)
88 for (x
= 0; x
< PIX_BORDER
; x
++) {
91 pixbuf
[i
+ (PIX_X
- PIX_BORDER
)] = color
;
96 /* render a character cell to the display */
98 void display_draw_cell(struct pixel_
*pixbuf
, DCPU16_WORD
*cell_map
, DCPU16_WORD index
, int cell_x
, int cell_y
, struct pixel_ fg
, struct pixel_ bg
) {
99 struct pixel_
*cellstart
= pixbuf
; /* start of display */
100 unsigned int pix_x
, pix_y
;
101 unsigned char *cell_bitmap
= (unsigned char *)(cell_map
+ (index
* sizeof index
));
103 assert(cell_x
< CELL_X
);
104 assert(cell_y
< CELL_Y
);
106 cellstart
+= (PIX_X
* PIX_BORDER
); /* skip top border */
108 cellstart
+= (CELL_Y_SZ
* PIX_X
) * cell_y
; /* skip down to row */
110 cellstart
+= PIX_BORDER
; /* skip side border */
112 cellstart
+= (CELL_X_SZ
) * cell_x
; /* skip to column */
114 for (pix_x
= 0; pix_x
< CELL_X_SZ
; pix_x
++) {
115 for (pix_y
= 0; pix_y
< CELL_Y_SZ
; pix_y
++) {
116 if ((cell_bitmap
[pix_x
] >> pix_y
) & 0x01)
117 cellstart
[((CELL_Y_SZ
- pix_y
- 1) * PIX_X
) + pix_x
] = fg
;
119 cellstart
[((CELL_Y_SZ
- pix_y
- 1) * PIX_X
) + pix_x
] = bg
;
125 void display_pnm_write(struct pixel_
*pixbuf
, const char *filename
) {
129 f
= fopen(filename
, "w");
131 fprintf(stderr
, "%s('%s'):%s\n", "fopen", filename
, strerror(errno
));
135 /* write header... */
139 fprintf(f
, "P6\n%d %d\n255\n", PIX_X
, PIX_Y
);
141 /* write out image bytes in r g b order */
142 for (i
= 0; i
< PIX_X
* PIX_Y
; i
++) {
143 fwrite(&pixbuf
[i
].r
, 1, 1, f
);
144 fwrite(&pixbuf
[i
].g
, 1, 1, f
);
145 fwrite(&pixbuf
[i
].b
, 1, 1, f
);
152 /* the callback to register to be run on display init/reset */
153 /* currently this populates the chargen map 'from rom'.. */
154 /* and clears the display buffers */
155 void display_reset_fn(struct dcpu16
*vm
, dcpu16_acct_event e
, DCPU16_WORD addr
, void *data
) {
156 struct dcpu16_display_
*d
= (struct dcpu16_display_
*)data
;
160 memcpy(vm
->ram
+ DISPLAY_CELL_MAP
, chargen_4x8_glyphs
, sizeof chargen_4x8_glyphs
);
162 memset(vm
->ram
+ DISPLAY_BASE
, 0, (DISPLAY_END
- DISPLAY_BASE
) * sizeof *(vm
->ram
));
164 memset(d
->pixbuf
, 0, PIX_X
* PIX_Y
* sizeof *(d
->pixbuf
));
167 /* the callback to register with the cpu for watching memory updates */
168 /* user data is an allocated display buffer */
169 void display_fn(struct dcpu16
*vm
, dcpu16_acct_event e
, DCPU16_WORD addr
, void *data
) {
170 DCPU16_DISPLAY
*d
= (DCPU16_DISPLAY
*)data
;
171 unsigned char index
, blink
, bg
, fg
;
172 unsigned int cell_x
, cell_y
;
176 if (addr
< DISPLAY_BASE
|| addr
> DISPLAY_MISC
)
179 if (addr
> DISPLAY_END
&& addr
< DISPLAY_MISC
) {
180 unsigned char updated_index
= addr
- DISPLAY_CELL_MAP
;
181 /* a cell map was updated, refresh entire screen */
182 for (cell_x
= 0; cell_x
< CELL_X
; cell_x
++) {
183 for (cell_y
= 0; cell_y
< CELL_Y
; cell_y
++) {
184 addr
= DISPLAY_BASE
+ cell_x
+ (cell_y
* CELL_X
);
185 index
= vm
->ram
[addr
] & 0x7f;
186 if (index
!= updated_index
)
188 blink
= (vm
->ram
[addr
] >> 7) & 0x01;
189 bg
= (vm
->ram
[addr
] >> 8) & 0x0f;
190 fg
= (vm
->ram
[addr
] >> 12) & 0x0f;
191 display_draw_cell(d
->pixbuf
, vm
->ram
+ DISPLAY_CELL_MAP
, index
, cell_x
, cell_y
, pcolor_(fg
), pcolor_(bg
));
195 display_pnm_write(d
->pixbuf
, d
->outfile
);
199 if (addr
== DISPLAY_MISC
) {
200 /* new border color */
201 char border
= vm
->ram
[addr
] & 0x0f;
202 display_draw_border(d
->pixbuf
, pcolor_(border
));
204 display_pnm_write(d
->pixbuf
, d
->outfile
);
208 cell_x
= (addr
- DISPLAY_BASE
) % CELL_X
;
209 cell_y
= (addr
- DISPLAY_BASE
) / CELL_X
;
211 index
= vm
->ram
[addr
] & 0x7f;
212 blink
= (vm
->ram
[addr
] >> 7) & 0x01;
213 bg
= (vm
->ram
[addr
] >> 8) & 0x0f;
214 fg
= (vm
->ram
[addr
] >> 12) & 0x0f;
216 display_draw_cell(d
->pixbuf
, vm
->ram
+ DISPLAY_CELL_MAP
, index
, cell_x
, cell_y
, pcolor_(fg
), pcolor_(bg
));
217 display_pnm_write(d
->pixbuf
, d
->outfile
);
220 /* init the pixel buffer */
221 DCPU16_DISPLAY
*display_new(const char *filename
) {
222 DCPU16_DISPLAY
*d
= calloc(1, sizeof *d
);
226 d
->pixbuf
= calloc(PIX_X
* PIX_Y
, sizeof *(d
->pixbuf
));
227 if (d
->pixbuf
== NULL
) {
232 d
->outfile
= strdup(filename
);
233 if (d
->outfile
== NULL
) {