drawfacesbegin=$

_onemask=1 ;одна таблица масок

dfxbase=#80;xbase ;по идее при #80 должны рисоваться любые грани шириной >128 пикс (_maxjr=31, т.е. можно 256 - сделать 512?), но не рисуются!!! todo

;############ draw faces (test) ##############
drawfaces
;todo процедура для каждого объекта
	ld a,(hl) ;NVERT
	ld hy,a
	inc hl
;как отличить треугольники от четырёхугольников? размер записи одинаковый!
;по неправильному числу в 4-й вершине (тогда видимость надо по 1,2,3, с пропуском)? или в 1-й?
;пусть все будут четырёхугольниками (в случае чего совмещать первые две вершины)
drawfaces_loop
	ld de,drawpolyv1
	ldi ;перебрасываем адрес вершины (не координаты!)
	ldi
	ld de,drawpolyv4 ;TODO e или inc
	ldi
	ldi
	ld de,drawpolyv3 ;TODO e или inc
	ldi
	ldi
	ld de,drawpolyv2 ;TODO e или inc
	ldi
	ldi
	ld a,(hl) ;l
	ld (temppolycoladdr),a
	inc hl ;skip l
	ld a,(hl) ;visible
	push iy
	push hl ;(pointer to visible)
	or a
	call m,DRAWPOLY ;m=visible
	pop hl ;(pointer to visible)
	pop iy
	inc hl ;skip visible
	;ld de,szpoly-9;7;1+(3*2) ;skip visible, e1,e2,e3
	;add hl,de
	dec hy
	jp nz,drawfaces_loop
	ret

;заливает односторонние
;полигоны, заданные по часовой стрелке
_maxjr=31
DRAWPOLY
;todo передавать координаты в регистрах
temppolycoladdr=$+1
	ld a,(coltab)
	 ld c,a ;штриховка
	 exx
        if 1==1
drawpolyv1=$+1
	ld hl,(0)
	 if ybase != #80
	 ld a,h
	 sub ybase-#80
	 ld h,a
	 endif
	 if dfxbase != xbase
	 ld a,l
	 add a,dfxbase-xbase
	 ld l,a
	 endif
	ld (temppolyvert),hl
drawpolyv2=$+1
	ld hl,(0)
	 if ybase != #80
	 ld a,h
	 sub ybase-#80
	 ld h,a
	 endif
	 if dfxbase != xbase
	 ld a,l
	 add a,dfxbase-xbase
	 ld l,a
	 endif
	ld (temppolyvert+2),hl
drawpolyv3=$+1
	ld hl,(0)
	 if ybase != #80
	 ld a,h
	 sub ybase-#80
	 ld h,a
	 endif
	 if dfxbase != xbase
	 ld a,l
	 add a,dfxbase-xbase
	 ld l,a
	 endif
	ld (temppolyvert+4),hl
drawpolyv4=$+1
	ld hl,(0)
	 if ybase != #80
	 ld a,h
	 sub ybase-#80
	 ld h,a
	 endif
	 if dfxbase != xbase
	 ld a,l
	 add a,dfxbase-xbase
	 ld l,a
	 endif
	ld (temppolyvert+6),hl
        endif
	ld hl,temppoly +1
	ld b,4-1 ;число вершин-1
        ;dec l
        ;LD (POLYBEG_hl),HL ;адрес копии первой вершины
	;ld a,l
	;ld (POLYBEG_l),a
        ;INC l;HL ;TODO убрать
           ;ld de,#80ff ;d=maxY, E=minY (так медленнее, т.к. лишний проход, и глюк при клипировании по Y)
        LD E,(HL) ;TODO читать из регистров
        ld D,E ;minY,maxY
        LD (DRWPOLYtopyaddr),HL ;адрес 2-го байта копии первой вершины
	ld a,l
	ld (RSBOTTm1_l),a
        INC l;HL ;TODO убрать
        ;LD (RSBOTT),HL ;адрес копии нижней вершины +2
FTB1    INC l;HL
        LD A,(HL) ;Y
        CP E ;minY
        ;jp p,FTB1nmin
	JR NC,FTB1nmin;TOP
        LD E,A
	ld (DRWPOLYtopyaddr),HL ;адрес 2-го байта копии верхней вершины
        INC l;HL
        DJNZ FTB1
        JR FTBQ
