Login

Subversion Repositories NedoOS

Rev

Rev 1510 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

        DEVICE ZXSPECTRUM128
        include "../../_sdk/sys_h.asm"

STACK=0x4000
MAXVERTICES=256
MAXEDGES=768;512;256
scrbase=0x8000
prarr_scrbase=0x8000

scrwidpix=320
scrhgt=200

COLORS_UNCROSSED=%11001001
COLORS_CROSSED=%11010010

nofocuskey=0xff

        org PROGSTART
begin
        ld sp,STACK
        OS_HIDEFROMPARENT

        ld e,0
        OS_SETGFX ;e=0:EGA, e=2:MC, e=3:6912, e=6:text ;+SET FOCUS ;e=-1: disable gfx (out: e=old gfxmode)

        ;OS_GETSCREENPAGES
;de=страницы 0-го экрана (d=старшая), hl=страницы 1-го экрана (h=старшая)
        call cls

        ld de,pal
        OS_SETPAL

        ld a,r
        ld (rndseed1),a
        OS_GETTIMER ;dehl=timer
        ld (rndseed2),hl
         ld (oldupdtimer),hl

        ld de,filename
        OS_OPENHANDLE
        ;ld a,-1
        or a
        jr nz,noloadini
        push bc
        ld de,SAVEDATA
        ld hl,SAVEDATAsz
        OS_READHANDLE
        pop bc
        OS_CLOSEHANDLE
        jr loadiniq
noloadini
        ;ld a,8
        xor a
        ld (level),a
        call countverticesneeded
        ;jr $
        call genmesh
loadiniq
         call cls
        call redraw
       
        jr mouseloop_go
mouseloop
;1. всё выводим
;2. ждём событие
;[3. всё стираем]
;4. обрабатываем событие (без перерисовки)
;5. всё стираем

        ld a,(clickstate)
        or a
        jr z,mouseloop_nomove
        call   drawcurvertex
        ;call   drawconnectedvertices
        call   drawcuredges

        ;call ahl_coords
        call movecurvertex

        call drawcuredges
        ;call drawconnectedvertices
        call drawcurvertex
       
        call ahl_coords
        cp 8
        jr nc,$+2+2+3
         ld a,1
         ld (invalidatetime),a
       
mouseloop_nomove

         call clsifneeded ;TODO убрать?
         call redrawifneeded ;TODO убрать?
         
        ld a,(key)
        cp nofocuskey
        call nz,prlevelifneeded

mouseloop_go
;сейчас всё выведено, кроме стрелки
        ld a,(key)
        cp nofocuskey
        jr z,mouseloop_noprarr
        call ahl_coords
        call shapes_memorizearr
        call ahl_coords
        call shapes_prarr8c
mouseloop_noprarr
        ;call waitsomething ;в это время стрелка видна
mainloop_nothing0
        call updatetime
;в это время стрелка видна
        YIELD ;halt
        call control
        jr nz,mainloop_something
         ld a,(invalidatetime)
         or a
        jr z,mainloop_nothing0
mainloop_something
;что-то изменилось
       
        ld a,(key)
        cp nofocuskey
        jr z,mouseloop_norearr
        ld a,(oldarry)
        ld hl,(oldarrx)
        call shapes_rearr
mouseloop_norearr
;сейчас всё выведено, кроме стрелки

key=$+1
        ld a,0
        cp key_esc
        call z,quitifnoclickstate
        cp key_redraw
        push af
        call z,cls
        pop af
        call z,redraw

        ;call control_keys
clickstate=$+1
        ld a,0
        or a
        jr nz,mouseloop_wasclicked
        ld a,(mousebuttons)
        cpl
        and 7
        call nz,mouse_fire
        jp mouseloop
mouseloop_wasclicked
        ld a,(mousebuttons)
        cpl
        and 7
        call z,mouse_unfire
        jp mouseloop


mouse_unfire
        ld a,1
        ld (doredraw),a
        xor a
        ld (clickstate),a

;обновить счётчик crossededges конкретно по рёбрам, которые пересекались в начале и в конце движения
;для этого для старой позиции вершины для каждого из связанных рёбер декрементируем все пересечения (у него и у пересечённого)
;а для новой позиции вершины для каждого из связанных рёбер инкрементируем все пересечения (у него и у пересечённого)

;для новой позиции вершины для каждого из связанных рёбер инкрементируем все пересечения (у него и у пересечённого)
        ld hl,inccrossedandself
        call inccrossededges
;или просто посчитаем каждый с каждым
        ;call countcrossededges
       
;после победы уже не проверяем победу
        ld a,(nextlevelon)
        or a
        ret nz

;check if untangled
        ;ld hl,(ncrossededges)
        ld hl,edges
        ld de,0 ;count*2
        ld bc,(nedges)
sumcrossededges0
        inc hl
        inc hl
        ld a,(hl) ;crossed
        inc hl
        add a,e
        ld e,a
         ld a,(hl) ;crossedHSB
        adc a,d
        ;sub e
        ld d,a
         inc hl
        dec bc
        ld a,b
        or c
        jr nz,sumcrossededges0
;de=2*ncrossededges
        ld a,d
        or e
        jr z,levelcomplete
       
        ret

levelcomplete
        ld a,' '
        ld (nextlevelon),a
        ;ld a,1
        ld (invalidatetime),a
        ret
       
mouse_fire_nextlevel
        call ahl_coords
        cp 8
        jr nc,mouse_fire_nonextlevel
        ld bc,-(8*(nextlevelon+1-tlevel))
        ;or a
        ;sbc hl,bc
        add hl,bc
        ld bc,8*10 ;"NEXT LEVEL"
        or a
        sbc hl,bc
        jr nc,mouse_fire_nonextlevel
;levelcomplete_go
        xor a
        ld (nextlevelon),a
        inc a;ld a,1
        ld (invalidatetime),a
        ;ld a,1
        ld (docls),a
        ld (doredraw),a
        ld hl,level
        inc (hl)
         ;jr $
        call countverticesneeded
        jp genmesh

mouse_fire
        ld a,(nextlevelon)
        or a
        jr nz,mouse_fire_nextlevel
mouse_fire_nonextlevel
        call ahl_coords
        call findvertex
        ret c ;not found
        ld (curvertex),a
        ld a,1
        ld (clickstate),a
;для старой позиции вершины для каждого из связанных рёбер декрементируем все пересечения (у него и у пересечённого)
        ld hl,deccrossedandself
        call inccrossededges
;стираем текущую вершину, текущие рёбра и перерисовываем их инверсией
        call undrawcurvertex
        call undrawconnectedvertices
        call undrawcuredges
        ;call cls
        call drawunconnectededges
        call drawunconnectedvertices

        call prlevel
       
        call drawcuredges
        call drawconnectedvertices
        ;jp drawcurvertex
drawcurvertex
        ;ld a,(clickstate)
        ;or a
        ;ret z ;unclicked
        call getcurvertexxy_ahl
        jp shapes_prarr_ring8c
drawringon
        bit 0,l
        ld de,sprringon_l+1
        jr nz,$+5+2
         ld de,sprringon_r+1
         dec hl
         dec hl
        jp prarr_cross8c_go


movecurvertex
        ld a,(clickstate)
        or a
        ret z ;unclicked
        call getcurvertexaddr
        push hl
        call ahl_coords
         cp 7
         jr nc,$+4
         ld a,7 ;max dy = 192 (for fast mul)
        ex de,hl
        pop hl
        ld (hl),e
        inc hl
        ld (hl),d ;x
        inc hl
        ld (hl),a ;y
        inc hl
        ld (hl),0
        ret

undrawcurvertex
        ;ld a,(clickstate)
        ;or a
        ;ret z ;unclicked
        call getcurvertexxy_ahl
        ;jp shapes_prarr_ring8c
drawringoff
        bit 0,l
        ld de,sprringoff_l+1
        jr nz,$+5+2
         ld de,sprringoff_r+1
         dec hl
         dec hl
        jp prarr_cross8c_go

getcurvertexxy_ahl
        call getcurvertexaddr
        ld c,(hl)
        inc hl
        ld b,(hl) ;x
        inc hl
        ld e,(hl)
        inc hl
        ld d,(hl) ;y
        ld a,e ;y
        ld h,b
        ld l,c ;x
        ret

getcurvertexaddr
curvertex=$+1
        ld hl,0
        ld de,vertices
        add hl,hl
        add hl,hl
        add hl,de
        ret

undrawcuredges
        call setlinenormalmask
        ;ld a,0x47 ;keep left pixel ;иначе надо cls перед redraw
        ;ld (lineverR_and_r),a
        ;ld (lineverL_and_r),a
        ;cpl
        ;ld (lineverR_and_l),a
        ;ld (lineverL_and_l),a
        ;ld hl,delpixel
        xor a
        jr drawcuredges_go
drawcuredges
        ld a,0xff
        ld (lineverR_and_l),a
        ld (lineverL_and_l),a
        ld (lineverR_and_r),a
        ld (lineverL_and_r),a
        ld (linehorR_and_r),a
        ld (linehorL_and_r),a
        ld (linehorR_and_l),a
        ld (linehorL_and_l),a
        ;ld hl,invpixel
        ;ld a,0xff
drawcuredges_go
        ;ld (pixelprocver),hl
        ;ld (pixelprochor),hl
        ld (drawcuredges_colormask),a
        ld a,(clickstate)
        or a
        ret z ;unclicked
