sortobjbegin=$

	macro RANGEXY xrange
_xrange=#61;#50;xrange
_yrange=#61;#58 иногда пропадает ;xrange
	ld a,e ;X'
	add a,_xrange
	cp _xrange*2+1
	ret nc
	;cp -_xrange;-xrange ;-#50
	;ret m;jp m,skipobj
	;cp _xrange+1;xrange ;+#50
	;ret p;jp p,skipobj
	;ld (xspaceshift),a
	ld a,e
	rla
	sbc a,a
	cp d
	ret nz;jp nz,skipobj
	ld a,l ;Y'
	;add a,a
	;ret pe ;overflow (yrange=-#40..+#3f)
	add a,_yrange
	cp _yrange*2+1
	ret nc
	;cp -xrange ;-#50
	;ret m;jp m,skipobj
	;cp xrange ;+#50
	;ret p;jp p,skipobj
	;ld (yspaceshift),a
	ld a,l
	rla
	sbc a,a
	cp h
	ret nz;jp nz,skipobj
	;CY=0
	endm

	macro RANGECHECK
;bc=Z'
;hl=Y'
;de=X'
;макс. размер объекта (размер кубика) = +-#20 (после вращения +-#30)
;range0 Z=#000..#050, zspaceshift=#00..#50 (Xshifted=+-#30) 0..2.5 полукубика
;range1 Z=#050..#0d0, zspaceshift=#28..#68 (Xshifted=+-#18) 2.5..6.5 полукубика
;range2 Z=#0d0..#1d0, zspaceshift=#34..#74 (Xshifted=+-#0c) 6.5..14.5 полукубика
;range3 Z=#1d0..#3d0, zspaceshift=#3a..#7a (Xshifted=+-#06) 14.5..30.5 полукубика
;range4 Z=#3d0..#7d0, zspaceshift=#3d..#7d (Xshifted=+-#03) 30.5..62.5 полукубика
;даёт глюки.
;поэтому сделаем проще:
;range0 Z=#000..#050, zspaceshift=#00..#50 (Xshifted=+-#30) 0..2.5 полукубика
;range1 Z=#050..#0c0, zspaceshift=#28..#60 (Xshifted=+-#18) 2.5..6 полукубика
;range2 Z=#0c0..#180, zspaceshift=#30..#60 (Xshifted=+-#0c) 6..12 полукубика
;range3 Z=#180..#300, zspaceshift=#30..#60 (Xshifted=+-#06) 12..24 полукубика
;range4 Z=#300..#480, zspaceshift=#30..#60-#18 (Xshifted=+-#03) 24..36 полукубика
;сумма всех диапазонов = #50+#38+#30+#30+#30-#18 = #100
	ld a,c
	inc b ;Z
	djnz doobjzrangeN0
	cp #50 ;maxz для выкидывания в другой диапазон
	jr c,doobjzrange0
doobjzrangeN0
	sra b
	rra ;rr c
	sra d
	rr e
	sra h
	rr l
	inc b ;Z
	djnz doobjzrangeN1
	cp #60;#68 ;maxz для выкидывания в другой диапазон
	jr c,doobjzrange1
doobjzrangeN1
	sra b
	rra ;rr c
	sra d
	rr e
	sra h
	rr l
	inc b ;Z
	djnz doobjzrangeN2
	cp #60;#74 ;maxz для выкидывания в другой диапазон
	jr c,doobjzrange2
doobjzrangeN2
	sra b
	rra ;rr c
	sra d
	rr e
	sra h
	rr l
	inc b ;Z
	djnz doobjzrangeN3
	cp #60;#7a ;maxz для выкидывания в другой диапазон
	jr c,doobjzrange3
doobjzrangeN3
	sra b
	rra ;rr c
	sra d
	rr e
	sra h
	rr l
	inc b ;Z
	djnz doobjzrangeN4
	cp #60-#18;#7d ;maxz для выкидывания в другой диапазон
	jr c,doobjzrange4
doobjzrangeN4
	ret
;	jp skipobj
_rangeshiftsz=6
doobjzrange0
	;cp #30 ;minz для сплющивания по Z
	;jr nc,$+2+2
	;ld a,#30 ;minz
	ld b,a;(zspaceshift),a
	;ld c,#00 ;zcodeadd
	ld c,#ff ;zcodeadd
	RANGEXY #50 ;=> CY=0
	xor a
	 ;or a
	jp doobjrangeq
doobjzrange1
	ld b,a;(zspaceshift),a
	;ld c,#50 ;zcodeadd
	ld c,#ff-#50+#28 ;zcodeadd
	RANGEXY #60;#68 ;=> CY=0
	ld a,rangeshiftjrbase+_rangeshiftsz*(rangeshiftmax-1)
	 ;or a
	jp doobjrangeq
doobjzrange2
	ld b,a;(zspaceshift),a
	;ld c,#50+#38 ;zcodeadd
	ld c,#ff-#50-#38+#30 ;zcodeadd
	RANGEXY #60;#74
	ld a,rangeshiftjrbase+_rangeshiftsz*(rangeshiftmax-2)
	;scf
	jp doobjrangeq
doobjzrange3
	ld b,a;(zspaceshift),a
	;ld c,#50+#38+#30 ;zcodeadd
	ld c,#ff-#50-#38-#30+#30 ;zcodeadd
	RANGEXY #60;#7a
	ld a,rangeshiftjrbase+_rangeshiftsz*(rangeshiftmax-3)
	;scf
	jp doobjrangeq
doobjzrange4
	ld b,a;(zspaceshift),a
	;ld c,#50+#38+#30+#30 ;zcodeadd
	ld c,#ff-#50-#38-#30-#30+#30 ;zcodeadd
	RANGEXY #60;#7d
	ld a,rangeshiftjrbase+_rangeshiftsz*(rangeshiftmax-4)
	;scf
doobjrangeq
	endm

;сортировка объектов пускай будет pigeonhole sort
;однозначно выиграет даже на 16 объектах, т.к. при сортировке поиском надо 16*16 чтений, что перекрывает оверхед от 256 push в инициализации pigeonhole sort
;данные состоят из таблицы начальных адресов 256*2 и блоков динамической памяти
	BEGIN256 SORTLEVELS*2;512
tsortobj
	ds SORTLEVELS*2;512 ;содержит указатель на первый блок памяти для данного Z (изначально NULL)
tsortobjend
	END256
;динамическая память растёт сверху вниз
;блок памяти:
	;ds 2 ;больше? ;для стека INT и вызовов
;указатель сюда
	;db yspaceshift
	;db zspaceshift ;todo один раз для каждого z
	;db xspaceshift
	;db rangeshiftpatch
	;dw angle
	;dw object
	;dw next

;запись блока памяти
DOOBJNROT
	xor a ;без поворота по рысканию
DOOBJ
	;ld hy,a;(OZangleobj),a
	ex af,af'
;bc=Y (будет =Z')
;hl=X (будет =X')
;de=Z (будет =Y')
	ADDCAM_ROT ;с ret
;bc=Z'
;hl=Y'
;de=X'
	RANGECHECK ;с ret
;теперь можно менять sp
	ld (DOOBJsp),sp
;a=rangeshiftpatch
;e=xspaceshift
;l=yspaceshift
;b(или c)=zspaceshift
;c(или b)=zcodeadd
	ld d,a ;rangeshiftpatch
	ld h,b ;или c ;zspaceshift
	ld a,c ;zcodeadd
	;add a,b ;zspaceshift
	; cpl ;todo оптимизировать, если sortpolypop в обратном порядке или sub b
	sub b
;a=zcode (0 дальше, #ff ближе)
	exx
	if SORTLEVELS==256
	add a,a
	else ;128
	and #fe
	endif
	ld l,a
	adc a,tsortobj/256
	sub l
	ld h,a
	ld (sortobjzaddr),hl
	ld e,(hl)
	inc l
	ld d,(hl) ;next
sortobjtabend=$+1
	ld sp,0
	push de ;next
	exx
	push ix ;object
	;push iy ;angle
	ex af,af'
	push af
	push de ;e=xspaceshift, d=rangeshiftpatch
	push hl ;l=yspaceshift, h=zspaceshift
sortobjzaddr=$+2
	ld (0),sp ;конец таблицы для данного z
	dup 4;2
	push af ;PADDING for INT
	edup
	ld (sortobjtabend),sp ;конец динамической памяти
DOOBJsp=$+1
	ld sp,0
	ret

;чтение блоков памяти и вызов отрисовки:
sortobjpop
	ld (sortobjpopsp),sp
	ld hl,tsortobj ;в +254 стоит произвольное чётное число-терминатор
	ld a,#ff
	jp sortobjdrawzgo
sortobjdrawz0
	ex de,hl
sortobjdraw
	ld sp,hl
	pop de
	ld a,e
	ld (yspaceshift),a
	ld a,d
	ld (zspaceshift),a
	 ld (zspaceshift2),a
	pop de
	ld a,e
	ld (xspaceshift),a
	 ld a,d
	 ld (rangeshiftpatch),a
;range0: ld a (#3e), tsqr/256
;range1: jr (#18), tsqr/256
;range2..4: jr (#18), tsqrsmall/256
	 dec a ;range 0 кодируется как 0, поэтому при сравнении будет c, а надо nc!
	 cp rangeshiftjrbase+_rangeshiftsz*(rangeshiftmax-1)-1 ;range 1 
	 inc a
	 ld a,#3e
	 jr z,$+2+2 ;range 0
	 ld a,#18 ;range1..4
	 ld (visibility_rangejr),a
	  sbc a,a
	  add a,tsqrbig/256
	  ;ld a,tsqrbig/256 ;видно мелкие от 4 пикс
	  ;jr nc,$+2+2 ;>= (range 0..1)
	  ;ld a,tsqrsmall/256 ;видно мелкие от 2 пикс (=tsqrbig-#100)
	 ld (visibility_tablepatch),a
	pop af ;OZangleobj
	;pop ix ;object
;только отдельные типы объектов могут вращаться
;как сделать быстрые терминаторы для диапазонов?
oldyaw=$+1
	cp 0
	ret z ;jump to object
	ld (oldyaw),a ;рыскание
frame_azimuth=$+1
	add a,0
	jp ROTATE_MATRIX ;rotate matrix, jump to object
	;call nz,ROTATE_MATRIX
	;jp ROTATE_VERTICES ;12300(fix 10800..11500)t (включая новую матрицу, min 9445 без матрицы), 8400..9000t inline (min 7045(6712 DIV8YPROC)(6216 DIV8YPROC без call pos)(5816 DIV8YPROC через стек)(5215 DIV8YPROC через стек без DIVCHECKOVERFLOW)(5063 один jr) без матрицы) (call+call+push+push+ push+INT)
	;ld (sortobjnexthl),sp
	;ld sp,vertbufend
	;jp (ix) ;ROTCUBE/ROTVB/и т.п.
sortobjnext
	;hl=poly
	;de=edge
	;push de ;edge
	;push hl ;poly
	;call checkvisibility ;11600t (4600t восьмибитное) (push+push+call+push+INT)
	;pop hl ;poly
	;call drawfaces ;(push+call+push+push+ call+call+push+push+INT) ;где ещё одна запись?
	;pop hl ;edge
	;call drawedges ;(call+push+call+call+ INT)

	;pop hl ;next
sortobjnexthl=$+1
	ld hl,(0)
	 ;jp sortobjpopq
	bit 0,l
	jp z,sortobjdraw ;not NULL
sortobjpopzaddr=$+1
	ld hl,0
	ld a,#ff
sortobjnextzfast
	 inc l
	inc l
sortobjdrawzgo
	cp (hl)
	jp z,sortobjnextzfast ;#ffff=NULL
	; ld e,(hl)
	;inc l
	; bit 0,e
	;jp nz,sortobjnextzfast ;#ffff=NULL
	ld (sortobjpopzaddr),hl
	 ld e,(hl)
	 inc l
	ld d,(hl)
	inc l
	jp nz,sortobjdrawz0 ;не конец списка
	if SORTLEVELS==256
	display "NOT SUPPORTED!!!"
	inc h
	ld a,h
	cp tsortobj/256+2
	jp nz,sortobjdrawz0 ;не конец списка
	endif
;sortobjpopq
sortobjpopsp=$+1
	ld sp,0
	ret

	display "sortobj size=",$-sortobjbegin
