Moved the creation of random flames from mainform and into a seperate unit

This commit is contained in:
ronaldhordijk 2005-03-27 13:28:52 +00:00
parent 73b68d554e
commit 7984e9851a
8 changed files with 282 additions and 234 deletions

View File

@ -988,7 +988,7 @@ begin
if ((maxx - minx) > 1000) or
((maxy - miny) > 1000) then
raise Exception.Create('Flame area to large');
raise EMathError.Create('Flame area to large');
center[0] := (minx + maxx) / 2;
center[1] := (miny + maxy) / 2;
@ -1084,7 +1084,7 @@ begin
if ((maxx - minx) > 1000) or
((maxy - miny) > 1000) then
raise Exception.Create('Flame area to large');
raise EMathError.Create('Flame area to large');
cp.center[0] := (minx + maxx) / 2;
cp.center[1] := (miny + maxy) / 2;
@ -1536,6 +1536,7 @@ begin
end;
end;
///////////////////////////////////////////////////////////////////////////////
function TControlPoint.HasNewVariants: boolean;
var
i: integer;

View File

@ -15,12 +15,14 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
}
{$D-,L-,O+,Q-,R-,Y-,S-}
unit Global;
interface
uses SysUtils, Classes, SyncObjs, Controls, Graphics, Math, MyTypes, controlpoint;
uses
SysUtils, Classes, SyncObjs, Controls, Graphics, Math,
cmap, MyTypes, controlpoint;
type
EFormatInvalid = class(Exception);
@ -52,6 +54,7 @@ const
FT_BMP = 1; FT_PNG = 2; FT_JPG = 3;
var
MainSeed: integer;
MainTriangles: TTriangles;
ConfirmDelete: boolean; // Flag confirmation of entry deletion
// FlameTitle: string;
@ -123,6 +126,9 @@ var
ShowProgress: Boolean;
defLibrary: string;
LimitVibrancy: Boolean;
DefaultPalette: TColorMap;
implementation
uses dialogs, Main;

View File

@ -125,7 +125,9 @@ procedure HSVToRGB(H, S, V: real; var Rb, Gb, Bb: integer);
implementation
uses Main, cmapdata, Math, Browser, Editor, Global, Save, Adjust, Mutate, ClipBrd;
uses
RndFlame, Main, cmapdata, Math, Browser, Editor, Global,
Save, Adjust, Mutate, ClipBrd, GradientHlpr;
{$R *.DFM}
@ -754,81 +756,13 @@ end;
procedure TGradientForm.mnuSaveasDefaultClick(Sender: TObject);
begin
MainForm.DefaultPalette := Palette;
DefaultPalette := Palette;
SaveMap(AppPath + 'default.map');
end;
procedure RGBBlend(a, b: integer; var Palette: TColorMap);
{ Linear blend between to indices of a palette }
var
c, v: real;
vrange, range: real;
i: integer;
begin
if a = b then
begin
Exit;
end;
range := b - a;
vrange := Palette[b mod 256][0] - Palette[a mod 256][0];
c := Palette[a mod 256][0];
v := vrange / range;
for i := (a + 1) to (b - 1) do
begin
c := c + v;
Palette[i mod 256][0] := Round(c);
end;
vrange := Palette[b mod 256][1] - Palette[a mod 256][1];
c := Palette[a mod 256][1];
v := vrange / range;
for i := a + 1 to b - 1 do
begin
c := c + v;
Palette[i mod 256][1] := Round(c);
end;
vrange := Palette[b mod 256][2] - Palette[a mod 256][2];
c := Palette[a mod 256][2];
v := vrange / range;
for i := a + 1 to b - 1 do
begin
c := c + v;
Palette[i mod 256][2] := Round(c);
end;
end;
function TGradientForm.RandomGradient: TColorMap;
var
a, b, n, nodes: integer;
rgb: array[0..2] of double;
hsv: array[0..2] of double;
pal: TColorMap;
begin
inc(MainForm.Seed);
RandSeed := MainForm.seed;
nodes := random((MaxNodes - 1) - (MinNodes - 2)) + (MinNodes - 1);
n := 256 div nodes;
b := 0;
hsv[0] := (random(MaxHue - (MinHue - 1)) + MinHue) / 100;
hsv[1] := (random(MaxSat - (MinSat - 1)) + MinSat) / 100;
hsv[2] := (random(MaxLum - (MinLum - 1)) + MinLum) / 100;
hsv2rgb(hsv, rgb);
Pal[0][0] := Round(rgb[0] * 255);
Pal[0][1] := Round(rgb[1] * 255);
Pal[0][2] := Round(rgb[2] * 255);
repeat
a := b;
b := b + n;
hsv[0] := (random(MaxHue - (MinHue - 1)) + MinHue) / 100;
hsv[1] := (random(MaxSat - (MinSat - 1)) + MinSat) / 100;
hsv[2] := (random(MaxLum - (MinLum - 1)) + MinLum) / 100;
hsv2rgb(hsv, rgb);
if b > 255 then b := 255;
Pal[b][0] := Round(rgb[0] * 255);
Pal[b][1] := Round(rgb[1] * 255);
Pal[b][2] := Round(rgb[2] * 255);
RGBBlend(a, b, pal);
until b = 255;
Result := Pal;
Result := GradientHelper.RandomGradient;
end;
procedure TGradientForm.mnuRandomizeClick(Sender: TObject);