;find all edges with current vertex (1st or 2nd), draw them
;vertex1,vertex2,crossed
        ld hl,edges
        ld bc,(nedges)
drawcuredges0
        push bc
        ld e,(hl)
        inc hl
        ld d,(hl)
        inc hl
        ld a,(curvertex)
        cp d
        jr z,$+3
        cp e
        jr nz,drawcuredgesno
        push hl
        ld a,(hl)
         inc hl
         or (hl) ;crossedHSB
;e=vertex1
;d=vertex2
;a=crossed
        or a
        ld a,COLORS_UNCROSSED;%11001001
        jr z,$+4
        ld a,COLORS_CROSSED;%11010010
drawcuredges_colormask=$+1
        and 0
        call drawedge
        pop hl
drawcuredgesno
        pop bc
         inc hl
        ;inc hl
        ;dec bc
        ;ld a,b
        ;or c
        ;jr nz,drawcuredges0
        cpi
        jp pe,drawcuredges0
        ;ld hl,prpixel
        ;ld (pixelprocver),hl
        ;ld (pixelprochor),hl
setlinenormalmask
        ld a,0x47 ;keep left pixel ;иначе надо cls перед redraw
        ld (lineverR_and_r),a
        ld (lineverL_and_r),a
        ld (linehorR_and_r),a
        ld (linehorL_and_r),a
        cpl
        ld (lineverR_and_l),a
        ld (lineverL_and_l),a
        ld (linehorR_and_l),a
        ld (linehorL_and_l),a
        ret

drawconnectedvertices
        ld hl,shapes_prarr_ring8c;drawringon
        jr drawconnectedvertices_go
undrawconnectedvertices
        ld hl,drawringoff
drawconnectedvertices_go
        ld (drawconnectedvertices_drawproc),hl
        ld hl,edges
        ld bc,(nedges)
drawconnectedvertices0
        push bc
        ld e,(hl)
        inc hl
        ld d,(hl)
        inc hl
;e=vertex1
;d=vertex2
        ld a,(curvertex)
        cp d
        jr z,drawconnectedvertices_e
        cp e
        jr nz,drawconnectedverticesno
        ld e,d
drawconnectedvertices_e
        push hl
        ld d,0 ;e=connected vertex
        ld hl,vertices
        add hl,de
        add hl,de
        add hl,de
        add hl,de
        ld c,(hl)
        inc hl
        ld b,(hl) ;x
        inc hl
        ld e,(hl)
        inc hl
        ld d,(hl) ;y
        ld a,e ;y
        ld h,b
        ld l,c ;x
drawconnectedvertices_drawproc=$+1
        call drawringon
        pop hl
drawconnectedverticesno
        pop bc
         inc hl ;crossedHSB
        ;inc hl
        ;dec bc
        ;ld a,b
        ;or c
        ;jr nz,drawconnectedvertices0
        cpi
        jp pe,drawconnectedvertices0
        ret

drawunconnectededges
;рисуем все рёбра, кроме связанных с текущей вершиной
;find all edges with current vertex (1st or 2nd), draw others
;vertex1,vertex2,crossed
        ld hl,edges
        ld bc,(nedges)
drawunconnectededges0
        push bc
        ld e,(hl)
        inc hl
        ld d,(hl)
        inc hl
        ld a,(curvertex)
        cp d
        jr z,$+3
        cp e
        jr  z,drawunconnectededgesno
        push hl
        ld a,(hl)
         inc hl
         or (hl) ;crossedHSB
;e=vertex1
;d=vertex2
;a=crossed
        or a
        ld a,COLORS_UNCROSSED;%11001001
        jr z,$+4
        ld a,COLORS_CROSSED;%11010010
        call drawedge
        pop hl
drawunconnectededgesno
        pop bc
         inc hl
        ;inc hl
        ;dec bc
        ;ld a,b
        ;or c
        ;jr nz,drawunconnectededges0
        cpi
        jp pe,drawunconnectededges0
        ret
       
drawunconnectedvertices
;рисуем все вершины, кроме текущей и связанных с ней
;для этого:
;чистим таблицу связанных вершин
        ld hl,vertlinkflags
        ld de,vertlinkflags+1
        ld bc,MAXVERTICES-1
        ld (hl),0
        ldir
;помечаем там текущую вершину
        ld de,vertlinkflags
        ld hl,(curvertex)
        ld h,b;0
        add hl,de
        inc (hl)
;перебираем все рёбра, ищем там связанные вершины и помечаем в таблице связанных вершин
        ld hl,edges
        ld bc,(nedges)
drawunconnectedvertices0
        ld e,(hl)
        inc hl
        ld d,(hl)
        inc hl
;e=vertex1
;d=vertex2
        ld a,(curvertex)
        cp d
        jr z,drawunconnectedvertices_e
        cp e
        jr nz,drawunconnectedverticesno
        ld e,d
drawunconnectedvertices_e
        push hl
        ld d,0 ;e=connected vertex
        ld hl,vertlinkflags
        add hl,de
        inc (hl)
        pop hl
drawunconnectedverticesno
         inc hl ;crossedHSB
        inc hl
        dec bc
        ld a,b
        or c
        jr nz,drawunconnectedvertices0
;перебираем все вершины, выводим только не попавшие в таблицу
        ld hl,vertlinkflags
        ld a,(nvertices)
        ld b,a
drawunconnectedvertices1
        push bc
        push hl
        ld a,(nvertices)
        sub b
        ld e,a
         ld a,(hl) ;linkflag
        ld d,0 ;e=connected vertex
        ld hl,vertices
        add hl,de
        add hl,de
        add hl,de
        add hl,de
        ld c,(hl)
        inc hl
        ld b,(hl) ;x
        inc hl
        ld e,(hl)
        inc hl
        ld d,(hl) ;y
         or a
        ld a,e ;y
        ld h,b
        ld l,c ;x
        call z,drawringon
        pop hl
        inc hl
        pop bc
        djnz drawunconnectedvertices1
        ret
       
countverticesneeded
        ld a,6
        ld (verticesneeded),a
        ld a,(level)
        or a
        ret z
        ld b,a
countverticesneeded0
        ld a,b
        add a,3 ;a=4..
        ld hl,verticesneeded
        add a,(hl)
        jr nc,$+3
        sbc a,a
        ld (hl),a
        djnz countverticesneeded0
        ret

ahl_coords
        ld a,(arry)
        ld hl,(arrx)
        ret


quitifnoclickstate
        ld a,(clickstate)
        or a
        ret nz
quit
        ld de,filename
        OS_CREATEHANDLE
        push bc
        ld de,SAVEDATA
        ld hl,SAVEDATAsz
        OS_WRITEHANDLE
        pop bc
        OS_CLOSEHANDLE
        QUIT
       
filename
        db "untangle.ini",0

redrawifneeded
        xor a
doredraw=$+1
        cp 0
        ret z
redraw
        xor a
        ld (doredraw),a
        call setscrpgs
        call drawedges
        call drawvertices
        jr prlevel

prlevelifneeded
        xor a
invalidatetime=$+1
        cp 0
        ret z
prlevel
        ld a,(level)
        inc a
        ld hl,tleveldig1
        call dectotxt12
        ;ld (tleveldig2),a
        ;ld a,b
        ;ld (tleveldig1),a
        ld a,(cur_h)
        ld hl,ttimeh1
        call dectotxt12
        ld a,(cur_m)
        ld hl,ttimem1
        call dectotxt12
        ld a,(cur_s)
        ld hl,ttimes1
        call dectotxt12
       
         xor a
         ld (invalidatetime),a
        ld b,a
        ld c,a ;ld bc,0
        ld hl,tlevel
        jp prtext

dectotxt12
        ld b,'0'-1
        inc b
        sub 10
        jr nc,$-3
        add a,'0'+10
         ld (hl),b
         inc hl
         ld (hl),a
        ret

updatetime
        OS_GETTIMER ;dehl=timer
        ld de,(oldupdtimer)
        ld (oldupdtimer),hl
        or a
        sbc hl,de ;hl=frames
        ret z
        ld b,h
        ld c,l
updatetime0
        call inctime
        ;dec bc
        ;ld a,b
        ;or c
        ;jr nz,updatetime0
        cpi
        jp pe,updatetime0
        ret
inctime
        ld hl,cur_f
        inc (hl)
        ld a,(hl)
        sub 50
        ret c
        ld (hl),a
         ld a,1
         ld (invalidatetime),a
        ld hl,cur_s
        inc (hl)
        ld a,(hl)
        sub 60
        ret c
        ld (hl),a
        ld hl,cur_m
        inc (hl)
        ld a,(hl)
        sub 60
        ret c
        ld (hl),a
        ld hl,cur_h
        inc (hl)
        ret

        if 1==0
genvertices
;x,X,y,Y
        ld hl,vertices
        ld a,(nvertices)
        ld b,a
genvertices0
        push bc
        ld c,160
        call rnd
        add a,a
        ld (hl),a
        inc hl
        ld (hl),0
        rl (hl)
        inc hl
        ld c,200
        call rnd
        ld (hl),a
        inc hl
        ld (hl),0
        inc hl
        pop bc
        djnz genvertices0
        ret
        endif

        if 1==0
genedges
;vertex1,vertex2,crossed
        ld hl,edges
        ld bc,(nedges)
