Isometric Chess display engine

The place for codemasters or beginners to talk about programming any language for the Spectrum.
Post Reply
User avatar
arkannoyed
Manic Miner
Posts: 436
Joined: Mon Feb 05, 2018 9:56 am
Location: Northamptonshire

Re: Graph Paper

Post by arkannoyed »

Thank you!

Generally more recently I just arrange coloured blocks in Illustrator when designing graphical stuff.

When I did the sprites for my Isometric Chess display engine (Looks whats possible in 924 bytes thread on WOS*) I had to colour code it all to keep track of what BITs did what.

*Actually its currently 722 bytes!
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Graph Paper

Post by Nomad »

arkannoyed wrote: Mon Feb 05, 2018 12:27 pm
When I did the sprites for my Isometric Chess display engine (Looks whats possible in 924 bytes thread on WOS*) I had to colour code it all to keep track of what BITs did what.

*Actually its currently 722 bytes!
Did you write about the development? I would be interested in finding out more how you did this :lol: Just curious. That is very impressive to get the display engine into such a state. Ok I admit it I am green with envy. :mrgreen: Welcome to the forum fella.
User avatar
arkannoyed
Manic Miner
Posts: 436
Joined: Mon Feb 05, 2018 9:56 am
Location: Northamptonshire

Re: Graph Paper

Post by arkannoyed »

Ta.

I sort of wrote about it on the WOS forums and posted the .ASM too. Its bloody complicated is what it is! I could do a thread trying to explain it all again maybe. I still have an ambition to re-write it (yet again!), and try to make it more straight forward to comprehend. Trouble is, the graphics format and actually decoding it is so finely balanced between beauty and utter disaster that I even struggle to remember its intricacies some days. Once I get a little free time I'll perhaps go for the push to get it under 700 bytes. Do you want me to post the .asm as it currently is?
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Graph Paper

Post by Nomad »

arkannoyed wrote: Mon Feb 05, 2018 3:32 pm Ta.

I sort of wrote about it on the WOS forums and posted the .ASM too. Its bloody complicated is what it is! I could do a thread trying to explain it all again maybe. I still have an ambition to re-write it (yet again!), and try to make it more straight forward to comprehend. Trouble is, the graphics format and actually decoding it is so finely balanced between beauty and utter disaster that I even struggle to remember its intricacies some days. Once I get a little free time I'll perhaps go for the push to get it under 700 bytes. Do you want me to post the .asm as it currently is?
Yes that would be great, I am trying to make my own chess program and its been slow going seeing some super slick ideas I think will give me the motivation to plow on with my own project :lol: The literate programming is good for projects that are mind benders as you can just write about them actually in the code as your working. No messing with external documentation tools. I'll have a look at WOS see if I can track down your thread.
User avatar
arkannoyed
Manic Miner
Posts: 436
Joined: Mon Feb 05, 2018 9:56 am
Location: Northamptonshire

Re: Graph Paper

Post by arkannoyed »

Here you go. I did try and comment the source as far as I could, honest!

Code: Select all

;Isometric Chess board display engine version 0.83c
;(c) 1992-2017 JES
;722 bytes

org 0fc00h

db %10010001,%00110011,%10000000,%11000100,%10000000,%10001000

initialise_board:
                   ld de,0ffc0h
                   ld hl,data_17
                   ld b,d
                   ld c,d
ib_loop1:
                   ld a,(hl)
                   inc a
                   ld (bc),a
                   ldi
                   jr nz,ib_loop1
                   dec e
                   ld b,20h
ib_loop2:
                   ld (de),a
                   inc e
                   djnz ib_loop2
              
                   ret                   ;24 bytes (+17 data)
                   nop

