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 */
40 DPIX
pcolor_(unsigned int c
) {
44 case 0x1: p
.r
=0x00, p
.g
=0x00, p
.b
=0xaa; break; /* dark blue */
45 case 0x2: p
.r
=0x00, p
.g
=0xaa, p
.b
=0x00; break; /* green */
46 case 0x3: p
.r
=0x00, p
.g
=0xaa, p
.b
=0xaa; break; /* cyan */
47 case 0x4: p
.r
=0xaa, p
.g
=0x00, p
.b
=0x00; break; /* red */
48 case 0x5: p
.r
=0xaa, p
.g
=0x00, p
.b
=0xaa; break; /* magenta */
49 case 0x6: p
.r
=0xaa, p
.g
=0xaa, p
.b
=0x55; break; /* yellow [] */
50 case 0x7: p
.r
=0xaa, p
.g
=0xaa, p
.b
=0xff; break; /* pale blue */
51 case 0x8: p
.r
=0x55, p
.g
=0x55, p
.b
=0x55; break; /* grey */
52 case 0x9: p
.r
=0x55, p
.g
=0x55, p
.b
=0xff; break; /* also blue */
53 case 0xa: p
.r
=0x55, p
.g
=0xff, p
.b
=0x55; break; /* light green */
54 case 0xb: p
.r
=0x55, p
.g
=0xff, p
.b
=0xff; break; /* light cyan */
55 case 0xc: p
.r
=0xff, p
.g
=0x55, p
.b
=0x55; break; /* light red */
56 case 0xd: p
.r
=0xff, p
.g
=0x55, p
.b
=0xff; break; /* light magenta */
57 case 0xe: p
.r
=0xff, p
.g
=0xff, p
.b
=0x55; break; /* light yellow */
58 case 0xf: p
.r
=0xff, p
.g
=0xff, p
.b
=0xff; break; /* white */
59 default: p
.r
=0x00, p
.g
=0x00, p
.b
=0x00; /* black */
65 /* should this just flood-fill entire display? */
67 void display_draw_border(DPIX
*pixbuf
, DPIX color
) {
72 for (y
= 0; y
< PIX_BORDER
; y
++) {
73 for (x
= 0; x
< PIX_X
; x
++) {
76 i
= ((PIX_Y
- y
) * PIX_X
) + x
;
82 for (y
= PIX_BORDER
; y
< (PIX_Y
- PIX_BORDER
+ 1); y
++)
83 for (x
= 0; x
< PIX_BORDER
; x
++) {
86 pixbuf
[i
+ (PIX_X
- PIX_BORDER
)] = color
;
91 /* render a character cell to the display */
93 void display_draw_cell(DPIX
*pixbuf
, DCPU16_WORD
*cell_map
, DCPU16_WORD index
, int cell_x
, int cell_y
, DPIX fg
, DPIX bg
) {
94 DPIX
*cellstart
= pixbuf
; /* start of display */
95 unsigned int pix_x
, pix_y
;
96 unsigned char *cell_bitmap
= (unsigned char *)(cell_map
+ (index
* sizeof index
));
98 assert(cell_x
< CELL_X
);
99 assert(cell_y
< CELL_Y
);
101 cellstart
+= (PIX_X
* PIX_BORDER
); /* skip top border */
103 cellstart
+= (CELL_Y_SZ
* PIX_X
) * cell_y
; /* skip down to row */
105 cellstart
+= PIX_BORDER
; /* skip side border */
107 cellstart
+= (CELL_X_SZ
) * cell_x
; /* skip to column */
109 for (pix_x
= 0; pix_x
< CELL_X_SZ
; pix_x
++) {
110 for (pix_y
= 0; pix_y
< CELL_Y_SZ
; pix_y
++) {
111 if ((cell_bitmap
[pix_x
] >> pix_y
) & 0x01)
112 cellstart
[((CELL_Y_SZ
- pix_y
- 1) * PIX_X
) + pix_x
] = fg
;
114 cellstart
[((CELL_Y_SZ
- pix_y
- 1) * PIX_X
) + pix_x
] = bg
;
120 void display_pnm_write(DPIX
*pixbuf
, const char *filename
) {
124 f
= fopen(filename
, "w");
126 fprintf(stderr
, "%s('%s'):%s\n", "fopen", filename
, strerror(errno
));
130 /* write header... */
134 fprintf(f
, "P6\n%d %d\n255\n", PIX_X
, PIX_Y
);
136 /* write out image bytes in r g b order */
137 for (i
= 0; i
< PIX_X
* PIX_Y
; i
++) {
138 fwrite(&pixbuf
[i
].r
, 1, 1, f
);
139 fwrite(&pixbuf
[i
].g
, 1, 1, f
);
140 fwrite(&pixbuf
[i
].b
, 1, 1, f
);
147 /* the callback to register to be run on display init/reset */
148 /* currently this populates the chargen map 'from rom'.. */
149 /* and clears the display buffers */
150 void display_reset_fn(struct dcpu16
*vm
, dcpu16_acct_event e
, DCPU16_WORD addr
, void *data
) {
151 DPIX
*pixbuf
= (DPIX
*)data
;
155 fprintf(stderr
, "DEBUG: event:%u\n", e
);
157 fprintf(stderr
, "DEBUG: loading chargen map from 0x%04x to 0x%04x (%zuo)\n",
159 DISPLAY_CELL_MAP
+ (unsigned short)(sizeof chargen_4x8_glyphs
/ sizeof addr
),
160 sizeof chargen_4x8_glyphs
);
161 memcpy(vm
->ram
+ DISPLAY_CELL_MAP
, chargen_4x8_glyphs
, sizeof chargen_4x8_glyphs
);
163 fprintf(stderr
, "DEBUG: clearing display buffer from 0x%04x to 0x%04x (%zuo)\n",
166 (DISPLAY_END
- DISPLAY_BASE
) * sizeof *(vm
->ram
));
167 memset(vm
->ram
+ DISPLAY_BASE
, 0, (DISPLAY_END
- DISPLAY_BASE
) * sizeof *(vm
->ram
));
169 fprintf(stderr
, "DEBUG: clearing pixel buffer (%zuo)\n",
170 PIX_X
* PIX_Y
* sizeof *pixbuf
);
171 memset(pixbuf
, 0, PIX_X
* PIX_Y
* sizeof *pixbuf
);
174 /* the callback to register with the cpu for watching memory updates */
175 /* user data is an allocated display buffer */
176 void display_fn(struct dcpu16
*vm
, dcpu16_acct_event e
, DCPU16_WORD addr
, void *data
) {
177 const char * const outfile
= "dcpu16-display.pnm";
178 DPIX
*pixbuf
= (DPIX
*)data
;
179 unsigned char index
, blink
, bg
, fg
;
180 unsigned int cell_x
, cell_y
;
184 if (addr
< DISPLAY_BASE
|| addr
> DISPLAY_MISC
)
187 if (addr
> DISPLAY_END
&& addr
< DISPLAY_MISC
) {
188 unsigned char updated_index
= addr
- DISPLAY_CELL_MAP
;
189 /* a cell map was updated, refresh entire screen */
190 for (cell_x
= 0; cell_x
< CELL_X
; cell_x
++) {
191 for (cell_y
= 0; cell_y
< CELL_Y
; cell_y
++) {
192 addr
= DISPLAY_BASE
+ cell_x
+ (cell_y
* CELL_X
);
193 index
= vm
->ram
[addr
] & 0x7f;
194 if (index
!= updated_index
)
196 blink
= (vm
->ram
[addr
] >> 7) & 0x01;
197 bg
= (vm
->ram
[addr
] >> 8) & 0x0f;
198 fg
= (vm
->ram
[addr
] >> 12) & 0x0f;
199 display_draw_cell(pixbuf
, vm
->ram
+ DISPLAY_CELL_MAP
, index
, cell_x
, cell_y
, pcolor_(fg
), pcolor_(bg
));
203 display_pnm_write(pixbuf
, outfile
);
207 if (addr
== DISPLAY_MISC
) {
208 /* new border color */
209 char border
= vm
->ram
[addr
] & 0x0f;
210 fprintf(stderr
, "display event: new border\n");
211 display_draw_border(pixbuf
, pcolor_(border
));
213 display_pnm_write(pixbuf
, outfile
);
217 cell_x
= (addr
- DISPLAY_BASE
) % CELL_X
;
218 cell_y
= (addr
- DISPLAY_BASE
) / CELL_X
;
220 index
= vm
->ram
[addr
] & 0x7f;
221 blink
= (vm
->ram
[addr
] >> 7) & 0x01;
222 bg
= (vm
->ram
[addr
] >> 8) & 0x0f;
223 fg
= (vm
->ram
[addr
] >> 12) & 0x0f;
225 fprintf(stderr
, "display event: cell %ux%u:%u '%c'\n", cell_x
, cell_y
, index
, index
);
227 display_draw_cell(pixbuf
, vm
->ram
+ DISPLAY_CELL_MAP
, index
, cell_x
, cell_y
, pcolor_(fg
), pcolor_(bg
));
228 display_pnm_write(pixbuf
, outfile
);
231 /* init the pixel buffer */
232 DPIX
*display_init_pixbuf(void) {
235 pixbuf
= calloc(PIX_X
* PIX_Y
, sizeof *pixbuf
);