genedges0
        push bc
        ld a,(nvertices)
        ld c,a
        call rnd
        ld (hl),a
        inc hl
        ld a,(nvertices)
        ld c,a
        call rnd
        ld (hl),a
        inc hl
        ld (hl),0 ;uncrossed
        inc hl
         ld (hl),0 ;crossedHSB
         inc hl
        pop bc
        dec bc
        ld a,b
        or c
        jr nz,genedges0
        ret
        endif

drawedges
;vertex1,vertex2,crossed
        ld hl,edges
        ld bc,(nedges)
drawedges0
        push bc
        ld e,(hl)
        inc hl
        ld d,(hl)
        inc hl
        ld a,(hl)
         inc hl
         or (hl) ;crossedHSB
        push hl
;e=vertex1
;d=vertex2
;a=crossed
        or a
        ld a,COLORS_UNCROSSED;%11001001
        jr z,$+4
        ld a,COLORS_CROSSED;%11010010
        call drawedge
        pop hl
        pop bc
        ;inc hl
        ;dec bc
        ;ld a,b
        ;or c
        ;jr nz,drawedges0
        cpi
        jp pe,drawedges0
        ret

drawvertices
;x,X,y,Y
        ld hl,vertices
        ld a,(nvertices)
        ld b,a
drawvertices0
        push bc
        ld c,(hl)
        inc hl
        ld b,(hl) ;x
        inc hl
        ld e,(hl)
        inc hl
        ld d,(hl) ;y
        inc hl
        push hl
        ld a,e ;y
        ld h,b
        ld l,c ;x
        call drawringon;shapes_prarr_ring8c
        pop hl
        pop bc
        djnz drawvertices0
        ret

findvertex
;in: hl=arrx, a=arry
;out: CY=not found, or else a=vertex #
        ex de,hl
        ld c,a
;x,X,y,Y
        ld hl,vertices
        ld a,(nvertices)
        ld b,a
findvertex0
        ld a,(hl)
        inc hl
        push hl
        ld h,(hl)
        ld l,a ;x
        or a
        sbc hl,de ;x-arrx
        inc hl
        inc hl
        push de
        ld de,5
        or a
        sbc hl,de ;CY = -2..+2
        pop de
        pop hl
        inc hl
        jr nc,findvertexno
        push hl
        ld a,(hl)
        inc hl
        ld h,(hl)
        ld l,a ;y
        push bc
        xor a
        ld b,a
        sbc hl,bc ;y=arry
        inc hl
        inc hl
        ld bc,5
        or a
        sbc hl,bc ;CY = -2..+2
        pop bc
        pop hl
        jr c,findvertexok
findvertexno
        inc hl
        inc hl
        djnz findvertex0
        scf
        ret
findvertexok
        ld a,(nvertices)
        sub b
        or a
        ret

rnd
;0..c-1
        ;ld a,r
        push de
        push hl
        call func_rnd
        pop hl
        pop de
rnd0
        sub c
        jr nc,rnd0
        add a,c
        ret

func_rnd
;Patrik Rak
rndseed1=$+1
        ld  hl,0xA280   ; xz -> yw
rndseed2=$+1
        ld  de,0xC0DE   ; yw -> zt
        ld  (rndseed1),de  ; x = y, z = w
        ld  a,e         ; w = w ^ ( w << 3 )
        add a,a
        add a,a
        add a,a
        xor e
        ld  e,a
        ld  a,h         ; t = x ^ (x << 1)
        add a,a
        xor h
        ld  d,a
        rra             ; t = t ^ (t >> 1) ^ w
        xor d
        xor e
        ld  h,l         ; y = z
        ld  l,a         ; w = t
        ld  (rndseed2),hl
        ;ex de,hl
        ;ld hl,0
        ;res 7,c ;int
        ret


div4signedup
        or a
        jp m,$+5
        add a,3
        sra a
        sra a
        ret

clsifneeded
        xor a
docls=$+1
        cp 0
        ret z
        ld (docls),a ;0
cls
        ld e,0
        OS_CLS
        ret

prtext
;bc=координаты
;hl=text
        ld a,(hl)
        or a
        ret z
        call prcharxy
        inc hl
        inc c
        jr prtext

prnum
        ld bc,1000
        call prdig
        ld bc,100
        call prdig
        ld bc,10
        call prdig
        ld bc,1
prdig
        ld a,'0'-1
prdig0
        inc a
        or a
        sbc hl,bc
        jr nc,prdig0
        add hl,bc
        ;push hl
        ;call prchar
        ;pop hl
        ;ret
prchar
;a=code
;de=screen
        push de
        push hl
        call prcharin
        pop hl
        pop de
        inc e
        ret
       
calcscraddr
;bc=yx
;можно портить bc
        ex de,hl
        ld a,c ;x
        ld l,b ;y
        ld h,0
        ld b,h
        ld c,l
        add hl,hl
        add hl,hl
        add hl,bc ;*5
         add hl,hl
         add hl,hl
         add hl,hl ;*40
         add hl,hl
         add hl,hl
         add hl,hl
        add a,l
        ld l,a
        ld a,h
        adc a,0x80
        ld h,a
        ex de,hl
        ret

prcharxy
;a=code
;bc=yx
        push de
        push hl
        push bc
        push af
        call calcscraddr
        pop af
        call prcharin
        pop bc
        pop hl
        pop de
        ret
       
prcharin
        sub 32
        ld l,a
        ld h,0
         add hl,hl
         add hl,hl
         add hl,hl
         add hl,hl
         add hl,hl
        ;ld bc,font-(32*32)
        ;add hl,bc
        ld a,h
        add a,font/256
        ld h,a
prcharin_go
        ex de,hl
       
        ld bc,40
        push hl
        push hl
        dup 8
        ld a,(de) ;font
        ld (hl),a ;scr
        inc de
        add hl,bc
        edup
        pop hl
        set 6,h
        ;ld d,font/256
        dup 8
        ld a,(de) ;font
        ld (hl),a ;scr
        inc de
        add hl,bc
        edup
        pop hl
        set 5,h
        push hl
        ;ld d,font/256
        dup 8
        ld a,(de) ;font
        ld (hl),a ;scr
        inc de
        add hl,bc
        edup
        pop hl
        set 6,h
        ;ld d,font/256
        dup 8
        ld a,(de) ;font
        ld (hl),a ;scr
        inc de
        add hl,bc
        edup        
        ret

        if 1==0

invpixel
;bc=x (не портится)
;e=y (не портится)
;screen pages are mapped in 2 CPU windows
;addr = tY(y) + tX(x)
        push bc
        ld a,b
        rra
        ld a,c
        rra
        ld l,a
        ;ld d,ty/256
        ;ld h,tx/256
        ld a,(de) ;(y*40)
        jr c,invpixel_r
        add a,(hl) ;x div 4
        ld c,a
        inc d
        inc h
        ld a,(de) ;'(y*40)
        adc a,(hl) ;f(x mod 4)
        ld b,a
        ld a,(bc)
invpixel_color_l=$+1
        xor 0;lx
        ld (bc),a
        dec h
        dec d
        pop bc
        ret
invpixel_r
        add a,(hl) ;x div 4
        ld c,a
        inc d
        inc h
        ld a,(de) ;'(y*40)
        adc a,(hl) ;f(x mod 4)
        ld b,a
        ld a,(bc)
invpixel_color_r=$+1
        xor 0;lx
        ld (bc),a
        dec h
        dec d
        pop bc
        ret

prpixel
;bc=x (не портится)
;e=y (не портится)
;screen pages are mapped in 2 CPU windows
;addr = tY(y) + tX(x)
        push bc
        ld a,b
        rra
        ld a,c
        rra
        ld l,a
        ;ld d,ty/256
        ;ld h,tx/256
        ld a,(de) ;(y*40)
        jr c,prpixel_r
        add a,(hl) ;x div 4
        ld c,a
        inc d
        inc h
        ld a,(de) ;'(y*40)
        adc a,(hl) ;f(x mod 4)
        ld b,a
        ld a,(bc)
        and 0xb8 ;keep right pixel ;иначе надо cls перед redraw
prpixel_color_l=$+1
        or 0;lx
        ld (bc),a
        dec h
        dec d
        pop bc
        ret
prpixel_r
        add a,(hl) ;x div 4
        ld c,a
        inc d
        inc h
        ld a,(de) ;'(y*40)
        adc a,(hl) ;f(x mod 4)
        ld b,a
        ld a,(bc)
        and 0x47 ;keep left pixel ;иначе надо cls перед redraw
prpixel_color_r=$+1
        or 0;lx
        ld (bc),a
        dec h
        dec d
        pop bc
        ret
       
delpixel
;bc=x (не портится)
;e=y (не портится)
;screen pages are mapped in 2 CPU windows
;addr = tY(y) + tX(x)
        push bc
        ld a,b
        rra
        ld a,c
        rra
        ld l,a
        ;ld d,ty/256
        ;ld h,tx/256
        ld a,(de) ;(y*40)
        jr c,delpixel_r
        add a,(hl) ;x div 4
        ld c,a
        inc d
        inc h
        ld a,(de) ;'(y*40)
        adc a,(hl) ;f(x mod 4)
        ld b,a
        ld a,(bc)
        and 0xb8 ;keep right pixel
        ld (bc),a
        dec h
        dec d
        pop bc
        ret
delpixel_r
        add a,(hl) ;x div 4
        ld c,a
        inc d
        inc h
        ld a,(de) ;'(y*40)
        adc a,(hl) ;f(x mod 4)
        ld b,a
        ld a,(bc)
        and 0x47 ;keep left pixel
        ld (bc),a
        dec h
        dec d
        pop bc
        ret
       
        endif

