Unit Vectors;

Interface

Type
  Vector = Object
    X: LongInt;
    Y: LongInt;
    Z: LongInt;
    Procedure Load(_X,_Y,_Z: LongInt);
    Procedure Add(Const V: Vector);
    Procedure Subtract(Const V: Vector);
    Procedure Cross(Const V: Vector);
    Procedure Normalize;
    Procedure Multiply(Const C: Real);
    Procedure Divide(Const C: Real);
    Procedure Copy(Const V: Vector);
    Function  VecLength: Real;
    Function  LongVecLength: LongInt;
  End;

Function _PFixedMul(X,Y: LongInt): LongInt;
Function _PFixedDiv(Dividend,Divisor: LongInt): LongInt;
Function RToF(R: Real): LongInt;
Function FToR(L: LongInt): Real;

Implementation

{Uses CPU;}

Const _32BIT = $66;

Var _CPUType : Word;

{$F+}
Function _PFixedMul(X,Y: LongInt): LongInt; External;
Function _PFixedDiv(Dividend,Divisor: LongInt): LongInt; External;
{$L FIXED.OBJ}

Function CPUValue: Word; External;
{$L CPURDMSR.OBJ}

Procedure Vector.Load(_X,_Y,_Z: LongInt);
Begin
{
  X := _X;
  Y := _Y;
  Z := _Z;
}
  Asm
    LES   DI,DWORD PTR Self
    DB    _32BIT
    MOV   AX,WORD PTR _X
    DB    _32BIT
    MOV   WORD PTR [ES:DI],AX

    DB    _32BIT
    MOV   AX,WORD PTR _Y
    DB    _32BIT
    MOV   WORD PTR [ES:DI+4],AX

    DB    _32BIT
    MOV   AX,WORD PTR _Z
    DB    _32BIT
    MOV   WORD PTR [ES:DI+8],AX
  End; { Asm }
End; { Vector.Load }


Procedure Vector.Add(Const V: Vector);
Begin
{
  Inc(X,V.X);
  Inc(Y,V.Y);
  Inc(Z,V.Z);
}
  Asm
    MOV   DX,DS
    LES   DI,DWORD PTR Self
    LDS   SI,DWORD PTR V
    DB    _32BIT
    MOV   AX,WORD PTR [SI]
    DB    _32BIT
    ADD   WORD PTR [ES:DI],AX

    DB    _32BIT
    MOV   AX,WORD PTR [SI+4]
    DB    _32BIT
    ADD   WORD PTR [ES:DI+4],AX

    DB    _32BIT
    MOV   AX,WORD PTR [SI+8]
    DB    _32BIT
    ADD   WORD PTR [ES:DI+8],AX
    MOV   DS,DX
  End; { Asm }
End; { Vector.Add }


Procedure Vector.Subtract(Const V: Vector);
Begin
{
  Dec(X,V.X);
  Dec(Y,V.Y);
  Dec(Z,V.Z);
}
  Asm
    MOV   DX,DS
    LES   DI,DWORD PTR Self
    LDS   SI,DWORD PTR V
    DB    _32BIT
    MOV   AX,WORD PTR [SI]
    DB    _32BIT
    SUB   WORD PTR [ES:DI],AX

    DB    _32BIT
    MOV   AX,WORD PTR [SI+4]
    DB    _32BIT
    SUB   WORD PTR [ES:DI+4],AX

    DB    _32BIT
    MOV   AX,WORD PTR [SI+8]
    DB    _32BIT
    SUB   WORD PTR [ES:DI+8],AX
    MOV   DS,DX
  End; { Asm }
End; { Vector.Subtract }


