part 2... hope all this MT stuff will work ;-)

This commit is contained in:
zueuk 2006-03-02 17:34:04 +00:00
parent 1270d58d49
commit 108f76ea5f
8 changed files with 645 additions and 284 deletions

View File

@ -1,5 +1,6 @@
{
Apophysis Copyright (C) 2001-2004 Mark Townsend
Apophysis Copyright (C) 2005-2006 Ronald Hordijk, Piotr Boris, Peter Sdobnov
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -36,7 +37,7 @@ const
RS_XO = 2;
RS_VO = 3;
AppVersionString = 'Apophysis 2.03c';
AppVersionString = 'Apophysis 2.03d pre-release 1';
type
TMouseMoveState = (msUsual, msZoomWindow, msZoomOutWindow, msZoomWindowMove, msZoomOutWindowMove, msDrag, msDragMove, msRotate, msRotateMove);
@ -358,6 +359,7 @@ var
MainForm: TMainForm;
pname, ptime: string;
nxform: integer;
FinalXformLoaded: boolean;
ParseCp: TControlPoint; // For parsing;
MainCp: TControlPoint;
@ -1312,10 +1314,11 @@ begin
Result := ' <colors count="256" data="';
for i := 0 to 255 do begin
Result := Result + IntToHex(0,2)
Result := Result + '00' //IntToHex(0,2)
+ IntToHex(cp1.cmap[i, 0],2)
+ IntToHex(cp1.cmap[i, 1],2)
+ IntToHex(cp1.cmap[i, 2],2);
if ((i and 7) = 7) and (i <> 255) then Result := Result + #13#10 + ' ';
end;
Result := Result + '"/>';
end;
@ -1375,33 +1378,15 @@ begin
{ Write transform parameters }
t := NumXForms(cp1);
for i := 0 to t - 1 do begin
for i := 0 to t - 1 do
FileList.Add(cp1.xform[i].ToXMLString);
// with cp1.xform[i] do
// begin
// a := c[0][0];
// b := c[1][0];
// cc := c[0][1];
// d := c[1][1];
// e := c[2][0];
// f := c[2][1];
// varlist := '';
// for j := 0 to NRVAR - 1 do
// begin
// if vars[j] <> 0 then
// begin
// varlist := varlist + varnames(j) + format('="%f" ', [vars[j]]);
// end;
// end;
// FileList.Add(Format(' <xform weight="%g" color="%g" symmetry="%g" ', [density, color, symmetry]) +
// varlist + Format('coefs="%g %g %g %g %g %g"/>', [a, cc, b, d, e, f]));
// end;
end;
// if cp1.HasFinalXForm then FileList.Add(cp1.finalxform.FinalToXMLString(cp1.finalXformEnabled));
if cp1.HasFinalXForm then FileList.Add(cp1.xform[t].FinalToXMLString(cp1.finalXformEnabled));
{ Write palette data }
if not sheep then begin
if not compact then
FileList.Add(ColorToXml(cp1));
FileList.Add(ColorToXmlcompact(cp1));
if compact then // say no to duplicated data! (?)
FileList.Add(ColorToXmlCompact(cp1))
else FileList.Add(ColorToXml(cp1));
end;
FileList.Add('</flame>');
@ -1562,7 +1547,7 @@ begin
until (Pos('<' + Tag + '>', FileList[FileList.count - 1]) <> 0) or
(Pos('</Flames>', FileList[FileList.count - 1]) <> 0);
FileList.Add(Trim(FlameToXML(cp1, false)));
FileList.Add(Trim(FlameToXML(cp1, false, true)));
FileList.Add('</Flames>');
FileList.SaveToFile(filename);
@ -1576,7 +1561,7 @@ begin
AssignFile(IFile, filename);
ReWrite(IFile);
Writeln(IFile, '<Flames name="' + Tag + '">');
Write(IFile, FlameToXML(cp1, false));
Write(IFile, FlameToXML(cp1, false, true));
Writeln(IFile, '</Flames>');
CloseFile(IFile);
end;
@ -1894,7 +1879,7 @@ begin
*)
MainCp.name := RandomPrefix + RandomDate + '-' +
IntToStr(RandomIndex);
Write(F, FlameToXML(MainCp, False));
Write(F, FlameToXML(MainCp, False, true));
// Write(F, FlameToString(Title));
// WriteLn(F, ' ');
end;
@ -2619,6 +2604,7 @@ begin
time := -1;
FileStrings := TStringList.Create;
ParamStrings := TStringList.Create;
if pos('*untitled', name) <> 0 then
begin
Tokens := TStringList.Create;
@ -2684,7 +2670,7 @@ begin
RedrawTimer.Enabled := True;
Application.ProcessMessages;
EditForm.SelectedTriangle := 1; // --Z--
EditForm.SelectedTriangle := 0; // (?)
UpdateWindows;
finally
@ -3578,8 +3564,10 @@ begin
ScriptEditor.Stopped := True;
StopThread;
nxform := 0;
FinalXformLoaded := false;
Parsecp.cmapindex := -2; // generate pallet from cmapindex and hue (apo 1 and earlier)
ParseCp.symmetry := 0;
ParseCP.finalXformEnabled := false;
XMLScanner.LoadFromBuffer(params);
XMLScanner.Execute;
cp1.copy(ParseCp);
@ -3600,6 +3588,11 @@ begin
end;
end;
if FinalXformLoaded = false then begin
MainCP.xform[nxform].Clear;
MainCP.xform[nxform].symmetry := 1;
end;
if nxform < NXFORMS then
for i := nxform to NXFORMS - 1 do
cp1.xform[i].density := 0;
@ -3987,77 +3980,83 @@ var
begin
Tokens := TStringList.Create;
try
if TagName = 'xform' then
if (TagName = 'xform') or (TagName = 'finalxform') then
if (TagName = 'finalxform') and (FinalXformLoaded) then ShowMessage('ERROR: No xforms allowed after FinalXform!')
else
begin
Parsecp.xform[nxform].Clear;
if (TagName = 'finalxform') then FinalXformLoaded := true;
with ParseCP.xform[nXform] do begin
Clear;
v := Attributes.Value('weight');
if v <> '' then ParseCp.xform[nxform].density := StrToFloat(v);
if (v <> '') and (TagName = 'xform') then density := StrToFloat(v);
if (TagName = 'finalxform') then
begin
v := Attributes.Value('enabled');
if v <> '' then ParseCP.finalXformEnabled := (StrToInt(v) <> 0)
else ParseCP.finalXformEnabled := false;
end;
v := Attributes.Value('color');
if v <> '' then Parsecp.xform[nxform].color := StrToFloat(v);
if v <> '' then color := StrToFloat(v);
v := Attributes.Value('symmetry');
if v <> '' then Parsecp.xform[nxform].symmetry := StrToFloat(v);
if v <> '' then symmetry := StrToFloat(v);
v := Attributes.Value('coefs');
GetTokens(v, tokens);
if Tokens.Count < 6 then ShowMessage('Not enough cooeficients...crash?');
with Parsecp.xform[nxform] do
begin
c[0][0] := StrToFloat(Tokens[0]);
c[0][1] := StrToFloat(Tokens[1]);
c[1][0] := StrToFloat(Tokens[2]);
c[1][1] := StrToFloat(Tokens[3]);
c[2][0] := StrToFloat(Tokens[4]);
c[2][1] := StrToFloat(Tokens[5]);
end;
c[0][0] := StrToFloat(Tokens[0]);
c[0][1] := StrToFloat(Tokens[1]);
c[1][0] := StrToFloat(Tokens[2]);
c[1][1] := StrToFloat(Tokens[3]);
c[2][0] := StrToFloat(Tokens[4]);
c[2][1] := StrToFloat(Tokens[5]);
v := Attributes.Value('post');
if v <> '' then begin
GetTokens(v, tokens);
if Tokens.Count < 6 then ShowMessage('Not enough post-cooeficients...crash?');
with Parsecp.xform[nxform] do
begin
p[0][0] := StrToFloat(Tokens[0]);
p[0][1] := StrToFloat(Tokens[1]);
p[1][0] := StrToFloat(Tokens[2]);
p[1][1] := StrToFloat(Tokens[3]);
p[2][0] := StrToFloat(Tokens[4]);
p[2][1] := StrToFloat(Tokens[5]);
end;
p[0][0] := StrToFloat(Tokens[0]);
p[0][1] := StrToFloat(Tokens[1]);
p[1][0] := StrToFloat(Tokens[2]);
p[1][1] := StrToFloat(Tokens[3]);
p[2][0] := StrToFloat(Tokens[4]);
p[2][1] := StrToFloat(Tokens[5]);
end;
for i := 0 to NRVAR - 1 do
begin
Parsecp.xform[nxform].vars[i] := 0;
vars[i] := 0;
v := Attributes.Value(varnames(i));
if v <> '' then
Parsecp.xform[nxform].vars[i] := StrToFloat(v);
vars[i] := StrToFloat(v);
end;
v := Attributes.Value('var1');
if v <> '' then
begin
for i := 0 to NRVAR - 1 do
Parsecp.xform[nxform].vars[i] := 0;
Parsecp.xform[nxform].vars[StrToInt(v)] := 1;
vars[i] := 0;
vars[StrToInt(v)] := 1;
end;
v := Attributes.Value('var');
if v <> '' then
begin
for i := 0 to NRVAR - 1 do
Parsecp.xform[nxform].vars[i] := 0;
vars[i] := 0;
GetTokens(v, tokens);
if Tokens.Count > NRVAR then ShowMessage('To many vars..crash?');
for i := 0 to Tokens.Count - 1 do
Parsecp.xform[nxform].vars[i] := StrToFloat(Tokens[i]);
vars[i] := StrToFloat(Tokens[i]);
end;
for i := 0 to GetNrVariableNames - 1 do begin
v := Attributes.Value(GetVariableNameAt(i));
if v <> '' then begin
d := StrToFloat(v);
Parsecp.xform[nxform].SetVariable(GetVariableNameAt(i), d);
SetVariable(GetVariableNameAt(i), d);
end;
end;
inc(nxform);
end;
Inc(nXform);
end;
if TagName = 'color' then
begin