drawedge
;e=vertex1
;d=vertex2
;a=color = %33210210
        ;ld (prpixel_color_l),a
        ;ld (prpixel_color_r),a
        ld l,a
        and 0x47;%01000111 ;keep left pixel
        ;ld (invpixel_color_l),a
         ;ld (prpixel_color_l),a
         ld (lineverR_color_l),a
         ld (lineverL_color_l),a
         ld (linehorR_color_l),a
         ld (linehorL_color_l),a
        xor l ;keep right pixel
        ;ld (invpixel_color_r),a
         ;ld (prpixel_color_r),a
         ld (lineverR_color_r),a
         ld (lineverL_color_r),a
         ld (linehorR_color_r),a
         ld (linehorL_color_r),a
        ld h,0
        ld l,e ;vertex1
        ld bc,vertices
        add hl,hl
        add hl,hl
        add hl,bc
        ld c,(hl)
        inc hl
        ld b,(hl) ;x
        inc hl
        ld a,(hl) ;y

        ld h,0
        ld l,d ;vertex2
        ld de,vertices
        add hl,hl
        add hl,hl
        add hl,de ;NC
        ld e,(hl)
        inc hl
        ld d,(hl) ;x2
        inc hl
;bc=x (в плоскости экрана, но может быть отрицательным)
;a=y
;de=x2
;(hl)=y2
        ;or a
        ;sbc hl,de
        ;add hl,de
        ;jp p,shapes_line_noswap
         sub (hl)
        jr c,shapes_line_noswap
        push af ;dy
        ld a,d
        ld d,b
        ld b,a
        ld a,e
        ld e,c
        ld c,a ;x <-> x2
        ex de,hl
        sbc hl,bc
        push hl ;dx
        ex de,hl
         ld e,(hl) ;y
         jp shapes_line_noswapq
shapes_line_noswap
        neg
        push af ;dy
        neg
        add a,(hl)
        ex de,hl
        or a
        sbc hl,bc
        push hl ;dx
         ld e,a ;y
shapes_line_noswapq
        exx
        pop bc ;dx
        ld a,0x03 ;inc bc
        jp p,shapes_line_nodec
        xor a
        sub c
        ld c,a
        sbc a,b
        sub c
        ld b,a ;dx >= 0
        ld a,0x0b ;dec bc
shapes_line_nodec
        pop hl ;dy
         ld l,h
         ld h,0
;a=код inc/dec bc
;bc'=x (в плоскости экрана, но может быть отрицательным)
;e'=y
        or a
        sbc hl,bc
        add hl,bc
;bc=dx
;hl=dy
        jp nc,shapes_linever ;dy>=dx
        ex de,hl
        ld hy,b
        ld ly,c ;counter=dx
       
;0x0000 -> 0x0101
;0x0001 -> 0x0102
;0x00ff -> 0x0100
;0x0100 -> 0x0201
        inc ly
        inc hy
       
        ;inc iy ;inc hy ;рисуем, включая последний пиксель (учтено в цикле)
        ld h,b
        ld l,c
        sra h
        rr l ;ym=dx div 2 ;TODO а если dx<0?
         ;xor a
         ;sub l
         ;ld l,a
         ;sbc a,h
         ;sub l
         ;ld h,a ;mym=256-(dx div 2)
        exx
        ld h,tx/256
        ld d,ty/256
         cp 0x03 ;inc bc
         jr nz,shapes_linehorL
         ;jr z,shapes_linehorR
        if 1==0
        ld (shapes_lineincx),a
;bc=x
;e=y
;hl'=xm
;bc'=dx
;de'=dy
shapes_linehor0
pixelprochor=$+1
        call prpixel
shapes_lineincx=$
        inc bc ;x+1        
        exx
        ;add hl,de ;mym+dy
        or a
        sbc hl,de ;ym-dy
        exx
        jr nc,shapes_linehor1
        inc  e ;y+1
        exx
        ;or a
        ;sbc hl,bc ;mym-dx
        add hl,bc ;ym+dx
        exx
shapes_linehor1
        dec ly
        jp nz,shapes_linehor0
        dec hy
        jp nz,shapes_linehor0
        ret
        endif

        if 1==1
shapes_linehorR
        ld a,b
        rra
        ld a,c
        rra
        ld l,a
        ld b,ly
        ld a,(de) ;(y*40)
        jr c,shapes_linehorR_r
        add a,(hl) ;x div 4
        ld c,a
        inc d
        inc h
        ld a,(de) ;'(y*40)
        adc a,(hl) ;f(x mod 4)
        ld h,a
        ld l,c
        ld de,40
;hl=scr
;de=40
;b=pixels
shapes_linehorR0_l
        ld a,(hl)
linehorR_and_l=$+1
        and 0xb8 ;keep right pixel ;иначе надо cls перед redraw
linehorR_color_l=$+1
        xor 0;lx
        ld (hl),a
        exx
        ;or a
        sbc hl,de ;ym-dy
        exx
        jr nc,shapes_linehorR0_ldjnz
        add hl,de ;y+1
        exx
        add hl,bc ;ym+dx
        exx
shapes_linehorR0_ldjnz
        djnz shapes_linehorR0_r
        dec hy
        jp nz,shapes_linehorR0_r
        ret
shapes_linehorR_r
        add a,(hl) ;x div 4
        ld c,a
        inc d
        inc h
        ld a,(de) ;'(y*40)
        adc a,(hl) ;f(x mod 4)
        ld h,a
        ld l,c
        ld de,40
;hl=scr
;de=40
;b=pixels
shapes_linehorR0_r
        ld a,(hl)
linehorR_and_r=$+1
        and 0x47 ;keep left pixel ;иначе надо cls перед redraw
linehorR_color_r=$+1
        xor 0;lx
        ld (hl),a        
        bit 6,h
        set 6,h
        jr z,shapes_linehorR_incxok
        ld a,h
        xor 0x60
        ld h,a
        and 0x20
        jr nz,shapes_linehorR_incxok
        inc hl
shapes_linehorR_incxok
        exx
        ;or a
        sbc hl,de ;ym-dy
        exx
        jr nc,shapes_linehorR0_rdjnz
        add hl,de ;y+1
        exx
        add hl,bc ;ym+dx
        exx
shapes_linehorR0_rdjnz
        djnz shapes_linehorR0_l
        dec hy
        jp nz,shapes_linehorR0_l
        ret

shapes_linehorL
        ld a,b
        rra
        ld a,c
        rra
        ld l,a
        ld b,ly
        ld a,(de) ;(y*40)
        jr c,shapes_linehorL_r
        add a,(hl) ;x div 4
        ld c,a
        inc d
        inc h
        ld a,(de) ;'(y*40)
        adc a,(hl) ;f(x mod 4)
        ld h,a
        ld l,c
        ld de,40
;hl=scr
;de=40
;b=pixels
shapes_linehorL0_l
        ld a,(hl)
linehorL_and_l=$+1
        and 0xb8 ;keep right pixel ;иначе надо cls перед redraw
linehorL_color_l=$+1
        xor 0;lx
        ld (hl),a
        bit 6,h
        res 6,h
        jr nz,shapes_linehorL_decxok
        ld a,h
        xor 0x60
        ld h,a
        and 0x20
        jr z,shapes_linehorL_decxok
        dec hl
shapes_linehorL_decxok
        exx
        ;or a
        sbc hl,de ;ym-dy
        exx
        jr nc,shapes_linehorL0_ldjnz
        add hl,de ;y+1
        exx
        add hl,bc ;ym+dx
        exx
shapes_linehorL0_ldjnz
        djnz shapes_linehorL0_r
        dec hy
        jp nz,shapes_linehorL0_r
        ret
shapes_linehorL_r
        add a,(hl) ;x div 4
        ld c,a
        inc d
        inc h
        ld a,(de) ;'(y*40)
        adc a,(hl) ;f(x mod 4)
        ld h,a
        ld l,c
        ld de,40
;hl=scr
;de=40
;b=pixels
shapes_linehorL0_r
        ld a,(hl)
linehorL_and_r=$+1
        and 0x47 ;keep left pixel ;иначе надо cls перед redraw
linehorL_color_r=$+1
        xor 0;lx
        ld (hl),a        
        exx
        ;or a
        sbc hl,de ;ym-dy
        exx
        jr nc,shapes_linehorL0_rdjnz
        add hl,de ;y+1
        exx
        add hl,bc ;ym+dx
        exx
shapes_linehorL0_rdjnz
        djnz shapes_linehorL0_l
        dec hy
        jp nz,shapes_linehorL0_l
        ret

        endif
       
shapes_linever
        ld d,h
        ld e,l
        ld hy,d
        ld ly,e ;counter=dy
       
;0x0000 -> 0x0101
;0x0001 -> 0x0102
;0x00ff -> 0x0100
;0x0100 -> 0x0201
        inc ly
        inc hy
       
        ;inc iy ;inc hy ;рисуем, включая последний пиксель (учтено в цикле)
        ;ld h,d
        ;ld l,e
        sra h
        rr l
         ;xor a
         ;sub l
         ;ld l,a
         ;sbc a,h
         ;sub l
         ;ld h,a ;mxm=256-(dy div 2)
        exx
        ld h,tx/256
        ld d,ty/256
         cp 0x03 ;inc bc
         jr nz,shapes_lineverL
         ;jr z,shapes_lineverR
        if 1==0
        ld (shapes_lineincx2),a