View File

@ -3,7 +3,7 @@ unit GradientHlpr;
interface
uses
windows, Graphics;
windows, Graphics, Cmap;
const
PixelCountMax = 32768;
@ -15,8 +15,10 @@ type
type
TGradientHelper = class
private
procedure RGBBlend(a, b: integer; var Palette: TColorMap);
public
function GetGradientBitmap(Index: integer; const hue_rotation: double): TBitmap;
function RandomGradient: TColorMap;
end;
var
@ -25,7 +27,7 @@ var
implementation
uses
Cmap;
Global;
{ TGradientHelper }
@ -55,6 +57,82 @@ begin
Result := BitMap;
end;
///////////////////////////////////////////////////////////////////////////////
function TGradientHelper.RandomGradient: TColorMap;
var
a, b, n, nodes: integer;
rgb: array[0..2] of double;
hsv: array[0..2] of double;
pal: TColorMap;
begin
inc(MainSeed);
RandSeed := Mainseed;
nodes := random((MaxNodes - 1) - (MinNodes - 2)) + (MinNodes - 1);
n := 256 div nodes;
b := 0;
hsv[0] := (random(MaxHue - (MinHue - 1)) + MinHue) / 100;
hsv[1] := (random(MaxSat - (MinSat - 1)) + MinSat) / 100;
hsv[2] := (random(MaxLum - (MinLum - 1)) + MinLum) / 100;
hsv2rgb(hsv, rgb);
Pal[0][0] := Round(rgb[0] * 255);
Pal[0][1] := Round(rgb[1] * 255);
Pal[0][2] := Round(rgb[2] * 255);
repeat
a := b;
b := b + n;
hsv[0] := (random(MaxHue - (MinHue - 1)) + MinHue) / 100;
hsv[1] := (random(MaxSat - (MinSat - 1)) + MinSat) / 100;
hsv[2] := (random(MaxLum - (MinLum - 1)) + MinLum) / 100;
hsv2rgb(hsv, rgb);
if b > 255 then b := 255;
Pal[b][0] := Round(rgb[0] * 255);
Pal[b][1] := Round(rgb[1] * 255);
Pal[b][2] := Round(rgb[2] * 255);
RGBBlend(a, b, pal);
until b = 255;
Result := Pal;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TGradientHelper.RGBBlend(a, b: integer; var Palette: TColorMap);
{ Linear blend between to indices of a palette }
var
c, v: real;
vrange, range: real;
i: integer;
begin
if a = b then
begin
Exit;
end;
range := b - a;
vrange := Palette[b mod 256][0] - Palette[a mod 256][0];
c := Palette[a mod 256][0];
v := vrange / range;
for i := (a + 1) to (b - 1) do
begin
c := c + v;
Palette[i mod 256][0] := Round(c);
end;
vrange := Palette[b mod 256][1] - Palette[a mod 256][1];
c := Palette[a mod 256][1];
v := vrange / range;
for i := a + 1 to b - 1 do
begin
c := c + v;
Palette[i mod 256][1] := Round(c);
end;
vrange := Palette[b mod 256][2] - Palette[a mod 256][2];
c := Palette[a mod 256][2];
v := vrange / range;
for i := a + 1 to b - 1 do
begin
c := c + v;
Palette[i mod 256][2] := Round(c);
end;
end;
///////////////////////////////////////////////////////////////////////////////
initialization
GradientHelper := TGradientHelper.create;
finalization