View File

@ -22,16 +22,16 @@ interface
uses
Windows, Graphics, ImageMaker,
Render, Controlpoint;
Render, xform, Controlpoint;
type
TRenderer64 = class(TBaseRenderer)
private
oversample: Int64;
oversample: integer;
BucketWidth, BucketHeight: integer;
BucketSize: integer;
BucketWidth: Int64;
BucketHeight: Int64;
BucketSize: Int64;
gutter_width: Integer;
max_gutter_width: Integer;
@ -40,8 +40,12 @@ type
Buckets: TBucketArray;
ColorMap: TColorMapArray;
bounds: array[0..3] of extended;
size: array[0..1] of extended;
FinalXform: ^TXform;
UseFinalXform: boolean;
camX0, camX1, camY0, camY1, // camera bounds
camW, camH, // camera sizes
bws, bhs, cosa, sina, rcX, rcY: double;
ppux, ppuy: extended;
FImageMaker: TImageMaker;
@ -53,8 +57,10 @@ type
procedure CreateColorMap;
procedure CreateCamera;
procedure AddPointsToBuckets(const points: TPointsArray); overload;
procedure AddPointsToBucketsAngle(const points: TPointsArray); overload;
procedure AddPointsToBuckets(const points: TPointsArray);
procedure AddPointsToBucketsAngle(const points: TPointsArray);
procedure AddPointsWithFX(const points: TPointsArray);
procedure AddPointsWithAngleFX(const points: TPointsArray);
procedure SetPixels;
public
@ -117,7 +123,7 @@ var
scale: double;
t0, t1: double;
t2, t3: double;
corner0, corner1: double;
corner_x, corner_y, Xsize, Ysize: double;
shift: Integer;
begin
scale := power(2, fcp.zoom);
@ -131,20 +137,32 @@ begin
t1 := (gutter_width) / (oversample * ppuy);
t2 := (2 * max_gutter_width - gutter_width) / (oversample * ppux);
t3 := (2 * max_gutter_width - gutter_width) / (oversample * ppuy);
corner0 := fcp.center[0] - fcp.Width / ppux / 2.0;
corner1 := fcp.center[1] - fcp.Height / ppuy / 2.0;
bounds[0] := corner0 - t0;
bounds[1] := corner1 - t1 + shift;
bounds[2] := corner0 + fcp.Width / ppux + t2;
bounds[3] := corner1 + fcp.Height / ppuy + t3; //+ shift;
if abs(bounds[2] - bounds[0]) > 0.01 then
size[0] := 1.0 / (bounds[2] - bounds[0])
corner_x := fcp.center[0] - fcp.Width / ppux / 2.0;
corner_y := fcp.center[1] - fcp.Height / ppuy / 2.0;
camX0 := corner_x - t0;
camY0 := corner_y - t1 + shift;
camX1 := corner_x + fcp.Width / ppux + t2;
camY1 := corner_y + fcp.Height / ppuy + t3; //+ shift;
camW := camX1 - camX0;
if abs(camW) > 0.01 then
Xsize := 1.0 / camW
else
size[0] := 1;
if abs(bounds[3] - bounds[1]) > 0.01 then
size[1] := 1.0 / (bounds[3] - bounds[1])
Xsize := 1;
camH := camY1 - camY0;
if abs(camH) > 0.01 then
Ysize := 1.0 / camH
else
size[1] := 1;
Ysize := 1;
bws := (BucketWidth - 0.5) * Xsize;
bhs := (BucketHeight - 0.5) * Ysize;
if FCP.FAngle <> 0 then
begin
cosa := cos(FCP.FAngle);
sina := sin(FCP.FAngle);
rcX := FCP.Center[0]*(1 - cosa) - FCP.Center[1]*sina - camX0;
rcY := FCP.Center[1]*(1 - cosa) + FCP.Center[0]*sina - camY0;
end;
end;
///////////////////////////////////////////////////////////////////////////////
@ -202,6 +220,9 @@ begin
CreateCamera;
CreateColorMap;
FinalXForm := @fcp.xform[fcp.NumXForms];
UseFinalXForm := fcp.finalXformEnabled and fcp.HasFinalXform;
end;
///////////////////////////////////////////////////////////////////////////////
@ -209,32 +230,19 @@ procedure TRenderer64.AddPointsToBuckets(const points: TPointsArray);
var
i: integer;
px, py: double;
bws, bhs: double;
bx, by: double;
wx, wy: double;
Bucket: PBucket;
MapColor: PColorMapColor;
begin
bws := (BucketWidth - 0.5) * size[0];
bhs := (BucketHeight - 0.5) * size[1];
bx := bounds[0];
by := bounds[1];
wx := bounds[2] - bounds[0];
wy := bounds[3] - bounds[1];
for i := SUB_BATCH_SIZE - 1 downto 0 do begin
if FStop then
Exit;
// if FStop then Exit;
px := points[i].x - bx;
py := points[i].y - by;
px := points[i].x - camX0;
if (px < 0) or (px > camW) then continue;
py := points[i].y - camY0;
if (py < 0) or (py > camH) then continue;
if ((px < 0) or (px > wx) or
(py < 0) or (py > wy)) then
continue;
MapColor := @ColorMap[Round(points[i].c * 255)];
Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth];
MapColor := @ColorMap[Round(points[i].c * 255)];
Inc(Bucket.Red, MapColor.Red);
Inc(Bucket.Green, MapColor.Green);
@ -243,49 +251,104 @@ begin
end;
end;
procedure TRenderer64.AddPointsWithFX(const points: TPointsArray);
const
const255: single = 255;
var
i: integer;
px, py: double;
Bucket: PBucket;
MapColor: PColorMapColor;
begin
try
for i := SUB_BATCH_SIZE - 1 downto 0 do begin
// if FStop then Exit;
FinalXform.NextPoint(points[i]);
{$if true}
px := points[i].x - camX0;
if (px < 0) or (px > camW) then continue;
py := points[i].y - camY0;
if (py < 0) or (py > camH) then continue;
Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth];
MapColor := @ColorMap[Round(points[i].c * 255)];
Inc(Bucket.Red, MapColor.Red);
Inc(Bucket.Green, MapColor.Green);
Inc(Bucket.Blue, MapColor.Blue);
Inc(Bucket.Count);
{$else}
asm
mov eax, [points]
lea edx, [eax + edi*8] // assert: "i" in edi
// fld qword ptr [edx + edi*8] // assert: "i" in edi
fld qword ptr [edx]
fsub qword ptr [bx]
fldz
fcomp st(1), st
fnstsw ax
sahf
jb @skip1
fld qword ptr [wx]
fcomp
fnstsw ax
sahf
jnbe @skip1
fld qword ptr [edx + 8]
fsub qword ptr [by]
fldz
fcomp
fnstsw ax
sahf
jb @skip2
fld qword ptr [wy]
fcomp
fnstsw ax
sahf
jnbe @skip2
fmul qword ptr [bhs]
fimul [BucketWidth]
fld qword ptr [edx + 16]
fmul dword ptr [const255]
sub esp, 4
fistp dword ptr [esp]
pop eax
@skip2:
fstp st
@skip1:
fstp st
@continue:
end;
{$ifend}
end
except
end
end;
///////////////////////////////////////////////////////////////////////////////
procedure TRenderer64.AddPointsToBucketsAngle(const points: TPointsArray);
var
i: integer;
px, py: double;
ca,sa: double;
nx, ny: double;
bws, bhs: double;
bx, by: double;
wx, wy: double;
Bucket: PBucket;
MapColor: PColorMapColor;
begin
bws := (BucketWidth - 0.5) * size[0];
bhs := (BucketHeight - 0.5) * size[1];
bx := bounds[0];
by := bounds[1];
wx := bounds[2] - bounds[0];
wy := bounds[3] - bounds[1];
ca := cos(FCP.FAngle);
sa := sin(FCP.FAngle);
for i := SUB_BATCH_SIZE - 1 downto 0 do begin
if FStop then
Exit;
// if FStop then Exit;
px := points[i].x - FCP.Center[0];
py := points[i].y - FCP.Center[1];
px := points[i].x * cosa + points[i].y * sina + rcX;
if (px < 0) or (px > camW) then continue;
py := points[i].y * cosa - points[i].x * sina + rcY;
if (py < 0) or (py > camH) then continue;
nx := px * ca + py * sa;
ny := -px * sa + py * ca;
px := nx + FCP.Center[0] - bx;
py := ny + FCP.Center[1] - by;
if ((px < 0) or (px > wx) or
(py < 0) or (py > wy)) then
continue;
MapColor := @ColorMap[Round(points[i].c * 255)];
Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth];
MapColor := @ColorMap[Round(points[i].c * 255)];
Inc(Bucket.Red, MapColor.Red);
Inc(Bucket.Green, MapColor.Green);
@ -294,6 +357,36 @@ begin
end;
end;
procedure TRenderer64.AddPointsWithAngleFX(const points: TPointsArray);
var
i: integer;
px, py: double;
Bucket: PBucket;
MapColor: PColorMapColor;
begin
try
for i := SUB_BATCH_SIZE - 1 downto 0 do
begin
// if FStop then Exit;
FinalXform.NextPoint(points[i]);
px := points[i].x * cosa + points[i].y * sina + rcX;
if (px < 0) or (px > camW) then continue;
py := points[i].y * cosa - points[i].x * sina + rcY;
if (py < 0) or (py > camH) then continue;
Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth];
MapColor := @ColorMap[Round(points[i].c * 255)];
Inc(Bucket.Red, MapColor.Red);
Inc(Bucket.Green, MapColor.Green);
Inc(Bucket.Blue, MapColor.Blue);
Inc(Bucket.Count);
end;
except
end
end;
///////////////////////////////////////////////////////////////////////////////
procedure TRenderer64.SetPixels;
var
@ -301,12 +394,25 @@ var
nsamples: Int64;
nrbatches: Integer;
points: TPointsArray;
AddPointsProc: procedure (const points: TPointsArray) of object;
begin
// if FileExists('c:\temp\flame.txt') then
// Deletefile('c:\temp\flame.txt');
// AssignFile(F, 'c:\temp\flame.txt');
// Rewrite(F);
if FCP.FAngle = 0 then begin
if UseFinalXForm then
AddPointsProc := AddPointsWithFX
else
AddPointsProc := AddPointsToBuckets;
end
else begin
if UseFinalXForm then
AddPointsProc := AddPointsWithAngleFX
else
AddPointsProc := AddPointsToBucketsAngle;
end;
SetLength(Points, SUB_BATCH_SIZE);
@ -330,19 +436,19 @@ begin
// break;
fcp.Testiterate(SUB_BATCH_SIZE, points);
{$ELSE}
{
case Compatibility of
0: fcp.iterate_Old(SUB_BATCH_SIZE, points);
1: fcp.iterateXYC(SUB_BATCH_SIZE, points);
end;
}
fcp.IterateXYC(SUB_BATCH_SIZE, points);
{$ENDIF}
// for j := SUB_BATCH_SIZE - 1 downto 0 do
// Writeln(f, FloatTostr(points[j].x) + #9 + FloatTostr(points[j].y) + #9 + FloatTostr(points[j].c));
if FCP.FAngle = 0 then
AddPointsToBuckets(points)
else
AddPointsToBucketsAngle(points);
AddPointsProc(points);
end;
// closefile(f);