;bc=x
;e=y
;hl'=xm
;bc'=dx
;de'=dy
shapes_linever0
pixelprocver=$+1
        call prpixel
        inc  e ;y+1
        exx
        ;add hl,bc ;mxm+dx
        or a
        sbc hl,bc ;xm-dx
        exx
        jr nc,shapes_linever1
shapes_lineincx2=$
        inc bc ;x+1
        exx
        ;or a
        ;sbc hl,de ;mxm-dy
        add hl,de ;xm+dy
        exx
shapes_linever1
        dec ly
        jp nz,shapes_linever0
        dec hy
        jp nz,shapes_linever0
        ret
        endif

        if 1==1
;bc=x
;e=y
;hl'=xm
;bc'=dx
;de'=dy
shapes_lineverR
        ld a,b
        rra
        ld a,c
        rra
        ld l,a
        ld b,ly
        ld a,(de) ;(y*40)
        jr c,shapes_lineverR_r
        add a,(hl) ;x div 4
        ld c,a
        inc d
        inc h
        ld a,(de) ;'(y*40)
        adc a,(hl) ;f(x mod 4)
        ld h,a
        ld l,c
        ld de,40
;hl=scr
;de=40
;b=pixels
shapes_lineverR0_l
        ld a,(hl)
lineverR_and_l=$+1
        and 0xb8 ;keep right pixel ;иначе надо cls перед redraw
lineverR_color_l=$+1
        xor 0;lx
        ld (hl),a
        add hl,de ;y+1 ;NC
        exx
        ;or a
        sbc hl,bc ;xm-dx
        jr c,shapes_lineverRincx_r
        ;add hl,de ;xm+dy
        exx
shapes_lineverR0_ldjnz
        djnz shapes_lineverR0_l
        dec hy
        jp nz,shapes_lineverR0_l
        ret
shapes_lineverR_r
        add a,(hl) ;x div 4
        ld c,a
        inc d
        inc h
        ld a,(de) ;'(y*40)
        adc a,(hl) ;f(x mod 4)
        ld h,a
        ld l,c
        ld de,40
shapes_lineverR0_r
        ld a,(hl)
lineverR_and_r=$+1
        and 0x47 ;keep left pixel ;иначе надо cls перед redraw
lineverR_color_r=$+1
        xor 0;lx
        ld (hl),a
        add hl,de ;y+1 ;NC
        exx
        ;or a
        sbc hl,bc ;xm-dx
        jr c,shapes_lineverRincx_l
        exx
        djnz shapes_lineverR0_r
        dec hy
        jp nz,shapes_lineverR0_r
        ret
shapes_lineverRincx_r
        add hl,de ;xm+dy
        exx
        djnz shapes_lineverR0_r
        dec hy
        jp nz,shapes_lineverR0_r
        ret
shapes_lineverRincx_l
        add hl,de ;xm+dy
        exx
        bit 6,h
        set 6,h
        jr z,shapes_lineverR0_ldjnz
        ld a,h
        xor 0x60
        ld h,a
        and 0x20
        jr nz,shapes_lineverR0_ldjnz
        inc hl
        jp shapes_lineverR0_ldjnz

shapes_lineverL
        ld a,b
        rra
        ld a,c
        rra
        ld l,a
        ld b,ly
        ld a,(de) ;(y*40)
        jr c,shapes_lineverL_r
        add a,(hl) ;x div 4
        ld c,a
        inc d
        inc h
        ld a,(de) ;'(y*40)
        adc a,(hl) ;f(x mod 4)
        ld h,a
        ld l,c
        ld de,40
;hl=scr
;de=40
;b=pixels
shapes_lineverL0_l
        ld a,(hl)
lineverL_and_l=$+1
        and 0xb8 ;keep right pixel ;иначе надо cls перед redraw
lineverL_color_l=$+1
        xor 0;lx
        ld (hl),a
        add hl,de ;y+1 ;NC
        exx
        ;or a
        sbc hl,bc ;xm-dx
        jr c,shapes_lineverLdecx_r
        ;add hl,de ;xm+dy
        exx
        djnz shapes_lineverL0_l
        dec hy
        jp nz,shapes_lineverL0_l
        ret
shapes_lineverL_r
        add a,(hl) ;x div 4
        ld c,a
        inc d
        inc h
        ld a,(de) ;'(y*40)
        adc a,(hl) ;f(x mod 4)
        ld h,a
        ld l,c
        ld de,40
shapes_lineverL0_r
        ld a,(hl)
lineverL_and_r=$+1
        and 0x47 ;keep left pixel ;иначе надо cls перед redraw
lineverL_color_r=$+1
        xor 0;lx
        ld (hl),a
        add hl,de ;y+1 ;NC
        exx
        ;or a
        sbc hl,bc ;xm-dx
        jr c,shapes_lineverLdecx_l
        exx
shapes_lineverL0_rdjnz
        djnz shapes_lineverL0_r
        dec hy
        jp nz,shapes_lineverL0_r
        ret
shapes_lineverLdecx_r
        add hl,de ;xm+dy
        exx
        bit 6,h
        res 6,h
        jr nz,shapes_lineverL0_rdjnz
        ld a,h
        xor 0x60
        ld h,a
        and 0x20
        jr z,shapes_lineverL0_rdjnz
        dec hl
        jp shapes_lineverL0_rdjnz
shapes_lineverLdecx_l
        add hl,de ;xm+dy
        exx
        djnz shapes_lineverL0_l
        dec hy
        jp nz,shapes_lineverL0_l
        ret

        endif

oldupdtimer
        dw 0

        align 256
tx
        dup 256
        db ($&0xff)/4
        edup
        dup 64
        db 0x80
        db 0xc0
        db 0xa0
        db 0xe0
        edup
ty
        dup 200
        db 0xff&(($&0xff)*40)
        edup
        ds 56,0xff&8000
        dup 200
        db (($&0xff)*40)/256
        edup
        ds 56,8000/256
font
        incbin "fontgfx"

genmesh
        xor a
        ld (nvertices),a
        ld (nvertices2),a
        ld (curmeshvertex),a
        ld h,a
        ld l,a ;ld hl,0
        ld (nedges),hl
        ;ld (ncrossededges),hl
        ld (genmeshedge_old),hl ;невозможное ребро
;создать ряд из 2 точек (или лучше из sqrt(verticesneeded)) с рёбрами между ними:
        ld (genmeshx),hl
        ld (genmeshy),hl
        call genmeshvertex ;in verlist2
        ld a,(verticesneeded)
        ;ld h,0
;sqrt
;in: a [hl]
;out: d
        or a
        ld de,64
        ;ld a,l
        ld l,d;h
        ld h,d
        ld b,8
sqrt0
        sbc hl,de
        jr nc,$+3
        add hl,de
        ccf
        rl d
        add a,a
        adc hl,hl
        add a,a
        adc hl,hl
        djnz sqrt0

        ld b,d ;будет одна лишняя сверх sqrt
genmeshfirstrow0
        push bc
        call newedgeinlist2 ;цепляем новое ребро в vertlist2
        pop bc
        djnz genmeshfirstrow0

        call copyvertlist2to1
       
genmeshrows0
;начинаем следующий ряд
        ld hl,(genmeshy)
        ld bc,25
        add hl,bc
        ld (genmeshy),hl
        xor a
        ld (curopenvertinlist1),a
        ld (nvertices2),a
        ld h,a
        ld l,a ;ld hl,0
        ld (genmeshx),hl
;сначала цепляем к первой открытой точке ребро
;.    .    .    .
;|    ^текущая открытая точка
;* текущая цепляемая точка
        ld a,(nvertices)
        push af
        call genmeshvertex ;in verlist2
        pop af ;новая точка
        ld (curmeshvertex),a
        call linktoopenvertex
       
genmeshrow00
        call func_rnd
        cp 128
;если rnd>0.?, то создаём ребро и циклимся здесь, иначе цепляем последнее ребро за следующую открытую точку
;TODO вероятность поставить в соответствие с числом nvertices2 - если сильно меньше, чем надо, то надо генерить рёбра
;.   .    .    .
;|_\/

;.    .    .    .
;|_\__|

;.    .    .    .
;|_\_.__\
;        * текущая цепляемая точка
;и так пока не кончатся открытые точки
        jr c,genmesh_nextopenvert
        call newedgeinlist2 ;цепляем новое ребро в vertlist2        
        ld a,(nvertices)
        ld hl,verticesneeded
        cp (hl)
        jr nc,genmesh_finishlastvertex;jp nc,linktoopenvertex ;сгенерили точек столько, сколько просили
;с некоторой вероятностью цепляем к текущей открытой точке
        call func_rnd
        cp 128
        call c,linktoopenvertex
        jr genmeshrow00
genmesh_finishlastvertex
;цепляем ребро к текущей открытой точке (даже ко всем открытым до конца! иначе при 2 рядах может остаться хвост в верхнем ряду) и выходим
genmesh_finishlastvertex0
        call linktoopenvertex ;цепляем ребро к текущей открытой точке
        ld de,curopenvertinlist1
        ld a,(de)
        inc a
        ld hl,nvertices1
        cp (hl)
        ret nc ;больше нет открытых точек - заканчиваем
        ld (de),a
        jr genmesh_finishlastvertex0