db %11111101,%10011001,%11111001,%11101110,%11111111,%10011001,%10111001,%10001011
db %10111011,%11001011,%11111011,%00100011,%00100010,%01100101,%01100100,%01100100
db %00100000,%00010011,%00110111,%10111101,%10011101,%10111011,%10001010,%10011011
db %01010111,%01010111,%01000101,%00011001,%01001101,%01101011,%00101001,%00001110
db %01101100,%00100000,%01001100,%01110011,%00110011,%01010101,%11111101,%10111111
db %11010011,%01101000,%01001000,%10111111,%11111101,%00001001,%01011101,%01001011
db %00111000,%01001111,%01001010,%00100000,%01101000,%01010011,%01010010,%01100001
db %01100001,%01011011,%11011011,%01110100,%11111001,%10000011,%11110001,%01010111
db %01000111,%00111100,%10100111,%00001100,%10100100,%10000011,%00010001,%11100010
db %01000010,%01111101,%11100000,%00000110,%10100110,%10010001,%10110001,%00000010
db %01011011,%01110101,%10101101,%10010010,%10000011,%10100100,%11100100,%11001110
db %10010001,%00110011,%11110011,%10100110,%10111111,%11001000,%10111011,%10101011
db %01001101,%01001101,%01100110,%01100010,%01010001,%00100110,%10110111,%11110011
db %11100011,%11001110,%11100001,%00100100,%01001000,%00111111,%10111111,%10011001
db %10111001,%00101100,%11111101,%01011111,%00100010,%00001001,%01100111,%01000101
db %01100101,%01100111,%01100110,%00001010,%11111011,%10101101,%00100010,%11101001
db %10101100,%00101010,%11111011,%00011001,%00111011,%00011101,%01011001,%00000110
db %00101000,%01010111,%00000011,%01100111,%10001001,%11001101,%10001101,%01000011
db %11111011,%10100011,%11100010,%00100111,%11100110,%00001010,%11101110,%00110011
db %11110101,%10110011,%10110101,%00101100,%11100000,%00011111,%10100011,%11000101
db %00100011,%11101101,%11000101,%01001101,%11000111,%10000011,%00100010,%11001101
db %10101110,%00111111,%11011011,%10110011,%10010011,%01010101,%11000110,%01001101
db %11001101,%01010100,%10111010,%10100011,%10100011,%00001001,%11101110,%01101111
db %11000010,%10100110,%01010111,%10011111,%11011010,%11001101,%11001010,%00000000
db %00010001,%01010100,%01100111,%00100110,%01100000,%10000011,%11111101,%10111101
db %11101000,%11000110,%11100111,%00000001,%01101111,%01101100,%00001100,%00111001
db %00011001,%01110111,%01110111,%01100110,%01000101,%10101010,%11101110,%01111011
db %10011011,%10110111,%11000110,%00010110,%11000010,%01011001,%11011011,%01011101
db %01001100,%11011101