Procedure Vector.Cross(Const V: Vector);
Var C: Vector;
Begin
{
  C.X := _PFixedMul(Y,V.Z) - _PFixedMul(Z,V.Y);
  C.Y := _PFixedMul(Z,V.X) - _PFixedMul(X,V.Z);
  C.Z := _PFixedMul(X,V.Y) - _PFixedMul(Y,V.X);
  X   := C.X;
  Y   := C.Y;
  Z   := C.Z;
}
  Asm
    MOV   BX,DS                    { MOV   BX,DS                   }
    LES   DI,DWORD PTR Self        { LES   DI,DWORD PTR Self       }
    LDS   SI,DWORD PTR V           { LDS   SI,DWORD PTR V          }

    { ------------------------------------------------------------ }

    DB    _32BIT                   { MOV   EAX,DWORD PTR [ES:DI+4] }
    MOV   AX,WORD PTR [ES:DI+4]
    DB    _32BIT                   { IMUL  DWORD PTR [SI+8]        }
    IMUL  WORD PTR [SI+8]
    DB    66h,0Fh,0ACh,0D0h,16     { SHRD  EAX,EDX,16              }
    DB    _32BIT                   { MOV   ECX,EAX                 }
    MOV   CX,AX

    DB    _32BIT                   { MOV   EAX,DWORD PTR [ES:DI+8] }
    MOV   AX,WORD PTR [ES:DI+8]
    DB    _32BIT                   { IMUL  DWORD PTR [SI+4]        }
    IMUL  WORD PTR [SI+4]
    DB    66h,0Fh,0ACh,0D0h,16     { SHRD  EAX,EDX,16              }
    DB    _32BIT                   { SUB   ECX,EAX                 }
    SUB   CX,AX
    DB    _32BIT                   { MOV   DWORD PTR C.X,ECX       }
    MOV   WORD PTR C.X,CX

    { ------------------------------------------------------------ }

    DB    _32BIT                   { MOV   EAX,DWORD PTR [ES:DI+8] }
    MOV   AX,WORD PTR [ES:DI+8]
    DB    _32BIT                   { IMUL  DWORD PTR [SI]          }
    IMUL  WORD PTR [SI]
    DB    66h,0Fh,0ACh,0D0h,16     { SHRD  EAX,EDX,16              }
    DB    _32BIT                   { MOV   ECX,EAX                 }
    MOV   CX,AX

    DB    _32BIT                   { MOV   EAX,DWORD PTR [ES:DI]   }
    MOV   AX,WORD PTR [ES:DI]
    DB    _32BIT                   { IMUL  DWORD PTR [SI+8]        }
    IMUL  WORD PTR [SI+8]
    DB    66h,0Fh,0ACh,0D0h,16     { SHRD  EAX,EDX,16              }
    DB    _32BIT                   { SUB   ECX,EAX                 }
    SUB   CX,AX
    DB    _32BIT                   { MOV   DWORD PTR C.Y,ECX       }
    MOV   WORD PTR C.Y,CX

    { ------------------------------------------------------------ }

    DB    _32BIT                   { MOV   EAX,DWORD PTR [ES:DI]   }
    MOV   AX,WORD PTR [ES:DI]
    DB    _32BIT                   { IMUL  DWORD PTR [SI+4]        }
    IMUL  WORD PTR [SI+4]
    DB    66h,0Fh,0ACh,0D0h,16     { SHRD  EAX,EDX,16              }
    DB    _32BIT                   { MOV   ECX,EAX                 }
    MOV   CX,AX

    DB    _32BIT                   { MOV   EAX,DWORD PTR [ES:DI+4] }
    MOV   AX,WORD PTR [ES:DI+4]
    DB    _32BIT                   { IMUL  DWORD PTR [SI]          }
    IMUL  WORD PTR [SI]
    DB    66h,0Fh,0ACh,0D0h,16     { SHRD  EAX,EDX,16              }
    DB    _32BIT                   { SUB   ECX,EAX                 }
    SUB   CX,AX
    DB    _32BIT                   { MOV   DWORD PTR C.Z,ECX       }
    MOV   WORD PTR C.Z,CX

    { ------------------------------------------------------------ }

    DB    _32BIT                   { MOV   EAX,DWORD PTR C.X       }
    MOV   AX,WORD PTR C.X
    DB    _32BIT                   { MOV   DWORD PTR [ES:DI],EAX   }
    MOV   WORD PTR [ES:DI],AX
    DB    _32BIT                   { MOV   EAX,DWORD PTR C.Y       }
    MOV   AX,WORD PTR C.Y
    DB    _32BIT                   { MOV   DWORD PTR [ES:DI+4],EAX }
    MOV   WORD PTR [ES:DI+4],AX
    DB    _32BIT                   { MOV   EAX,DWORD PTR C.Z       }
    MOV   AX,WORD PTR C.Z
    DB    _32BIT                   { MOV   DWORD PTR [ES:DI+8],EAX }
    MOV   WORD PTR [ES:DI+8],AX

    MOV   DS,BX                    { MOV   DS,BX                   }
  End; { Asm }