View File

@ -27,7 +27,7 @@ object MainForm: TMainForm
Left = 160
Top = 28
Width = 4
Height = 434
Height = 454
end
object ToolBar: TToolBar
Left = 0
@ -251,7 +251,7 @@ object MainForm: TMainForm
Left = 0
Top = 28
Width = 160
Height = 434
Height = 454
Align = alLeft
Columns = <
item
@ -270,7 +270,7 @@ object MainForm: TMainForm
Left = 164
Top = 28
Width = 402
Height = 434
Height = 454
Align = alClient
BevelInner = bvLowered
BevelOuter = bvNone
@ -293,7 +293,7 @@ object MainForm: TMainForm
end
object StatusBar: TStatusBar
Left = 0
Top = 462
Top = 482
Width = 566
Height = 19
Panels = <

View File

@ -353,7 +353,6 @@ type
procedure DrawZoomWindow(ARect: TRect);
procedure DrawRotatelines(Angle: double);
procedure FavoriteClick(Sender: TObject);
procedure HandleThreadCompletion(var Message: TMessage);
message WM_THREAD_COMPLETE;
@ -361,14 +360,12 @@ type
message WM_THREAD_TERMINATE;
public
{ Public declarations }
Seed: Integer;
UndoIndex, UndoMax: integer;
Center: array[0..1] of double;
MainZoom: double;
StartTime: TDateTime;
Remainder: TDateTime;
AnimPal: TColorMap;
DefaultPalette: TColorMap;
procedure LoadXMLFlame(filename, name: string);
procedure DisableFavorites;
procedure EnableFavorites;
@ -428,7 +425,7 @@ implementation
uses Editor, Options, Regstry, Gradient, Render,
FullScreen, FormRender, Mutate, Adjust, Browser, Save, About, CmapData,
HtmlHlp, ScriptForm, FormFavorites, Size, FormExport, msMultiPartFormData,
Sheep, ImageColoring;
Sheep, ImageColoring, RndFlame;
{$R *.DFM}
@ -663,8 +660,8 @@ procedure RandomVariation(cp: TControlPoint);
var
a, b, i, j: integer;
begin
inc(MainForm.seed);
RandSeed := MainForm.seed;
inc(MainSeed);
RandSeed := MainSeed;
for i := 0 to NumXForms(cp) - 1 do
begin
for j := 0 to NVARS - 1 do
@ -713,6 +710,9 @@ var
r, s, theta, phi: double;
skip: boolean;
begin
cp1.Free;
cp1 := RandomFlame(MainCP, alg);
(*
Min := randMinTransforms;
Max := randMaxTransforms;
case randGradient of
@ -726,18 +726,18 @@ begin
2: cmap := MainCp.cmap;
3: cmap := GradientForm.RandomGradient;
end;
inc(Seed);
RandSeed := Seed;
inc(MainSeed);
RandSeed := MainSeed;
transforms := random(Max - (Min - 1)) + Min;
repeat
try
inc(Seed);
RandSeed := Seed;
inc(MainSeed);
RandSeed := MainSeed;
cp1.clear;
cp1.RandomCP(transforms, transforms, false);
cp1.SetVariation(Variation);
inc(Seed);
RandSeed := Seed;
inc(MainSeed);
RandSeed := MainSeed;
case alg of
1: rnd := 0;
@ -861,6 +861,7 @@ begin
cp1.zoom := 0;
cp1.Nick := SheepNick;
cp1.URl := SheepURL;
*)
end;
function TMainForm.GradientFromPalette(const pal: TColorMap; const title: string): string;
@ -1984,8 +1985,8 @@ var
b, RandFile: string;
begin
b := IntToStr(BatchSize);
inc(seed);
RandSeed := Seed;
inc(MainSeed);
RandSeed := MainSeed;
try
AssignFile(F, AppPath + 'apophysis.rand');
OpenFile := AppPath + 'apophysis.rand';
@ -1995,10 +1996,10 @@ begin
begin
inc(RandomIndex);
Statusbar.SimpleText := 'Generating ' + IntToStr(i + 1) + ' of ' + b;
RandSeed := Seed;
RandSeed := MainSeed;
if randGradient = 0 then cmap_index := random(NRCMAPS);
inc(Seed);
RandSeed := Seed;
inc(MainSeed);
RandSeed := MainSeed;
RandomizeCP(MainCp);
MainCp.CalcBoundbox;
@ -2181,8 +2182,8 @@ procedure TMainForm.mnuRWeightsClick(Sender: TObject);
begin
StopThread;
UpdateUndo;
inc(seed);
RandSeed := Seed;
inc(MainSeed);
RandSeed := MainSeed;
RandomWeights(MainCp);
RedrawTimer.Enabled := True;
UpdateWindows;
@ -2191,8 +2192,8 @@ end;
procedure TMainForm.mnuRandomBatchClick(Sender: TObject);
begin
ScriptEditor.Stopped := True;
inc(seed);
RandSeed := Seed;
inc(MainSeed);
RandSeed := MainSeed;
RandomBatch;
OpenFile := AppPath + 'apophysis.rand';
OpenFileType := ftXML;
@ -2305,7 +2306,7 @@ procedure TMainForm.mnuRandomClick(Sender: TObject);
begin
StopThread;
UpdateUndo;
inc(seed);
inc(MainSeed);
RandomizeCP(MainCp);
inc(RandomIndex);
MainCp.name := RandomPrefix + RandomDate + '-' +
@ -2495,7 +2496,7 @@ begin
GetScripts;
Compatibility := 1; // for Drave's compatibility
Randomize;
Seed := Random(1234567890);
MainSeed := Random(1234567890);
maincp := TControlPoint.Create;
ParseCp := TControlPoint.create;
OpenFileType := ftXML;
@ -2542,8 +2543,8 @@ begin
UndoIndex := 0;
UndoMax := 0;
ListView.RowSelect := True;
inc(seed);
RandSeed := Seed;
inc(MainSeed);
RandSeed := MainSeed;
Variation := vRandom;
Maincp.brightness := defBrightness;
maincp.gamma := defGamma;
@ -2551,8 +2552,8 @@ begin
maincp.sample_density := defSampleDensity;
maincp.spatial_oversample := defOversample;
maincp.spatial_filter_radius := defFilterRadius;
inc(seed);
RandSeed := Seed;
inc(MainSeed);
RandSeed := MainSeed;
if FileExists(AppPath + 'default.map') then
begin
DefaultPalette := GradientBrowser.LoadFractintMap(AppPath + 'default.map');
@ -2564,7 +2565,8 @@ begin
GetCMap(cmap_index, 1, maincp.cmap);
DefaultPalette := maincp.cmap;
end;
if FileExists(AppPath + 'apophysis.rand') then DeleteFile(AppPath + 'apophysis.rand');
if FileExists(AppPath + 'apophysis.rand') then
DeleteFile(AppPath + 'apophysis.rand');
if (defFlameFile = '') or (not FileExists(defFlameFile)) then
begin
MainCp.Width := image.width;
@ -3087,8 +3089,8 @@ begin
mnuVRandom.Checked := True;
StopThread;
UpdateUndo;
inc(seed);
RandSeed := Seed;
inc(MainSeed);
RandSeed := MainSeed;
repeat
Variation := vRandom;
SetVariation(maincp);
@ -3161,8 +3163,8 @@ begin
strings := TStringList.Create;
try
begin
inc(seed);
RandSeed := Seed;
inc(MainSeed);
RandSeed := MainSeed;
OpenDialog.Filter := 'All (*.bmp;*.jpg;*.jpeg)|*.bmp;*.jpg;*.jpeg|JPEG images (*.jpg;*.jpeg)|*.jpg;*.jpeg|BMP images (*.bmp)|*.bmp';
OpenDialog.InitialDir := ImageFolder;
OpenDialog.Title := 'Select Image File';
@ -3518,8 +3520,8 @@ procedure TMainForm.mnuRandomizeColorValuesClick(Sender: TObject);
var
i: integer;
begin
inc(seed);
RandSeed := seed;
inc(MainSeed);
RandSeed := MainSeed;
StopThread;
UpdateUndo;
for i := 0 to Transforms - 1 do