index_data:
                    db %00000000;line 00
                    db 80h      ;line 01
                    db 80h      ;line 02
                    db %00000100;line 03
                    db %00000111;line 04
                    db %00001001;line 05
                    db %00011001;line 06
                    db %01110100;line 07
                    db %01110100;line 08
                    db 87h      ;line 09
                    db 88h      ;line 0A
                    db %01000111;line 0B
                    db %00101001;line 0C
                    db %00011001;line 0D
                    db %00001001;line 0E   end of base

                    db %01000100;line 0F
                    db %01000011;line 10
                    db %01000011;line 11
                    db 90h      ;line 12
                    db 91h      ;line 13
                    db %00110011;line 14
                    db %00100100;line 15
                    db 94h      ;line 16
                    db 95h      ;line 17
                    db %00100011;line 18
                    db %00100011;line 19
                    db 98h      ;line 1A
                    db 99h      ;line 1B
                    db 98h      ;line 1C
                    db %00000110;line 1D
                    db %00000111;line 1E
                    db %01000100;line 1F
                    db %00110101;line 20
                    db %00000111;line 21
                    db %00000110;line 22
                    db %00100011;line 23
                    db %00110011;line 24
                    db %00110011;line 25
                    db 0a4h     ;line 26
                    db %01000011;line 27
                    db %00100101;line 28
                    db %00010111;line 29
                    db %00010110;line 2A
                    db %00000110;line 2B
                    db %00000100;line 2C
                    db %01000001;line 2D
                    db %00010011;line 2E
                    db %00000011;line 2F
                    db %00000001;line 30   end of king

                    db %00010110;line 31
                    db %00010111;line 32
                    db %00010111;line 33
                    db %00000111;line 34
                    db %00000100;line 35
                    db %00010001;line 36
                    db 0b0h     ;line 37   end of queen

                    db 98h      ;line 38
                    db 9dh      ;line 39
                    db 9eh      ;line 3A
                    db 9fh      ;line 3B
                    db 0a0h     ;line 3C
                    db 0a1h     ;line 3D
                    db 0a2h     ;line 3E
                    db 0a3h     ;line 3F
                    db 0a4h     ;line 40
                    db 0a5h     ;line 41
                    db 0a4h     ;line 42
                    db %00100100;line 43
                    db %00010100;line 44
                    db %00000101;line 45
                    db %00010011;line 46
                    db %00010011;line 47
                    db %00000011;line 48
                    db %00100010;line 49
                    db %00010010;line 4A
                    db 0b6h     ;line 4B
                    db 0b0h     ;line 4C   end of bishop

                    db %00010101;line 4D
                    db 9dh      ;line 4E
                    db 9eh      ;line 4F
                    db 9fh      ;line 50
                    db 0a0h     ;line 51
                    db 0a1h     ;line 52
                    db %00000110;line 53
                    db 91h      ;line 54
                    db %01010011;line 55
                    db 9fh      ;line 56
                    db 0d5h     ;line 57
                    db 9fh      ;line 58
                    db %00100110;line 59
                    db %00010111;line 5A
                    db %00010111;line 5B
                    db %00010111;line 5C
                    db %00000111;line 5D
                    db 83h      ;line 5E   end of castle

                    db 91h      ;line 5F
                    db %00110011;line 60
                    db %00110011;line 61
                    db %00100011;line 62
                    db 99h      ;line 63
                    db %00010100;line 64
                    db 9dh      ;line 65
                    db 9eh      ;line 66
                    db 9fh      ;line 67               
                    db 0a0h     ;line 68
                    db 0a1h     ;line 69
                    db 0a2h     ;line 6A
                    db %00100011;line 6B
                    db 0a4h     ;line 6C
                    db 0a5h     ;line 6D
                    db 0a4h     ;line 6E
                    db 0a5h     ;line 6F
                    db 98h      ;line 70
                    db %00010100;line 71
                    db 0b5h     ;line 72
                    db %00000010;line 73   end of pawn

                    db 91h      ;line 74
                    db 90h      ;line 75
                    db 95h      ;line 76
                    db %00010101;line 77
                    db 9dh      ;line 78
                    db 9eh      ;line 79
                    db 9fh      ;line 7A
                    db 0a0h     ;line 7B
                    db 0a1h     ;line 7C
                    db %00100100;line 7D
                    db %00000111;line 7E
                    db %00001000;line 7F
                    db %01010011;line 80
                    db %01000100;line 81
                    db %00001001;line 82
                    db %00001001;line 83
                    db %00001001;line 84
                    db %00001001;line 85
                    db %00011000;line 86
                    db %00001010;line 87
                    db %00001011;line 88
                    db %00001011;line 89
                    db %00001010;line 8A
                    db %00001001;line 8B
                    db %00001000;line 8C
                    db %00010101;line 8D
                    db %00000101;line 8E
                    db %00000100;line 8F
                    db %00000011;line 90
                    db %00000010;line 91
                   ;db %00000001;line 92               shared with first byte of routine.
                                          ;end of knight

                                                  ;145 bytes

chess_builder:
                   ld bc,00c0h                    ;start address of board
                   ld ixh,0fch                    ;data Hi-byte
main_loop:
                   dec b                          ;B=FFh
                   ld a,(bc)                      ;get piece occupying square into A
                   ld (main_call+1),a             ;store

get_piece_height:
                   ld hl,piece_sizes-2            ;piece sizes & positions table base address
                   rra                            ;find piece data
                   ld b,a                         ;/2 into L
                   add a,a                        ;X2
                   add a,b                        ;+L = X3 = Trigger line, jump line, piece height
                   add a,l                        ;
                   ld l,a                         ;

                   ld a,(hl)                      ;this byte determines which index line we make the jump at
                   ld (jump_line+1),a             ;
                   inc l                          ;