End; { Vector.Cross }


Procedure Vector.Normalize;
Var Length : LongInt;
Begin
  Length := RToF(Sqrt(FToR(_PFixedMul(X,X) + _PFixedMul(Y,Y) + _PFixedMul(Z,Z))));
  X := _PFixedDiv(X,Length);
  Y := _PFixedDiv(Y,Length);
  Z := _PFixedDiv(Z,Length);
End; { Vector.Normalize }


Function Vector.VecLength: Real;
Begin
  VecLength := RToF(Sqrt(FToR(_PFixedMul(X,X) + _PFixedMul(Y,Y) + _PFixedMul(Z,Z))));
End; { Vector.VecLength }


Function Vector.LongVecLength: LongInt;
Begin
{
  LongVecLength := _PFixedMul(X,X) + _PFixedMul(Y,Y) + _PFixedMul(Z,Z);
}
  Asm
    LES   DI,DWORD PTR Self        { LES   DI,DWORD PTR Self       }

    { ------------------------------------------------------------ }

    DB    _32BIT                   { MOV   EAX,DWORD PTR [ES:DI]   }
    MOV   AX,WORD PTR [ES:DI]
    DB    _32BIT                   { IMUL  EAX                     }
    IMUL  AX
    DB    _32BIT                   { MOV   ECX,EAX                 }
    MOV   CX,AX
    DB    _32BIT                   { MOV   EBX,EDX                 }
    MOV   BX,DX

    DB    _32BIT                   { MOV   EAX,DWORD PTR [ES:DI+4] }
    MOV   AX,WORD PTR [ES:DI+4]
    DB    _32BIT                   { IMUL  EAX                     }
    IMUL  AX
    DB    _32BIT                   { ADD   ECX,EAX                 }
    ADD   CX,AX
    DB    _32BIT                   { ADC   EBX,EDX                 }
    ADC   BX,DX

    DB    _32BIT                   { MOV   EAX,DWORD PTR [ES:DI+8] }
    MOV   AX,WORD PTR [ES:DI+8]
    DB    _32BIT                   { IMUL  EAX                     }
    IMUL  AX
    DB    _32BIT                   { ADD   EAX,ECX                 }
    ADD   AX,CX
    DB    _32BIT                   { ADC   EDX,EBX                 }
    ADC   DX,BX

    DB    66h,0Fh,0ACh,0D0h,16     { SHRD  EAX,EDX,16              }
    DB    _32BIT                   { MOV   DWORD PTR @Result,EAX   }
    MOV   WORD PTR @Result,AX
  End; { Asm }
End; { Vector.LongVecLength }


Procedure Vector.Multiply(Const C: Real);
Var L: LongInt;
Begin
  L := RToF(C);
  X := _PFixedMul(X,L);
  Y := _PFixedMul(Y,L);
  Z := _PFixedMul(Z,L);
End; { Vector.Multiply }


Procedure Vector.Divide(Const C: Real);
Var L: LongInt;
Begin
  L := RToF(C);
  X := _PFixedDiv(X,L);
  Y := _PFixedDiv(Y,L);
  Z := _PFixedDiv(Z,L);
End; { Vector.Divide }


Procedure Vector.Copy(Const V: Vector);
Begin
  Self := V;
End; { Vector.Copy }


