visibilitybegin=$
;четырёхугольники должны быть выпуклые!

;***************************** CHECK VISIBILITY (test) *********************************
;  for i:=0 to NPOLY-1 do
;  begin
;    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;
;    poly[i].visible := ((x21*y31 - x31*y21) > 0);
;  end;

;  TPoly = record
;    v1,v2,v3: integer; //^TVertex //нужно для checkvisibility //для скорости лучше указывать прямо на xscr,yscr
; l:byte;
;    visible: boolean; //temporary
;    e1,e2,e3: integer; //^TEdge //нужно для drawintersects //для скорости лучше указывать прямо на intersect
;  end;

checkvisibility
	ld a,(hl) ;NVERT
	ld hy,a
	inc hl
	inc hl ;skip vertex
	inc hl ;
checkvisibility_loop
	ld e,(hl)
	inc hl
	ld d,(hl)
	inc hl
	;de=v1
	  ex de,hl
	  ld c,(hl)
	  inc hl
	  ld b,(hl)
	  ex de,hl
	 push bc ;y1x1
	;bc=y1x1
	ld e,(hl)
	inc hl
	ld d,(hl)
	inc hl
	;de=v2
	  ex de,hl
	  ld a,(hl)
	  inc hl
	  ld h,(hl)
	  ld l,a
	  ex de,hl
	;de=y2x2

	ld a,(hl)
	inc hl
	 pop bc ;y1x1
	;bc=y1x1
	push hl ;(pointer to visible)-1-1

	ld h,(hl)
	ld l,a
	;hl=v3
	  ld a,(hl)
	  inc hl
	  ld h,(hl)
	  ld l,a
	;bc=y1x1
	;de=y2x2
	;hl=y3x3
	
       if VISIBILITY16 != 1 ;16bit для больших полигонов на MINZ=#16 не помогает даже со сдвигом
visibility_rangejr=$
	jr visibility_norange0 ;для дальних объектов не делаем предделение на 2
	;ld a,(rangeshiftpatch)
	;or a
	;jr nz,visibility_norange0
       endif
;близкий объект
;делим на 2 через add:rra (для xbase, ybase = 0x80)

	if VISIBILITY16 != 0
;    x21:=vert[poly[i].v2].xscr-vert[poly[i].v1].xscr;
	ld a,e ;x2
	sub c ;x1
	 rra ;sra a ;rra
	ld e,a ;dx1 = x21
;    x31:=vert[poly[i].v3].xscr-vert[poly[i].v1].xscr;
	ld a,l ;x3
	sub c ;x1
	 rra ;sra a ;rra
	ld c,a ;dx2 = x31
;    y21:=vert[poly[i].v2].yscr-vert[poly[i].v1].yscr;
	ld a,d ;y2
	sub b ;y1
	 rra ;sra a ;rra
	ld d,a ;dy1 = y21
;    y31:=vert[poly[i].v3].yscr-vert[poly[i].v1].yscr;
	ld a,h ;y3
	sub b ;y1
	 rra ;sra a ;rra
	ld b,a ;dy2 = y31
	;de,bc=vectors