View File

@ -42,8 +42,15 @@ type
Buckets: TBucketArray;
ColorMap: TColorMapArray;
bounds: array[0..3] of extended;
size: array[0..1] of extended;
FinalXform: ^TXform;
UseFinalXform: boolean;
camX0, camX1, camY0, camY1, // camera bounds
camW, camH, // camera sizes
Xsize, Ysize: double;
bws, bhs, cosa, sina, rcX, rcY: double;
// bounds: array[0..3] of extended;
// size: array[0..1] of extended;
ppux, ppuy: extended;
FNrOfTreads: integer;
WorkingThreads: array of TBucketFillerThread;
@ -113,7 +120,7 @@ var
scale: double;
t0, t1: double;
t2, t3: double;
corner0, corner1: double;
corner_x, corner_y: double;
shift: Integer;
begin
scale := power(2, fcp.zoom);
@ -127,8 +134,9 @@ begin
t1 := (gutter_width) / (oversample * ppuy);
t2 := (2 * max_gutter_width - gutter_width) / (oversample * ppux);
t3 := (2 * max_gutter_width - gutter_width) / (oversample * ppuy);
corner0 := fcp.center[0] - fcp.Width / ppux / 2.0;
corner1 := fcp.center[1] - fcp.Height / ppuy / 2.0;
corner_x := fcp.center[0] - fcp.Width / ppux / 2.0;
corner_y := fcp.center[1] - fcp.Height / ppuy / 2.0;
{
bounds[0] := corner0 - t0;
bounds[1] := corner1 - t1 + shift;
bounds[2] := corner0 + fcp.Width / ppux + t2;
@ -141,6 +149,31 @@ begin
size[1] := 1.0 / (bounds[3] - bounds[1])
else
size[1] := 1;
}
camX0 := corner_x - t0;
camY0 := corner_y - t1 + shift;
camX1 := corner_x + fcp.Width / ppux + t2;
camY1 := corner_y + fcp.Height / ppuy + t3; //+ shift;
camW := camX1 - camX0;
if abs(camW) > 0.01 then
Xsize := 1.0 / camW
else
Xsize := 1;
camH := camY1 - camY0;
if abs(camH) > 0.01 then
Ysize := 1.0 / camH
else
Ysize := 1;
bws := (BucketWidth - 0.5) * Xsize;
bhs := (BucketHeight - 0.5) * Ysize;
if FCP.FAngle <> 0 then
begin
cosa := cos(FCP.FAngle);
sina := sin(FCP.FAngle);
rcX := FCP.Center[0]*(1 - cosa) - FCP.Center[1]*sina - camX0;
rcY := FCP.Center[1]*(1 - cosa) + FCP.Center[0]*sina - camY0;
end;
end;
///////////////////////////////////////////////////////////////////////////////
@ -317,6 +350,7 @@ begin
Result.BucketWidth := BucketWidth;
Result.BucketHeight := BucketHeight;
Result.Buckets := @Buckets;
{
Result.size[0] := size[0];
Result.size[1] := size[1];
Result.bounds[0] := Bounds[0];
@ -325,6 +359,18 @@ begin
Result.bounds[3] := Bounds[3];
Result.RotationCenter[0] := FCP.Center[0];
Result.RotationCenter[1] := FCP.Center[1];
}
Result.camX0 := camX0;
Result.camY0 := camY0;
Result.camW := camW;
Result.camH := camH;
Result.bws := bws;
Result.bhs := bhs;
Result.cosa := cosa;
Result.sina := sina;
Result.rcX := rcX;
Result.rcY := rcY;
Result.ColorMap := colorMap;
Result.CriticalSection := CriticalSection;
Result.Nrbatches := FNrBatches;