View File

@ -308,10 +308,6 @@ var
FileList: TStringList;
function Mul33(M1, M2: TMatrix): TMatrix;
procedure Rotate(xform: TXForm; const degrees: double);
procedure Scale(xform: TXForm; const s: double);
procedure translate(xform: TXForm; const x, y: double);
procedure multiply(var xform: TXform; const a, b, c, d: double);
procedure Normalize(var cp: TControlPoint);
implementation
@ -1291,7 +1287,7 @@ begin
try
if (ActiveTransform < 0) or (ActiveTransform > NXFORMS - 1) then raise EFormatInvalid.Create('Transform out of range.');
with AMachine do
Rotate(ScriptEditor.cp.xform[ActiveTransform], GetInputArgAsFloat(0));
ScriptEditor.cp.xform[ActiveTransform].Rotate(GetInputArgAsFloat(0));
except on E: EFormatInvalid do
begin
ScriptEditor.Console.Lines.Add('Rotate: ' + E.message);
@ -1306,10 +1302,10 @@ begin
try
if (ActiveTransform < 0) or (ActiveTransform > NXFORMS - 1) then raise EFormatInvalid.Create('Transform out of range.');
with AMachine do
Multiply(ScriptEditor.cp.xform[ActiveTransform], GetInputArgAsFloat(0), GetInputArgAsFloat(1), GetInputArgAsFloat(2), GetInputArgAsFloat(3));
ScriptEditor.cp.xform[ActiveTransform].Multiply(GetInputArgAsFloat(0), GetInputArgAsFloat(1), GetInputArgAsFloat(2), GetInputArgAsFloat(3));
except on E: EFormatInvalid do
begin
ScriptEditor.Console.Lines.Add('Rotate: ' + E.message);
ScriptEditor.Console.Lines.Add('Multiply: ' + E.message);
Application.ProcessMessages;
LastError := E.Message;
end;
@ -1624,7 +1620,7 @@ begin
try
if (ActiveTransform < 0) or (ActiveTransform > NXFORMS - 1) then raise EFormatInvalid.Create('Transform out of range.');
with AMachine do
Scale(ScriptEditor.cp.xform[ActiveTransform], GetInputArgAsFloat(0));
ScriptEditor.cp.xform[ActiveTransform].Scale(GetInputArgAsFloat(0));
except on E: EFormatInvalid do
begin
ScriptEditor.Console.Lines.Add('Scale: ' + E.message);
@ -1881,7 +1877,7 @@ begin
try
if (ActiveTransform < 0) or (ActiveTransform > NXFORMS - 1) then raise EFormatInvalid.Create('Transform out of range.');
with AMachine do
Translate(ScriptEditor.cp.xform[ActiveTransform], GetInputArgAsFloat(0), GetInputArgAsFloat(1));
ScriptEditor.cp.xform[ActiveTransform].Translate(GetInputArgAsFloat(0), GetInputArgAsFloat(1));
except on E: EFormatInvalid do
begin
Application.ProcessMessages;
@ -2948,116 +2944,6 @@ end;
{ ******************************* functions ********************************** }
procedure Rotate(xform: TXForm; const degrees: double);
var
r: double;
Matrix, M1: TMatrix;
begin
r := degrees * pi / 180;
M1 := Identity;
M1[0, 0] := cos(r);
M1[0, 1] := -sin(r);
M1[1, 0] := sin(r);
M1[1, 1] := cos(r);
Matrix := Identity;
with xform do
begin
Matrix[0][0] := c[0, 0];
Matrix[0][1] := c[0, 1];
Matrix[1][0] := c[1, 0];
Matrix[1][1] := c[1, 1];
Matrix[0][2] := c[2, 0];
Matrix[1][2] := c[2, 1];
Matrix := Mul33(Matrix, M1);
c[0, 0] := Matrix[0][0];
c[0, 1] := Matrix[0][1];
c[1, 0] := Matrix[1][0];
c[1, 1] := Matrix[1][1];
c[2, 0] := Matrix[0][2];
c[2, 1] := Matrix[1][2];
end;
end;
procedure Scale(xform: TXform; const s: double);
var
Matrix, M1: TMatrix;
begin
M1 := Identity;
M1[0, 0] := s;
M1[1, 1] := s;
Matrix := Identity;
with xform do
begin
Matrix[0][0] := c[0, 0];
Matrix[0][1] := c[0, 1];
Matrix[1][0] := c[1, 0];
Matrix[1][1] := c[1, 1];
Matrix[0][2] := c[2, 0];
Matrix[1][2] := c[2, 1];
Matrix := Mul33(Matrix, M1);
c[0, 0] := Matrix[0][0];
c[0, 1] := Matrix[0][1];
c[1, 0] := Matrix[1][0];
c[1, 1] := Matrix[1][1];
c[2, 0] := Matrix[0][2];
c[2, 1] := Matrix[1][2];
end;
end;
procedure translate(xform: TXForm; const x, y: double);
var
Matrix, M1: TMatrix;
begin
M1 := Identity;
M1[0, 2] := x;
M1[1, 2] := y;
Matrix := Identity;
with xform do
begin
Matrix[0][0] := c[0, 0];
Matrix[0][1] := c[0, 1];
Matrix[1][0] := c[1, 0];
Matrix[1][1] := c[1, 1];
Matrix[0][2] := c[2, 0];
Matrix[1][2] := c[2, 1];
Matrix := Mul33(Matrix, M1);
c[0, 0] := Matrix[0][0];
c[0, 1] := Matrix[0][1];
c[1, 0] := Matrix[1][0];
c[1, 1] := Matrix[1][1];
c[2, 0] := Matrix[0][2];
c[2, 1] := Matrix[1][2];
end;
end;
procedure multiply(var xform: TXform; const a, b, c, d: double);
var
Matrix, M1: TMatrix;
begin
M1 := Identity;
M1[0, 0] := a;
M1[0, 1] := b;
M1[1, 0] := c;
M1[1, 1] := d;
// M1[0, 2] := e;
// M1[1, 2] := f;
Matrix := Identity;
Matrix[0][0] := xform.c[0, 0];
Matrix[0][1] := xform.c[0, 1];
Matrix[1][0] := xform.c[1, 0];
Matrix[1][1] := xform.c[1, 1];
Matrix[0][2] := xform.c[2, 0];
Matrix[1][2] := xform.c[2, 1];
Matrix := Mul33(Matrix, M1);
xform.c[0, 0] := Matrix[0][0];
xform.c[0, 1] := Matrix[0][1];
xform.c[1, 0] := Matrix[1][0];
xform.c[1, 1] := Matrix[1][1];
xform.c[2, 0] := Matrix[0][2];
xform.c[2, 1] := Matrix[1][2];
end;
{ ******************************* Parseing *********************************** }