genmesh_nextopenvert
;переходим к следующей открытой точке, если она есть, и цепляем к ней ребро
        ld de,curopenvertinlist1
        ld a,(de)
        inc a
        ld hl,nvertices1
        cp (hl)
        jr nc,genmesh_rowend ;больше нет открытых точек - заканчиваем ряд
        ld (de),a
        call linktoopenvertex ;цепляем ребро к текущей открытой точке
        jr genmeshrow00
genmesh_rowend
        call linktoopenvertex ;цепляем ребро к текущей (последней) открытой точке
;ряд открытых точек заменить новым
        call copyvertlist2to1
        jr genmeshrows0

newedgeinlist2
;цепляем новое ребро в vertlist2
        ld a,(nvertices)
        push af
        call genmeshvertex ;in verlist2
        ld a,(curmeshvertex)
        ld e,a ;текущая цепляемая точка
        pop af ;новая точка
        ld (curmeshvertex),a
        ld d,a
        jp genmeshedge

linktoopenvertex
curmeshvertex=$+1
        ld d,0 ;номер точки, которую надо прицепить
curopenvertinlist1=$+1
        ld a,0
        ld hl,vertlist1
        add a,l
        ld l,a
        adc a,h
        sub l
        ld h,a
        ld e,(hl) ;текущая открытая точка
        jp genmeshedge

genmeshvertex
;in verlist2
genmeshx=$+1
        ld bc,0
genmeshy=$+1
        ld de,0
       
        if 1==1
        ld c,160
        call rnd
        add a,a
        ld c,a
        ld b,0
        rl b
        push bc
        ld c,200-8
        call rnd
        add a,8
        ld e,a
        ;ld d,0
        pop bc
        endif
;bc=x
;e=y
        ld a,(nvertices2)
        ld hl,vertlist2
        add a,l
        ld l,a
        adc a,h
        sub l
        ld h,a
        ld a,(nvertices)
        ld (hl),a
        ld l,a
        ld h,0
        add hl,hl
        add hl,hl
        push bc
        ld bc,vertices
        add hl,bc
        pop bc
        ld (hl),c
        inc hl
        ld (hl),b ;x
        inc hl
        ld (hl),e
        inc hl
        ld (hl),0;d ;y
        ld hl,nvertices
        inc (hl)
        ld hl,nvertices2
        inc (hl)
        ld hl,(genmeshx)
        ld bc,24
        add hl,bc
        ld (genmeshx),hl
        ret
       
copyvertlist2to1
        ld hl,vertlist2
        ld de,vertlist1
        ld bc,MAXVERTICES
        ldir
        ld a,(nvertices2)
        ld (nvertices1),a
        ret
       
genmeshedge
;d=vertex1
;e=vertex2
;проверим, что мы уже не прицепили это ребро
genmeshedge_old=$+1
        ld hl,0
        or a
        sbc hl,de
        ld (genmeshedge_old),de
        ret z
        ld bc,(nedges)
        ld hl,edges
        add hl,bc
        add hl,bc
        add hl,bc
         add hl,bc
        push hl
        ld (hl),d
        inc hl
        ld (hl),e
         inc hl
         ld (hl),0 ;crossed
         inc hl
         ld (hl),0 ;crossedHSB
        pop hl
;check if this edge crossed with something, mark crossing here and there
        ld bc,(nedges)
        call checkcrossedwith_oldedges
        ld hl,(nedges)
        inc hl
        ld (nedges),hl
        ret

        if 1==0
countcrossededges
;проверяем пересечение всех со всеми
        ;ld hl,0
        ;ld (ncrossededges),hl
        ld hl,edges
        ld bc,(nedges)
initcrossededges0
        inc hl
        inc hl
        ld (hl),0 ;uncrossed
        inc hl
         ld (hl),0 ;crossedHSB
         inc hl
        dec bc
        ld a,b
        or c
        jr nz,initcrossededges0
       
        ld hl,edges
        ld bc,(nedges)
        ld de,0 ;counter (+1)
countcrossededges0
        push bc
        push de
        push hl
        ld b,d
        ld c,e
        call checkcrossedwith_oldedges
        pop hl
        inc hl
        inc hl
        inc hl
         inc hl
        pop de
        pop bc
        inc de
        dec bc
        ld a,b
        or c
        jr nz,countcrossededges0
        ret
        endif

inccrossededges
        ld (inccrossededges_proc),hl
;для каждого из связанных рёбер инкрементируем/декрементируем все пересечения (у него и у пересечённого)
        ld hl,edges
        ld bc,(nedges)
inccrossededges0
;ищем связанные рёбра
        ld e,(hl)
        inc hl
        ld d,(hl)
        dec hl
;e=vertex1
;d=vertex2
        ld a,(curvertex)
        cp d
        jr z,inccrossededgesok
        cp e
        jr nz,inccrossededgesno
inccrossededgesok
;нашли связанное ребро, ищем все его пересечения (по всем рёбрам, кроме самого себя) и их инкрементируем (и у себя тоже)
        push bc
        push hl
        ld (inccrossededges_selfaddr),hl
        ld hl,edges
        ld bc,(nedges)
inccrossededges00
inccrossededges_selfaddr=$+1
        ld de,0
        or a
        sbc hl,de
        add hl,de
        jr z,inccrossededges00_skipself
        push bc
;hl=edge1addr
;de=edge2addr
        push hl
        call checkcrossed_edge ;out: CY=crossed
        pop hl
inccrossededges_proc=$+1
        call c,inccrossedandself
        pop bc
inccrossededges00_skipself
        inc hl
        inc hl
         inc hl
        ;inc hl
        ;dec bc
        ;ld a,b
        ;or c
        ;jr nz,inccrossededges00
        cpi
        jp pe,inccrossededges00
;конец обработки связанного ребра
        pop hl
        pop bc
inccrossededgesno
        inc hl
        inc hl
         inc hl
        ;inc hl
        ;dec bc
        ;ld a,b
        ;or c
        ;jr nz,inccrossededges0
        cpi
        jp pe,inccrossededges0
        ret
inccrossedandself
        push hl
        inc hl
        inc hl
        inc (hl)
         jr nz,$+4
         inc hl
         inc (hl)
        ld hl,(inccrossededges_selfaddr)
        inc hl
        inc hl
        inc (hl)
         jr nz,$+4
         inc hl
         inc (hl)
        pop hl
        ret
deccrossedandself
        push hl
        inc hl
        inc hl
         inc (hl)
         dec (hl)
         jr nz,$+5
          inc hl
          dec (hl)        
          dec hl
        dec (hl)
        ld hl,(inccrossededges_selfaddr)
        inc hl
        inc hl
         inc (hl)
         dec (hl)
         jr nz,$+5
          inc hl
          dec (hl)        
          dec hl
        dec (hl)
        pop hl
        ret

checkcrossedwith_oldedges
;hl=edge to check
;bc=nedges before current edge
        ;inc hl
        ;inc hl
        ;ld (hl),0
         ;inc hl
         ;ld (hl),0
         ;dec hl
        ;dec hl
        ;dec hl
        ld de,edges
        ld a,b
        or c
        ret z;jr z,genmeshedge_nocheckcrossed
;bc=was nedges
genmeshedge_checkcrossed0
        push bc
        push de
        push hl
        call checkcrossed_edge
        pop hl
        pop de
        pop bc
        inc de
        inc de
        jr nc,genmeshedge_nocrossed
        ex de,hl
        inc (hl)
         jr nz,$+5
          inc hl
          inc (hl)
          dec hl
        ex de,hl
        inc hl
        inc hl
        inc (hl)
         jr nz,$+5
          inc hl
          inc (hl)
          dec hl
        dec hl
        dec hl
genmeshedge_nocrossed
         inc de ;crossedHSB
        inc de
        dec bc
        ld a,b
        or c
        jr nz,genmeshedge_checkcrossed0
;genmeshedge_nocheckcrossed
        ret

checkcrossedcoord
;ix<=bc: AB
;hl<=de: CD
;out: CY=crossed

; all possible configurations:
;
; 1.
;  A===B
;        C===D
;
; 2.
;  C===D
;        A===B
;
; 3.
; A======B
;   C==D
;
; 4.
; C======D
;   A==B
;
; 5.
; A===B
;   C===D
;
; 6.
; C===D
;   A===B

; hence NON-crossed case is:
;
; if B(bc)<C(hl), otherwise if D(de)<A(ix)

        or      a
        sbc     hl,bc ; C(hl)-B(bc): Z if B==C, cy if B>C, nc if B<C and not Z
        jr      z,checkcrossedcoord_crossed
        ret     nc

        push    ix
        pop     hl
        or      a
        sbc     hl,de   ;A(hl, was ix)-D(de)
        ret     nz
checkcrossedcoord_crossed:
        scf
        ret



 if 1==0
;crossed case1: C(hl)<=B(bc), D(de)>=B(bc)
        or a
        sbc hl,bc
        add hl,bc
        jr z,checkcrossedcoord_maybecrossed1
        ;jr c,checkcrossedcoord_maybecrossed1
        jr nc,checkcrossedcoord_cross1q
checkcrossedcoord_maybecrossed1
        ex de,hl
        ;or a
        sbc hl,bc
        add hl,bc
        ;ex de,hl
        jr nc,checkcrossedcoord_crossed
checkcrossedcoord_cross1q
;crossed case2: A(ix)<=C(hl), B(bc)>=C(hl)
        push ix
        pop de
        or a
        sbc hl,de
        add hl,de
        jr c,checkcrossedcoord_notcrossed
        ;or a
        sbc hl,bc
        add hl,bc
        jr z,checkcrossedcoord_crossed
        jr c,checkcrossedcoord_crossed