View File

@ -22,7 +22,7 @@ interface
uses
Windows, Graphics,
Render, Controlpoint, ImageMaker;
Render, Controlpoint, ImageMaker, XForm;
type
TRendererMM64 = class(TBaseRenderer)
@ -41,9 +41,15 @@ type
Buckets: TBucketArray;
ColorMap: TColorMapArray;
bounds: array[0..3] of extended;
size: array[0..1] of extended;
FRotationCenter: array[0..1] of extended;
FinalXform: ^TXform;
UseFinalXform: boolean;
camX0, camX1, camY0, camY1, // camera bounds
camW, camH, // camera sizes
bws, bhs, cosa, sina, rcX, rcY: double;
// bounds: array[0..3] of extended;
// size: array[0..1] of extended;
// FRotationCenter: array[0..1] of extended;
ppux, ppuy: extended;
nrSlices: int64;
Slice: int64;
@ -56,8 +62,10 @@ type
procedure CreateColorMap;
procedure CreateCamera;
procedure AddPointsToBuckets(const points: TPointsArray); overload;
procedure AddPointsToBucketsAngle(const points: TPointsArray); overload;
procedure AddPointsToBuckets(const points: TPointsArray);
procedure AddPointsToBucketsAngle(const points: TPointsArray);
procedure AddPointsWithFX(const points: TPointsArray);
procedure AddPointsWithAngleFX(const points: TPointsArray);
procedure SetPixels;
protected
@ -106,7 +114,7 @@ procedure TRendererMM64.CreateCamera;
var
scale: double;
t0, t1: double;
corner0, corner1: double;
corner_x, corner_y, Xsize, Ysize: double;
shift: Integer;
begin
scale := power(2, fcp.zoom);
@ -117,8 +125,9 @@ begin
shift := 0;
t0 := gutter_width / (oversample * ppux);
t1 := gutter_width / (oversample * ppuy);
corner0 := fcp.center[0] - image_width / ppux / 2.0;
corner1 := fcp.center[1] - image_height / ppuy / 2.0;
corner_x := fcp.center[0] - image_width / ppux / 2.0;
corner_y := fcp.center[1] - image_height / ppuy / 2.0;
{
bounds[0] := corner0 - t0;
bounds[1] := corner1 - t1 + shift;
bounds[2] := corner0 + image_width / ppux + t0;
@ -131,6 +140,31 @@ begin
size[1] := 1.0 / (bounds[3] - bounds[1])
else
size[1] := 1;
}
camX0 := corner_x - t0;
camY0 := corner_y - t1 + shift;
camX1 := corner_x + image_width / ppux / 2.0;
camY1 := corner_y + image_height / ppuy + t1; //+ shift;
camW := camX1 - camX0;
if abs(camW) > 0.01 then
Xsize := 1.0 / camW
else
Xsize := 1;
camH := camY1 - camY0;
if abs(camH) > 0.01 then
Ysize := 1.0 / camH
else
Ysize := 1;
bws := (BucketWidth - 0.5) * Xsize;
bhs := (BucketHeight - 0.5) * Ysize;
if FCP.FAngle <> 0 then
begin
cosa := cos(FCP.FAngle);
sina := sin(FCP.FAngle);
rcX := FCP.Center[0]*(1 - cosa) - FCP.Center[1]*sina - camX0;
rcY := FCP.Center[1]*(1 - cosa) + FCP.Center[0]*sina - camY0;
end;
end;
///////////////////////////////////////////////////////////////////////////////
@ -188,6 +222,9 @@ begin
InitBuffers;
CreateColorMap;
FinalXForm := @fcp.xform[fcp.NumXForms];
UseFinalXForm := fcp.finalXformEnabled and fcp.HasFinalXform;
end;
///////////////////////////////////////////////////////////////////////////////
@ -195,34 +232,21 @@ procedure TRendererMM64.AddPointsToBuckets(const points: TPointsArray);
var
i: integer;
px, py: double;
bws, bhs: double;
bx, by: double;
wx, wy: double;
// R: double;
// V1, v2, v3: integer;
Bucket: PBucket;
MapColor: PColorMapColor;
begin
bws := (BucketWidth - 0.5) * size[0];
bhs := (BucketHeight - 0.5) * size[1];
bx := bounds[0];
by := bounds[1];
wx := bounds[2] - bounds[0];
wy := bounds[3] - bounds[1];
for i := SUB_BATCH_SIZE - 1 downto 0 do begin
if FStop then
Exit;
// if FStop then Exit;
px := points[i].x - bx;
py := points[i].y - by;
px := points[i].x - camX0;
if (px < 0) or (px > camW) then continue;
py := points[i].y - camY0;
if (py < 0) or (py > camH) then continue;
if ((px < 0) or (px > wx) or
(py < 0) or (py > wy)) then
continue;
MapColor := @ColorMap[Round(points[i].c * 255)];
Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth];
MapColor := @ColorMap[Round(points[i].c * 255)];
Inc(Bucket.Red, MapColor.Red);
Inc(Bucket.Green, MapColor.Green);
@ -231,57 +255,90 @@ begin
end;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TRendererMM64.AddPointsToBucketsAngle(const points: TPointsArray);
procedure TRendererMM64.AddPointsWithFX(const points: TPointsArray);
var
i: integer;
px, py: double;
ca,sa: double;
nx, ny: double;
bws, bhs: double;
bx, by: double;
wx, wy: double;
// R: double;
// V1, v2, v3: integer;
Bucket: PBucket;
MapColor: PColorMapColor;
begin
bws := (BucketWidth - 0.5) * size[0];
bhs := (BucketHeight - 0.5) * size[1];
bx := bounds[0];
by := bounds[1];
wx := bounds[2] - bounds[0];
wy := bounds[3] - bounds[1];
ca := cos(FCP.FAngle);
sa := sin(FCP.FAngle);
try
for i := SUB_BATCH_SIZE - 1 downto 0 do begin
if FStop then
Exit;
// if FStop then Exit;
px := points[i].x - FRotationCenter[0];
py := points[i].y - FRotationCenter[1];
FinalXform.NextPoint(points[i]);
nx := px * ca + py * sa;
ny := -px * sa + py * ca;
px := points[i].x - camX0;
if (px < 0) or (px > camW) then continue;
py := points[i].y - camY0;
if (py < 0) or (py > camH) then continue;
px := nx + FRotationCenter[0] - bx;
py := ny + FRotationCenter[1] - by;
if ((px < 0) or (px > wx) or
(py < 0) or (py > wy)) then
continue;
MapColor := @ColorMap[Round(points[i].c * 255)];
Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth];
MapColor := @ColorMap[Round(points[i].c * 255)];
Inc(Bucket.Red, MapColor.Red);
Inc(Bucket.Green, MapColor.Green);
Inc(Bucket.Blue, MapColor.Blue);
Inc(Bucket.Count);
end;
except
end
end;
///////////////////////////////////////////////////////////////////////////////
procedure TRendererMM64.AddPointsToBucketsAngle(const points: TPointsArray);
var
i: integer;
px, py: double;
Bucket: PBucket;
MapColor: PColorMapColor;
begin
for i := SUB_BATCH_SIZE - 1 downto 0 do begin
// if FStop then Exit;
px := points[i].x * cosa + points[i].y * sina + rcX;
if (px < 0) or (px > camW) then continue;
py := points[i].y * cosa - points[i].x * sina + rcY;
if (py < 0) or (py > camH) then continue;
Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth];
MapColor := @ColorMap[Round(points[i].c * 255)];
Inc(Bucket.Red, MapColor.Red);
Inc(Bucket.Green, MapColor.Green);
Inc(Bucket.Blue, MapColor.Blue);
Inc(Bucket.Count);
end;
end;
procedure TRendererMM64.AddPointsWithAngleFX(const points: TPointsArray);
var
i: integer;
px, py: double;
Bucket: PBucket;
MapColor: PColorMapColor;
begin
try
for i := SUB_BATCH_SIZE - 1 downto 0 do
begin
// if FStop then Exit;
FinalXform.NextPoint(points[i]);
px := points[i].x * cosa + points[i].y * sina + rcX;
if (px < 0) or (px > camW) then continue;
py := points[i].y * cosa - points[i].x * sina + rcY;
if (py < 0) or (py > camH) then continue;
Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth];
MapColor := @ColorMap[Round(points[i].c * 255)];
Inc(Bucket.Red, MapColor.Red);
Inc(Bucket.Green, MapColor.Green);
Inc(Bucket.Blue, MapColor.Blue);
Inc(Bucket.Count);
end;
except
end
end;
///////////////////////////////////////////////////////////////////////////////
@ -309,10 +366,13 @@ begin
Progress(0);
// generate points
{
case Compatibility of
0: fcp.iterate_Old(SUB_BATCH_SIZE, points);
1: fcp.iterateXYC(SUB_BATCH_SIZE, points);
end;
}
fcp.IterateXYC(SUB_BATCH_SIZE, points);
if FCP.FAngle = 0 then
AddPointsToBuckets(points)
@ -343,8 +403,8 @@ var
begin
FStop := False;
FRotationCenter[0] := fcp.center[0];
FRotationCenter[1] := fcp.center[1];
// FRotationCenter[0] := fcp.center[0];
// FRotationCenter[1] := fcp.center[1];
image_height := fcp.Height;
image_Width := fcp.Width;