View File

@ -20,6 +20,8 @@ type
end;
PXYpoint = ^TXYpoint;
TMatrix = array[0..2, 0..2] of double;
type
TXForm = class
private
@ -61,6 +63,9 @@ type
procedure Fan; // var[22]
function Mul33(const M1, M2: TMatrix): TMatrix;
function Identity: TMatrix;
public
vars: array[0..NVARS - 1] of double; // normalized interp coefs between variations
c: array[0..2, 0..1] of double; // the coefs to the affine part of the function
@ -83,6 +88,10 @@ type
procedure NextPointXY(var px, py: double);
procedure NextPoint2C(var px, py, pc1, pc2: double);
procedure Rotate(const degrees: double);
procedure Translate(const x, y: double);
procedure Multiply(const a, b, c, d: double);
procedure Scale(const s: double);
end;
implementation
@ -752,4 +761,136 @@ begin
py := FPy;
end;
///////////////////////////////////////////////////////////////////////////////
function TXForm.Mul33(const M1, M2: TMatrix): TMatrix;
begin
result[0, 0] := M1[0][0] * M2[0][0] + M1[0][1] * M2[1][0] + M1[0][2] * M2[2][0];
result[0, 1] := M1[0][0] * M2[0][1] + M1[0][1] * M2[1][1] + M1[0][2] * M2[2][1];
result[0, 2] := M1[0][0] * M2[0][2] + M1[0][1] * M2[1][2] + M1[0][2] * M2[2][2];
result[1, 0] := M1[1][0] * M2[0][0] + M1[1][1] * M2[1][0] + M1[1][2] * M2[2][0];
result[1, 1] := M1[1][0] * M2[0][1] + M1[1][1] * M2[1][1] + M1[1][2] * M2[2][1];
result[1, 2] := M1[1][0] * M2[0][2] + M1[1][1] * M2[1][2] + M1[1][2] * M2[2][2];
result[2, 0] := M1[2][0] * M2[0][0] + M1[2][1] * M2[1][0] + M1[2][2] * M2[2][0];
result[2, 0] := M1[2][0] * M2[0][1] + M1[2][1] * M2[1][1] + M1[2][2] * M2[2][1];
result[2, 0] := M1[2][0] * M2[0][2] + M1[2][1] * M2[1][2] + M1[2][2] * M2[2][2];
end;
///////////////////////////////////////////////////////////////////////////////
function TXForm.Identity: TMatrix;
var
i, j: integer;
begin
for i := 0 to 2 do
for j := 0 to 2 do
Result[i, j] := 0;
Result[0][0] := 1;
Result[1][1] := 1;
Result[2][2] := 1;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Rotate(const degrees: double);
var
r: double;
Matrix, M1: TMatrix;
begin
r := degrees * pi / 180;
M1 := Identity;
M1[0, 0] := cos(r);
M1[0, 1] := -sin(r);
M1[1, 0] := sin(r);
M1[1, 1] := cos(r);
Matrix := Identity;
Matrix[0][0] := c[0, 0];
Matrix[0][1] := c[0, 1];
Matrix[1][0] := c[1, 0];
Matrix[1][1] := c[1, 1];
Matrix[0][2] := c[2, 0];
Matrix[1][2] := c[2, 1];
Matrix := Mul33(Matrix, M1);
c[0, 0] := Matrix[0][0];
c[0, 1] := Matrix[0][1];
c[1, 0] := Matrix[1][0];
c[1, 1] := Matrix[1][1];
c[2, 0] := Matrix[0][2];
c[2, 1] := Matrix[1][2];
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Translate(const x, y: double);
var
Matrix, M1: TMatrix;
begin
M1 := Identity;
M1[0, 2] := x;
M1[1, 2] := y;
Matrix := Identity;
Matrix[0][0] := c[0, 0];
Matrix[0][1] := c[0, 1];
Matrix[1][0] := c[1, 0];
Matrix[1][1] := c[1, 1];
Matrix[0][2] := c[2, 0];
Matrix[1][2] := c[2, 1];
Matrix := Mul33(Matrix, M1);
c[0, 0] := Matrix[0][0];
c[0, 1] := Matrix[0][1];
c[1, 0] := Matrix[1][0];
c[1, 1] := Matrix[1][1];
c[2, 0] := Matrix[0][2];
c[2, 1] := Matrix[1][2];
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Multiply(const a, b, c, d: double);
var
Matrix, M1: TMatrix;
begin
M1 := Identity;
M1[0, 0] := a;
M1[0, 1] := b;
M1[1, 0] := c;
M1[1, 1] := d;
Matrix := Identity;
Matrix[0][0] := Self.c[0, 0];
Matrix[0][1] := Self.c[0, 1];
Matrix[1][0] := Self.c[1, 0];
Matrix[1][1] := Self.c[1, 1];
Matrix[0][2] := Self.c[2, 0];
Matrix[1][2] := Self.c[2, 1];
Matrix := Mul33(Matrix, M1);
Self.c[0, 0] := Matrix[0][0];
Self.c[0, 1] := Matrix[0][1];
Self.c[1, 0] := Matrix[1][0];
Self.c[1, 1] := Matrix[1][1];
Self.c[2, 0] := Matrix[0][2];
Self.c[2, 1] := Matrix[1][2];
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Scale(const s: double);
var
Matrix, M1: TMatrix;
begin
M1 := Identity;
M1[0, 0] := s;
M1[1, 1] := s;
Matrix := Identity;
Matrix[0][0] := c[0, 0];
Matrix[0][1] := c[0, 1];
Matrix[1][0] := c[1, 0];
Matrix[1][1] := c[1, 1];
Matrix[0][2] := c[2, 0];
Matrix[1][2] := c[2, 1];
Matrix := Mul33(Matrix, M1);
c[0, 0] := Matrix[0][0];
c[0, 1] := Matrix[0][1];
c[1, 0] := Matrix[1][0];
c[1, 1] := Matrix[1][1];
c[2, 0] := Matrix[0][2];
c[2, 1] := Matrix[1][2];
end;
///////////////////////////////////////////////////////////////////////////////
end.