;    poly[i].visible := ((x21*y31 - x31*y21) > 0);
	 push bc ;dy2dx2
	ld a,c ;dx2
	rla
	sbc a,a
	ld b,a ;SIGN(dx2)
	ld a,d ;dy1
	call MULSIGN ;bc*a => hl (dx2*dy1)
	 pop bc ;dy2dx2
	ld a,e ;dx1
	rla
	sbc a,a
	 ld c,a
	ld a,b ;dy2
	 ld b,c ;SIGN(dx1)
	ld c,e ;dx1
	ex de,hl
	call MULSIGN ;bc*a => hl (dx1*dy2)
	;or a
	sbc hl,de ;(dx1*dy2)-(dx2*dy1)
	 ;add hl,hl
	ld a,h ;<0=visible
        if VISIBILITY16 != 1
	jp visibility_rangeok
        endif

	else ;VISIBILITY16 == 0

	 if 1==0;1
	 ;костыль для y/2 (по x так не получится из-за диапазона #40..#13f)
	 srl b
	 srl d
	 srl h
	 endif
	
	 if 0 ;1==1
	 ;костыль для x/2
	 if xbase
	 ld a,c
	 sub xbase
	 ld c,a
	 ld a,e
	 sub xbase
	 ld e,a
	 ld a,l
	 sub xbase
	 ld l,a
	 endif
	 sra c
	 sra e
	 sra l
	 endif
	
	 ld a,h;b ;y1
	sub b;h ;y3 (сейчас переставлено для смены знака результата)
	rra ;sra a
	 ;sra a
	ld h,a ;-dy2 = -y31

	ld a,d;b ;y1
	sub b;d ;y2 (сейчас переставлено для смены знака результата)
	rra ;sra a
	 ;sra a
	ld d,a ;-dy1 = -y21

	 ld a,l ;x3
	sub c ;x1
	rra ;sra a
	 ;sra a
	add a,d
	 ld b,a ;(A/2-(-d)/2)
	sub d
	sub d ;d+(A/2-(-d)/2)
	 ld l,a

	ld a,e ;x2
	sub c ;x1
	rra ;sra a
	 ;sra a
	add a,h
	 ld e,a ;(A/2-(-b)/2)
	sub h
	sub h ;b+(A/2-(-b)/2)
	 ld d,a

	 ld h,tsqrbig/256
	ld a,(hl)
	ld l,b
	sub (hl) ;a=(dx2*dy1)=-63..+63
;вычесть e*b => a (dx1*dy2)
	ld l,d
	sub (hl)
	ld l,e
	add a,(hl) ;(dx1*dy2)=-63..+63
;a=-126..+126
;если 0 при range0, то надо пересчитать точнее
	jp nz,visibility_rangeok
       endif 
       
       if VISIBILITY16 != 1
visibility_norange0
	 if 1==0
	 ;костыль для y/2 (по x так не получится из-за диапазона #40..#13f)
	 srl b
	 srl d
	 srl h
	 endif
	
	 if 1==0
	 ;костыль для x/2
	 if xbase
	 ld a,c
	 sub xbase
	 ld c,a
	 ld a,e
	 sub xbase
	 ld e,a
	 ld a,l
	 sub xbase
	 ld l,a
	 endif
	 sra c
	 sra e
	 sra l
	 endif
	
	 if 1==0
	 if xbase==#c0
	 ;костыль для логического сплющивания по правому краю экрана (почему по левому не нужен??????)
	 ld a,c ;x1
	 cp #40
	 jr nc,$+3
	 sbc a,a
	 ld c,a
	 ld a,e ;x2
	 cp #40
	 jr nc,$+3
	 sbc a,a
	 ld e,a
	 ld a,l ;x3
	 cp #40
	 jr nc,$+3
	 sbc a,a
	 ld l,a
	 endif
	 endif
	
	 ld a,h;b ;y1
	sub b;h ;y3 (сейчас переставлено для смены знака результата)
	 ;call rangeshiftleft
	ld h,a ;-dy2 = -y31
	add a,e ;x2
	sub c ;x1 ;при вычитании иксов может быть переполнение!
;a += (dx1 = x21)
;e*b => a (dx1*dy2)
	ld e,a ;(A/2-(-b)/2)
	sub h
	sub h ;b+(A/2-(-b)/2)
	 ld h,a
	ld a,d;b ;y1
	sub b;d ;y2 (сейчас переставлено для смены знака результата)
	 ;call rangeshiftleft
	ld d,a ;-dy1 = -y21
	add a,l ;x3
	sub c ;x1 ;при вычитании иксов может быть переполнение!
;a += (dx2 = x31)
;a*d => a (dx2*dy1)
	ld b,a ;(A/2-(-d)/2)
	sub d
	sub d ;d+(A/2-(-d)/2)
	ld l,a
	 ld d,h

visibility_tablepatch=$+1
	ld h,tsqrsmall/256 ;big для range 1, small для range 2..
	ld a,(hl)
	ld l,b
	sub (hl) ;a=(dx2*dy1)=-63..+63
;вычесть e*b => a (dx1*dy2)
	ld l,d
	sub (hl)
	ld l,e
	add a,(hl) ;(dx1*dy2)=-63..+63
;a=-126..+126
;123t (не считая ld bc:ld de:ld hl)
	;dec a ;нули (малые площади) становятся видимыми, в том числе обратные стороны       
visibility_rangeok
       endif ;VISIBILITY16 != 1

	pop hl ;(pointer to visible)-1-1
	inc hl ;skip to l
	;rla
	;sbc a,a
	inc hl
	ld (hl),a ;visibility на месте light (<0=visible)
	;ld de,szpoly-7 ;1+(3*2) ;skip visible, e1,e2,e3
	;add hl,de
         inc hl
         inc hl
         inc hl
	dec hy
	jp nz,checkvisibility_loop

	ret

	if VISIBILITY16 != 0
MULSIGN
;для checkvisibility
;+0.7 * +0.7 = +0.15
        ADD A,A
        jr nc,_MULPLUS
        LD L,A
        XOR A
        SUB C
        LD C,A
        SBC A,B
        SUB C
        LD B,A
        XOR A
        SUB L
_MULPLUS
;+0.7 * 0.7 = +0.15
;BC * A = HL
;badmul=$+1
        LD HL,1;0 ;1 для правильного округления (будем брать H)
       DUP 7
        ADD A,A
        jr nc,$+3
        ADD HL,BC
        ADD HL,HL
       EDUP 
        RET 
        
        endif

	if VISIBILITY16 != 1

	;.ALIGN 256
        if VISIBILITY16 == 0
	BEGIN256 512
        else
	BEGIN256 256 ;VISIBILITY16 == 2
        endif
tsqrsmall
;для далёких объектов (range=2..4)
;по математике надо max=63, чтобы избежать переполнения в знак. Но для реальных полигонов (даже маленьких, как низ лампы) недопустимо такое усечение
	;display "tsqrsmall=",tsqrsmall
	dup 32 +14 ;0..61
_=($&#ff)
	db (_*_+8)/16 ;max=63
	edup
	dup 2*96+1 -28
	db 127;63
	edup
	dup 31 +14 ;-31..-1
_=256-($&#ff)
	db (_*_+8)/16 ;max=63
	edup

        if VISIBILITY16 == 0
tsqrbig
;для близких объектов (range=1 или 0 (с предварительным x/2, y/2))
	;display "tsqrbig=",tsqrbig
	 if 1==0
	dup 127 ;0..126
_=($&#ff)
	db (_*_+128)/256 ;max=63
	edup
	dup 2
	db 63
	edup
	dup 127 ;-127..-1
_=256-($&#ff)
	db (_*_+128)/256 ;max=63
	edup
	 endif

	dup 64 ;0..63
_=($&#ff)
	db (_*_+32)/64 ;max=63
	edup
	dup 2*64+1
	db 63
	edup
	dup 63 ;-63..-1
_=256-($&#ff)
	db (_*_+32)/64 ;max=63
	edup
	endif ;VISIBILITY16 == 0
	END256
	
	endif ;VISIBILITY16 != 1

	display "visibility size=",$-visibilitybegin