View File

@ -22,17 +22,15 @@ interface
uses
Windows, Graphics,
Render, Controlpoint, ImageMaker, BucketFillerThread;
Render, Controlpoint, ImageMaker, BucketFillerThread, XForm;
type
TRendererMM64_MT = class(TBaseRenderer)
private
oversample: Integer;
image_Width: Int64;
image_Height: Int64;
BucketWidth: Integer;
BucketHeight: Integer;
image_Width, image_Height: integer; // we're not going to render images
BucketWidth, BucketHeight: integer; // more then 2^32 pixels wide, are we? :)
BucketSize: Integer;
gutter_width: Integer;
@ -41,9 +39,16 @@ type
Buckets: TBucketArray;
ColorMap: TColorMapArray;
bounds: array[0..3] of extended;
size: array[0..1] of extended;
FRotationCenter: array[0..1] of extended;
FinalXform: ^TXform;
UseFinalXform: boolean;
camX0, camX1, camY0, camY1, // camera bounds
camW, camH, // camera sizes
bws, bhs, cosa, sina, rcX, rcY: double;
// bounds: array[0..3] of extended;
// size: array[0..1] of extended;
// FRotationCenter: array[0..1] of extended;
ppux, ppuy: extended;
nrSlices: int64;
Slice: int64;
@ -62,8 +67,10 @@ type
procedure CreateColorMap;
procedure CreateCamera;
procedure AddPointsToBuckets(const points: TPointsArray); overload;
procedure AddPointsToBucketsAngle(const points: TPointsArray); overload;
procedure AddPointsToBuckets(const points: TPointsArray);
procedure AddPointsToBucketsAngle(const points: TPointsArray);
procedure AddPointsWithFX(const points: TPointsArray);
procedure AddPointsWithAngleFX(const points: TPointsArray);
procedure SetPixels;
procedure SetPixelsMT;
@ -119,7 +126,7 @@ procedure TRendererMM64_MT.CreateCamera;
var
scale: double;
t0, t1: double;
corner0, corner1: double;
corner_x, corner_y, Xsize, Ysize: double;
shift: Integer;
begin
scale := power(2, fcp.zoom);
@ -130,8 +137,9 @@ begin
shift := 0;
t0 := gutter_width / (oversample * ppux);
t1 := gutter_width / (oversample * ppuy);
corner0 := fcp.center[0] - image_width / ppux / 2.0;
corner1 := fcp.center[1] - image_height / ppuy / 2.0;
corner_x := fcp.center[0] - image_width / ppux / 2.0;
corner_y := fcp.center[1] - image_height / ppuy / 2.0;
{
bounds[0] := corner0 - t0;
bounds[1] := corner1 - t1 + shift;
bounds[2] := corner0 + image_width / ppux + t0;
@ -144,6 +152,31 @@ begin
size[1] := 1.0 / (bounds[3] - bounds[1])
else
size[1] := 1;
}
camX0 := corner_x - t0;
camY0 := corner_y - t1 + shift;
camX1 := corner_x + image_width / ppux + t0;
camY1 := corner_y + image_height / ppuy + t1; //+ shift;
camW := camX1 - camX0;
if abs(camW) > 0.01 then
Xsize := 1.0 / camW
else
Xsize := 1;
camH := camY1 - camY0;
if abs(camH) > 0.01 then
Ysize := 1.0 / camH
else
Ysize := 1;
bws := (BucketWidth - 0.5) * Xsize;
bhs := (BucketHeight - 0.5) * Ysize;
if FCP.FAngle <> 0 then
begin
cosa := cos(FCP.FAngle);
sina := sin(FCP.FAngle);
rcX := FCP.Center[0]*(1 - cosa) - FCP.Center[1]*sina - camX0;
rcY := FCP.Center[1]*(1 - cosa) + FCP.Center[0]*sina - camY0;
end;
end;
///////////////////////////////////////////////////////////////////////////////
@ -201,6 +234,9 @@ begin
InitBuffers;
CreateColorMap;
FinalXForm := @fcp.xform[fcp.NumXForms];
UseFinalXForm := fcp.finalXformEnabled and fcp.HasFinalXform;
end;
///////////////////////////////////////////////////////////////////////////////
@ -208,34 +244,21 @@ procedure TRendererMM64_MT.AddPointsToBuckets(const points: TPointsArray);
var
i: integer;
px, py: double;
bws, bhs: double;
bx, by: double;
wx, wy: double;
// R: double;
// V1, v2, v3: integer;
Bucket: PBucket;
MapColor: PColorMapColor;
begin
bws := (BucketWidth - 0.5) * size[0];
bhs := (BucketHeight - 0.5) * size[1];
bx := bounds[0];
by := bounds[1];
wx := bounds[2] - bounds[0];
wy := bounds[3] - bounds[1];
for i := SUB_BATCH_SIZE - 1 downto 0 do begin
if FStop then
Exit;
// if FStop then Exit;
px := points[i].x - bx;
py := points[i].y - by;
px := points[i].x - camX0;
if (px < 0) or (px > camW) then continue;
py := points[i].y - camY0;
if (py < 0) or (py > camH) then continue;
if ((px < 0) or (px > wx) or
(py < 0) or (py > wy)) then
continue;
MapColor := @ColorMap[Round(points[i].c * 255)];
Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth];
MapColor := @ColorMap[Round(points[i].c * 255)];
Inc(Bucket.Red, MapColor.Red);
Inc(Bucket.Green, MapColor.Green);
@ -244,57 +267,90 @@ begin
end;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TRendererMM64_MT.AddPointsToBucketsAngle(const points: TPointsArray);
procedure TRendererMM64_MT.AddPointsWithFX(const points: TPointsArray);
var
i: integer;
px, py: double;
ca,sa: double;
nx, ny: double;
bws, bhs: double;
bx, by: double;
wx, wy: double;
// R: double;
// V1, v2, v3: integer;
Bucket: PBucket;
MapColor: PColorMapColor;
begin
bws := (BucketWidth - 0.5) * size[0];
bhs := (BucketHeight - 0.5) * size[1];
bx := bounds[0];
by := bounds[1];
wx := bounds[2] - bounds[0];
wy := bounds[3] - bounds[1];
ca := cos(FCP.FAngle);
sa := sin(FCP.FAngle);
try
for i := SUB_BATCH_SIZE - 1 downto 0 do begin
if FStop then
Exit;
// if FStop then Exit;
px := points[i].x - FRotationCenter[0];
py := points[i].y - FRotationCenter[1];
FinalXform.NextPoint(points[i]);
nx := px * ca + py * sa;
ny := -px * sa + py * ca;
px := points[i].x - camX0;
if (px < 0) or (px > camW) then continue;
py := points[i].y - camY0;
if (py < 0) or (py > camH) then continue;
px := nx + FRotationCenter[0] - bx;
py := ny + FRotationCenter[1] - by;
if ((px < 0) or (px > wx) or
(py < 0) or (py > wy)) then
continue;
MapColor := @ColorMap[Round(points[i].c * 255)];
Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth];
MapColor := @ColorMap[Round(points[i].c * 255)];
Inc(Bucket.Red, MapColor.Red);
Inc(Bucket.Green, MapColor.Green);
Inc(Bucket.Blue, MapColor.Blue);
Inc(Bucket.Count);
end;
except
end
end;
///////////////////////////////////////////////////////////////////////////////
procedure TRendererMM64_MT.AddPointsToBucketsAngle(const points: TPointsArray);
var
i: integer;
px, py: double;
Bucket: PBucket;
MapColor: PColorMapColor;
begin
for i := SUB_BATCH_SIZE - 1 downto 0 do begin
// if FStop then Exit;
px := points[i].x * cosa + points[i].y * sina + rcX;
if (px < 0) or (px > camW) then continue;
py := points[i].y * cosa - points[i].x * sina + rcY;
if (py < 0) or (py > camH) then continue;
Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth];
MapColor := @ColorMap[Round(points[i].c * 255)];
Inc(Bucket.Red, MapColor.Red);
Inc(Bucket.Green, MapColor.Green);
Inc(Bucket.Blue, MapColor.Blue);
Inc(Bucket.Count);
end;
end;
procedure TRendererMM64_MT.AddPointsWithAngleFX(const points: TPointsArray);
var
i: integer;
px, py: double;
Bucket: PBucket;
MapColor: PColorMapColor;
begin
try
for i := SUB_BATCH_SIZE - 1 downto 0 do
begin
// if FStop then Exit;
FinalXform.NextPoint(points[i]);
px := points[i].x * cosa + points[i].y * sina + rcX;
if (px < 0) or (px > camW) then continue;
py := points[i].y * cosa - points[i].x * sina + rcY;
if (py < 0) or (py > camH) then continue;
Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth];
MapColor := @ColorMap[Round(points[i].c * 255)];
Inc(Bucket.Red, MapColor.Red);
Inc(Bucket.Green, MapColor.Green);
Inc(Bucket.Blue, MapColor.Blue);
Inc(Bucket.Count);
end;
except
end
end;
///////////////////////////////////////////////////////////////////////////////
@ -304,7 +360,21 @@ var
nsamples: Int64;
nrbatches: Integer;
points: TPointsArray;
AddPointsProc: procedure (const points: TPointsArray) of object;
begin
if FCP.FAngle = 0 then begin
if UseFinalXForm then
AddPointsProc := AddPointsWithFX
else
AddPointsProc := AddPointsToBuckets;
end
else begin
if UseFinalXForm then
AddPointsProc := AddPointsWithAngleFX
else
AddPointsProc := AddPointsToBucketsAngle;
end;
SetLength(Points, SUB_BATCH_SIZE);
nsamples := Round(sample_density * bucketSize / (oversample * oversample));
@ -322,15 +392,14 @@ begin
Progress(0);
// generate points
case Compatibility of
{ case Compatibility of
0: fcp.iterate_Old(SUB_BATCH_SIZE, points);
1: fcp.iterateXYC(SUB_BATCH_SIZE, points);
end;
}
fcp.IterateXYC(SUB_BATCH_SIZE, points);
if FCP.FAngle = 0 then
AddPointsToBuckets(points)
else
AddPointsToBucketsAngle(points);
AddPointsProc(points)
end;
Progress(1);
@ -355,8 +424,8 @@ var
begin
FStop := False;
FRotationCenter[0] := fcp.center[0];
FRotationCenter[1] := fcp.center[1];
// FRotationCenter[0] := fcp.center[0];
// FRotationCenter[1] := fcp.center[1];
image_height := fcp.Height;
image_Width := fcp.Width;
@ -493,6 +562,7 @@ begin
Result.BucketWidth := BucketWidth;
Result.BucketHeight := BucketHeight;
Result.Buckets := @Buckets;
{
Result.size[0] := size[0];
Result.size[1] := size[1];
Result.bounds[0] := Bounds[0];
@ -501,6 +571,18 @@ begin
Result.bounds[3] := Bounds[3];
Result.RotationCenter[0] := FRotationCenter[0];
Result.RotationCenter[1] := FRotationCenter[1];
}
Result.camX0 := camX0;
Result.camY0 := camY0;
Result.camW := camW;
Result.camH := camH;
Result.bws := bws;
Result.bhs := bhs;
Result.cosa := cosa;
Result.sina := sina;
Result.rcX := rcX;
Result.rcY := rcY;
Result.ColorMap := colorMap;
Result.CriticalSection := CriticalSection;
Result.Nrbatches := FNrBatches;

