@@ -108,6 +108,9 @@ void create_window() | |||
xcb_map_window(conn, win); | |||
} | |||
// To make things simple with X11, we only support monochrome display, which is | |||
// inverted: As soon as the color of the pixel is non-black, we show a black | |||
// pixel. If the pixel is white, we show black. | |||
void draw_pixels() | |||
{ | |||
xcb_get_geometry_reply_t *geom; | |||
@@ -51,6 +51,7 @@ void vdp_data_wr(VDP *vdp, uint8_t val) | |||
} | |||
} | |||
// Returns a 8-bit RGB value (0b00bbggrr) | |||
uint8_t vdp_pixel(VDP *vdp, uint16_t x, uint16_t y) | |||
{ | |||
if (x >= VDP_SCREENW) { | |||
@@ -63,6 +64,8 @@ uint8_t vdp_pixel(VDP *vdp, uint16_t x, uint16_t y) | |||
uint16_t offset = 0x3800 + ((y/8) << 6) + ((x/8) << 1); | |||
uint16_t tableval = vdp->vram[offset] + (vdp->vram[offset+1] << 8); | |||
uint16_t tilenum = tableval & 0x1ff; | |||
// is palette select bit on? if yes, use sprite palette instead | |||
uint8_t palettemod = tableval & 0x800 ? 0x10 : 0; | |||
// tile offset this time. Each tile is 0x20 bytes long. | |||
offset = tilenum * 0x20; | |||
// Each 4 byte is a row. Find row first. | |||
@@ -70,8 +73,10 @@ uint8_t vdp_pixel(VDP *vdp, uint16_t x, uint16_t y) | |||
uint8_t bitnum = 7 - (x%8); | |||
// Now, let's compose the result by pushing the right bit of our 4 bytes | |||
// into our result. | |||
return ((vdp->vram[offset] >> bitnum) & 1) + \ | |||
uint8_t palette_id = ((vdp->vram[offset] >> bitnum) & 1) + \ | |||
(((vdp->vram[offset+1] >> bitnum) & 1) << 1) + \ | |||
(((vdp->vram[offset+2] >> bitnum) & 1) << 2) + \ | |||
(((vdp->vram[offset+3] >> bitnum) & 1) << 3); | |||
uint8_t rgb = vdp->vram[0x4000+palettemod+palette_id]; | |||
return rgb; | |||
} |
@@ -119,7 +119,7 @@ gridPushScr: | |||
pop de | |||
ret | |||
; Set character under cursor to A | |||
; Set character under cursor to A. C is passed to GRID_SETCELL as-is. | |||
gridSetCur: | |||
push de | |||
push hl | |||
@@ -137,11 +137,27 @@ gridSetCur: | |||
pop de | |||
ret | |||
; Call gridSetCur with C = 1. | |||
gridSetCurH: | |||
push bc | |||
ld c, 1 | |||
call gridSetCur | |||
pop bc | |||
ret | |||
; Call gridSetCur with C = 0. | |||
gridSetCurL: | |||
push bc | |||
ld c, 0 | |||
call gridSetCur | |||
pop bc | |||
ret | |||
; Clear character under cursor | |||
gridClrCur: | |||
push af | |||
ld a, ' ' | |||
call gridSetCur | |||
call gridSetCurL | |||
pop af | |||
ret | |||
@@ -210,7 +226,7 @@ gridPutC: | |||
cp ' ' | |||
ret c ; ignore unhandled control characters | |||
call gridSetCur | |||
call gridSetCurL | |||
push af ; --> lvl 1 | |||
; Move cursor | |||
ld a, (GRID_CURX) | |||
@@ -181,7 +181,7 @@ padGetC: | |||
; no action button pressed, but because our pad status changed, update | |||
; VDP before looping. | |||
ld a, (PAD_SELCHR) | |||
call gridSetCur | |||
call gridSetCurH | |||
jp padGetC | |||
.return: | |||
ld a, LF | |||
@@ -190,7 +190,7 @@ padGetC: | |||
.advance: | |||
ld a, (PAD_SELCHR) | |||
; Z was already set from previous BIT instruction | |||
ret | |||
jp gridSetCurL | |||
.backspace: | |||
ld a, BS | |||
; Z was already set from previous BIT instruction | |||
@@ -23,8 +23,8 @@ | |||
; *** Code *** | |||
vdpInit: | |||
ld hl, vdpInitData | |||
ld b, vdpInitDataEnd-vdpInitData | |||
ld hl, .initData | |||
ld b, .initDataEnd-.initData | |||
ld c, VDP_CTLPORT | |||
otir | |||
@@ -47,10 +47,10 @@ vdpInit: | |||
out (VDP_CTLPORT), a | |||
ld a, 0xc0 | |||
out (VDP_CTLPORT), a | |||
xor a ; palette 0: black | |||
out (VDP_DATAPORT), a | |||
ld a, 0x3f ; palette 1: white | |||
out (VDP_DATAPORT), a | |||
ld hl, .paletteData | |||
ld b, .paletteDataEnd-.paletteData | |||
ld c, VDP_DATAPORT | |||
otir | |||
; Define tiles | |||
xor a | |||
@@ -97,6 +97,28 @@ vdpInit: | |||
out (VDP_CTLPORT), a | |||
ret | |||
; VDP initialisation data | |||
.initData: | |||
; 0x8x == set register X | |||
.db 0b00000100, 0x80 ; Bit 2: Select mode 4 | |||
.db 0b00000000, 0x81 | |||
.db 0b11111111, 0x82 ; Name table: 0x3800 | |||
.db 0b11111111, 0x85 ; Sprite table: 0x3f00 | |||
.db 0b11111111, 0x86 ; sprite use tiles from 0x2000 | |||
.db 0b11111111, 0x87 ; Border uses palette 0xf | |||
.db 0b00000000, 0x88 ; BG X scroll | |||
.db 0b00000000, 0x89 ; BG Y scroll | |||
.db 0b11111111, 0x8a ; Line counter (why have this?) | |||
.initDataEnd: | |||
.paletteData: | |||
; BG palette | |||
.db 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |||
.db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |||
; Sprite palette (inverted colors) | |||
.db 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |||
.db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |||
.paletteDataEnd: | |||
; Convert ASCII char in A into a tile index corresponding to that character. | |||
; When a character is unknown, returns 0x5e (a '~' char). | |||
vdpConv: | |||
@@ -108,7 +130,8 @@ vdpConv: | |||
ld a, 0x5e | |||
ret | |||
; grid routine. Sets cell at row D and column E to character A | |||
; grid routine. Sets cell at row D and column E to character A. If C is one, we | |||
; use the sprite palette. | |||
vdpSetCell: | |||
call vdpConv | |||
; store A away | |||
@@ -141,18 +164,11 @@ vdpSetCell: | |||
; We're ready to send our data now. Let's go | |||
ex af, af' | |||
out (VDP_DATAPORT), a | |||
; Palette select is on bit 3 of MSB | |||
ld a, 1 | |||
and c | |||
rla \ rla \ rla | |||
out (VDP_DATAPORT), a | |||
ret | |||
; VDP initialisation data | |||
vdpInitData: | |||
; 0x8x == set register X | |||
.db 0b00000100, 0x80 ; Bit 2: Select mode 4 | |||
.db 0b00000000, 0x81 | |||
.db 0b11111111, 0x82 ; Name table: 0x3800 | |||
.db 0b11111111, 0x85 ; Sprite table: 0x3f00 | |||
.db 0b11111111, 0x86 ; sprite use tiles from 0x2000 | |||
.db 0b11111111, 0x87 ; Border uses palette 0xf | |||
.db 0b00000000, 0x88 ; BG X scroll | |||
.db 0b00000000, 0x89 ; BG Y scroll | |||
.db 0b11111111, 0x8a ; Line counter (why have this?) | |||
vdpInitDataEnd: |