GLGraph - z:=f(x,y)
disclaimer
For a sample application lookup glgraph_test
the code
{ GLScene component
generates the OpenGL primitives to draw a function z:=f(x,y)
which is external to this unit.
eg.
function GLGraph_callback(x,y:single):single;
begin
result:=sin(2*pi*x)*cos(2*pi*y);
end;
myGraph.callback:=GLGraph_callback;
the functionvalues are buffered in a Float2DArray, as the function
may be more complicated and timeconsuming than the above example.
declare :
USES ..,Geometry, GLTexture, GLGraph,..
TForm=class(..)
..
public
..
MyGraph:TGLGraph;
end;
creation : ( requires a dummycube )
mygraph:=TGLGraph(Dummycube1.addNewchild((TGLGraph)));
mygraph.callback:=GLGraph_callback;
mygraph.xlow:=0; mygraph.ylow:=0;
mygraph.xhigh:=5; mygraph.yhigh:=5;
mygraph.dx:=0.05; mygraph.dy:=0.05;
mygraph.showaxes:=true;
mygraph.lowcolor:=clrBlack;
mygraph.highcolor:=clrYellow;
mygraph.getvalues;
mygraph.transformationmode:=tmParentNoPos;
}
unit GLGraph;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
OpenGL12, Geometry, GLTexture, GLMisc, GLScene;
type
ZofXY=function(x,y:single):single; // the external callback for the z:=f(x,y)
Float2DArray=class // internal storage 2D Array of single
protected
fdata:pointer;
fsizex,fsizey:integer;
function getitem(index1,Index2:integer):single;
procedure setitem(index1,Index2:integer;j:single);
public
property Q[index1,Index2:integer]:single read getitem write setitem; default;
constructor create(x,y:integer);
destructor destroy; override;
procedure clear;
published
property sizex:integer read fsizex;
property sizey:integer read fsizey;
end;
TGLGraph = class(TGLSceneObject)
private
{ Private declarations }
fcallback:ZofXY;
fdata:Float2DArray;
fxlow,fxhigh,fylow,fyhigh,fdx,fdy:TGLFloat;
fcenter:boolean;
fminz,fmaxz:single; // colorspread between them, filled by getvalues
flowcolor,fhighcolor:TVector;
protected
{ Protected declarations }
public
{ Public declarations }
constructor create(AOwner: TComponent); override;
destructor destroy; override;
procedure getvalues; // using the callback
procedure BuildList; override;
procedure Assign(Source: TPersistent); override;
property callback:ZofXY read fcallback write fcallback; // z:=f(x,y)
property lowcolor:TVector read flowcolor write flowcolor; // lower z color
property highcolor:TVector read fhighcolor write fhighcolor; // upper z color
published
{ Published declarations }
property XLow:TGLFloat read fxlow write fxlow; // lower x
property XHigh:TGLFloat read fxhigh write fxhigh; // upper x
property YLow:TGLFloat read fylow write fylow; // lower y
property YHigh:TGLFloat read fyhigh write fyhigh; // upper y
property dx:TGLFloat read fdx write fdx; // how many increments
property dy:TGLFloat read fdy write fdy; // how many increments
property center:boolean read fcenter write fcenter; // x/y center the graph ?
end;
procedure Register;
implementation
// ... Float2DArray ...........................................
// implements a dynamic 2D array of TGLFloats
type FloatPtr=^TGLFloat;
function Float2DArray.getitem(index1,Index2:integer):TGLFloat;
var p:FloatPtr;
k:integer absolute p;
begin
p:=fdata;
k:=k+(index1+Index2*fsizex)*sizeof(TGLFloat);
result:=p^;
end;
procedure Float2DArray.setitem(index1,Index2:integer;j:TGLFloat);
var p:FloatPtr;
k:integer absolute p;
begin
p:=fdata;
k:=k+(index1+Index2*fsizex)*sizeof(TGLFloat);
p^:=j;
end;
constructor Float2DArray.create(x,y:integer);
begin
inherited create;
fsizex:=x; fsizey:=y;
GetMem(fdata,fsizex*fsizey*sizeof(TGLFloat));
end;
destructor Float2DArray.destroy;
begin
FreeMem(fdata,fsizex*fsizey*sizeof(TGLFloat));
inherited destroy;
end;
procedure Float2DArray.clear;
begin
FillChar(fdata^,fsizex*fsizey*sizeof(TGLFloat),0);
end;
//... TGLGraph ...............................................
constructor TGLGraph.create(AOwner: TComponent);
begin
inherited create(AOwner);
fdata:=nil;
fcallback:=nil;
fcenter:=true;
fdx:=0; fdy:=0; fxlow:=0; fylow:=0; fxhigh:=1; fyhigh:=1;
fminz:=0;fmaxz:=1;
flowcolor:=clrNavy;
fhighcolor:=clrYellow;
end;
destructor TGLGraph.destroy;
begin
if (fdata < > nil) then fdata.destroy;
inherited destroy;
end;
procedure TGLGraph.BuildList;
var h,v,xs,ys:integer;
x,y1,y2,z,xh,yh:TGLFLOAT;
color:TVector;
begin
inherited buildlist;
gldisable(GL_CULL_FACE);
ys:=fdata.sizey;
xs:=fdata.sizex;
y1:=fylow;
xh:=(fxlow+fxhigh)/2; // for centering
yh:=(fylow+fyhigh)/2; // for centering
for v:=0 to ys-2 do begin // horizontal strips
glBegin(GL_TRIANGLE_STRIP);
// glColor3f(0.4,0.3,0.5);
y2:=y1+fdy;
x:=fxlow;
for h:=0 to xs-1 do begin
z:=fdata[h,v];
color:=VectorLerp(flowcolor,fhighcolor,(z-fminz)/(fmaxz-fminz));
//glcolor3f(0.2,0.2,0.5+z/2);
glcolor3f(color[0],color[1],color[2]);
if fcenter then glVertex3f(x-xh,y1-yh,z)
else glVertex3f(x,y1,z);
z:=fdata[h,v+1];
if fcenter then glVertex3f(x-xh,y2-yh,z)
else glVertex3f(x,y2,z);
x:=x+fdx;
end;
glEnd;
y1:=y1+fdy;
end;
end;
procedure TGLGraph.getvalues;
var h,v,xs,ys:integer;
x,y,z:single;
begin
if (fdx < > 0) and (fdy < > 0) then begin
xs:=round((fxhigh-fxlow)/dx);
ys:=round((fyhigh-fylow)/dy);
if fdata < > nil then fdata.destroy;
fdata:=Float2DArray.create(xs,ys);
if assigned(fcallback) then begin
fmaxz:=-1e20; fminz:=1e20; // preset
for h:=0 to xs-1 do begin
x:=fxlow+h*fdx;
for v:=0 to ys-1 do begin
y:=fylow+v*fdy;
z:=fcallback(x,y);
if (z > fmaxz) then fmaxz:=z; // get max z
if (z < fminz) then fminz:=z; // get min z
fdata[h,v]:=z;
end;
end;
end; //callback exists
end; // dx,dy < > 0
StructureChanged;
end;
procedure TGLGraph.Assign(Source: TPersistent);
begin
if assigned(Source) and (Source is TGLGraph) then
begin
fcallback:=TGLGraph(Source).fcallback;
fxlow:=TGLGraph(Source).fxlow;
fxhigh:=TGLGraph(Source).fxhigh;
fylow:=TGLGraph(Source).fylow;
fyhigh:=TGLGraph(Source).fyhigh;
fdx:=TGLGraph(Source).fdx;
fdy:=TGLGraph(Source).fdy;
fdata:=nil;
fcenter:=TGLGraph(Source).fcenter;
getvalues;
end;
inherited Assign(Source);
end;
procedure Register;
begin
RegisterComponents('GLScene', [TGLGraph]);
end;
end.
OpenGL
home
last updated: 11.aug.00
Copyright (99,2000) Ing.Büro R.Tschaggelar