jump_to:
                   ld a,(hl)                      ;
                   ex af,af'                      ;this is the index line to jump to.
                   inc l                          ;
set_height:
                   ld b,(hl)                      ;this is the piece height

                   push bc                        ;

calc_square_addr:
                   ld a,c
                   ld de,0022h                    ;DE constant
                   ld hl,09f0h                    ;HL=square 00 address - 47h (47F0h)*
csa_lp0:
                   ld bc,031eh                    ;B=counter, C=next offset to add for rows
csa_lp1:
                   rra                            ;get lsb into carry
                   jr nc,csa_ovr                  ;
                   add hl,de                      ;
csa_ovr:
                   rl e                           ;E x 2
                   djnz csa_lp1                   ;loop
                   ld e,c                         ;ld E,1Eh
                   jr c,csa_lp0                   ;if we arrived here from the 1st pass, the carry
                                                  ;would be set, so we loop again with the new E value
                   ld a,h                         ;
                   add a,a                        ;x2
                   add a,a                        ;x4
                   add a,a                        ;x8
                   dec a                          ;
                   ld h,a                         ;HL=square address

                   pop bc                         ;B=height C=current square ;D=00 already for line counter
get_len:
                   push de                        ;save current line
                   push bc                        ;save height + current square no.
current_square:
                   ld a,c                         ;c=curent square
                   and 09h                        ;
                   jp pe,main_call                ;if white square, jump to main call
                                                  ;change to JP PO to effectively rotate the board
                                                  ;90 degrees.
new_calc_line:
                   ld a,d                         ;D=current line
                   sub 11h                        ;are we above the height of the board square?
                   jr nc,main_call                ;if so, skip drawing the line

                   adc a,d                        ;
                   jr nc,ovr_e                    ;
                   jr z,skp1                      ;
                   dec a                          ;
skp1:
                   cpl                            ;
ovr_e:
                   and 0fh                        ;
                                                  ;
                   inc a                          ;
                   ld b,a                         ;line length /2 in B
add_line_in:
                   ld d,l                         ;save HL position
                   ld e,80h
addl_lp1:
                   rlc e                          ;next bit left
                   jr nc,addl_ovr1                ;
                   dec l                          ;update HL if theres a carry
addl_ovr1:
                   djnz addl_lp1                  ;loop
draw_line:
                   add a,a                        ;x2 to get line length
                   ld b,a                         ;into B again
addl_lp2:
                   ld a,(hl)                      ;
                   or e                           ;
                   ld (hl),a                      ;merge bit with screen content
                   rrc e                          ;next right bit
                   jr nc,addl_ovr2                ;
                   inc l                          ;update HL if carry occurs
addl_ovr2:
                   djnz addl_lp2                  ;

                   ld l,d                         ;restore HL

main_call:
                   ld a,00h                       ;piece occupying the current square
                   or a                           ;is it empty?

                   call nz,builder_core           ;call main build routine if a piece occupies the square
reset_centre:
                   res 0,l                        ;ensure we're at the centre again.

next_line_up:
                   ld a,h                         ;fairly standard stuff
                   dec h                          ;I'm sure we're all
                   and 07h                        ;familiar with!
                   jr nz,nlu_end                  ;
                   ld a,l                         ;
                   add a,0e0h                     ;
                   ld l,a                         ;
                   sbc a,a                        ;
                   and 08h                        ;
                   add a,h                        ;
                   ld h,a                         ;
nlu_end:
                   pop bc                         ;B=height C=current square
                   pop de                         ;D=line
                   inc d                          ;inc line

                   djnz get_len                   ;inner loop for pieces

                   xor a                          ;reset the index pointer
                   ld (hl_store+1),a              ;
end_check_board:
                   inc c                          ;next square
                   jp nz,main_loop                ;repeat if needed

                   ret                            ;ret
                   
data_17:
                   db 04h,06h,08h,0ch,0ah,08h,06h,04h
                   db 02h,02h,02h,02h,02h,02h,02h,02h,0ffh          ;17 bytes

