{$N+,A+,G+,F+,D-,E-,L-,R-,S-,Q-,Y-}
unit sandb_tc;

interface

procedure scene_sandbox;

implementation
uses global, math2, screen, palette, memory, resource, line;


type
  xyz = record
  x,y,z : longint;
  end;

type
  xyz_i = record
  x,y,z : integer;
  end;

type
  xyz_s = record
  x,y,z : single;
  end;

var
Aantal, T1: word;
start_time, old_time:word;
elapsed_time:word;

Intersect:xyz;
Reflect:xyz_i;


const
g_scale=1024*8;

cubic: array[0..23+3] of shortint =
(-1,-1,-1, -1,-1,1, -1,1,-1,-1,1,1, 1,-1,-1, 1,-1,1,1,1,-1, 1,1,1,    0,0,0);
pindexc: array[0..23] of byte =
(0,3,1,2, 0,5,4,1, 0,6,2,4, 6,3,2,7, 3,5,1,7, 4,7,6,5);

var
cubeDc:array[0..23+3] of longint;
cube1,cube2:array[0..23+3] of single;

per:longint;
N_plan:xyz;
N_plan_normal:xyz_s;
Distance:longint;


{Вычисляем нормаль плоскости по трем точкам A,B,C}
Procedure PlanNormal(A,B,C:xyz);
var
VectorAB, VectorAC: xyz;
N:xyz_s;
len:single;
begin
{N :=  VectorProduct(CreateVector(A,B),CreateVector(A,C));}
VectorAB.x := B.x-A.x;
VectorAB.y := B.y-A.y;
VectorAB.z := B.z-A.z;

VectorAC.x := C.x-A.x;
VectorAC.y := C.y-A.y;
VectorAC.z := C.z-A.z;