checkcrossedcoord_notcrossed
        or a
        ret
checkcrossedcoord_crossed
        scf
        ret
 endif




checkcrossed_edge
;hl=edge1addr
;de=edge2addr
;out: CY=crossed
;для надёжности сделаем hl>=de всегда (похоже, тест некоммутативный в редких случаях)
        or a
        sbc hl,de
        add hl,de
        jr nc,$+3
        ex de,hl

;если A=C или A=D или B=C или B=D, то непересечение (примыкание) - надо проверять не координаты, а номера вершин!!!
        ld a,(de)
        cp (hl)
        ret z ;примыкание
        inc hl
        cp (hl)
        ret z ;примыкание
        inc de
        ld a,(de)
        cp (hl)
        ret z ;примыкание
        dec hl
        cp (hl)
        ret z ;примыкание

        ld c,(hl) ;edge1vertex1
        inc hl
        ld a,(hl) ;edge1vertex2
        ld b,0
        ld hl,vertices
        add hl,bc
        add hl,bc
        add hl,bc
        add hl,bc
        ld c,(hl)
        inc hl
        ld b,(hl)
        ld (checkxA),bc
        inc hl
        ld c,(hl)
        inc hl
        ld b,(hl)
        ld (checkyA),bc
        ld l,a ;edge1vertex2
        ld h,0
        ld bc,vertices
        add hl,hl
        add hl,hl
        add hl,bc
        ld c,(hl)
        inc hl
        ld b,(hl)
        ld (checkxB),bc
        inc hl
        ld c,(hl)
        inc hl
        ld b,(hl)
        ld (checkyB),bc
       
        ex de,hl

        ld a,(hl) ;edge2vertex2
        dec hl
        ld c,(hl) ;edge2vertex1
        ld b,0
        ld hl,vertices
        add hl,bc
        add hl,bc
        add hl,bc
        add hl,bc
        ld c,(hl)
        inc hl
        ld b,(hl)
        ld (checkxC),bc
        inc hl
        ld c,(hl)
        inc hl
        ld b,(hl)
        ld (checkyC),bc
        ld l,a ;edge2vertex2
        ld h,0
        ld bc,vertices
        add hl,hl
        add hl,hl
        add hl,bc
        ld c,(hl)
        inc hl
        ld b,(hl)
        ld (checkxD),bc
        inc hl
        ld c,(hl)
        inc hl
        ld b,(hl)
        ld (checkyD),bc

        if 1==1
;test xA..xB doesn't cross xC..xD: if cross, check y...
        ld hl,(checkxA)
        ld de,(checkxB)
        call maxhl_de_tode ;de>=hl
        push hl
        pop ix
        ld b,d
        ld c,e ;bc>=ix
        ld hl,(checkxC)
        ld de,(checkxD)
        call maxhl_de_tode ;de>=hl
        call checkcrossedcoord ;out: CY=crossed
        ret nc
;test yA..yB doesn't cross yC..yD
        ld hl,(checkyA)
        ld de,(checkyB)
        call maxhl_de_tode ;de>=hl
        push hl
        pop ix
        ld b,d
        ld c,e ;bc>=ix
        ld hl,(checkyC)
        ld de,(checkyD)
        call maxhl_de_tode ;de>=hl
        call checkcrossedcoord ;out: CY=crossed
        ret nc
        endif
       
;проверка пересечения AB и CD
;проверить одинаковую левость (знак векторного произведения двух сторон) треугольников ABC и BCD. Если одинаковая, то пересечение.
;Ложное срабатывание! Поэтому если левость одинаковая, надо проверить ещё левость DBA - если такая же, то пересечение.
;ложное срабатывание при палке B,A над CD ;проверяем DCA
;Как при этом гарантировать [0..1]?
;Если (A=C и B=D) или (B=C и A=D), то пересечение (чтобы не выигрывали методом наложения отрезков)
        if 1==1
        ld hl,(checkxA)
        ld de,(checkxC)
        or a
        sbc hl,de
        jr nz,checkcrossed_noAC
        ld hl,(checkyA)
        ld de,(checkyC)
        or a
        sbc hl,de
        jr nz,checkcrossed_noAC
        ld hl,(checkxB)
        ld de,(checkxD)
        or a
        sbc hl,de
        jr nz,checkcrossed_noAC
        ld hl,(checkyB)
        ld de,(checkyD)
        or a
        sbc hl,de
        scf
        ret z ;пересечение
checkcrossed_noAC
        ld hl,(checkxB)
        ld de,(checkxC)
        or a
        sbc hl,de
        jr nz,checkcrossed_noBC
        ld hl,(checkyB)
        ld de,(checkyC)
        or a
        sbc hl,de
        jr nz,checkcrossed_noBC
        ld hl,(checkxA)
        ld de,(checkxD)
        or a
        sbc hl,de
        jr nz,checkcrossed_noBC
        ld hl,(checkyA)
        ld de,(checkyD)
        or a
        sbc hl,de
        scf
        ret z ;пересечение
checkcrossed_noBC
        endif
       
;если A=C или A=D или B=C или B=D, то непересечение (примыкание) - надо проверять не координаты, а номера вершин!!! поэтому убрано тут, см. выше
        if 1==0
        ld hl,(checkxA)
        ld de,(checkxC)
        or a
        sbc hl,de
        jr nz,checkcrossed_noACcommon
        ld hl,(checkyA)
        ld de,(checkyC)
        or a
        sbc hl,de
        ret z ;примыкание
checkcrossed_noACcommon
        ld hl,(checkxA)
        ld de,(checkxD)
        or a
        sbc hl,de
        jr nz,checkcrossed_noADcommon
        ld hl,(checkyA)
        ld de,(checkyD)
        or a
        sbc hl,de
        ret z ;примыкание
checkcrossed_noADcommon
        ld hl,(checkxB)
        ld de,(checkxC)
        or a
        sbc hl,de
        jr nz,checkcrossed_noBCcommon
        ld hl,(checkyB)
        ld de,(checkyC)
        or a
        sbc hl,de
        ret z ;примыкание
checkcrossed_noBCcommon
        ld hl,(checkxB)
        ld de,(checkxD)
        or a
        sbc hl,de
        jr nz,checkcrossed_noBDcommon
        ld hl,(checkyB)
        ld de,(checkyD)
        or a
        sbc hl,de
        ret z ;примыкание
checkcrossed_noBDcommon
        endif
        ;or a
        ;ret
       
;иначе считаем математику
        ld hl,(checkxA)
        ld (trix1),hl
        ld hl,(checkxB)
        ld (trix2),hl
        ld hl,(checkxC)
        ld (trix3),hl
        ld hl,(checkyA)
        ld (triy1),hl
        ld hl,(checkyB)
        ld (triy2),hl
        ld hl,(checkyC)
        ld (triy3),hl
        call checktriangle ;ABC
       
        if 1==1
        sbc a,a
        push hl
        push af
        ld hl,(checkxD)
        ld (trix1),hl
        ld hl,(checkyD)
        ld (triy1),hl
        call checktriangle ;DBC
        sbc a,a
        pop bc
        pop de
        xor b
        ret nz ;разная левость - нет пересечения
        ld a,h
        or l
        or d
        or e
        jr z,checkcrossed_collinear ;все 4 на одной линии - отдельная проверка
        push bc
        ld hl,(checkxA)
        ld (trix3),hl
        ld hl,(checkyA)
        ld (triy3),hl
        call checktriangle ;DBA
        sbc a,a
        pop bc
        xor b
        ret nz ;разная левость - нет пересечения
;ложное срабатывание при палке B,A над CD
;проверяем DCA
        push bc
        ld hl,(checkxC)
        ld (trix2),hl
        ld hl,(checkyC)
        ld (triy2),hl
        call checktriangle ;DCA
        sbc a,a
        pop bc
        xor b
        rla
        ccf
        ret ;одинаковая левость - есть пересечение

        else
       
        push hl
        ld hl,(checkxD)
        ld (trix1),hl
        ld hl,(checkyD)
        ld (triy1),hl
        call checktriangle ;DBC
        pop de
        ld a,h
        xor d
        rla
        ccf
        ret nc ;разная левость - нет пересечения
        push hl
        ld hl,(checkxA)
        ld (trix3),hl
        ld hl,(checkyA)
        ld (triy3),hl
        call checktriangle ;DBA
        pop bc
        ld a,h
        xor b
        rla
        ccf
        ret nc ;разная левость - нет пересечения
        ld a,h
        or l
        or d
        or e
        jr z,checkcrossed_collinear ;площадь DBC = 0 - отдельная проверка
;ложное срабатывание при палке B,A над CD
;проверяем DCA
        push hl
        ld hl,(checkxC)
        ld (trix2),hl
        ld hl,(checkyC)
        ld (triy2),hl
        call checktriangle ;DCA
        pop de
        ld a,h
        xor d
        rla
        ccf
        ret ;одинаковая левость - есть пересечение
        endif
       
checkcrossed_collinear
;отрезки на одной прямой
;отдельно проверить, что отрезки лежат друг на друге (раньше площади 0 считались как непересечение)
;найти самую большую ось (max-min)
        ld hl,(checkxA)
        ld bc,(checkxB)
        call minhl_bc_tobc
        ld (checkxminAB),bc
        push bc
        ld hl,(checkxC)
        ld bc,(checkxD)
        call minhl_bc_tobc
        ld (checkxminCD),bc
        pop hl
        call minhl_bc_tobc