builder_core:
                   push hl                        ;save screen position
                   ld de,081eh                    ;set the bit markers, 08h = White

                   rra                            ;is it a black or white piece?
                   jr c,hl_store
                   ld d,80h                       ;D=80h bit marker for Black
hl_store:
                   ld hl,0fd00h                   ;line no. current. in the index
                   ld a,l                         ;
                   inc a                          ;next index line
jump_line:
                   cp 00h                         ;test for line switch.
                   jr nz,update_line_point        ;
switch:
                   ex af,af'                      ;restore A' holding index line to jump to
update_line_point:
                   ld (hl_store+1),a              ;update the index pointer
calc_data_addr:
                   ld a,(hl)                      ;get the index data
                   add a,a                        ;test BIT 7
                   ld b,l                         ;
                   jr nc,calc_ovr                 ;if its a line, not a reference, then process
                   rrca                           ;
                   ld b,a                         ;corrected line reference

calc_ovr:
                   ld l,00h                       ;HL = base address FD00
                   ld c,e                         ;C holds data Lo byte
calc_lp0:
                   ld a,(hl)                      ;get index line data into A
                   add a,a                        ;test bit 7 and multiply data length x 2
                   jr c,calc_no_inc               ;if no bit 7 then process addition of data len to the current position
                   and e                          ;mask data length value *1Eh
                   add a,c                        ;add current to total
                   jr nc,calc_lp1                  ;
                   rrc d                          ;advance to next cycle bit
                   ld a,e                         ;reset data address to FD1Eh
calc_lp1:
                   ld c,a                         ;update data Lo byte
calc_no_inc:
                   inc l                          ;next index line
                   djnz calc_lp0                  ;loop

                   ld ixl,c                       ;IX=data address

set_counters:
                   ld a,(hl)                      ;(HL) into A
                   add a,a                        ;X2
                   and e                          ;AND 1Eh
                   ld b,a                         ;into B
                   ld a,(hl)                      ;(HL) into A
                   rrca                           ;
                   rrca                           ;
                   rrca                           ;/8 (=C x 2)
                   and e                          ;mask again 1Eh
                   ld c,a                         ;into C
                   add a,b                        ;ADD B to get line length
restore_scradd:
                   pop hl                         ;restore buffer address
                   ret z                          ;if 00 then RET

                   rra                            ;line length /2 to give offset to left
                   ld e,80h                       ;set E screen bit mask
off_lp1:
                   rlc e                          ;calc offset left on screen
                   jr nc,off_lp2                  ;
                   dec l                          ;
off_lp2:
                   dec a                          ;
                   jr nz,off_lp1

save_sp:
                   ld (sp_save+1),sp              ;save SP to be restored at the end
set_white_ovr:
                   ld iy,4000h                    ;white overlay *depending upon the ititial value of IYL, this may not work reliably

                   push de                        ;save current bit position marker E
                   ld e,a                         ;set it to 00 invisible mode

b_w_check:
                   ld a,d                         ;current bit mask into A
                   add a,0f0h                     ;test for White
                   sbc a,a                        ;if white then there will be no carry
                   jr z,white                     ;result = 00 then jump to White
black:                                            ;result = FF then Black
                   adc a,b
                   jr nz,get_bit                  ;

                   dec c                          ;the Black overlay is a 1 bit until C=00, then inverts to a 0 bit
                   sub c                          ;
                   jr alter_jr                    ;
white:
                   or c                           ;
                   jr z,get_bit                   ;go get data if C=00

                   dec c                          ;
                   add iy,iy                      ;propagate overlay bit into Carry
                   jr alter_jr                    ;
get_bit:
                   dec b                          ;DEC data counter
                   ld a,(ix+00)                   ;A=data byte
                   inc ixl                        ;next data byte for next pass
                   and d                          ;mask bit
                   sub d                          ;
alter_jr:
                   sbc a,a
                   jr nz,put_bit                  ;test if we've hit a zero bit to switch to placing data
                   pop de                         ;switch on E bit for screen printing