Function RToF(R: Real): LongInt;
Begin
  If _CPUType < 2 Then RToF := Round(R * 65536)
  Else
  Asm
    DB    _32BIT                    { XOR   EAX,EAX                  }
    XOR   AX,AX
    MOV   BX,WORD PTR R             { MOV   BX,WORD PTR R            }
    OR    BX,WORD PTR R[2]          { OR    BX,WORD PTR R[2]         }
    OR    BX,WORD PTR R[4]          { OR    BX,WORD PTR R[4]         }
    JZ    @L2                       { JZ    @L2                      }
    SUB   BX,BX                     { SUB   BX,BX                    }
    DB    _32BIT                    { MOV   EAX,DWORD PTR R[2]       }
    MOV   AX,WORD PTR R[2]
    DB    _32BIT                    { SHL   EAX,1                    }
    SHL   AX,1
    RCR   BH,1                      { RCR   BH,1                     }
    STC                             { STC                            }
    DB    _32BIT                    { RCR   EAX,1                    }
    RCR   AX,1
    MOV   BL,BYTE PTR R             { MOV   BL,BYTE PTR R            }
    SUB   BL,129 - 16               { SUB   BL,129 - 16              }
    CMP   BL,30                     { CMP   BL,30                    }
    JBE   @L1                       { JB    @L1                      }

    { Overflow -- make the result as high as it can be }

    DB    _32BIT                    { XOR   EAX,EAX                  }
    XOR   AX,AX
    DB    _32BIT                    { NOT   EAX                      }
    NOT   AX
    DB    _32BIT                    { SHR   EAX,1                    }
    SHR   AX,1
    JMP   @L3                       { JMP   @L3                      }
@L1:                                { @L1:                           }
    MOV   CL,31                     { MOV   CL,31                    }
    SUB   CL,BL                     { SUB   CL,BL                    }
    DB    _32BIT                    { SHR   EAX,CL                   }
    SHR   AX,CL
@L3:
    TEST  BH,80h                    { TEST  BH,80h                   }
    JZ    @L2                       { JZ    @L2                      }
    DB    _32BIT                    { NEG   EAX                      }
    NEG   AX
@L2:                                { @L2:                           }
    DB    _32BIT                    { MOV   DWORD PTR @Result,EAX    }
    MOV   WORD PTR @Result,AX
  End; { Asm }
End; { RToF }


Function FToR(L: LongInt): Real;
Begin
  If _CPUType < 2 Then FToR := L / 65536
  Else
  Asm
    SUB   BX,BX                     { SUB   BX,BX                    }
    DB    _32BIT                    { MOV   EAX,DWORD PTR L          }
    MOV   AX,WORD PTR L
    DB    _32BIT                    { OR    EAX,EAX                  }
    OR    AX,AX
    JZ    @L3                       { JZ    @L3                      }
    MOV   BX,14                     { MOV   BX,14                    }
    DB    _32BIT                    { AND   EAX,EAX                  }
    AND   AX,AX
    JNS   @L1                       { JNS   @L1                      }
    DB    _32BIT                    { NEG   EAX                      }
    NEG   AX
    OR    BH,80h                    { OR    BH,80h                   }
@L1:                                { @L1:                           }
    DB    _32BIT                    { SHL   EAX,1                    }
    SHL   AX,1
@L2:                                { @L2:                           }
    DEC   BL                        { DEC   BL                       }
    DB    _32BIT                    { ROL   EAX,1                    }
    ROL   AX,1
    JNC   @L2                       { JNC   @L2                      }
    DB    _32BIT                    { SHR   EAX,1                    }
    SHR   AX,1
    INC   BL                        { INC   BL                       }
    ADD   BL,129                    { ADD   BL,129                   }
@L3:                                { @L3                            }
    MOV   BYTE PTR @Result,BL       { MOV   BYTE PTR @Result,BL      }
    DB    _32BIT                    { MOV   DWORD PTR @Result[2],EAX }
    MOV   WORD PTR @Result[2],AX
    MOV   BYTE PTR @Result[1],0     { MOV   BYTE PTR @Result[1],0    }
    OR    BYTE PTR @Result[5],BH    { OR    BYTE PTR @Result[5],BH   }
  End; { Asm }
End; { FToR }

Begin
  _CPUType := CPUValue And $FF;
  If _CPUType > 0 Then Dec(_CPUType);
End.
