floorbegin=$
;todo!!! нет защиты от случая, когда все 4 точки спереди (потолок при взгляде вверх)
;todo привязать #40 и #3f к scrwid (в drawedges тоже)

FLOORZ=0
CEILINGZ=-#100
FLOORLEFT=+#0c0;+#100
FLOORRIGHT=-#200
FLOORFRONT=-#240;-#300 переполнение по x' при взгляде из угла
FLOORBACK=+#040;+#100

FLOORPOINTxz=6
FLOORPOINTyz=7;8
FLOORPOINTSZ=8;10

DOFLOOR
;при переполнении t вернём #ff&(ybase-#80) для потолка или #ff&(ybase+#7f) для пола
	ld hl,floorpoly
	ld (floorlinepolyaddr),hl
	ld hl,FLOORZ
	ld a,(frame_tangage) ;тангаж
	cp #e8;#e0 (+45 гр. вверх - пол не видно)
	ld ly,#ff&(ybase+#7f) ;переполнение для пола
	call p,DOFLOORPP ;пол
	 ;ret
	ld hl,ceilingpoly
	ld (floorlinepolyaddr),hl
	ld hl,CEILINGZ
	ld a,(frame_tangage) ;тангаж
	cp #18;#20 (-45 гр. вниз - потолок не видно)
	ret p
	ld ly,#ff&(ybase-#80) ;переполнение для потолка
	                 ;потолок