put_bit:
                   push hl                        ;backup screen address
                   xor (hl)                       ;
                   and e                          ;mask the bit
                   xor (hl)                       ;
                   ld (hl),a                      ;place the byte
                   push af                        ;backup byte result onto stack
next_right:
                   rrc e                          ;next bit right
                   jr nc,next_ovr
                   inc l
next_ovr:
                   push de
end_test:
                   ld a,b                         ;test if both counters = 00
                   or c                           ;
                   jr nz,b_w_check                ;repeat if counters are not 00
restore_rhs:
                   pop de                         ;disregard this POP
                   pop af                         ;using the push'ed AFs
                   pop hl                         ;we can restore the background up to the point
                   ld (hl),a                      ;where we encounter a 0 bit
                   jr c,restore_rhs               ;if 1 then we need to restore the bit from the background
sp_save:
                   ld sp,0000h                    ;restore base position of Stack Pointer

                   ret


piece_sizes:
                   db 11h                         ;square only - will use 2 previous bytes as blanks
                   db 0fh,5fh,24h                 ;pawn
                   db 17h,4dh,29h                 ;castle
                   db 0fh,74h,2eh                 ;knight
                   db 1ah,38h,2fh                 ;bishop
                   db 28h,31h,2fh                 ;queen
                   db 00h,00h,30h                 ;king
Just ask if anything doesn't make sense. Actually thats probably most of it!
C.Born
Manic Miner
Posts: 209
Joined: Sat Dec 09, 2017 4:09 pm

Re: Graph Paper

Post by C.Born »

arkannoyed wrote: Mon Feb 05, 2018 3:53 pm Apologies, I really should've perhaps created a new thread for it rather that ruin this one.
does it help printing real isometric graph papers?
thats the one missing in this tread and the type off graph paper on which i learn some basics of 3d isometric drawing.
I was on school for 4 month to be a 'pipefitter' but my back is not strong enough (anymore).
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Isometric Chess display engine

Post by Ast A. Moore »

Hey, [mention]arkannoyed[/mention] is here! Hello there, mate! ;)
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
Seven.FFF
Manic Miner
Posts: 744
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: Isometric Chess display engine

Post by Seven.FFF »

Hiii. Yes the WoS thread makes interesting reading.

This, leading on to this.
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Isometric Chess display engine

Post by Nomad »

Know this is a bit cheeky arkannoyed but do you have a copy of the sprite reference sheet that you talk about, the dropbox link is 404. :lol:

https://www.worldofspectrum.org/forums/ ... 4-bytes/p3

https://dl.dropboxusercontent.com/u/280 ... g%20v4.pdf

That is quite an optimisation job, I didn't think you could get it that compact but each time you or Einar and the rest of the team take a look it seems bites are dropping off left and right :lol:
User avatar
arkannoyed
Manic Miner
Posts: 436
Joined: Mon Feb 05, 2018 9:56 am
Location: Northamptonshire

Re: Isometric Chess display engine

Post by arkannoyed »

Thanks everyone!

The sprite reference sheet would be a good place to begin, as its the case that the whole thing was built around the graphics data format initially.

I'll try and write some sort of easy to follow guide based upon a fragment of the data as an example.

https://dl.dropbox.com/s/2ncksrk1pgjv0 ... 4.pdf?dl=1

There have been a few minor changes to the actual sprites, but they were sort of done on the fly to save a few bits here and there, so I never got round to producing a 'final' graphics sheet.

The key on the top left hopefully gives an indication of what colour refers to what type of data the bit represents.
User avatar
arkannoyed
Manic Miner
Posts: 436
Joined: Mon Feb 05, 2018 9:56 am
Location: Northamptonshire

Re: Isometric Chess display engine

Post by arkannoyed »

By the way, perhaps obvious to only me, but its upside-down because the sprites are drawn from the bottom up, so it was just easier to read it like that for me.

As you might be able to see, the White and Black pieces are the same width for each line, and symmetrical about the center line, except for when we get to the Knight.

