PHP код:
//----------------------------------------
// 3D 2-Axis table rotator
//----------------------------------------
; Максимально возможная длина по осям в одну сторону 15
; (т.е. общая длина оси в обе стороны 31, что
; в принципе вполне достаточно для чанковых эффектов,
; но если нужно например для диапазона в 256 т.е. для
; точек, то можно соответственным образом подкорректировать
; таблицу проекций, считая ее умножая координаты на 4)
; Вычисление таблицы проекций здесь не приводится
; Считать ее можно так:
; PX = X0 + (X*CamDist)/(CamDist+Z));
; PY = Y0 + (Y*CamDist)/(CamDist+Z));
; Для диапазона координат -XYZMAX..0..+XYZMAX
; или для диапазона -127..0..+127
; PX = X0 + (4*X*CamDist)/(CamDist+Z*4));
; PY = Y0 + (4*Y*CamDist)/(CamDist+Z*4));
; где X0,Y0 - координаты центра экрана
; CamDist - расстояние до камеры (подбираем на глаз)
; Диапазон изменения угла вращения 0..127
; Поворот осуществляется вокруг осей Ox,Oy
; по адресу Ay - угол вращения вокруг Oy
; по адресу Ax - угол вращения вокруг Ox
//----------------------------------------
// Переменные и константы
//----------------------------------------
XYZMAX EQU 15 ; максимальная длина по осям (в одну сторону)
COR_PZ EQU #E0+XYZMAX ; коэффициент для Z
COR_Z EQU #C0+XYZMAX
COR_PX EQU XYZMAX
COR_PY EQU #20+XYZMAX
; Начальные координаты точек хранятся в формате
; X=X+COR_Z
; Y=Y+COR_Z
; Z=Z+COR_Z
; (т.е. с прибавленным смещением до начала таблиц)
//----------------------------------------
// Формулы вращения
//----------------------------------------
; OX:
; y =y*cos(Ay) - z*sin(Ay)
; z =y*sin(Ay) + z*cos(Ay)
; OY:
; x =x*cos(Ax) - z*sin(Ax)
; z =x*sin(Ax) + z*cos(Ax)
//----------------------------------------
// Формат хранения таблиц:
//----------------------------------------
; Таблица произведений:
; #C000 #C080
; +--------------+--------------+
; Coord| Coord*cos(A) | Coord*sin(A) |
; +--------------+--------------+
; Alpha Alpha
; Таблица проекций
; #E000 #E020
; +------+------+
; Z| PX | PY |
; +------+------+
; X Y
; вообще говоря можно таблицу проекций
; совместить с таблицей произведений,
; уменьшив при этом диапазон угла
; вращений до 0..95, как показано ниже,
; но приведенные тут значения соответствуют
; верхним таблицам
; #C000 #C060 #C080 #C0E0
; +--------------+-----+-------------+-----+
; Coord| Coord*cos(A) | PX |Coord*sin(A) | PY |Z
; +--------------+-----+-------------+-----+
; Alpha X Alpha Y
//----------------------------------------
// Создание таблицы произведений:
//----------------------------------------
; Изначально имеем таблицу cosA,sinA со значениями*256 (т.е. макс знач =1 в старшем байте)
; Можно написать генерилку, а можно расчитать на бейсике/паскале
; var
; alpha: integer;
; sc_tbl: array [0..255] of word;
; for alpha:=0 to 127 do
; begin
; sc_tbl[alpha]:=trunc(256*Cos(alpha*Pi/64));
; sc_tbl[alpha+128]:=trunc(256*Sin(alpha*Pi/64));
; end;
; далее считаем на асме
SC_TBL INCBIN "SC_TBL" ; Сгенерированная таблица [512 байт]
TMP_SC EQU #???? ; временная таблица, изначально содержит нули [512 байт]
CALC_TBL_PROIZV
; таблицы считаем накопительным сложением
//--- нулевой ряд
LD HL,#C000+XYZMAX*256
LD D,H
LD E,L
INC E
LD (HL),0
LD BC,255
LDIR
//--- положительный ряд
EXX
LD HL,#C000+256+XYZMAX*256
LD C,XYZMAX
SCC1 EXX
LD IX,TMP_SC
LD HL,SC_TBL
EXX
LD B,0
SCC0 EXX
LD E,(IX)
INC IX
LD D,(IX)
INC IX
LD C,(HL)
INC HL
LD B,(HL)
INC HL
EX DE,HL
ADD HL,BC
EX DE,HL
LD (IX-2),E
LD (IX-1),D
LD A,D
EXX
LD (HL),A
INC HL
DEC B
JP NZ,SCC0
DEC C
JP NZ,SCC1
//--- отрицательный ряд
LD HL,#C000+256+XYZMAX*256
LD DE,#C000-256+XYZMAX*256
LD C,XYZMAX
SSC3 LD B,0
PUSH DE
SSC2 LD A,(HL)
INC HL
NEG
LD (DE),A
INC DE
DJNZ SSC2
POP DE
PUSH HL
LD HL,0-256
ADD HL,DE
EX DE,HL
POP HL
DEC C
JP NZ,SSC3
//---
RET
//----------------------------------------
// Вращение и проецирование:
//----------------------------------------
; in: D-y E-x С-z
; out: D-py,E-px,A-z спроецированные координаты
//----
ROT3D //--- вращение по оси OY:
LD L,0 ;7
Ay EQU $-1
LD H,E ;4 (HL)=X*cosA
LD A,(HL) ;7 A=X*cosA
LD H,C ;4
SET 7,L ;8 (HL)=Z*sinA
SUB (HL) ;7 A=X*cosA-Z*sinA
ADD A,COR_PX ;7
LD B,A ;4
LD H,E ;4
LD A,(HL) ;7
LD H,C ;4
RES 7,L ;8
ADD A,(HL) ;7
ADD A,COR_Z ;7
LD C,A ;4 // 49+24+16=89
//--- вращение по оси OX:
LD L,0 ;7
Ax EQU $-1
LD H,D ;4
LD A,(HL) ;7
LD H,C ;4
SET 7,L ;8
SUB (HL) ;7
ADD A,COR_PY ;7
LD E,A ;4
LD H,D ;4
LD A,(HL) ;7
LD H,C ;4
RES 7,L ;8
ADD A,(HL) ;7
ADD A,COR_PZ ;7 // 49+24+16=89
//--- проецирование
LD H,A ;4
LD L,E ;4
LD D,(HL) ;7
LD L,C ;4
LD E,(HL) ;7
SUB COR_PZ-XYZMAX ;7 // 12+21=33 нормализация Z в диапазоне 0..XYZMAX*2+1
//---
RET