FTB1nmin
        CP D ;maxY
        ;jp m,FTBnmax
	JR C,FTBnmax
        LD D,A
	;ld (RSBOTT),HL;BOTTOM ;адрес копии нижней вершины +2
	ld a,l
	ld (RSBOTTm1_l),a
FTBnmax
        INC l;HL
        DJNZ FTB1
FTBQ    
        LD A,D ;maxY=Ybottom
        CP E ;minY=Ytop
        RET Z ;Ymin=Ymax означает нулевую высоту => выход
	;sub #40 ;ybase-#c0
	;cp (scrbuf&#ff)-#40
	 cp #80-(scrhgt/2)
	ret c ;Ybottom выше верха экрана
        ;LD (POLYEND_hl),HL ;адрес после последнего байта полигона
	;ld a,l
	;ld (POLYEND_l),a
DRWPOLYtopyaddr=$+1
	LD HL,0 ;адрес 2-го байта копии верхней вершины
	ld a,e;(hl) ;Y
	;cp #40 ;ybase-#c0
	;ret c
	;cp (scrbuf&#ff)+scrhgt
	 cp #80+(scrhgt/2)
	ret nc ;Ytop ниже низа экрана
	 if ybase != #80
	 add a,ybase-#80
	 endif
        EXX 
        ;LD HL,(DRWPOLYtopyaddr) ;адрес 2-го байта копии верхней вершины
        LD e,a;(HL) ;Y
	if _onemask
	ld h,tleftmask/256
	endif
        EXX 
        DEC l;HL ;адрес копии верхней вершины
        LD (LSPTR),HL
        LD (RSPTR),HL

        CALL RSECT
        ;RET Z
        ;CALL LSECT
	jp LSECTlrKEEP

	.ALIGN 256
	dup 32
	jr DRSNO2 ;overflow
	edup
DRSNO2	jp DRSNO ;overflow
coltab
	db #00;,#00
	db #44;,#55 ;#41
	db #55;,#ff ;#5a
	db #dd;,#aa ;#d7
col1a	db #55;,#55 ;#50
col3a	db #cc;,#ff ;#c3
	db #ff;,#ff
temppoly
;temppolycol1
;	db #55 ;штриховка
;temppolycol2
;	db #aa ;штриховка2
	;db 4;3 ;число вершин
temppolyvert
;4 вершины (или хватит 3?)
;drawpolyv1
	dw 0
;drawpolyv2
	dw 0
;drawpolyv3
	dw 0
;drawpolyv4
	dw 0
temppolyvertend

	ds 121-($&#ff)
DRSRSECT
	ld ly,a
	;ld (_LY),a
	call RSECT ;устанавливает HY, проверяет выход (Z)
	jr nz,lrKEEP
	ret
DRSNSAME ;если лев. и прав. стороны в одном байте
;scr = (scr^c)&(~m|b)^c = ~(~(scr^c)|~(~m|b))^c = ((scr^~c)|(m&~b))^~c
	ld a,(hl);h
	if _onemask
	cpl
	endif
	or b;l
	ld l,a
	 ld a,(de)
	 xor c ;texture
	 and l
	 xor c ;texture
	 ld (de),a
	inc e ;Y
	exx
	add hl,de ;left
	add ix,bc ;right
	dec hy
	jp nz,DRS1_ ;переход чаще, чем мимо
DRSKEEP
	ld a,ly
	;ld a,(_LY)
lrSUBn=$+1
	sub 0
lrJC=$
	jr c,DRSRSECT
	ld hy,a
LSECTlrKEEP ;первый вход (RSECT уже посчитан)
	call LSECT ;устанавливает LY
lrKEEP
	ld a,ly
	;ld a,(_LY)
	 cp hy
	 ld a,48 ;JNC => RSECT
	 jr nc,lrKEEPL
;LY опустошится раньше => LSECT
	ld a,hy
	ld hy,ly;0
;_LY=$-1
;	ld (_LY),a
        ld ly,a
	 ld a,56 ;JC => LSECT
lrKEEPL
	 ld (lrJC),a
	 ld a,hy
	 dec a ;чтобы LY не обнулилось при SUB
	 ld (lrSUBn),a
	jp DRS1_
	;display $-DRSKEEP
	;display 256-(2*_maxjr+2+1)-($&#ff)
	ds 256-(2*_maxjr+2+1)-($&#ff) +1 ;+1 для neg/skip вместо cpl
DRSLOOP
	dup _maxjr
	ld (de),a ;texture
	dec d ;inc d
	edup
	 ld a,(de)
	 xor c ;texture
	 and b;l;%11100000 ;h;%00000111
	 xor c ;texture
	 ld (de),a
DRSNO
	inc e ;Y
	  ;ret z ;выгодно, если прижать экран снизу к #xx00? но тогда трудно считать видимость
	exx
	add hl,de ;left
	add ix,bc ;right
	dec hy
	jr z,DRSKEEP ;с b в теории выигрыш 4t(5t для SAME) на строку, но на практике проигрыш (не хватает регистра)
;HL=XL   DE=dXL
;IX=XR   BC=dXR
;LY=hgtL/R HY=hgtR/L
;DE'=screen (D=X)
DRS1_
	ld a,h
	exx
;a=h'=XL
	;117t тактов тут ~ 16800t на сцене из 5 кубиков
	;1t ~ 144t
	ld l,a
	if _onemask==0
	ld h,tleftmask/256
	endif
	ld b,(hl) ;leftmask
	inc h
	ld a,(hl) ;endx
	 ld d,hx ;XR
	ld l,d
	ld d,(hl) ;beginx
	if _onemask
	dec h
	else
	inc h
	endif
	sub d ;beginx
	jp z,DRSNSAME ;если лев. и прав. стороны в одном байте
	jr nc,DRSNO ;c при neg/cpl  ;ret c ;overflow??? (при патче jr убирание выигрывает 5 тактов, но даёт глюк из-за левой маски)
	   add a,a
	   ld (DRSjr),a
	 ld a,(de)
	 xor c ;texture
	if _onemask
	cpl
	 or (hl);h;~%00000111 ;l;%11100000
	cpl
	else
	 and (hl);h;%00000111 ;l;%11100000
	endif
	 xor c ;texture
	 ld (de),a
	 dec d;inc d
	ld a,c ;texture
DRSjr=$+1
	jp DRSLOOP ;отрисовка байтов
;один сканлайн 1+1+1 = 234t
;один сканлайн 1+0+1 = 223t
;один сканлайн 1(L=R)= 167t

;TRACE RIGHT, THINK ABOUT ENDPOINT(=ZF)
;расчёт нового BC
RSECT
        PUSH HL,DE
RSPTR=$+1
        LD HL,0
RSECTloop  
        LD C,(HL)
        INC l;HL; X1
        LD B,(HL)
	ld a,l
RSBOTTm1_l=$+1
	cp 0 ;адрес копии нижней вершины +1 (проверка младшего байта)
        JR Z,RSECTQ ;выход из RSECT (заодно и из полигона, т.к. Z)
;POLYEND_l=$+1
	cp 0+(temppolyvertend&#ff)-1 ;адрес после последнего байта полигона (проверка младшего байта или терминатора)
        JR NZ,$+2+2
;POLYBEG_hl=$+1
	 ld l,0+(temppolyvert&#ff)-1 ;адрес копии первой вершины полигона
        INC l;HL; Y1
	LD E,(HL)
        INC l;HL; X2
        LD A,(HL)
        DEC l;HL; Y2
        SUB B ;Y1
        JR Z,RSECTloop
        ;jp m,RSECT4 ;JR C,RSECT4 ;выход из полигона? когда такое может быть до RSBOTT?
        LD (RSPTR),HL
        LD L,A
	ld hy,a ;DY
        LD A,E
        SUB C;DX CF=SIGN
;FASTDIV 8/8=8.8
;HL(SGN)=A(SGN)/L  CF=SIGN
        CALL FDIVB ;138..333t

        LD HX,C
	ld LX,#80 ;центр пикселя
        OR 1;LX ;NZ (не выходим из полигона)
        LD B,H
	ld C,L

RSECTQ  POP DE,HL
        RET 
;RSECT4  POP DE,HL,HL
;        RET ;JR DRSEX

;TRACE LEFT
;расчёт нового DE
LSECT
        PUSH BC
LSPTR=$+1
        LD HL,0
LSECT1  LD C,(HL)
        INC l;HL; X1
        LD B,(HL)
        DEC l;HL; Y1
	ld a,l
POLYBEG_l=$+1
	cp temppolyvert&#ff ;адрес начала полигона (проверка младшего байта или терминатора)
        JR NZ,$+2+3
POLYEND_hl=$+1
	 ld hl,temppolyvertend ;адрес после последнего байта полигона
	DEC l;HL
        LD A,(HL); Y2
        DEC l;HL
        LD E,(HL); X2
        SUB B
        JR Z,LSECT1
        jp m,LSECTQ ;JR C,LSECT3 ;выход из полигона (если убрать, то глючный байт внизу полигона)
        LD (LSPTR),HL
        LD L,A
	ld LY,A;     DY
	;ld (_LY),A
        LD A,E
        SUB C;DX CF=SIGN
;FASTDIV 8/8=8.8
;HL(SGN)=A(SGN)/L  CF=SIGN
        CALL FDIVB ;было 138..333t (стало 130..300t)
        EX DE,HL
        LD H,C
        LD L,#80 ;центр пикселя

        POP BC
        RET 
LSECTQ  POP BC,HL
        RET ;JP DRSEX

;FASTDIV 8/8=8.8
;HL(SGN)=A(SGN)/L  S=SIGN
FDIVB
	if dfxbase==#c0
	jp m,FDIVBNEG ;CY нельзя для вычитания знаковых
	else
	 ;if dfxbase==0
	 ;jp pe,FDIVBNEG
	 ;else ;#80
	 jr c,FDIVBNEG ;должно работать для +-255
	 ;endif
	endif
        LD H,TBLOG2/256
        LD E,(HL)
        INC H
        LD D,(HL)
        LD L,A
        LD A,(HL)
        DEC H
        ADD A,8
        LD L,(HL)
        LD H,A
        SBC HL,DE ;=LOG(A/L)
        JP P,DIVC1
DIVCZ   LD HL,0 ;LOG<0 => результат <1 =0
        RET 
DIVC1   LD A,H
	 ;ld D,A
        LD H,TB2X/256
        LD L,(HL)
        LD H,1
        cp 8 ;SUB 8
	 cpl
        JR NC,DIVC2
         ;LD A,7
         ;SUB D
	 add a,8
        LD ($+4),A
        JR NZ,$
       DUP 7
        ADD HL,HL
       EDUP 
        LD L,H
	ld H,0
        RET 
DIVC2    ;LD A,#0F
         ;SUB D
	 add a,#10
        LD ($+4),A
        JR NZ,$
       DUP 7
        ADD HL,HL
       EDUP 
        RET 

FDIVBNEG
	NEG
        LD H,TBLOG2/256
        LD E,(HL)
        INC H
        LD D,(HL)
        LD L,A
        LD A,(HL)
        DEC H
        ADD A,8
        LD L,(HL)
        LD H,A
        SBC HL,DE ;=LOG(A/L)
        JP M,DIVCZ ;LOG<0 => результат <1 =0
        LD A,H
	 ;ld D,A
        LD H,TB2X/256
        LD L,(HL)
        LD H,1
        CP 8 ;SUB 8
	 cpl
        JR NC,DIVCN2
         ;LD A,7
         ;SUB D
	 add a,8
        LD ($+4),A
        JR NZ,$
       DUP 7
        ADD HL,HL
       EDUP 
        LD A,h
        CPL 
        LD L,A
        ld h,-1
        INC HL
        RET 
DIVCN2   ;LD A,#0F
         ;SUB D
	 add a,#10
        LD ($+4),A
        JR NZ,$
       DUP 7
        ADD HL,HL
       EDUP 
        XOR A
        SUB L
        LD L,A
        SBC A,H
        SUB L
        LD H,A
        RET 

        ;.ALIGN 256
	if _onemask
	BEGIN256 #200
	else
	BEGIN256 #300
	endif

	macro TLEFTMASK_LEFTINVISIBLE
;слева за экраном
	dup 64
	db #00
	edup
	endm
	macro TLEFTMASK_LEFTVISIBLE
;в экране
_=#00 ;левый пиксель экрана
	dup 64/4
	;db #00,#c0,#f0,#fc
	db _,#e0,#f8,#fe
_=#80
	edup
	endm
	macro TLEFTMASK_RIGHTVISIBLE
;в экране
	dup 64/4
	;db #00,#c0,#f0,#fc
	db #80,#e0,#f8,#fe
	edup
	org $-1
	db #ff ;правый пиксель экрана
	endm
	macro TLEFTMASK_RIGHTINVISIBLE
;справа за экраном
	dup 64
	db #ff
	edup
	endm

tleftmask
	if dfxbase==#c0
	TLEFTMASK_RIGHTINVISIBLE
	TLEFTMASK_LEFTINVISIBLE
	TLEFTMASK_LEFTVISIBLE
	TLEFTMASK_RIGHTVISIBLE
	else
	if dfxbase==0
	TLEFTMASK_RIGHTVISIBLE
	TLEFTMASK_RIGHTINVISIBLE
	TLEFTMASK_LEFTINVISIBLE
	TLEFTMASK_LEFTVISIBLE
	else ;#80
	TLEFTMASK_LEFTINVISIBLE
	TLEFTMASK_LEFTVISIBLE
	TLEFTMASK_RIGHTVISIBLE
	TLEFTMASK_RIGHTINVISIBLE
	endif
	endif
;;;;;;;;;;;;;;;;;;;
	macro TX_LEFTINVISIBLE
;слева за экраном
	dup 64
	db #e0
	edup
	endm
	macro TX_LEFTVISIBLE
;в экране
_=scrbuf/#100
	dup 64/4
	db _,_,_,_
_=_+1
	edup
	endm
	macro TX_RIGHTVISIBLE
;в экране
_=scrbufmid/#100
	dup 64/4
	db _,_,_,_
_=_+1
	edup
	endm
	macro TX_RIGHTINVISIBLE
;справа за экраном
	dup 64
	db #ff
	edup
	endm
	
tx
	if dfxbase==#c0
	TX_RIGHTINVISIBLE
	TX_LEFTINVISIBLE
	TX_LEFTVISIBLE
	TX_RIGHTVISIBLE
	else
	if dfxbase==0
	TX_RIGHTVISIBLE
	TX_RIGHTINVISIBLE
	TX_LEFTINVISIBLE
	TX_LEFTVISIBLE
	else ;#80
	TX_LEFTINVISIBLE
	TX_LEFTVISIBLE
	TX_RIGHTVISIBLE
	TX_RIGHTINVISIBLE
	endif
	endif
;;;;;;;;;;;;;;;;;;;
	macro TRIGHTMASK_LEFTINVISIBLE
;слева за экраном
	dup 64
	db #ff
	edup
	endm
	macro TRIGHTMASK_LEFTVISIBLE
;в экране
	dup 64/4
	;db #ff,#3f,#0f,#03
	db #7f,#1f,#07,#01
	edup
	endm
	macro TRIGHTMASK_RIGHTVISIBLE
;в экране
	dup 64/4
	;db #ff,#3f,#0f,#03
	db #7f,#1f,#07,#01
	edup
	org $-1
	db #00 ;для x=#ff
	endm
	macro TRIGHTMASK_RIGHTINVISIBLE
;справа за экраном
	dup 64
	db #00
	edup
	endm

	if _onemask==0
trightmask
	if dfxbase==#c0
	TRIGHTMASK_RIGHTINVISIBLE
	TRIGHTMASK_LEFTINVISIBLE
	TRIGHTMASK_LEFTVISIBLE
	TRIGHTMASK_RIGHTVISIBLE
	else
	if dfxbase==0
	TRIGHTMASK_RIGHTVISIBLE
	TRIGHTMASK_RIGHTINVISIBLE
	TRIGHTMASK_LEFTINVISIBLE
	TRIGHTMASK_LEFTVISIBLE
	else ;#80
	TRIGHTMASK_LEFTINVISIBLE
	TRIGHTMASK_LEFTVISIBLE
	TRIGHTMASK_RIGHTVISIBLE
	TRIGHTMASK_RIGHTINVISIBLE
	endif
	endif
	endif ;_onemask==0
	END256

	BEGIN256 512
TBLOG2
	ds 512 ;log2(X)
	END256
	
	BEGIN256 256
TB2X
	ds 256 ;(2^X)-1 (0<X<1)
	END256

	display "drawfaces size=",$-drawfacesbegin
