summaryrefslogtreecommitdiff
path: root/vgasrc
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2015-01-02 12:32:25 -0500
committerKevin O'Connor <kevin@koconnor.net>2015-01-06 09:54:44 -0500
commit60e0e55f212dadd043ab9e39bee05a48013ddd8f (patch)
tree0bf0b2b3ddcc2b7724be67a2f2a49e53e7bab137 /vgasrc
parent9c29148ea6e2ba0c1ca81f92138a4f71e5f8d6d7 (diff)
downloadqemu-seabios-60e0e55f212dadd043ab9e39bee05a48013ddd8f.tar.gz
vgabios: implement read char in graphics mode
GWBasic relies on this, so implement it to enable some serious retrocomputing. There is no better way to do it than trying to match all characters one by one against the current font. This makes it possible to actually do something in SCREEN 1 and SCREEN 2 (without it, you can use graphics in the programs but not in direct mode). I couldn't find documentation for what to return as the attribute, but experimenting with DOSBox suggests 0 (and GWBasic accepts it). Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'vgasrc')
-rw-r--r--vgasrc/vgafb.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/vgasrc/vgafb.c b/vgasrc/vgafb.c
index 59ddc56..4bbbc16 100644
--- a/vgasrc/vgafb.c
+++ b/vgasrc/vgafb.c
@@ -454,6 +454,43 @@ gfx_write_char(struct vgamode_s *vmode_g
}
}
+// Read a character from the screen in graphics mode.
+static struct carattr
+gfx_read_char(struct vgamode_s *vmode_g, struct cursorpos cp)
+{
+ u8 lines[16];
+ int cheight = GET_BDA(char_height);
+ if (cp.x >= GET_BDA(video_cols) || cheight > ARRAY_SIZE(lines))
+ goto fail;
+
+ // Read cell from screen
+ struct gfx_op op;
+ init_gfx_op(&op, vmode_g);
+ op.op = GO_READ8;
+ op.x = cp.x * 8;
+ op.y = cp.y * cheight;
+ u8 i, j;
+ for (i=0; i<cheight; i++, op.y++) {
+ u8 line = 0;
+ handle_gfx_op(&op);
+ for (j=0; j<8; j++)
+ if (op.pixels[j])
+ line |= 0x80 >> j;
+ lines[i] = line;
+ }
+
+ // Determine font
+ u16 car;
+ for (car=0; car<256; car++) {
+ struct segoff_s font = get_font_data(car);
+ if (memcmp_far(GET_SEG(SS), lines
+ , font.seg, (void*)(font.offset+0), cheight) == 0)
+ return (struct carattr){car, 0, 0};
+ }
+fail:
+ return (struct carattr){0, 0, 0};
+}
+
// Draw/undraw a cursor on the framebuffer by xor'ing the cursor cell
void
gfx_set_swcursor(struct vgamode_s *vmode_g, int enable, struct cursorpos cp)
@@ -607,23 +644,15 @@ vgafb_read_char(struct cursorpos cp)
{
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
- goto fail;
+ return (struct carattr){0, 0, 0};
vgafb_set_swcursor(0);
- if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
- // FIXME gfx mode
- dprintf(1, "Read char in graphics mode\n");
- goto fail;
- }
+ if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT)
+ return gfx_read_char(vmode_g, cp);
u16 *dest_far = text_address(cp);
u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *dest_far);
- struct carattr ca = {v, v>>8, 0};
- return ca;
-
-fail: ;
- struct carattr ca2 = {0, 0, 0};
- return ca2;
+ return (struct carattr){v, v>>8, 0};
}
// Draw/undraw a cursor on the screen