As you can see, there are several leading (reading from the left) or trailing RED bits. These are balancing bits, which the sprite drawing routine ignores as actual sprite data, but interprets them as just an instruction to move the print position to the next pixel right. This allows the sprites to all be symmetrical without actually having to conform to that restriction in all cases.

The clever bit with this (well I thought so anyway!) is that these are no extra switch bits or whatever needed. The routine switches from mask to print mode. All of this is done in a rather memory hungry way by using the stack.
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Isometric Chess display engine

Post by Nomad »

Ah I see so the red bits are position data for the drawing routine. That is very slick. Kind of like how the 32 byte demos use the UGL to encode commands.

So if you just use a colour you know you will not need, you can encode the bits with data and not have it display. That is very nice. I had a tile draw routine I was trying to figure out a way to encode attribute data to the tiles without extra data structures this would be a good method I think.
User avatar
arkannoyed
Manic Miner
Posts: 436
Joined: Mon Feb 05, 2018 9:56 am
Location: Northamptonshire

Re: Isometric Chess display engine

Post by arkannoyed »

The data is actually inverted due to the way the XOR/ AND/ XOR bit placing works.

So, for instance for the top line (the bottom line of the base, which is common to all the pieces), it is 8 x 0 bits for both the Black and White pieces.
its encoded as;

11111111

There is a separate index that gives the line lengths. Lines are either all data, or a mix of data and a standard infill (different whether Black or White)

The infill for Black is: 1111111110, where the leading '1's can be any length up to 16 bits and will always be on the Right, after the data has finished being placed.

The infill for White is:0100000000, where the trailing '0's can be any length up to 16 bits and will always be on the Left, and placed before the Data.

Sorry if I've lost anyone so far!!

The index of line data is constructed as follows;

Bit 7 indicates whether it is line data(0), or a reference to another line (1)

Bits 6-4 indicate the standard infill length

Bits 3-0 indicate the data length.

The line length is then made by adding the infill+data x 2

To find the print position to start from we take infill+data and move the position left from the center until we find it, which is a bit of a bottleneck in some on of the longer lines.

So, the index for the bottom line of the base is;

0 000 0100 (04h)

Before I move on, any questions? :)
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Isometric Chess display engine

Post by Nomad »

Just one, how did you come to use this technique it was something you discovered from another program or it was a technique you cooked up? I like the way that the repeated graphics data gets copied across the chessmen.

I had seen isometric chess before on the spectrum but nothing like this. Haha its voodoo. :lol: so what gave you the insperation to try the project in the first place. Was it a way to showcase the technique or did the techniques grow out of the project requirements?

It seems the knight was the real headache :lol: If it were checkers no doubt you could have done it in a few hundred bytes.
User avatar
arkannoyed
Manic Miner
Posts: 436
Joined: Mon Feb 05, 2018 9:56 am
Location: Northamptonshire

Re: Isometric Chess display engine

Post by arkannoyed »

Inspiration...well I can't actually remember that far back! :lol:

I designed the original sprites in about 1992 on a real Speccy. The board was just a huge 4096 bytes screen block and the sprites along with masks were 4000 bytes exactly.

Then there were data tables for the Print position for each square on the board, sprite address+size.

Many years later after rescuing it by using SAM disk on my old +D disks, I one day began looking at trying to make it a little less...huge?!

To begin with I made use of the fact that both Black and White used the same masks, that saved quite a chunk. Then the more I examined the sprite data, the more it became apparent that with very few alterations, there was the possibility to re-use many of the lines in other places within the sprite as a whole.

The standard infill data was then identified, which got the graphics data smaller again. Then I wondered if it was possible to make some sort of intelligent masking system. By actually just printing the pixels needed, there isn't any need to mask at all. as you retain the background anyway.

In the case of the Knight, it actually didn't take much to come up with the idea of 'balancing bits', and initially the stack was a quick and dirty way of doing it. However, the more I optimised everything else, the more I realised that no matter how hard I tried, I couldn't find a better way of doing it.

The DATA for the index and sprites continued to shrink along with the actual code to decode it. To the point that the Graphics now actually only occupy
145 bytes for the lines index, 19 bytes for the piece sizes and index positions, and 232 bytes for Sprite BMPs, giving a total of 396 bytes, which is less than 10% of the original 'circa 1992' size. 8-)

