Friday, October 22, 2010

Matrices, for what?

Another very important type in the system is TMatrix, any entity (2d or 3d) that needs to be rotated, scaled, moved, etc in the system uses this type.

Main methods are:

  • Matrix
    • Prepares the matrix for a given vector
  • Identity
  • Add
    • Sum two matrices
  • Multiply
    • Multiply two matrices
  • Subtract
    • Subtracts two matrices
Implementation


unit BB.Math.Matrix;

interface

uses
  BB.Types;

type
  T4x4 = array[0..2, 0..3] of TFloat;

  PMatrix = ^TMatrix;
  TMatrix = record
  public
    _4x4: T4x4;

    constructor Create(aX, aY, aZ: TFloat); overload;
    //constructor Create(const aVector: TVector); overload;
    class operator Multiply(const aMatrixA, aMatrixB: TMatrix): TMatrix; inline;
    class operator Add(const aMatrixA, aMatrixB: TMatrix): TMatrix; inline;
    class operator Subtract(const aMatrixA, aMatrixB: TMatrix): TMatrix; inline;

    procedure Matrix(aX, aY, aZ: TFloat);
    procedure Identity;
    procedure Clear;
    procedure Transpose(const aMatrix: TMatrix);
  end;

implementation

uses
  BB.Math;

{ TMatrix }

class operator TMatrix.Add(const aMatrixA, aMatrixB: TMatrix): TMatrix;
var
  i, j: integer;

begin
  for j := High(T4x4) DownTo Low(T4x4) do
    for i := High(T4x4) DownTo Low(T4x4) do
      Result._4x4[j, i] := aMatrixA._4x4[i, j] + aMatrixB._4x4[i, j];
end;

constructor TMatrix.Create(aX, aY, aZ: TFloat);
begin
  Matrix(aX, aY, aZ);
end;

procedure TMatrix.Identity;
var
  i, j: integer;

begin
  j := High(T4x4);
  while j >= Low(T4x4) do
  begin
    i := High(T4x4);
    while i >= Low(T4x4) do
    begin
      _4x4[j, i] := Ord(i = j);
      Dec(i);
    end;

    Dec(j);
  end;
end;

procedure TMatrix.Matrix(aX, aY, aZ: TFloat);
var
  xSin, xCos, ySin, yCos, zSin, zCos, sxsz, sxcz, szcx, cxcz: TFloat;

begin
  SinCos(aX * RAD, xSin, xCos);
  SinCos(aY * RAD, ySin, yCos);
  SinCos(aZ * RAD, zSin, zCos);

  sxsz := xSin * zSin;
  sxcz := xSin * zCos;
  szcx := zSin * xCos;
  cxcz := xCos * zCos;

  _4x4[0, 0] := yCos * zCos;
  _4x4[1, 0] := yCos * zSin;
  _4x4[2, 0] := -ySin;

  _4x4[0, 1] := ySin * sxcz - szcx;
  _4x4[1, 1] := ySin * sxsz + cxcz;
  _4x4[2, 1] := xSin * yCos;

  _4x4[0, 2] := ySin * cxcz + sxsz;
  _4x4[1, 2] := ySin * szcx - sxcz;
  _4x4[2, 2] := xCos * yCos;
end;

class operator TMatrix.Multiply(const aMatrixA, aMatrixB: TMatrix): TMatrix;
var
  i, j: integer;

begin
  j := High(T4x4);
  while j >= Low(T4x4) do
  begin
    i := High(T4x4);
    while i >= Low(T4x4) do
    begin
      Result._4x4[i, j] :=  (aMatrixA._4x4[i, 0] * aMatrixB._4x4[0, j]) +
                            (aMatrixA._4x4[i, 1] * aMatrixB._4x4[1, j]) +
                            (aMatrixA._4x4[i, 2] * aMatrixB._4x4[2, j])
                             { + (m1[i, 3] * m2[3, j])};
      Dec(i);
    end;

    Dec(j);
  end;
end;

procedure TMatrix.Clear;
begin
  FillChar(_4x4, SizeOf(_4x4), 0);
end;

class operator TMatrix.Subtract(const aMatrixA, aMatrixB: TMatrix): TMatrix;
var
  i, j: integer;

begin
  for j := High(T4x4) DownTo Low(T4x4) do
    for i := High(T4x4) DownTo Low(T4x4) do
      Result._4x4[j, i] := aMatrixA._4x4[i, j] - aMatrixB._4x4[i, j];
end;

procedure TMatrix.Transpose(const aMatrix: TMatrix);
var
  i, j: integer;

 begin
  for j := High(T4x4) downto Low(T4x4) do
    for i := High(T4x4) downto Low(T4x4) do
      _4x4[j, i] := aMatrix._4x4[i, j];
end;

end.
The way that a sprite (surface) ir rotated is via vectors and matrices:
var
  matrix: TMatrix;
  vector: TVector;
  w, h,
  x, y: integer;
poly: TPolygon;

begin
  matrix := TMatrix.Create(0, 0, -aAngle);
  w := GetWidth(Zoom) div 2;
  h := GetHeight(Zoom) div 2;
  x := FX;
  y := FY;

  //1
  //xxx
  //3xxx2
  vector.Rotate(TVector.Create(-w, -h, 0), matrix);
poly[0] := TVector.Create(x + vector.X, y + vector.Y, FZ);
vector.Rotate(TVector.Create(w, h, 0), matrix);
poly[1] := TVector.Create(x + vector.X, y + vector.Y, FZ);
vector.Rotate(TVector.Create(-w, h, 0), matrix);
poly[2] := TVector.Create(x + vector.X, y + vector.Y, FZ);
DrawPoly(poly);
  //1xxx2
  //  xxx
  //    3
  vector.Rotate(TVector.Create(-w, -h, 0), matrix);
poly[0] := TVector.Create(x + vector.X, y + vector.Y, FZ);
vector.Rotate(TVector.Create(w, -h, 0), matrix);
poly[1] := TVector.Create(x + vector.X, y + vector.Y, FZ);
vector.Rotate(TVector.Create(w, h, 0), matrix);
poly[2] := TVector.Create(x + vector.X, y + vector.Y, FZ);
DrawPoly(poly);
//In this case what is filled is a polygon, //so with the rotation of the two triangles we get a rectangle, //after apply a texture on that rectangle we get our sprite zoomed and/or 
  //rotated
end;

No comments:

Post a Comment