DOFLOORPP
	ld (curfloorz),hl
	;# вращаем 4 точки, от начала по часовой стрелке ищем самую левую и самую правую точки, попавшие в экран (как в рисовалке полигона)
	;ld hl,-#4000
	;ld (floormaxx),hl
	xor a
	ld (floormaxx),a
	;ld hl,+#3fff
	;ld (floorminx),hl
	dec a;ld a,#ff
	ld (floorminx),a
	ld ix,tcurfloor+FLOORPOINTSZ
	ld bc,FLOORRIGHT ;bc=Y (будет =Z')
	ld hl,FLOORFRONT ;hl=X (будет =X')
	call DOFLOORPOINT ;ближняя правая
	ld bc,FLOORLEFT;+#100 ;bc=Y (будет =Z')
	ld hl,FLOORFRONT ;hl=X (будет =X')
	call DOFLOORPOINT ;ближняя левая
	ld bc,FLOORLEFT;+#100 ;bc=Y (будет =Z')
	ld hl,FLOORBACK;+#100 ;hl=X (будет =X')
	call DOFLOORPOINT ;дальняя левая
	ld bc,FLOORRIGHT ;bc=Y (будет =Z')
	ld hl,FLOORBACK;+#100 ;hl=X (будет =X')
	call DOFLOORPOINT ;дальняя правая
	;итого 15000

	ld hl,tcurfloor+(4*FLOORPOINTSZ)
	ld de,tcurfloor
	ld bc,FLOORPOINTSZ
	ldir
	ex de,hl
	;ld hl,tcurfloor+FLOORPOINTSZ
	;ld de,tcurfloor+(5*FLOORPOINTSZ)
	ld c,4*FLOORPOINTSZ
	ldir
;теперь мы можем смотреть влево от первой точки и пройти на 3 точки вправо от правой точки + там смотреть вправо
	
;# переставляем указатель на самую левую видимую точку
;если ни одна точка не найдена, то выбираем в соответствии с азимутом
floorminxaddr=$+2
	ld ix,0
	;ld a,(floormaxx+1)
	;cp -#40
	ld a,(floormaxx)
	or a
	jr nz,floorpointspresent
;нет точек в поле экрана - ищем по азимуту
;ld ix,tcurfloor+FLOORPOINTSZ ;около #80
;ld ix,tcurfloor+FLOORPOINTSZ*2 ;около #c0
;ld ix,tcurfloor+FLOORPOINTSZ*3 ;около #00
;ld ix,tcurfloor+FLOORPOINTSZ*4 ;около #40
	ld a,(frame_azimuth)
	sub #60
	and #c0 ;*64
	;rlca
	;rlca ;*1
	; inc a
	; ld b,a
	;ld ix,tcurfloor
	;ld de,FLOORPOINTSZ
	;add ix,de
	;djnz $-2
	rrca
	rrca
	rrca ;*8
	 add a,#ff&(tcurfloor+FLOORPOINTSZ)
	ld lx,a
	ld a,b;0
	 adc a,0+(tcurfloor+FLOORPOINTSZ)/256
	ld hx,a
floorpointspresent

;# ищем пересечение левее неё с левой стороной экрана. если оно есть, добавляем его в буфер
;t = (x1'+z1')/((x1'+z1')-x2'-z2')
	 scf ;t = (x1'+z1')/((x1'+z1')-x2'-z2')
	call floormiddlez ;z' = z1' + (z2'-z1')*t
	ld (ix+FLOORPOINTxz-FLOORPOINTSZ),xbase-#40 ;x/z
	;ld (ix+FLOORPOINTxz+1-FLOORPOINTSZ),#ff ;x/z HSB
	ld (ix+FLOORPOINTyz-FLOORPOINTSZ),a ;y/z + ybase
	;ld (ix+FLOORPOINTyz+1-FLOORPOINTSZ),b ;y/z HSB

	;итого досюда 4728

	ld b,+(4+1)-(0+1);hy,+(4+1)-(0+1)

	;ld a,(floormaxx+1)
	;cp -#40
	ld a,(floormaxx)
	or a
	jr z,floorloopskip ;нет ни одной точки
	dec b;hy ;если сейчас сравнения годно, то есть одна точка

	push ix ;адрес левой видимой точки

;# по часовой стрелке от левой включительно до правой (ищем её по известному значению - а если её нет?) добавляем точки в буфер
;если ни одна точка не найдена, то пропускаем этот цикл
	ld de,FLOORPOINTSZ
	if 1==0
floormaxxaddr=$+1
	ld a,0;(floormaxxaddr)
	sub lx
	rra
	rra
	rra ;/8
	and 3
	jr z,floorloopnorpix ;не найдена вторая точка (minx==maxx)
	ld b,a ;число дополнительных точек
	add ix,de
	djnz $-2
	add a,2
	ld hy,a
	pop af
	 or a
	jr floorloopskipq
floorloopnorpix
	else
	ld a,(floormaxxaddr)
	add a,4*FLOORPOINTSZ
	ld (floormaxxaddrp4x),a
floorloop0
	;ld l,(ix+6) ;x/z
	;ld h,(ix+7) ;x/z HSB
	ld a,lx
	add ix,de
	;ld de,(floormaxx)
	;or a
	;sbc hl,de
floormaxxaddr=$+1
	cp 0;(floormaxxaddr)
	jr z,floorloopq
floormaxxaddrp4x=$+1
	cp 0;(floormaxxaddr)
	jr z,floorloopq
	 ;ld a,hy
	 ;cp +(4+1)-(4+1) ;проверили 3 точки справа и не нашли - значит, нет правой точки (т.е. есть только одна точка)
	;dec hy
	;jr nz,floorloop0
	djnz floorloop0
	endif
;есть только одна точка
;правую точку будем делать из левой клипированной и начальной левой видимой
	 pop ix ;адрес левой видимой точки
	push af
	 ld b,+(4+1)-1;hy,+(4+1)-1
;то, что под ix, будет клипировано (правее правой видимой точки или здесь начальная левая видимая)
	;inc hy
floorloopq
	;dec hy
	pop af
floorloopskip
	ld a,4+1
	sub b;hy
	ld hy,a ;CY=0
floorloopskipq
;# ищем пересечение правее. если оно есть, добавляем его в буфер
	 ;or a ;t = (x1'-z1')/((x1'-z1')-x2'+z2')
	call floormiddlez ;z' = z1' + (z2'-z1')*t
	;ld (ix+FLOORPOINTxz),xbase+#3f;#40 ;x/z
	;;ld (ix+FLOORPOINTxz+1),#00 ;x/z HSB
	;ld (ix+FLOORPOINTyz),a ;y/z + ybase
	;;ld (ix+FLOORPOINTyz+1),b ;y/z HSB

	;итого досюда 3923

	ld h,xbase+#3f
	ld l,a

;# рисуем между точками, попавшими в буфер
;hy=число линий (1 при отсутствии видимых точек, 2 при одной, 3 при двух, 4 при трёх, [5 при четырёх])
	;pop ix

floordrawloop0	
	ld d,(ix+FLOORPOINTxz-FLOORPOINTSZ);-64 ;x'/z' + xbase
	ld e,(ix+FLOORPOINTyz-FLOORPOINTSZ);c ;y'/z' + ybase
	;ld h,(ix+FLOORPOINTxz) ;x2'/z2' + xbase
	;ld l,(ix+FLOORPOINTyz) ;y2'/z2' + ybase
	push de
	;call line
	call floorline
	pop hl
	ld bc,-FLOORPOINTSZ
	add ix,bc
	dec hy
	jr nz,floordrawloop0
	;рисование 16717
	ret

floorpoly
	db br3a;3
;x,y
floorpolyright
	db xbase+#3f,ybase ;верх
floorpolyleft
	db xbase-#40,ybase ;
	db xbase-#40,ybase+(scrhgt/2)
	db xbase+#3f,ybase+(scrhgt/2)
ceilingpoly
	db br2;1
;x,y
ceilingpolyleft
	db xbase-#40,ybase ;
ceilingpolyright
	db xbase+#3f,ybase ;низ
	db xbase+#3f,ybase-(scrhgt/2)
	db xbase-#40,ybase-(scrhgt/2)

floorline
;de=xy1, hl=xy2
	push ix
	push iy
	ld a,l ;y2
	ld l,h
	ld h,a
;обе точки выше экрана - приводим в экран
	 if ybase != #80
	 sub ybase-#80
	 endif
	cp ybase-(scrhgt/2);#40
	jr nc,floorlineinscrtop
	ld a,e ;y1
	 if ybase != #80
	 sub ybase-#80
	 endif
	cp ybase-(scrhgt/2);#40
	jr nc,floorlineinscrtop
	ld h,ybase-(scrhgt/2);ybase-#40 ;y2=scrtop
	ld e,h ;y1=scrtop
floorlineinscrtop
;обе точки ниже экрана - приводим в экран (+1, чтобы было не видно)
	 if ybase != #80
	 sub ybase-#80
	 endif
	cp ybase+(scrhgt/2);#ff
	jr c,floorlineinscrbottom
	ld a,e ;y1
	 if ybase != #80
	 sub ybase-#80
	 endif
	cp ybase+(scrhgt/2);#ff
	jr c,floorlineinscrbottom
	ld h,ybase+(scrhgt/2);ybase+#40 ;y2=scrbottom
	ld e,h ;y1=scrbottom
floorlineinscrbottom
	ld (floorpolyright),hl
	ld (ceilingpolyright),hl
	ld h,e ;y1
	ld l,d
	ld (floorpolyleft),hl
	ld (ceilingpolyleft),hl
floorlinepolyaddr=$+1
	ld hl,floorpoly
	ld a,(hl);br3
	ld (temppolycoladdr),a
	inc hl
	ld (drawpolyv1),hl
	inc hl
	inc hl
	ld (drawpolyv4),hl
	inc hl
	inc hl
	ld (drawpolyv3),hl
	inc hl
	inc hl
	ld (drawpolyv2),hl
	call DRAWPOLY ;todo рисовать через полигон только верхний треугольник, а прямоугольник как-то попроще
	pop iy
	pop ix
	ret

floormiddlez
;CY=1: t = (x1'+z1')/((x1'+z1')-x2'-z2') ;для пересечения с левой стороной экрана
;CY=0: t = (x1'-z1')/((x1'-z1')-x2'+z2') ;для пересечения с правой стороной экрана
;t=0: берём точку 1
;t=1: берём точку 2
	ld l,(ix-FLOORPOINTSZ) ;x1
	ld h,(ix+1-FLOORPOINTSZ) ;x1 HSB
	ld e,(ix+4-FLOORPOINTSZ) ;z1
	ld d,(ix+5-FLOORPOINTSZ) ;z1 HSB
	push de ;z1
	push af
	 ;sbc a,a
	 ;ld ly,a ;CY=1 = левая сторона, переполнение t трактуем к точке 2 (#ff)
	         ;CY=0 = правая сторона, переполнение t трактуем к точке 1 (#00)
	;add hl,de
	 jr c,$+2+2+2
	 sbc hl,de
	 jr $+2+1
	 add hl,de
	;push hl ;(x1'+z1')
	ld d,h
	ld e,l
	ld c,(ix) ;x2
	ld b,(ix+1) ;x2 HSB
	or a
	sbc hl,bc
	ld c,(ix+4) ;z2
	ld b,(ix+5) ;z2 HSB
	pop af
	push bc ;z2
	ccf
	;or a
	;sbc hl,bc
	 jr c,$+2+2+2
	 sbc hl,bc
	 jr $+2+1
	 add hl,bc
	;pop de
	ex de,hl
	call div16 ;hl/de => bc (+-7.8) ;1182t

;z' = z1' + (z2'-z1')*t
	;ld l,(ix+4) ;z2
	;ld h,(ix+5) ;z2 HSB
	pop hl ;z2
	;ld e,(ix+4-FLOORPOINTSZ) ;z1
	;ld d,(ix+5-FLOORPOINTSZ) ;z1 HSB
	pop de ;z1

;при переполнении t вернём #ff&(ybase-#80) для потолка или #ff&(ybase+#7f) для пола
	 ld a,b
	 or a
	 jr z,floorntover
	 dec bc ;для #0100 -> #00ff
	 ld a,b
	 or a
	  ld a,ly
	  ret nz
	 ;ld c,#ff ;max
	 ;ld a,ly
	 ;ret
floorntover
	;t=0..1

	;push de ;z1
	call submul16add ;de{z1}+(hl{z2}-de{z1})*bc{t} => hl (+-7.8)
	;ld e,(ix+4-FLOORPOINTSZ) ;z1
	;ld d,(ix+5-FLOORPOINTSZ) ;z1 HSB
	;pop de ;z1
	;add hl,de
	bit 7,h
	jr nz,submulzmin
	inc h
	dec h
	jr nz,submulzok ;z>#100
	ld a,4;8
	cp l
	jr c,submulzok ;z>4;8 (число от балды, не проверялось)
submulzmin
	ld hl,4;8
submulzok
	push hl ;z'
;y' = y1' + (y2'-y1')*t
	ld l,(ix+2) ;y2
	ld h,(ix+3) ;y2 HSB
	ld e,(ix+2-FLOORPOINTSZ) ;y1
	ld d,(ix+3-FLOORPOINTSZ) ;y1 HSB
	;push de ;y1
	call submul16add ;de{y1}+(hl{y2}-de{y1})*bc{t} => hl (+-7.8)
	;ld e,(ix+2-FLOORPOINTSZ) ;y1
	;ld d,(ix+3-FLOORPOINTSZ) ;y1 HSB
	;pop de ;z1
	;add hl,de
	pop de ;z'
	call div16 ;hl/de => bc (+-7.8)
;bc = y'/z'
	;поле экрана = -256..+255
	sra b
	rr c
	;поле экрана = -128..+127
	sra b
	rr c
	;поле экрана = -64..+63
	ld a,c
	rla
	sbc a,a
	cp b
	jr nz,floormiddlemaximize ;вне поля 2 экрана
	ld a,c
	add a,ybase
	ret
floormiddlemaximize
	bit 7,b
	ld a,#ff&(ybase-#80)
	ret nz
	 ld a,#ff&(ybase+#7f)
	ret

DOFLOORPOINT
curfloorz=$+1
	ld de,FLOORZ ;de=Z (будет =Y')
;bc=Y (будет =Z')
;hl=X (будет =X')
;de=Z (будет =Y')
	call AddCamRotObj_fastZ
	call AddCamRotObj_continue
;bc=Z'
;hl=Y'
;de=X'
	ld (ix+0),e
	ld (ix+1),d ;X'
	ld (ix+2),l
	ld (ix+3),h ;Y'
	ld (ix+4),c
	ld (ix+5),b ;Z'
	bit 7,b
	jr nz,floorq ;Z'<0 (todo прописать псевдорезультат деления, т.к. проверка по значению)
	inc b
	djnz floornq
	ld a,c
	cp 8
	jr c,floorq ;z<8 (число от балды, не проверялось)
floornq
	push hl ;Y'
;de/bc=x'/z'
	ex de,hl
	ld d,b
	ld e,c
;hl/de=x'/z'
	call div16 ;=> bc (+-7.8)
	pop hl ;Y'
	;поле экрана = -256..+255
	sra b
	rr c
	;поле экрана = -128..+127
	ld a,c
	rla
	sbc a,a
	cp b
	jr nz,floorq ;вне поля экрана
	ld a,c
	sra a
	;поле экрана = -64..+63
	add a,xbase
	ld (ix+FLOORPOINTxz),a
	;ld (ix+FLOORPOINTxz+1),b
	 sub xbase-#80 ;todo убрать?
	;поле экрана = 64..191
;a=x'/z'
	;push hl
floorminx=$+1
	cp 0
	jr nc,floornmin
	;ld hl,0
	;or a
	;sbc hl,bc
	;jp m,floornmin ;minx<x
	ld (floorminx),a;(floorminx),bc
	ld (floorminxaddr),ix
floornmin
floormaxx=$+1
	cp 0
	jr c,floornmax
	;ld hl,0
	;or a
	;sbc hl,bc
	;jp p,floornmax ;maxx>=x
	ld (floormaxx),a;(floormaxx),bc
	;ld (floormaxxaddr),ix
	ld a,lx
	ld (floormaxxaddr),a
floornmax
	;pop hl
	
	;ld l,(ix+2)
	;ld h,(ix+3) ;Y'
	;ld e,(ix+4)
	;ld d,(ix+5) ;Z'
	;bit 7,d
	;jr nz,floorq
;hl/de=y'/z'
	call div16 ;=> bc (+-7.8)
	;поле экрана = -256..+255
	sra b
	rr c
	;поле экрана = -128..+127
	sra b
	rr c
	;поле экрана = -64..+63
	ld a,c
	rla
	sbc a,a
	cp b
	jr nz,floorymaximize ;вне поля 2 экрана
	ld a,c
	add a,ybase
flooryq
	ld (ix+FLOORPOINTyz),a
	;ld (ix+FLOORPOINTyz+1),b
;a=y'/z'
floorq	
	ld de,FLOORPOINTSZ
	add ix,de
	ret
floorymaximize
	bit 7,b
	ld a,#ff&(ybase-#80)
	jr nz,flooryq
	ld a,#ff&(ybase+#7f)
	jr flooryq

submul16add
;de+(hl-de)/bc => hl
	push de
	xor a
	sbc hl,de
	ex de,hl
;mul16
;+-de * +-bc => hl
;+-15 * +-7.8 => +-15
	;ld hl,0
	ld l,a
	ld h,a
;+-15 * 0.8 => +-15 реально
	ld a,c
	if 1==0
	 dup 8
	 rla
	 jr nc,$+3
	 add hl,de
	 add hl,hl
	 edup
	 ld l,h ;неправильное округление
	 ld h,a
	else
	dup 8 ;неточно!
	 sra d
	 rr e
	 rlca
	 jr nc,$+3
	 add hl,de
	edup
	; sra d
	; rr e
	; rlca
	;ret nc
	; add hl,de
	endif
	pop de
	add hl,de
	ret
	
div16
;+-hl/+-de => bc (+-7.8)
;not optimized
	bit 7,h
	jr nz,div16neg_
div16pos_
	bit 7,d
	jr z,div16pos_pos
div16pos_neg
	call div16negde_pos_pos
	xor a
	sub c
	ld c,a
	sbc a,b
	sub c
	ld b,a
	ret
div16neg_
	xor a
	sub l
	ld l,a
	sbc a,h
	sub l
	ld h,a
	bit 7,d
	jr nz,div16neg_neg
div16neg_pos
;hl negated
	call div16pos_pos
	xor a
	sub c
	ld c,a
	sbc a,b
	sub c
	ld b,a
	ret
div16neg_neg
;hl negated
div16negde_pos_pos
	xor a
	sub e
	ld e,a
	sbc a,d
	sub e
	ld d,a
div16pos_pos
;сделано как 8.8, но реально старший бит не нужен
;первое сравнение (которое не нужно) hl*256 против de
;(для настоящего 8.8 надо первое сравнение hl*128 против de)
;поэтому результат надо *2?
	 add hl,hl ;CY=0
	ld a,l ;bit0=0
	ld l,h
	ld h,0
	;or a
	;sbc hl,de
	;jr nc,$+2+1
	;add hl,de
	;rl b
	;rla
	;adc hl,hl
	dup 7
	sbc hl,de
	jr nc,$+2+1
	add hl,de
	;rl b
	rla
	adc hl,hl
	edup
	 cpl
	ld b,a
;первое сравнение hl против de
;(для настоящего 8.8 надо первое сравнение hl/2 против de)
;поэтому результат надо *2?
	dup 8
	;or a
	sbc hl,de
	jr nc,$+2+1
	add hl,de
	;rl c
	rla
	adc hl,hl
	edup
	 cpl
	add a,a
	ld c,a
	 rl b ;результат*2
	ret
	
tcurfloor
	dup 1+4+4 ;1 копия + 4 точки + 4 копии
	ds FLOORPOINTSZ ;x',y',z',x'/z',y'/z'
	edup

	display "floor size=",$-floorbegin