;bc=minx
        ld hl,(checkxA)
        ld de,(checkxB)
        call maxhl_de_tode
        ld (checkxmaxAB),de
        push de
        ld hl,(checkxC)
        ld de,(checkxD)
        call maxhl_de_tode
        ld (checkxmaxCD),de
        pop hl
        call maxhl_de_tode
;de=maxx
        ex de,hl
        or a
        sbc hl,bc
        push hl ;maxx-minx

        ld hl,(checkyA)
        ld bc,(checkyB)
        call minhl_bc_tobc
        ld (checkyminAB),bc
        push bc
        ld hl,(checkyC)
        ld bc,(checkyD)
        call minhl_bc_tobc
        ld (checkyminCD),bc
        pop hl
        call minhl_bc_tobc
;bc=miny
        ld hl,(checkyA)
        ld de,(checkyB)
        call maxhl_de_tode
        ld (checkymaxAB),de
        push de
        ld hl,(checkyC)
        ld de,(checkyD)
        call maxhl_de_tode
        ld (checkymaxCD),de
        pop hl
        call maxhl_de_tode
;de=maxy
        ex de,hl
        or a
        sbc hl,bc ;maxy-miny
       
        pop de ;maxx-minx
       
;если нет пересечения, то должно быть max(A,B)<min(C,D) или max(C,D)<min(A,B)
        or a
        sbc hl,de ;NC: разброс по y >= разброс по x, берём y
        jr nc,checkcrossed_collinear_y
;разброс по y < разброс по x, берём x
checkxmaxAB=$+1
        ld hl,0
checkxminCD=$+1
        ld de,0
        or a
        sbc hl,de
        ccf
        ret nc ;нет пересечения
checkxmaxCD=$+1
        ld hl,0
checkxminAB=$+1
        ld de,0
        or a
        sbc hl,de
        ccf
        ret
checkcrossed_collinear_y
;разброс по y >= разброс по x, берём y
checkymaxAB=$+1
        ld hl,0
checkyminCD=$+1
        ld de,0
        or a
        sbc hl,de
        ccf
        ret nc ;нет пересечения
checkymaxCD=$+1
        ld hl,0
checkyminAB=$+1
        ld de,0
        or a
        sbc hl,de
        ccf
        ret

minhl_bc_tobc
        or a
        sbc hl,bc
        add hl,bc
        ret nc ;bc<=hl
        ld b,h
        ld c,l
        ret

maxhl_de_tode ;de>=hl
        or a
        sbc hl,de
        add hl,de
        ret c ;de>hl
        ex de,hl
        ret ;de>=hl

checkxA
        dw 0
checkyA
        dw 0
checkxB
        dw 0
checkyB
        dw 0
checkxC
        dw 0
checkyC
        dw 0
checkxD
        dw 0
checkyD
        dw 0

checktriangle
;out: CY=левость, hl==0 вырожденность
;    x21:=vert[poly[i].v2].xscr-vert[poly[i].v1].xscr;
;    x31:=vert[poly[i].v3].xscr-vert[poly[i].v1].xscr;
;    y21:=vert[poly[i].v2].yscr-vert[poly[i].v1].yscr;
;    y31:=vert[poly[i].v3].yscr-vert[poly[i].v1].yscr;
        ld bc,tsqr/2
triy2=$+1
        ld hl,0
triy1=$+1
        ld de,0
        or a
        sbc hl,de
        ld (y21),hl
triy3=$+1
        ld hl,0
        or a
        sbc hl,de
        ld (y31),hl
trix2=$+1
        ld hl,0
trix1=$+1
        ld de,0
        or a
        sbc hl,de
        add hl,bc
        ld (x21),hl
trix3=$+1
        ld hl,0
        or a
        sbc hl,de
        add hl,bc
        ;ld (x31),hl
;    poly[i].visible := ((x21*y31 - x31*y21) > 0);
;x31=$+1
        ;ld hl,0
        ld bc,0
y21=$-2
        call mul9 ;out: CYhl ;_MULLONG. ;out: hl(high), de(low)
         sbc a,a
        ld lx,a ;hsb
        ex de,hl
x21=$+1
        ld hl,0
        ld bc,0
y31=$-2
        call mul9 ;out: CYhl ;_MULLONG. ;out: hl(high), de(low)
         sbc a,a
        or a
        sbc hl,de ;lsw
        sbc a,lx ;hsb
        rla ;CY=результат сравнения знаковых (LVD)
        ret

mul9
;9*9 -> 18
;можно использовать для +-319*+-192, тогда результат со знаком в CY
;hl=A+(tsqr/2) (A=+-319)
;bc=B = +-192
;A*B = ((A+B)^2)/4 - ((A-B)^2)/4 ;младшие 2 бита перед делением одинаковые слева и справа, определяются чётностью
        push hl
        add hl,bc
;hl=A+B
        add hl,hl
;CY=0
        ld (mulpatchadd),hl
        pop hl
        sbc hl,bc
;hl=A-B
        add hl,hl
;CY=0
        ld (mulpatchsub),hl
mulpatchadd=$+1
        ld hl,(0) ;ok
mulpatchsub=$+2
        ld bc,(0) ;ok
        sbc hl,bc
;HL = %rrrrrrrr rrrrrrrr
        ret

        align 2
tsqrsize=(320+200)
_=tsqrsize
        dup tsqrsize
_=_-1
        dw ((_*_)/4)&0xffff
        edup
tsqr
_=0
        dup tsqrsize
        dw ((_*_)/4)&0xffff
_=_+1
        edup


        if 1==0
;hl * de (signed = unsigned)
;out: hl
_MUL.
        ld a,h
        ld c,l
        ld hl,0
        ld b,16
_MUL0.
        add hl,hl
        rl c
        rla
        jr nc,$+3
        add hl,de
        djnz _MUL0.
        ret
        endif

        if 1==0
;hl, de * bc, ix
;out: hl(high), de(low)
_MULLONG.
        ;EXPORT _MULLONG.
;signed mul is equal to unsigned mul
;hlde*bcix = hlde*b000 + hlde*c00 + hlde*i0 + hlde*x
        ld a,lx
        push af ;lx
        push ix ;hx
        ld a,c
        push af ;c
        ld a,b
;bcde <= hlde:
        ld b,h
        ld c,l
;hlix <= 0
        ld hl,0
        ;ld ix,0
        push hl
        pop ix
        call _MULLONGP. ;hlix = (hlix<<8) + "b*hlde"
        pop af ;c
        call _MULLONGP. ;hlix = (hlix<<8) + "c*hlde"
        pop af ;hx
        call _MULLONGP. ;hlix = (hlix<<8) + "hx*hlde"
        pop af ;lx
        call _MULLONGP. ;hlix = (hlix<<8) + "lx*hlde"
        push ix
        pop de
        ret
;hlix = (hlix<<8) + a*bcde
_MULLONGP.
        exx
        ld b,8
_MULLONG0.
        exx
        add ix,ix
        adc hl,hl
        rla
        jr nc,$+2+2+2
        add ix,de
        adc hl,bc
        exx
        djnz _MULLONG0. ;можно по a==0 (первый вход с scf:rla, далее add a,a) ;или раскрыть цикл
        exx
        ret
        endif

setscrpgs
        ld a,(user_scr0_low) ;ok
        SETPG32KLOW
        ld a,(user_scr0_high) ;ok
        SETPG32KHIGH
        ret

        display $
SAVEDATA
level
        db 0
verticesneeded
        db 10
nvertices
        db 0

nvertices1
        db 0
nvertices2
        db 0
       
vertlinkflags
vertlist1
        ds MAXVERTICES
vertlist2
        ds MAXVERTICES

vertices
;x,X,y,Y
        ds MAXVERTICES*4
edges
;vertex1,vertex2,crossed,crossedHSB
        ds MAXEDGES*4
nedges
        dw 0
;ncrossededges
;        dw 0
cur_h
        db 0
cur_m
        db 0
cur_s
        db 0
cur_f
        db 0

tlevel
        db "LEVEL 00"
tleveldig1=$-2
tleveldig2=$-1
        db " TIME 00:00:00"
ttimeh1=$-8
ttimeh2=$-7
ttimem1=$-5
ttimem2=$-4
ttimes1=$-2
ttimes2=$-1
nextlevelon=$ ;этот флаг надо сохранять
        db 0
        db "NEXT LEVEL"
        db 0

SAVEDATAsz=$-SAVEDATA

pal ;DDp palette: %grbG11RB(low),%grbG11RB(high), inverted
        dw 0xffff,0xfefe,0xfdfd,0xfcfc,0xefef,0xeeee,0xeded,0xecec
        ;dw 0xffff,0xdede,0xbdbd,0x9c9c,0x6f6f,0x4e4e,0x2d2d,0x0c0c
        dw 0xffff,0x6f6f,0xbdbd,0x6f6f,0x6f6f,0x4e4e,0x2d2d,0x0c0c

        macro SHAPESPROC name
name
        endm

        include "prarrow.asm"

        include "control.asm"

end

        display "End=",end
        ;display "Free after end=",/d,#c000-end
        ;display "Size ",/d,end-begin," bytes"
       
        savebin "untangle.com",begin,end-begin
       
        LABELSLIST "..\..\..\us\user.l"