{//Векторное произведение}
N.x := (VectorAB.y*VectorAC.z - VectorAC.y*VectorAB.z);
N.y := (VectorAB.z*VectorAC.x - VectorAC.z*VectorAB.x);
N.z := (VectorAB.x*VectorAC.y - VectorAC.x*VectorAB.y);

{нормализуем нормаль}
len:=1/sqrt_(n.x*n.x + n.y*n.y + n.z*n.z);
n_plan_normal.x:=(n.x*len);
n_plan_normal.y:=(n.y*len);
n_plan_normal.z:=(n.z*len);

n_plan.x:=round(n_plan_normal.x*256);
n_plan.y:=round(n_plan_normal.y*256);
n_plan.z:=round(n_plan_normal.z*256);
end;


procedure CalsDistance(A, X:xyz);
var v:xyz;
begin
{// расстояние до плоскости по нормали}
{d :=  DotProduct(N,V);}
Distance :=shl_(N_plan.x*(A.x-X.x) + N_plan.y*(A.y-X.y) + N_plan.z*(A.z-X.z), 8);
end;


procedure cube_draw(culface:integer; xx,yy:integer; scale:single; col:byte; where:word);
var p,n,v, gg_scale:word;
x,y,z : array[0..3] of single;
q3, per_, pom, axv,ayv,azv,bxv,byv,bzv,nx,ny,nz:single;
begin
q3:=-4;
gg_scale:=13;
for n:=0 to 5 do begin
  p:=n*4;
  for v:=0 to 3 do
  begin
    per_:= per / (per-cubeDc[pindexc[p+v]*3+2]);
    x[v]:=(cubeDc[pindexc[p+v]*3]   * per_) *scale;
    y[v]:=(cubeDc[pindexc[p+v]*3+1] * per_) *scale;
    z[v]:=(cubeDc[pindexc[p+v]*3+2]) * scale;
  end;
  axv:=x[2]-x[0];{cx-ax;}
  ayv:=y[2]-y[0];{cy-ay;}
  azv:=z[2]-z[0];{cz-az;}
  bxv:=x[1]-x[0];{bx-ax;}
  byv:=y[1]-y[0];{by-ay;}
  bzv:=z[1]-z[0];{bz-az;}
  nx:=ayv*bzv-azv*byv;
  ny:=azv*bxv-axv*bzv;
  nz:=axv*byv-ayv*bxv;
  pom:=nz*q3+nx*axv+ny*ayv+nz*azv;
  if culface>0 then pom:=-pom;
  if pom<0 then begin
    DrawLine(sar_(round(x[0]), gg_scale)+xx, sar_(round(y[0]), gg_scale)+yy,
             sar_(round(x[2]), gg_scale)+xx, sar_(round(y[2]), gg_scale)+yy,  col, where);
    DrawLine(sar_(round(x[1]), gg_scale)+xx, sar_(round(y[1]), gg_scale)+yy,
             sar_(round(x[3]), gg_scale)+xx, sar_(round(y[3]), gg_scale)+yy,  col, where);
    DrawLine(sar_(round(x[2]), gg_scale)+xx, sar_(round(y[2]), gg_scale)+yy,
             sar_(round(x[1]), gg_scale)+xx, sar_(round(y[1]), gg_scale)+yy,  col, where);
    DrawLine(sar_(round(x[3]), gg_scale)+xx, sar_(round(y[3]), gg_scale)+yy,
             sar_(round(x[0]), gg_scale)+xx, sar_(round(y[0]), gg_scale)+yy,  col, where);
    end;
  end;
end;



procedure cube_rotate(var inp:array of single; var out:array of single;  xc,yc,zc,  xr,yr,zr:single);
var x,y,z,X1,Y1,Z1:single;
CosX, CosY, CosZ, SinX,SinY,SinZ:single;
p:integer;
begin
CosX:=cos_(Xr);SinX:=sin_(Xr);
CosY:=cos_(Yr);SinY:=sin_(Yr);
CosZ:=cos_(Zr);SinZ:=sin_(Zr);
 for p:=0 to 7+1 do begin
  x:=inp[p*3]   +xc;
  y:=inp[p*3+1] +yc;
  z:=inp[p*3+2] +zc;
  x1:=cosy*x-siny*z;
  z1:=siny*x+cosy*z;
  x:=cosz*x1+sinz*y;
  y1:=cosz*y-sinz*x1;
  z:=cosx*z1-sinx*y1;
  y:=sinx*z1+cosx*y1;
  out[p*3]:=x;
  out[p*3+1]:=y;
  out[p*3+2]:=z;
end;
end;

procedure cube_scale(var inp:array of single; var out:array of longint; xx,yy,zz:single; scalec:xyz_s);
var
p:integer;
begin
 for p:=0 to 7+1 do begin
  out[p*3]:=  round(Inp[p*3]     *scalec.x+xx);
  out[p*3+1]:=round(Inp[p*3+1]   *scalec.y+yy);
  out[p*3+2]:=round(Inp[p*3+2]   *scalec.z+zz);
end;
end;



procedure dots_collision(from_dots,to_dots:word; damping:single; A, CubeC:xyz);
var
count_dots:integer;
seg_coord,seg_vect, ofs_coord,ofs_vect:word;
begin
seg_coord:=vaddr2;
seg_vect:=vaddr3;
ofs_coord:=0;
ofs_vect:=0;

count_dots:=to_dots-from_dots;

if count_dots<=0 then exit;

ofs_coord:=ofs_coord + from_dots*12;
ofs_vect:= ofs_vect  + from_dots*6;

asm
mov es, seg_coord
mov ax, seg_vect
db $8E,$E0 {mov fs, ax}
mov cx, count_dots

mov di, ofs_vect
db $66; shl di, 16
mov di, ofs_coord


{------------self-moding---------------}
db $66; mov ax, word ptr A.x
db $66; mov cs:[offset @Ax+2], ax
db $66; mov ax, word ptr A.y
db $66; mov cs:[offset @Ay+3], ax
db $66; mov ax, word ptr A.z
db $66; mov cs:[offset @Az+3], ax

db $66; mov ax, word ptr n_plan.x
db $66; mov cs:[offset @n_plan_x0+3], ax
db $66; mov cs:[offset @n_plan_x1+3], ax
db $66; mov cs:[offset @n_plan_x2+3], ax
db $66; mov cs:[offset @n_plan_x3+3], ax
db $66; mov ax, word ptr n_plan.y
db $66; mov cs:[offset @n_plan_y0+3], ax
db $66; mov cs:[offset @n_plan_y1+3], ax
db $66; mov cs:[offset @n_plan_y2+3], ax
db $66; mov cs:[offset @n_plan_y3+3], ax
db $66; mov ax, word ptr n_plan.z
db $66; mov cs:[offset @n_plan_z0+3], ax
db $66; mov cs:[offset @n_plan_z1+3], ax
db $66; mov cs:[offset @n_plan_z2+3], ax
db $66; mov cs:[offset @n_plan_z3+3], ax

db $66; mov ax, word ptr CubeC.x
db $66; mov cs:[offset @CubeC_x1+3], ax
db $66; mov cs:[offset @CubeC_x2+3], ax
db $66; mov ax, word ptr CubeC.y
db $66; mov cs:[offset @CubeC_y1+3], ax
db $66; mov cs:[offset @CubeC_y2+3], ax
db $66; mov ax, word ptr CubeC.z
db $66; mov cs:[offset @CubeC_z1+3], ax
db $66; mov cs:[offset @CubeC_z2+3], ax

db $66; mov ax, word ptr distance
db $66; cwd
db $66; mov cs:[offset @distance_ax+2], ax
db $66; mov cs:[offset @distance_dx+2], dx

jmp @clear_prefetch; @clear_prefetch:
{--------------------------------------}


db $9b,$db,$e3 {finit}
fld dword ptr damping
push bp

@l:
push cx

db $66; mov si, es:[di]   {P.x}
db $66; mov bx, es:[di+4] {P.y}
db $66; mov cx, es:[di+8] {P.z}

{Определяем с какой стороны плоскости (грани) находится частица}
{O.x := P.x - A.x; O.y := P.y - A.y; O.z := P.z - A.z;}
db $66; mov ax, si
db $66; mov dx, bx
db $66; mov bp, cx
@Ax: db $66; sub ax, 1234h; dw $5678 {sub eax, A.x}
@Ay: db $66; sub dx, 1234h; dw $5678 {sub edx, A.y}
@Az: db $66; sub bp, 1234h; dw $5678 {sub ebp, A.z}
{k := (N_plan.x*O.x + N_plan.y*O.y + N_plan.z*O.z);}
@n_plan_x0: db $66,$69,$c0,  $00,$00,$00,$00 {imul eax, (N_plan.x)}
@n_plan_y0: db $66,$69,$d2,  $00,$00,$00,$00 {imul edx, (N_plan.y)}
db $66; add ax, dx
@n_plan_z0: db $66,$69,$ed,  $00,$00,$00,$00 {imul ebp, (N_plan.z)}
db $66; add bp, ax
{if k<0 then begin}
jns @section_test_fail

{Вычисляем точку пересечения прямой (от центра до частицы) и плоскости}

{P.x := P.x-CubeC.x; P.y := P.y-CubeC.y; P.z := P.z-CubeC.z;}
@CubeC_x1: db $66; sub si, 1234h; db $56,$78; {word ptr CubeC.x}
@CubeC_y1: db $66; sub bx, 1234h; db $56,$78; {word ptr CubeC.y}
@CubeC_z1: db $66; sub cx, 1234h; db $56,$78; {word ptr CubeC.z}

{e := N_plan.x*P.x + N_plan.y*P.y + N_plan.z*P.z;}
@n_plan_x1: db $66,$69,$c6,  $00,$00,$00,$00 {imul eax, esi, (N_plan.x)}
@n_plan_y1: db $66,$69,$d3,  $00,$00,$00,$00 {imul edx, ebx, (N_plan.y)}
db $66; add ax, dx
@n_plan_z1: db $66,$69,$e9,  $00,$00,$00,$00 {imul ebp, ecx, (N_plan.z)}
db $66; add bp, ax

{jns @section_test_fail {if e<0 then begin}
{d := distance div e;}
@distance_ax: db $66; mov ax, 1234h; db $56,$78; {distance}
@distance_dx: db $66; mov dx, 1234h; db $56,$78;
db $66; idiv bp

{Intersect.x := sar_( (P.x * d) , 8);}
db $66,$0f,$af,$f0 {imul esi, eax}
db $66; sar si, 8

{Intersect.y := sar_( (P.y * d) , 8);}
db $66,$0f,$af,$d8 {imul ebx, eax}
db $66; sar bx, 8

{Intersect.z := sar_( (P.z * d) , 8);}
db $66,$0f,$af,$c8 {imul ecx, eax}
db $66; sar cx, 8

{P.x := P.x+CubeC.x; P.y := P.y+CubeC.y; P.z := P.z+CubeC.z;}
@CubeC_x2: db $66; add si, 1234h; db $56,$78; {word ptr CubeC.x}
@CubeC_y2: db $66; add bx, 1234h; db $56,$78; {word ptr CubeC.y}
@CubeC_z2: db $66; add cx, 1234h; db $56,$78; {word ptr CubeC.z}

db $66; mov es:[di],   si
db $66; mov es:[di+4], bx
db $66; mov es:[di+8], cx

{-------------------REFLECTION--------------------------------}
    db $66; rol di, 16

    {dot:=v.x*n_plan.x + v.y*n_plan.y + v.z*n_plan.z;}
    db $64,$66,$0f,$bf,$15 {movsx edx, fs:[di]} {v.x}
    @n_plan_x2: db $66,$69,$d2,  $00,$00,$00,$00 {imul edx, n_plan.x}

    db $64,$66,$0f,$bf,$75,$02 {movsx esi, fs:[di+2]} {v.y}
    @n_plan_y2: db $66,$69,$f6,  $00,$00,$00,$00  {imul esi, n_plan_y}
    db $66; add dx, si

    db $64,$66,$0f,$bf,$75,$04 {movsx esi, fs:[di+4]} {v.z}
    @n_plan_z2: db $66,$69,$f6,  $00,$00,$00,$00  {imul esi, n_plan.z}
    db $66; add dx, si

    db $66; add dx, dx {dot:=dot+dot;}

    {Reflect.x:= v.x - sar_(dot * n_plan.x, 16);
    Reflect.y:= v.y - sar_(dot * n_plan.y, 16);
    Reflect.z:= v.z - sar_(dot * n_plan.z, 16);}

    @n_plan_x3: db $66,$69,$c2,  $00,$00,$00,$00 {imul eax, edx, n_plan.x}
    db $66; sar ax, 16
    @n_plan_y3: db $66,$69,$da,  $00,$00,$00,$00 {imul ebx, edx, n_plan.y}
    db $66; sar bx, 16
    @n_plan_z3: db $66,$69,$ca,  $00,$00,$00,$00 {imul ecx, edx, n_plan.z}
    db $66; sar cx, 16

    db $64; sub [di],   ax
    db $64; sub [di+2], bx
    db $64; sub [di+4], cx

    {dots_vect[n].x:=round(Reflect.x * damping);
    dots_vect[n].y:=round(Reflect.y * damping);
    dots_vect[n].z:=round(Reflect.z * damping);}
    db $64,$df,$05      {fild  word ptr fs:[di]}
    db $d8,$c9          {fmul  st(0), st(1)}
    db $64,$df,$45,$02  {fild  word ptr fs:[di+2]}
    db $d8,$ca          {fmul  st(0), st(2)}
    db $64,$df,$45,$04  {fild  word ptr fs:[di+4]}
    db $d8,$cb          {fmul  st(0), st(3)}
    db $64,$df,$5d,$04  {fistp word ptr fs:[di+4]}
    db $64,$df,$5d,$02  {fistp word ptr fs:[di+2]}
    db $64,$df,$1d      {fistp word ptr fs:[di]}

    db $66; rol di, 16
    db $66,$81,$c7,$0C,$00,$06,$00 {add edi, 06 00 0Ch (ofs_coord+12, ofs_vect+6)}
    pop cx
    dec cx
    jnz @l
jmp @exit

@section_test_fail:
db $66,$81,$c7,$0C,$00,$06,$00 {add edi, 06 00 0Ch (ofs_coord+12, ofs_vect+6)}

pop cx
dec cx
jnz @l

@exit:
pop bp
end;
end;


procedure dots_process(count:integer; gravy, speed_scale:word);
var seg_coord,seg_vect, ofs_coord,ofs_vect:word;
begin
if count<=0 then exit;
seg_coord:=vaddr2;
seg_vect:=vaddr3;
ofs_coord:=0;
ofs_vect:=0;
asm
push ds
  mov es, seg_coord
  mov di, ofs_coord
  mov bx, speed_scale
  mov dx, gravy
  mov cx, count
  mov si, ofs_vect
  mov ds, seg_vect
  @l:{for n:=0 to count-1 do}
       {dots_vect[n].y:=dots_vect[n].y + gravy;}
       add ds:[si+2], dx

       {dots_coord[n].x:=dots_coord[n].x + dots_vect[n].x * speed_scale;}
       mov ax, ds:[si]
       db $0f,$af,$c3 {imul ax, bx}
       db $66,$0f,$bf,$c0 {movsx eax, ax}
       db $66; add es:[di], ax
       {dots_coord[n].y:=dots_coord[n].y + dots_vect[n].y * speed_scale;}
       mov ax, ds:[si+2]
       db $0f,$af,$c3 {imul ax, bx}
       db $66,$0f,$bf,$c0 {movsx eax, ax}
       db $66; add es:[di+4], ax
       {dots_coord[n].z:=dots_coord[n].z + dots_vect[n].z * speed_scale;}
       mov ax, ds:[si+4]
       db $0f,$af,$c3 {imul ax, bx}
       db $66,$0f,$bf,$c0 {movsx eax, ax}
       db $66; add es:[di+8], ax

       add di, 12
       add si, 6
  loop @l
pop ds
end;
end;


procedure dots_process_e8(count:integer; gravy:word);
var seg_coord,seg_vect, ofs_coord,ofs_vect:word;
begin
if count<=0 then exit;
seg_coord:=vaddr2;
seg_vect:=vaddr3;
ofs_coord:=0;
ofs_vect:=0;
asm
push ds
  mov es, seg_coord
  mov di, ofs_coord
  {mov bx, speed_scale}
  mov dx, gravy
  mov cx, count
  mov si, ofs_vect
  mov ds, seg_vect
  @l:{for n:=0 to count-1 do}
       {dots_vect[n].y:=dots_vect[n].y + gravy;}
       add ds:[si+2], dx

       {dots_coord[n].x:=dots_coord[n].x + dots_vect[n].x * speed_scale;}
       mov ax, ds:[si]
       shl ax, 3 {db $0f,$af,$c3 {imul ax, bx}
       db $66,$0f,$bf,$c0 {movsx eax, ax}
       db $66; add es:[di], ax
       {dots_coord[n].y:=dots_coord[n].y + dots_vect[n].y * speed_scale;}
       mov ax, ds:[si+2]
       shl ax, 3 {db $0f,$af,$c3 {imul ax, bx}
       db $66,$0f,$bf,$c0 {movsx eax, ax}
       db $66; add es:[di+4], ax
       {dots_coord[n].z:=dots_coord[n].z + dots_vect[n].z * speed_scale;}
       mov ax, ds:[si+4]
       shl ax, 3 {db $0f,$af,$c3 {imul ax, bx}
       db $66,$0f,$bf,$c0 {movsx eax, ax}
       db $66; add es:[di+8], ax

       add di, 12
       add si, 6
  loop @l
pop ds
end;
end;

procedure dots_process_e16(count:integer; gravy:word);
var seg_coord,seg_vect, ofs_coord,ofs_vect:word;
begin
if count<=0 then exit;
seg_coord:=vaddr2;
seg_vect:=vaddr3;
ofs_coord:=0;
ofs_vect:=0;
asm
push ds
  mov es, seg_coord
  mov di, ofs_coord
  {mov bx, speed_scale}
  mov dx, gravy
  mov cx, count
  mov si, ofs_vect
  mov ds, seg_vect
  @l:{for n:=0 to count-1 do}
       {dots_vect[n].y:=dots_vect[n].y + gravy;}
       add ds:[si+2], dx

       {dots_coord[n].x:=dots_coord[n].x + dots_vect[n].x * speed_scale;}
       mov ax, ds:[si]
       shl ax, 4 {db $0f,$af,$c3 {imul ax, bx}
       db $66,$0f,$bf,$c0 {movsx eax, ax}
       db $66; add es:[di], ax
       {dots_coord[n].y:=dots_coord[n].y + dots_vect[n].y * speed_scale;}
       mov ax, ds:[si+2]
       shl ax, 4 {db $0f,$af,$c3 {imul ax, bx}
       db $66,$0f,$bf,$c0 {movsx eax, ax}
       db $66; add es:[di+4], ax
       {dots_coord[n].z:=dots_coord[n].z + dots_vect[n].z * speed_scale;}
       mov ax, ds:[si+4]
       shl ax, 4 {db $0f,$af,$c3 {imul ax, bx}
       db $66,$0f,$bf,$c0 {movsx eax, ax}
       db $66; add es:[di+8], ax

       add di, 12
       add si, 6
  loop @l
pop ds
end;
end;

procedure dots_process_e24(count:integer; gravy:word);
var seg_coord,seg_vect, ofs_coord,ofs_vect:word;
begin
if count<=0 then exit;
seg_coord:=vaddr2;
seg_vect:=vaddr3;
ofs_coord:=0;
ofs_vect:=0;
asm
push ds
  mov es, seg_coord
  mov di, ofs_coord
  {mov bx, speed_scale}
  mov dx, gravy
  mov cx, count
  mov si, ofs_vect
  mov ds, seg_vect
  @l:{for n:=0 to count-1 do}
       {dots_vect[n].y:=dots_vect[n].y + gravy;}
       add ds:[si+2], dx

       {dots_coord[n].x:=dots_coord[n].x + dots_vect[n].x * speed_scale;}
       mov ax, ds:[si]
       mov bx, ax {db $0f,$af,$c3 {imul ax, bx}
       shl ax, 4
       shl bx, 3
       add ax, bx
       db $66,$0f,$bf,$c0 {movsx eax, ax}
       db $66; add es:[di], ax
       {dots_coord[n].y:=dots_coord[n].y + dots_vect[n].y * speed_scale;}
       mov ax, ds:[si+2]
       mov bx, ax {db $0f,$af,$c3 {imul ax, bx}
       shl ax, 4
       shl bx, 3
       add ax, bx
       db $66,$0f,$bf,$c0 {movsx eax, ax}
       db $66; add es:[di+4], ax
       {dots_coord[n].z:=dots_coord[n].z + dots_vect[n].z * speed_scale;}
       mov ax, ds:[si+4]
       mov bx, ax {db $0f,$af,$c3 {imul ax, bx}
       shl ax, 4
       shl bx, 3
       add ax, bx
       db $66,$0f,$bf,$c0 {movsx eax, ax}
       db $66; add es:[di+8], ax

       add di, 12
       add si, 6
  loop @l
pop ds
end;
end;


procedure dots_draw(from_dots, count_dots:integer; xx,yy, scale:integer; and_color:byte; where:word);
var n:word;
per_long_scale, x,y,z, per_long,scale_long : longint;
seg_coord,seg_vect, ofs_coord,ofs_vect:word;
begin
if (count_dots<=0) or (from_dots<0) then exit;

seg_coord:=vaddr2;
ofs_coord:=0;
per_long:=per;
scale_long:=scale;
per_long_scale:=per*scale;

ofs_coord:=ofs_coord + from_dots*12;

  asm
  mov es, where
  mov di, ofs_coord

  {------------self-moding-------------------}
   mov al, and_color
   mov cs:[offset @and_color+1], al

   db $66; mov ax, word ptr per_long
   db $66; mov cs:[offset @per_long+2], ax

   db $66; mov ax, word ptr per_long_scale
   db $66; shl ax, 8
   db $66; mov cs:[offset @per_256+2], ax

   mov ax, word ptr yy
   mov cs:[offset @yy+2], ax

   jmp @clear_prefetch; @clear_prefetch:
  {------------------------------------------}

  mov cx, count_dots

  db $66; mov si, word ptr scale_long

  mov ax, xx

  push bp
  push ds

  mov ds, seg_coord
  mov bp, ax

  @l:{for n:=0 to count-1 do begin}

    {p:=(per shl 8) div (per-dots_coord[n].z)}
    @per_long: db $66; mov bx, 1234h; db $56,$78 {word ptr per_long}
    db $66; sub bx, ds:[di+8]
    @per_256: db $66; mov ax, 1234h; db $56,$78
    db $66; cwd
    db $66; idiv bx
    db $66; mov bx, ax

    {x:=(dots_coord[n].x * p }
    db $66,$0f,$af,$05     {imul eax, ds:[di]}
    {y:=(dots_coord[n].y * p }
    db $66,$0f,$af,$5d,$04 {imul ebx, ds:[di+4]}

{    db $66,$0f,$af,$c6 {imul eax, esi} {x*scale_long}
{    db $66,$0f,$af,$de {imul ebx, esi} {y*scale_long}
    db $66; sar ax, 13+8
    db $66; sar bx, 13+8
    @yy: add bx, 1234h {+yy}
{    js @skip_draw {if y<0 then skip_draw}
    cmp bx, 198
    ja @skip_draw

    {call x+y*320}
    xchg bh, bl
    mov  dx, bx
    shr  dx, 2
    add  bx, dx
    add  bx, ax

    add  bx, bp {+xx}

    mov al, cl
    @and_color: and al, 0ffh
    mov ah, al
    mov es:[bx+1], al
    mov es:[bx+320], al
    mov es:[bx-320], al
    inc ah
    mov es:[bx-1], ax
    @skip_draw:

  add di, 12
  dec cx
  jnz @l
  pop ds
  pop bp
  end;
end;


procedure dots_draw_clip(count_dots:integer; xx,yy, scale:integer; and_color:byte; where:word);
var n:word;
x,y,z, per_long,scale_long : longint;
seg_coord,seg_vect, ofs_coord,ofs_vect:word;
begin
if (count_dots<=0) then exit;

seg_coord:=vaddr2;
seg_vect:=vaddr3;

ofs_coord:=0;
per_long:=per;
scale_long:=scale;

  asm
  mov es, where
  mov ax, seg_coord
  db $8E,$E0 {mov fs, ax}
  mov di, ofs_coord

  mov ax, seg_vect
  db $8E,$E8 {mov gs, ax}

  {------------self-moding-------------------}
   mov al, and_color
   mov cs:[offset @and_color+1], al

   db $66; mov ax, word ptr per_long
   db $66; mov cs:[offset @per_long+2], ax
   db $66; shl ax, 8
   db $66; mov cs:[offset @per_256+2], ax

   db $66; mov ax, word ptr scale_long
   db $66; mov cs:[offset @scale_long+2], ax

   mov ax, word ptr xx
   mov cs:[offset @xx+2], ax
   mov ax, word ptr yy
   mov cs:[offset @yy+1], ax

   jmp @clear_prefetch; @clear_prefetch:
  {------------------------------------------}


  mov cx, count_dots

  push bp
  xor bp, bp

  @l:{for n:=0 to count-1 do begin}

    {p:=(per shl 8) div (per-dots_coord[n].z)}
    @per_long: db $66; mov si, 1234h; db $56,$78 {word ptr per_long}
    db $66,$64; sub si, [di+8]
    @per_256: db $66; mov ax, 1234h; db $56,$78
    db $66; cwd
    db $66; idiv si
    db $66; mov bx, ax

    {x:=(dots_coord[n].x * p }
    db $64,$66,$0f,$af,$1d     {imul ebx, fs:[di]}

    {y:=(dots_coord[n].y * p }
    db $64,$66,$0f,$af,$45,$04 {imul eax, fs:[di+4]}

    @scale_long: db $66; mov dx, 1234h; db $56,$78 {word ptr scale_long}
    db $66,$0f,$af,$c2 {imul eax, edx}
    db $66,$0f,$af,$da {imul ebx, edx}
    db $66; sar ax, 13+8
    db $66; sar bx, 13+8
    @yy: add ax, 1234h; {yy}
    js @skip_draw {if y<0 then skip_draw}
    cmp ax, 198
    jg @clear_vectors

    @xx: add bx, 1234h; {xx}
{    cmp bx, 1
    jl @skip_draw
    cmp bx, 318
    jg @skip_draw}

    {call x+y*320}
    xchg ah, al
    mov  si, ax
    shr  si, 2
    add  si, ax
    add  si, bx

    mov al, cl
    @and_color: and al, 0ffh
    mov ah, al
    mov es:[si+1], al
    mov es:[si+320], al
    mov es:[si-320], al
    inc ah
    mov es:[si-1], ax
    @skip_draw:

  add di, 12
  add bp, 6
  dec cx
  jnz @l
  jmp @exit

  @clear_vectors:
    db $65,$66,$c7,$46,$0,$0,$0,$0,$0 {mov dword ptr gs:[bp], 0}
    db $65,$c7,$46,$04,$0,$0          {mov word ptr gs:[bp+4],0}
    add di, 12
    add bp, 6
    dec cx
    jnz @l


  @exit:
  pop bp
  end;
end;



function var2value_plus(X,value:longint; step:word):longint;
begin
      if (X<value) then
        begin
           X:=X+step;
           if X>value  then begin var2value_plus:=value; exit; end;
           var2value_plus:=X;
           exit;
        end;
     var2value_plus:=X;
end;



var
jump_on:array[0..9] of word;
event, plan, p, p1,p2, q,n, count_dots, active_dots:word;
glitch_jump, kryshka2, damping:single;
jump, kryshka, gravy:longint;
cube_jump, x,y, a,b,c:xyz;
scale, add_cube_rotate, cube_coord, rotate, cube_angle, cube_center:xyz_s;
CubeC:xyz;
seg_glitch, seg_wave, seg_random, seg_coord,seg_vect, ofs_coord,ofs_vect:word;
color_mode, safe_draw_dots, draw_cube_on, col,kryshka_down, rotate3d_on:byte;



procedure scene_sandbox;

procedure collision_detect(p1,p2:byte);
begin
    for plan:=p1 to p2 do
      begin;
              p:=plan*4;

              {центр куба после поворота}
              CubeC.x := cubeDc[24];
              CubeC.y := cubeDc[25];
              CubeC.z := cubeDc[26];

              {координаты плоскости со сдвигом в к нулевому центру координат}
              A.x:=cubeDc[pindexc[p]*3];
              A.y:=cubeDc[pindexc[p]*3+1];
              A.z:=cubeDc[pindexc[p]*3+2];
              B.x:=cubeDc[pindexc[p+1]*3];
              B.y:=cubeDc[pindexc[p+1]*3+1];
              B.z:=cubeDc[pindexc[p+1]*3+2];
              C.x:=cubeDc[pindexc[p+2]*3];
              C.y:=cubeDc[pindexc[p+2]*3+1];
              C.z:=cubeDc[pindexc[p+2]*3+2];

              PlanNormal(A,B,C);
              CalsDistance(A, CubeC);

              Dots_collision(0, active_dots, damping, A, CubeC);
      end;
end;

procedure boost_vectors;
begin
for n:=0 to count_dots-1 do
  if (n and 1 =1) then
      begin
        memw[vaddr3:n*6]:=memw[vaddr3:n*6]     shl 1;
        memw[vaddr3:n*6+2]:=memw[vaddr3:n*6+2] shl 1;
        memw[vaddr3:n*6+4]:=memw[vaddr3:n*6+4] shl 1;
      end;
end;

procedure boost_vectors_invert_y;
begin
for n:=0 to count_dots-1 do
      begin
        if memw[vaddr3:n*6+2]>0 then
                   memw[vaddr3:n*6+2]:=-memw[vaddr3:n*6+2] shl 1
                   else memw[vaddr3:n*6+2]:=memw[vaddr3:n*6+2] shl 1;
      end;
end;



function jump1(var jump_this:word; d, speed:single):single;
var jump:single;
begin
  jump:= sin((q-jump_this)/speed)*d;
  if jump<0 then begin jump_this:=0; jump:=0;end;
  jump1:=jump;
end;

procedure go_event(e:word;name:string; param1:integer);
begin
  if (e=event) then begin

     if      name='jump1' then begin
                         jump_on[1]:=q;
             end
     else if name='jump2' then begin
                         jump_on[2]:=q;
             end
     else if name='jump3' then begin
                         jump_on[3]:=q;
             end
     else if name='jump4' then begin
                         jump_on[4]:=q;
             end
     else if name='jump5' then begin
                         jump_on[5]:=q;
             end
     else if name='jump6' then begin
                         jump_on[6]:=q;
             end
     else if name='glitch1' then begin
                         jump_on[7]:=q;
             end
     else if name='glitch2' then begin
                         jump_on[8]:=q;
             end
     else if name='glitch3' then begin
                         jump_on[9]:=q;
             end

     else if name='boost' then begin
                         boost_vectors;
             end;
  inc(event);
  end;
end;


begin

per:=30*g_scale;

kryshka:=-4*g_scale;
kryshka2:=1;
kryshka_down:=0;
rotate3d_on:=0;
rotate.x:=0;
rotate.y:=0;
rotate.z:=0;
cube_coord.x:=0;
cube_coord.y:=0;
cube_coord.z:=0;
cube_center.x:=0;
cube_center.y:=0;
cube_center.z:=0;


cube_jump.y:=0;
jump:=0;
add_cube_rotate.x:=0;
add_cube_rotate.y:=0;
add_cube_rotate.z:=0;

gravy:=round(0.001*g_scale/8);
damping:=0.85;

count_dots:=1100;
active_dots:=0;

scale.x:=g_scale;
scale.y:=g_scale;
scale.z:=g_scale;

draw_cube_on:=1;
safe_draw_dots:=1;
color_mode:=255;

for n:=0 to 23+3 do cube1[n]:=cubic[n];
for n:=0 to 7 do jump_on[n]:=0;


for n:=0 to count_dots-1 do begin
meml[vaddr2:n*12]:=round(((random(40))/100 -0.9) * g_scale);
meml[vaddr2:n*12+4]:=round(((random(30))/100 -2.4) * g_scale);
meml[vaddr2:n*12+8]:=round(((random(100))/100 -0.5) * g_scale);
memw[vaddr3:n*6]:=random(10)+20;
memw[vaddr3:n*6+2]:=random(10);
memw[vaddr3:n*6+4]:=10-5;
end;


LoadBin('sandbox3.pal', seg_palitra,  ofs_palitra+palette1);

{mem2mem(seg_palitra,ofs_palitra+palette1+3*2,  seg_palitra,ofs_palitra+palette1+127*3*2 , 127*3*2);}

{init for screen glitch}
seg_random:=vaddr3+2000;
seg_wave:=seg_random+256;
table_for_FlipScreen2(0, 1, seg_random);
if useXMS=1 then LoadBufferFromXMS('glitch_table2', seg_wave, 0)
            else table_for_FlipScreen2(1, 1, seg_wave);
seg_glitch:=seg_random;

Clear(0,65535, vaddr);
DrawLine(107,47, 212,47, 131, vaddr);
DrawLine(212,47, 212,152, 131, vaddr);
DrawLine(212,152, 107, 152, 131, vaddr);
DrawLine(107,152, 107, 47, 131, vaddr);
setonecolor2memw(130, 16,16,16, palette1,seg_palitra,ofs_palitra);
setonecolor2memw(131, 48,48,48, palette1,seg_palitra,ofs_palitra);
Midas_WaitVR;
setpalette_from_memW(palette1,seg_palitra,ofs_palitra);
FlipScreen(vaddr, vga);

MP^.GetInformation(@info);

Aantal:=0; T1:=mTimer;
old_time:=mtimer;
start_time:=mtimer;

repeat
q:=mtimer-start_time;
elapsed_time:=(mtimer-old_time);
old_time:=mtimer;


Clear(0, 64000, vaddr);

{-------------------------------------------------------------------------}
if (elapsed_time>0) then {} begin

     MP^.GetInformation(@info);

     case event of

     0: if (music_pos(65,32)) then begin go_event(0, 'glitch3',0); seg_glitch:=seg_random; end; {glitch}
     1: if (music_pos(65,50)) then begin go_event(1, 'glitch3',0); seg_glitch:=seg_wave; end; {glitch}

     2: if music_pos(67,0) then go_event(2, 'jump6',0);   {y rotate jump}
     3: if music_pos(67,0) then go_event(3, 'jump4',0);   {-x center jump}
     4: if (music_pos(67,8)) then go_event(4, 'jump5',0); {x coord jump}
     5: if (music_pos(67,8)) then go_event(5, 'boost',0); {x coord jump}


     6: if (music_pos(67,16)) then go_event(6, 'jump1',0); {x rotate jump}
     7: if (music_pos(67,16)) then go_event(7, 'jump3',0); {z center jump}

     8: if (music_pos(67,50)) then begin go_event(8, 'glitch1',0); seg_glitch:=seg_random; end; {glitch}
     9: if (music_pos(67,52)) then begin inc(event); color_mode:=47; {47,15,60} end;
    10: if (music_pos(67,56)) then begin go_event(10, 'glitch2',0); seg_glitch:=seg_wave; end; {glitch}

    11: if (music_pos(68,56)) then begin go_event(11, 'glitch1',0); seg_glitch:=seg_random; end; {glitch}
    12: if (music_pos(68,60)) then begin inc(event); color_mode:=15; {47,15,60} end;

    13: if q>900 then              go_event(13, 'jump2',0); {y rotate jump}
    14: if q>905 then              go_event(14, 'boost',0); {boost vectors}
    15: if q>915 then begin go_event(15, 'glitch1',0); seg_glitch:=seg_random; end; {glitch}
    16: if q>935 then begin inc(event); color_mode:=60; {47,15,60} end;

    17: if (music_pos(70,54)) then go_event(17, 'jump2',0); {y rotate jump}

    18: if (music_pos(69,61)) then begin go_event(18, 'glitch1',0); seg_glitch:=seg_random; end; {glitch}

    19:  if music_pos(71,0)  then begin
                  per:=100*g_scale;
                  draw_cube_on:=0;
                  safe_draw_dots:=1;
                  scale.x:=g_scale*3;
                  scale.y:=g_scale*2;
                  scale.z:=g_scale*1.5;
                  gravy:=2; boost_vectors_invert_y; inc(event) end;
    end;

    if (jump_on[7]>0)  then glitch_jump:=jump1(jump_on[7], 15, 10);
    if (jump_on[8]>0)  then glitch_jump:=jump1(jump_on[8], 15, 10);
    if (jump_on[9]>0)  then glitch_jump:=jump1(jump_on[9], 15, 5);


     if (kryshka_down>1) then begin
           jump:=word(var2value_plus(jump, 2500, 10*elapsed_time));
           cube_jump.y:=cube_jump.y+elapsed_time;
           cube_coord.y:=(sin_(cube_jump.y/7)*jump);
           end;



     if rotate3d_on<1 then begin cube_angle.x:=0; end
      else begin

            if (jump_on[1]>0) then add_cube_rotate.x:=jump1(jump_on[1], 0.14, 25);{}
            if (jump_on[2]>0) then add_cube_rotate.y:=jump1(jump_on[2], 0.14, 25);{}
            if (jump_on[3]>0) then cube_center.z:=jump1(jump_on[3], 0.8, 25);{}
            if (jump_on[4]>0) then cube_center.x:=-jump1(jump_on[4], 1, 15);{}
            if (jump_on[5]>0) then cube_coord.x:=jump1(jump_on[5], 6000, 16);{}
            if (jump_on[6]>0) then add_cube_rotate.y:=jump1(jump_on[6], 0.1, 35);{}


            rotate.x:=rotate.x+elapsed_time;

            cube_angle.x:=cube_angle.x+elapsed_time/300+(add_cube_rotate.x*elapsed_time);

            cube_angle.y:=cube_angle.y+elapsed_time/50+(add_cube_rotate.y*elapsed_time);


            if (rotate.x>400) then kryshka_down:=3;

            if (draw_cube_on=1) and (per>5*g_scale) then
               begin
                 per:=per - elapsed_time*3000;
                 if per<5*g_scale then per:=5*g_scale;
                 if per=5*g_scale then safe_draw_dots:=0;
               end;
      end;

      if kryshka_down<2 then cube_angle.z:=0
         else begin
            rotate.z:=rotate.z+elapsed_time;
            cube_angle.z:=rad(sin_(rotate.z/130+pi/2)*360);
            if (rotate.z>180) and (rotate3d_on=0) then rotate3d_on:=1;
            end;

      if draw_cube_on=0 then begin
              cube_angle.x:=0; cube_angle.y:=0; cube_angle.z:=0;
              cube_coord.x:=0; cube_coord.y:=1000; cube_coord.z:=0;
              cube_center.x:=0; cube_center.y:=0; cube_center.z:=0;
              kryshka2:=1;
            end;


      cube_rotate(cube1, cube2,  0, 0, 0,
                                 0, 0,  cube_angle.z);

      cube_rotate(cube2, cube2,  0, 0, 0,
                                 0,  cube_angle.y, 0);

      cube_rotate(cube2, cube2,  cube_center.x, cube_center.y, cube_center.z,
                                 cube_angle.x,  0, 0);

      cube_scale(cube2, cubeDc,   cube_coord.x,cube_coord.y,0,  scale);

      active_dots:=word(var2value_plus(active_dots, count_dots, 20*elapsed_time));

      if active_dots=count_dots
      then if kryshka_down=0 then kryshka_down:=1;


      if kryshka_down=1 then begin
           if kryshka<-1*g_scale then kryshka:=kryshka+elapsed_time*400;
           if kryshka>-1*g_scale then begin kryshka_down:=2; damping:=0.98; end;
      end;

      if kryshka_down<2 then begin {верхняя грань, которую опускаем после засыпки}
           cubeDc[0*3+1]:=kryshka; cubeDc[1*3+1]:=kryshka;
           cubeDc[4*3+1]:=kryshka; cubeDc[5*3+1]:=kryshka;
      end;

      if (kryshka_down>2) then begin  {сужение верхней грани для превращение в пирамидку}
           cube1[0*3]:=-kryshka2; cube1[1*3]:=-kryshka2;
           cube1[4*3]:=kryshka2;  cube1[5*3]:=kryshka2;
           cube1[0*3+2]:=-kryshka2; cube1[1*3+2]:=kryshka2;
           cube1[4*3+2]:=-kryshka2; cube1[5*3+2]:=kryshka2;

           if (draw_cube_on=1) and (kryshka2>0.01) then kryshka2:=kryshka2-elapsed_time/200;
           if kryshka2<0.01 then begin kryshka2:=0.01; end;
      end;


      {===============================================}


      if elapsed_time=1 then      Dots_process_e8(active_dots,  gravy)
      else if elapsed_time=2 then Dots_process_e16(active_dots, gravy*2)
      else if elapsed_time=3 then Dots_process_e24(active_dots, gravy*3)
      else
           Dots_process(active_dots, gravy*elapsed_time, elapsed_time*8);


      Collision_detect(0, 5);

      {=============================================}

end; {-----------------------------------------------------------------}


if (rotate3d_on=1) and (draw_cube_on=1) then cube_draw(1, 160,100, 51, 130, vaddr);{нелицевые ребра}


if safe_draw_dots=0 then dots_draw(0, active_dots, 160,100, 50, color_mode, vaddr)
                    else dots_draw_clip(active_dots, 160,100, 50, color_mode, vaddr);


if (kryshka_down>=2) and (draw_cube_on=1) then cube_draw(-1, 160,100, 51, 131, vaddr);{лицевые ребра}

if (kryshka_down<2) then begin
     DrawLine(107,47, 212,47, 131, vaddr);
     DrawLine(212,47, 212,152, 131, vaddr);
     DrawLine(212,152, 107, 152, 131, vaddr);
     DrawLine(107,152, 107, 47, 131, vaddr);
end;


if Vsync_mode=1 then Midas_WaitVR;

if glitch_jump>0 then FlipScreen2(mtimer, round(glitch_jump), seg_glitch, vaddr,vga)
else FlipScreen(vaddr, vga);{}

Inc(Aantal);
if FPS_Mode=1 then WriteFps(255, mtimer, T1, Aantal, vga);


until (esc_test) or (music_pos(72,0));

{Wait_music_pos(72, 0); if ESC_PRESSED=1 then exit;}


end;

end.