The board was examined and I decided that I liked the idea of building it procedurally, and in actual fact, why do we need to print the White squares? So there is a small routine to calculate the line length based upon the current overall line number (always beginning with 00), followed by a simple offset finder and line plotter together 39 bytes.

If the current line is above where the square would need to be drawn (if it were a Black square) then that routine is skipped.

Now, instead of the Print positions address table, we have a routine that calculates it by just being given the current square number (00-3fh, 0-63)
That routine is 27 bytes.

...and breathe!!. :o
User avatar
arkannoyed
Manic Miner
Posts: 436
Joined: Mon Feb 05, 2018 9:56 am
Location: Northamptonshire

Re: Isometric Chess display engine

Post by arkannoyed »

The other very important part is the board builder that sets the positions for the start of a new game.

Its actually a routine the Einar mainly contributed to, and has changed little since.

It consists of a 23 byte routine and 17 bytes of data to set the 64 positions of the board.

The routine currently resides in an empty space created amongst the Sprite data with 1 annoying spare byte at the end!

The data is plonked between the 2 main routines.

I've not given this routine much attention, but I'm fairly sure that with some clever processing I could make it all routine and no data, and probably smaller than 40 bytes.

The actual board map therefore isn't part of the overall size, as its built when needed, and can actually be located elsewhere if needed.
User avatar
arkannoyed
Manic Miner
Posts: 436
Joined: Mon Feb 05, 2018 9:56 am
Location: Northamptonshire

Re: Isometric Chess display engine

Post by arkannoyed »

So, once you've digested that, I'll try and clear up anything that I've not explained clearly enough, which is probably most of it, before I move on to some other aspects.
User avatar
arkannoyed
Manic Miner
Posts: 436
Joined: Mon Feb 05, 2018 9:56 am
Location: Northamptonshire

Re: Isometric Chess display engine

Post by arkannoyed »

Nomad wrote: Tue Feb 06, 2018 11:58 am Just one, how did you come to use this technique it was something you discovered from another program or it was a technique you cooked up? I like the way that the repeated graphics data gets copied across the chessmen.

I had seen isometric chess before on the spectrum but nothing like this. Haha its voodoo. :lol: so what gave you the insperation to try the project in the first place. Was it a way to showcase the technique or did the techniques grow out of the project requirements?

It seems the knight was the real headache :lol: If it were checkers no doubt you could have done it in a few hundred bytes.
The Knight was a headache, and if I did without the whole masking thing, it would be faster and save 18 bytes too. But, I wanted from the outset to ensure that the sprites remained as true to the original design as was possible.
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Isometric Chess display engine

Post by Nomad »

It's so fast :o that is some nice work. I can't pretend to understand what voodoo your working to get it to be that way lol. It will be fun figuring out exactly what its doing. Are you planning on adding the coordinates as isometric fonts?
User avatar
arkannoyed
Manic Miner
Posts: 436
Joined: Mon Feb 05, 2018 9:56 am
Location: Northamptonshire

Re: Isometric Chess display engine

Post by arkannoyed »

One day, when I get as far as some control method and indication of state etc, I'll try to make it text free, and perhaps just graphically based. I did do some work towards that last year before moving on to other Speccy projects.
User avatar
arkannoyed
Manic Miner
Posts: 436
Joined: Mon Feb 05, 2018 9:56 am
Location: Northamptonshire

Re: Isometric Chess display engine

Post by arkannoyed »

Theres definately on Voodoo involved. I'd really like to find a way to explain it clearly enough so that it de-mystifies it. Its not really so complex once you get to understand whats going on. I started to write a sprite designer in Basic on the Speccy that can encode the sprites as they need to be for the display routine. I could also write some sort of demonstration with annotations that could show step by step whats going on I suppose.
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Isometric Chess display engine

Post by Nomad »

Lol its just me being a potato, I am sure once I sit down and work through it following the comments it will become clear. Don't let me put you out with extra work :lol:
Post Reply