View File

@ -432,6 +432,9 @@ begin
Result.zoom := 0;
Result.Nick := SheepNick;
Result.URl := SheepURL;
Result.xform[Result.NumXForms].Clear;
Result.xform[Result.NumXForms].symmetry := 1;
end;
end.

View File

@ -78,6 +78,7 @@ type
procedure Bubble; // var[24]
procedure Cylinder; // var[25]
procedure Smoke; // var[26]
procedure Noise; // var[27]
function Mul33(const M1, M2: TMatrix): TMatrix;
function Identity: TMatrix;
@ -123,6 +124,7 @@ type
procedure GetVariable(const name: string; var Value: double);
function ToXMLString: string;
function FinalToXMLString(IsEnabled: boolean): string;
end;
implementation
@ -131,7 +133,7 @@ uses
SysUtils, Math;
const
EPS: double = 1E-10;
EPS: double = 1E-6;
procedure SinCos(const Theta: double; var Sin, Cos: double); // I'm not sure, but maybe it'll help...
asm
@ -1488,6 +1490,39 @@ asm
{$endif}
end;
//--27--///////////////////////////////////////////////////////////////////////
procedure TXForm.Noise;
{$ifndef _ASM_}
var
r, sinr, cosr: double;
begin
SinCos(random * 2*pi, sinr, cosr);
r := vars[27]*random;//(sqrt(sqr(ftx)+sqr(fty)) + eps);
FPx := FPx + {FTx*}r*cosr;
FPy := FPy + {FTy*}r*sinr;
{$else}
asm
mov edx, [ebx + vars]
fld qword ptr [edx + 27*8]
call System.@RandExt
fmulp
call System.@RandExt
fadd st, st
fldpi
fmulp
fsincos
fmul st, st(2)
fmul qword ptr [ebx + FTx]
fadd qword ptr [ebx + FPx]
fstp qword ptr [ebx + FPx]
fmulp
fmul qword ptr [ebx + FTy]
fadd qword ptr [ebx + FPy]
fstp qword ptr [ebx + FPy]
fwait
{$endif}
end;
//***************************************************************************//
procedure TXForm.NextPoint(var px, py, pc: double);
@ -1849,6 +1884,7 @@ begin
FFunctionList[24] := Bubble;
FFunctionList[25] := Cylinder;
FFunctionList[26] := Smoke;
FFunctionList[27] := Noise;
//registered
for i := 0 to High(FRegVariations) do
@ -1924,6 +1960,34 @@ begin
Result := Result + '/>';
end;
function TXForm.FinalToXMLString(IsEnabled: boolean): string;
var
i, j: integer;
Name: string;
Value: double;
begin
result := Format(' <finalxform enabled="%d" color="%g" symmetry="%g" ',
[ifthen(IsEnabled, 1, 0), color, symmetry]);
for i := 0 to nrvar - 1 do begin
if vars[i] <> 0 then
Result := Result + varnames(i) + format('="%g" ', [vars[i]]);
end;
Result := Result + Format('coefs="%g %g %g %g %g %g" ', [c[0,0], c[0,1], c[1,0], c[1,1], c[2,0], c[2,1]]);
if (p[0,0]<>1) or (p[0,1]<>0) or(p[1,0]<>0) or (p[1,1]<>1) or (p[2,0]<>0) or (p[2,1]<>0) then
Result := Result + Format('post="%g %g %g %g %g %g" ', [p[0,0], p[0,1], p[1,0], p[1,1], p[2,0], p[2,1]]);
for i := 0 to High(FRegVariations) do begin
if vars[i+NRLOCVAR] <> 0 then
for j:= 0 to FRegVariations[i].GetNrVariables -1 do begin
Name := FRegVariations[i].GetVariableNameAt(j);
FRegVariations[i].GetVariable(Name,Value);
Result := Result + Format('%s="%g" ', [name, value]);
end;
end;
Result := Result + '/>';
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.SetVariable(const name: string; var Value: double);
var

View File

@ -6,7 +6,7 @@ uses
BaseVariation;
const
NRLOCVAR = 26;
NRLOCVAR = 28;
function NrVar: integer;
function Varnames(const index: integer): String;
@ -60,8 +60,9 @@ const
'fan',
'eyefish',
'bubble',
'cylinder'
// 'smoke' - variation disabled... for now :)
'cylinder',
'smoke',
'noise'
);
begin
if Index < NRLOCVAR then