rotmatrixbegin=$

	if ($&#ff)>(256-9)
	.ALIGN 256
	endif
MATRIX
;(for x)
	if TWOAXES==0
OXz	db 0 ;todo убрать (=0 без крена), это коэффициент при z для расчёта x'
	endif
OXx	db 0
OXy	db 0
;(for y)
OYz	db 0
OYx	db 0
OYy	db 0
;(for z)
OZz	db 0
OZx	db 0
OZy	db 0
MATRIXend
	if ($&#ff)>(256-9)
	.ALIGN 256
	endif
MATRIX2
	ds 9

;OXx = (-sin(b)                     )
;OXz = (-1/2[ sin(a+b) + sin(a-b) ] )
;OXy = ( 1/2[ cos(a+b) + cos(a-b) ] )

;OYx = ( 1/2[ sin(b-g) - sin(b+g) ] )
;OYz = ( 1/2[ cos(a+g) + cos(a-g) ] + 1/4[ sin(a-b+g) - sin(a-b-g) - sin(a+b+g) + sin(a+b-g) ] )
;OYy = ( 1/2[ sin(a+g) + sin(a-g) ] - 1/4[ cos(a+b-g) - cos(a+b+g) - cos(a-b-g) + cos(a-b+g) ] )

;OZx = ( 1/2[ cos(b+g) + cos(b-g) ] )
;OZz = ( 1/2[ sin(a+g) - sin(a-g) ] - 1/4[ cos(a-b+g) + cos(a-b-g) - cos(a+b+g) - cos(a+b-g) ] )
;OZy = ( 1/2[ cos(a-g) - cos(a+g) ] + 1/4[ sin(a+b+g) + sin(a+b-g) - sin(a-b+g) - sin(a-b-g) ] )

;надо вращать в следующем порядке:
;1. азимут+рыскание объекта (ось Z(=yscr) - угол beta)
;2. наклон (тангаж) (ось Y(=xscr) - угол gamma)
;3. крен экрана, если надо (ось X(=zscr) - угол alpha)

;или без крена:

;( cb*cg -cb*sg    -sb )
;(    sg     cg      0 )
;( sb*cg -sb*sg     cb )
;cb*cg = (cos(b+g)+cos(b-g))/2
;sb*sg = (cos(b-g)-cos(b+g))/2
;sb*cg = (sin(b+g)+sin(b-g))/2
;cb*sg = (sin(b+g)-sin(b-g))/2

;OXx = (-sin(b) )
;OXz = ( 0 )
;OXy = ( cos(b) )

;OYx = ( 1/2*(sin(b-g)-sin(b+g)) )
;OYz = ( cos(g) )
;OYy = ( 1/2*(cos(b+g)-cos(b-g)) )

;OZx = ( 1/2*(cos(b+g)+cos(b-g)) )
;OZz = ( sin(g) )
;OZy = ( 1/2*(sin(b+g)+sin(b-g)) )

	;.ALIGN 256
	BEGIN256 (768+256+512)
CUTS
	ds 768
;X+x=-#80..+#7f  ;+-(#6d(X)+#36(x))=+-#a3
;Z = #2b..#55
;Z+z=#13..#87, 2048/(Z+z)=#10..#6c
;a+c = #11..#ec ;#10..#10f (256 значений)
;a-c = -#6b..#70 ;-#6c..#93 (256 значений)
;значения квадратов просто поделены на 256 для FOV=90 градусов

_divisor=18;16 ;при 16 переполняется при x/z=2
_halfdivisor=_divisor/2
;надо домножить 1/z на _divisor

t1divz
	display "  t1divz=",$
	dup #13 +2 +1; +2 для _divisor=17
	db #6c
	edup
	dup #85-#13
_=$&#ff
	db ((256*_divisor/_)+1)/2 ;правильное округление
	edup
	dup (($|#ff)+1)-$-#36
	db #10
	edup
	dup #36 ;zmax
	db #6c ;для отрицательных Z+z
	edup

	;a-c = -#6b..#70 ;-#6c..#93 (256 значений)
trotsqrsigned
	display "  trotsqrsigned=",$
	dup 128
_=($&#ff)
	db #ff&(-(((_/2)*(_/2)+_halfdivisor)/_divisor)) ;max=-63*2 *2
	edup
	db #ff&(#80 *2)
	dup 127
_=(256-($&#ff))
	db #ff&(-(((_/2)*(_/2)+_halfdivisor)/_divisor)) ;max=-63*2 *2
	edup

;a+c = #11..#ec ;#10..#10f (256 значений)
trotsqrpos
	display "  trotsqrpos=",$
	dup 256
_=($&#ff)
	db #ff&(((_/2)*(_/2)+_halfdivisor)/_divisor) ;max=255*2 *2 ;не работает с вычитанием 1 (на случай результата #100 при x/z=2)
	edup
	END256

	macro SUM1
;sum = +c0-c1+c2-c3
;h,l,d,e
	xor a
	sub h ;c1
	ld c,a
	rla
	sbc a,a
	ld b,a
	ld a,l ;c0
	rla
	sbc a,a
	ld h,a
	add hl,bc
	xor a
	sub d ;c3
	ld c,a
	rla
	sbc a,a
	ld b,a
	add hl,bc
	ld a,e ;c2
	;ld c,a
	rla
	sbc a,a
	ld d,a;b,a
	add hl,de;bc
	sra h
	rr l
	inc hl ;после следующего деления на 2 будет правильное округление (0>0, 1>0, 2>1, 3>1, 4>1, 5>1, 6>2...)
	endm

	macro SUM2
;sum2= +c0-c1-c2+c3
;b,c,d,e (keep de)
	xor a
	sub b ;c1
	ld l,a
	rla
	sbc a,a
	ld h,a
	ld a,c ;c0
	;ld l,a
	rla
	sbc a,a
	ld b,a;h,a
	add hl,bc
	xor a
	sub e ;c2
	ld c,a
	rla
	sbc a,a
	ld b,a
	add hl,bc
	ld a,d ;c3
	ld c,a
	rla
	sbc a,a
	ld b,a
	add hl,bc
	sra h
	rr l
	inc hl ;после следующего деления на 2 будет правильное округление (0>0, 1>0, 2>1, 3>1, 4>1, 5>1, 6>2...)
	endm

ROTATE_MATRIX
frame_tangage=$+1
	ld c,0
	ld b,a ;beta (yaw)
	ld l,b ;beta

	if TWOAXES ;без крена
	
	ld h,tsindiv2/256
	
	xor a
	sub (hl)
	if MATRIXDIV2
	sra a
	endif
	ld (OXx),a ;-sin(b)
	
	ld a,l
	add a,#40 ;cos
	ld l,a
	ld a,(hl)
	if MATRIXDIV2
	sra a
	endif
	ld (OXy),a ;cos(b)
	
	ld l,c ;gamma
	ld a,(hl)
	if MATRIXDIV2
	sra a
	endif
	ld (OZz),a ;sin(g)
	
	ld a,l
	add a,#40 ;cos
	ld l,a
	ld a,(hl)
	if MATRIXDIV2
	sra a
	endif
	ld (OYz),a ;cos(g)
	
	ld a,b ;beta
	add a,c ;gamma
	ld l,a ;b+g
	ld e,(hl) ;sin(b+g)
	sub c
	sub c
	ld l,a ;b-g
	ld d,(hl) ;sin(b-g)
	add a,#40 ;cos
	ld l,a ;b-g+pi/2 (for cos)
	ld b,(hl) ;cos(b-g)
	add a,c
	add a,c
	ld l,a ;b+g+pi/2 (for cos)
	ld c,(hl) ;cos(b+g)

	ld a,d ;sin(b-g)
	sub e ;sin(b+g)
	sra a
	if MATRIXDIV2
	sra a
	endif
	ld (OYx),a ;1/2*(sin(b-g)-sin(b+g))

	ld a,c ;cos(b+g)
	sub b ;cos(b-g)
	sra a
	if MATRIXDIV2
	sra a
	endif
	ld (OYy),a ;1/2*(cos(b+g)-cos(b-g))

	ld a,c ;cos(b+g)
	add a,b ;cos(b-g)
	sra a
	if MATRIXDIV2
	sra a
	endif
	ld (OZx),a ;1/2*(cos(b+g)+cos(b-g))

	ld a,d ;sin(b-g)
	add a,e ;sin(b+g)
	sra a
	if MATRIXDIV2
	sra a
	endif
	ld (OZy),a ;1/2*(sin(b+g)+sin(b-g))

	else ;с креном

	;ld l,b ;beta
	ld h,tsindiv2/256
	xor a
	sub (hl)
	if MATRIXDIV2
	sra a
	endif
	ld (OXx),a ;-sin(b)
	
	ld a,(alpha)
	ld ly,a ;alpha
	sub l
	ld e,a ;a-b
	add a,l
	add a,l
	ld l,a ;a+b
	add a,#40 ;cos
	ld d,a
	xor a
	sub (hl) ;sin(a+b)
	ld l,e ;a-b
	sub (hl) ;sin(a-b)
	sra a
	if MATRIXDIV2
	sra a
	endif
	ld (OXz),a ;-1/2*(sin(a+b)+sin(a-b))
	
	ld a,l
	add a,#40 ;cos
	ld l,a
	ld a,(hl) ;cos(a-b)
	ld l,d
	add a,(hl) ;cos(a+b)
	sra a
	if MATRIXDIV2
	sra a
	endif
	ld (OXy),a ;1/2*(cos(a+b)+cos(a-b))
	
	ld a,b ;beta
	add a,c ;gamma
	ld e,a ;b+g
	sub c
	sub c
	ld l,a ;b-g
	add a,#40 ;cos
	ld d,a ;b-g+pi/2 (for cos)
	ld a,(hl) ;sin(b-g)
	ld l,e
	sub (hl) ;sin(b+g)
	sra a
	if MATRIXDIV2
	sra a
	endif
	ld (OYx),a ;1/2*(sin(b-g)-sin(b+g))
	ld a,l
	add a,#40 ;cos
	ld l,a
	ld a,(hl) ;cos(b+g)
	ld l,d ;b-g+pi/2
	add a,(hl) ;cos(b-g)
	sra a
	if MATRIXDIV2
	sra a
	endif
	ld (OZx),a ;1/2*(cos(b+g)+cos(b-g))
	
;prepare big formula
	ld a,ly ;alpha
	sub c ;gamma
	ld l,a ;a-g
	ld e,(hl) ;sin(a-g)
	add a,c
	add a,c
	ld l,a ;a+g
	ex af,af' ;a+g
	ld l,(hl) ;sin(a+g)
	ld a,l
	rla
	sbc a,a
	ld h,a ;sin(a+g)
	ld a,e
	rla
	sbc a,a
	ld d,a ;sin(a-g)
	or a
	sbc hl,de
	push hl ;sin(a+g)-sin(a-g)
	add hl,de
	add hl,de
	ld (sinapg_sinamg),hl ;sin(a+g)+sin(a-g)
	
	ld h,tsindiv2/256
	ex af,af' ;a+g
	add a,#40
	ld l,a ;a+g+pi/2 (for cos)
	ld e,(hl) ;cos(a+g)
	sub c
	sub c
	ld l,a ;a-g+pi/2 (for cos)
	ld l,(hl) ;cos(a-g)
	ld a,l
	rla
	sbc a,a
	ld h,a ;cos(a-g)
	ld a,e
	rla
	sbc a,a
	ld d,a ;cos(a+g)
	or a
	sbc hl,de
	ld (cosamg_mcosapg),hl ;cos(a-g)-cos(a+g)
	add hl,de
	add hl,de
	ld (cosamg_cosapg),hl ;cos(a-g)+cos(a+g)
		
;do big formula
	ld a,ly ;alpha
	add a,c ;a+g
	sla c ;2g
	add a,b ;a+b+g
	sla b ;2b
	push bc ;b=2b, c=2g
	
	ld h,tsindiv2/256
	ld l,a
	sub b ;2b
	ld d,(hl) ;sin(a+b+g)
	ld l,a
	sub c ;2g
	ld e,(hl) ;sin(a-b+g)
	ld l,a
	add a,b ;2b
	ld b,(hl) ;sin(a-b-g)
	ld l,a
	ld c,(hl) ;sin(a+b-g)
	ex af,af' ;a+b-g
	push bc ;b=sin(a-b-g), c=sin(a+b-g)
	
	SUM2 ;+1/2*(sin(a+b+g) + sin(a+b-g) - sin(a-b+g) - sin(a-b-g))
cosamg_mcosapg=$+1
	ld bc,0 ;cos(a-g)-cos(a+g)
	add hl,bc
	sra h
	ld a,l
	rra
	if MATRIXDIV2
	sra a
	endif
	ld (OZy),a ;1/2*(cos(a-g)-cos(a+g)) + 1/4*(sin(a+b+g) + sin(a+b-g) - sin(a-b+g) - sin(a-b-g))
	
	pop hl ;h=sin(a-b-g), l=sin(a+b-g)
	SUM1 ;+1/2*(sin(a-b+g) - sin(a-b-g) - sin(a+b+g) + sin(a+b-g))
cosamg_cosapg=$+1
	ld bc,0 ;cos(a-g)+cos(a+g)
	add hl,bc
	sra h
	ld a,l
	rra
	if MATRIXDIV2
	sra a
	endif
	ld (OYz),a ;1/2*(cos(a+g)+cos(a-g)) + 1/4*(sin(a-b+g) - sin(a-b-g) - sin(a+b+g) + sin(a+b-g))
	
	pop bc ;b=2b, c=2g
	
	ex af,af' ;a+b-g
	add a,#40
	ld h,tsindiv2/256
	ld l,a
	sub b ;2b
	ld e,(hl) ;cos(a+b-g)
	ld l,a
	add a,c ;2g
	ld d,(hl) ;cos(a-b-g)
	ld l,a
	add a,b ;2b
	ld b,(hl) ;cos(a-b+g)
	ld l,a
	ld c,(hl) ;cos(a+b+g)
	push bc ;b=cos(a-b+g), c=cos(a+b+g)
	
	SUM2 ;-1/2*(cos(a+b-g) - cos(a+b+g) - cos(a-b-g) + cos(a-b+g))
sinapg_sinamg=$+1
	ld bc,0 ;sin(a+g)+sin(a-g)
	add hl,bc
	sra h
	ld a,l
	rra
	if MATRIXDIV2
	sra a
	endif
	ld (OYy),a ;1/2*(sin(a+g)+sin(a-g)) - 1/4*(cos(a+b-g) - cos(a+b+g) - cos(a-b-g) + cos(a-b+g))
	
	pop hl ;h=cos(a-b+g), l=cos(a+b+g)
	SUM1 ;-1/2*(cos(a-b+g) + cos(a-b-g) - cos(a+b+g) - cos(a+b-g))
	pop bc ;sin(a+g)-sin(a-g)
	add hl,bc
	sra h
	ld a,l
	rra
	if MATRIXDIV2
	sra a
	endif
	ld (OZz),a ;1/2*(sin(a+g)-sin(a-g)) - 1/4*(cos(a-b+g) + cos(a-b-g) - cos(a+b+g) - cos(a+b-g))
		
	endif ;с креном
		
	if 1==1
;построение засечек
;если только push hl, то можем использовать только чётные байты в таблице
;9[8] штук (только положительные для [OXz],OXx,OXy, OYz,OYx,OYy, OZz,OZx,OZy)
;расположение:
;CUTS+#000...#01f = OXx ;CUTS+#000...#01f = OXy
;6156t для 31 засечки (63 позиции в единичном кубе) - эквивалентно 10 вершинам
;3078t для 15 засечек (31 позиция в единичном кубе) - эквивалентно 5 вершинам
;todo убрать Xy (=0 без крена) - это вторая клетка матрицы
	ld (mkcutssp),sp
	ld de,MATRIX
;_=0
;_sp=CUTS+#80 ;#00..#1f = stack for INT
	ld hl,CUTS+#80
	ld c,3

	if TWOAXES
	ld sp,CUTS+#60 ;skip z
	ld b,2
	jr mkcuts1
	endif

mkcuts0
	ld sp,hl;_sp
	ld b,3
mkcuts1
	ld a,(de);(MATRIX+_)
	inc e
	exx
	add a,a ;*2
	ld l,a
	sbc a,a
	ld h,a
	add hl,hl ;*4
	 add hl,hl ;*8
	ld d,h
	ld e,l ;de=m*8
	ld b,0
	dup 15
	ld c,h
	push bc
	add hl,de
	ld b,h
	add hl,de
	edup ;de*0..de*29
	ld c,h
	push bc ;de*30..de*31
	exx
;_=_+1
	djnz mkcuts1
;_sp=_sp+#100
	inc h
	dec c
	jp nz,mkcuts0
mkcutssp=$+1
	ld sp,0
	endif
	ret
	
	display "rotmatrix size=",$-rotmatrixbegin
