home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue69 / OpenGL / BasicOpenGL.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2001-04-16  |  15.1 KB  |  527 lines

  1. unit BasicOpenGL;
  2.  
  3. interface
  4.   Uses Windows, Controls, Messages, Dialogs, Forms, Classes, ComCtrls,//standard units
  5.        Opengl12,                          //OpenGL header unit from Mike  Lishke
  6.        Geometry,                          //support unit with data constructs
  7.        DGLUT;                             //OpenGL utility Library
  8.  
  9.  Type
  10.    TBasicOpenGL = class;
  11.    TOpenGLObject = Class;
  12.  
  13.    TGLUpdateTreeEventNotify = Procedure Of Object;  //Event used to update a treeview
  14.  
  15.    TGLPoint       = packed Record
  16.      X, Y, Z: TGLDouble;
  17.    End;
  18.  
  19.    TGLColorVal     = Array [0..3] Of TGlFloat;
  20.  
  21.    TSelectMode =(tsMouseSelect, //will set the select flag to true on objects found
  22.                  tsWindowCull); //will set the viewCull flag to false on those in the view
  23.  
  24.    TBasicOpenGL    = Class(TWinControl)
  25.    Private
  26.       FRenderDC       : HDC;             //create and hold device context for the session
  27.       FHRC            : HGLRC;           //rendering context assigned to device context and windows handle
  28.  
  29.     procedure SetViewAngle(const Value: Single);          // used to tag initial setup been done
  30.  
  31.    Protected
  32.       FRootObject     : TOpenGLObject;
  33.       FViewAngle      : Single;
  34.       FOnUpdateTreeView   : TGLUpdateTreeEventNotify;
  35.       FViewPosition   : Integer;
  36.  
  37.  //override original functionality to get the OpenGL window running
  38.       Procedure WMPaint(Var Message: TWMPaint); Message WM_PAINT;
  39.       procedure WMSize(var Message: TWMSize); message WM_SIZE;
  40.       Procedure WMEraseBkgnd(Var Message: TWmEraseBkgnd); Message WM_ERASEBKGND;
  41.       Procedure WMSetFocus(Var Message: TWMSetFocus); Message WM_SETFOCUS;
  42.  
  43.       Procedure DestroyWindowHandle; Override;
  44.       Procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); Override;
  45.  
  46.       Procedure GLShutDown;              //GL session shutdown
  47.       Procedure ClearWindow;             //clear the OpenGL window
  48.       Procedure GetSelectList(X,Y:Integer; SelectMode :TSelectMode); //returns a list of objects
  49.       Procedure RenderWindow;  Virtual;          //Render the window similar to Paint
  50.  
  51.    Public
  52.       Constructor Create(Owner:TComponent);Override;
  53.  
  54.       Procedure GLStartUp;               // GL startup
  55.       Procedure CullView;                //remove all objects not in the current view frame from the draw list
  56.  
  57.       Property RootObject:TOpenGLObject read FRootObject write FRootObject;
  58.       Property ViewAngle:Single Read fViewAngle write SetViewAngle;
  59.  
  60.       Property OnUpdateTreeView : TGLUpdateTreeEventNotify Read FOnUpdateTreeView write FOnUpdateTreeView;
  61.       Property ViewPosition:Integer read fViewPosition write fViewPosition;
  62.    end;
  63.  
  64.   TOpenGLObject = Class (TObject)
  65.   //class will be attached to the TreeNodes as Data as the TTreeNode is not extendable
  66.   private
  67.     procedure setSelected(const Value: Boolean);
  68.     procedure setViewCulled(const Value: Boolean);
  69.     procedure settext(const Value: String);
  70.     function getText: String;
  71.     function GetChild(Index: Integer): TOpenGLObject;
  72.     function GetChildrenCount: Integer;
  73.   Protected
  74.     FParent        : TOpenGLObject;  //parent in the scene
  75.     FChildrenList  : TList;       //holds all children
  76.     FViewCulled : Boolean;  //if true then this object is not currently in the view
  77.     FSelected   : Boolean;  // true if this is selected
  78.     FTranslation: TGLPoint; // a translation which will effect all the children
  79.     FRotation,             //a rotation about X,Y and Z axis
  80.     FScale      : TGLPoint;//a scale in X, Y and Z directions
  81.     FText       : String;
  82.     FMode       : Integer;
  83.   Public
  84.     Constructor Create;
  85.     Destructor Destroy;Override;
  86.     Procedure DoRender;
  87.     Function AddChild: TOpenGLObject;
  88.     Procedure BuildTreeView(ATreeView:TTreeView;ParentNode:TTreeNode);
  89.     Procedure CullAllObjects(Value:Boolean);  //set all objects as NOT visible;
  90.  
  91.  //access properties
  92.     Property ChildCount:Integer Read GetChildrenCount;
  93.     Property Child[Index: Integer]: TOpenGLObject Read GetChild;
  94.     Property ViewCulled : Boolean read FViewCulled write setViewCulled ;
  95.     Property Selected  : Boolean  read FSelected  write setSelected;
  96.     Property Translation: TGLPoint read FTranslation write FTranslation ;
  97.     Property Rotation: TGLPoint read FRotation write FRotation ;
  98.     Property Scale: TGLPoint read FScale write FScale ;
  99.     Property Text:String read getText write settext;
  100.     Property Mode:Integer Read fMode write fMode;
  101.   end;
  102.  
  103.   const
  104.     glRed     : TGLColorVal = (1, 0, 0, 1);
  105.     glGreen   : TGLColorVal = (0, 1, 0, 1);
  106.     glBlue    : TGLColorVal = (0, 0, 1, 1);
  107.     glGray    : TGLColorVal = (0.8, 0.8, 0.8, 0.5);
  108. implementation
  109.  
  110. { TBasicOpenGL }
  111. procedure TBasicOpenGL.GLShutDown;
  112. begin
  113.    If (wglGetCurrentContext=fHRC) Then
  114.        wglMakeCurrent(0,0) ;
  115.           //if this window  session is active the deactivate
  116.  
  117.    If fHRC<>0 Then
  118.       Begin
  119.          wglDeleteContext(fHRC);  //delete the Rendering context
  120.          fHRC:=0;
  121.       End ;
  122.  
  123.    If fRenderDC<>0 Then
  124.       ReleaseDC(handle,fRenderDC);  //release the device context
  125.  
  126.    fRenderDC:=0;
  127. end;
  128.  
  129. procedure TBasicOpenGL.GLStartUp;
  130. // Startn up the GLSession
  131. Begin { TdvAbstractOpenGL.GLStartUp }
  132.    If fHRC<>0 then exit;
  133.  
  134.    If not HandleAllocated then
  135.       HandleNeeded;            //request a windows handle now.
  136.  
  137.    If not HandleAllocated then exit;//if not assigned a handle then exit
  138.  
  139.    If fRenderDC=0 then
  140.       fRenderDC:=GetDC(handle);  //create a device context for the handle
  141.  
  142.    If fRenderDC=0 Then Exit;     //fail to start
  143.  
  144. // Create the Render Context for the device context
  145.    fHRC:=CreateRenderingContext(fRenderDC,
  146.                                 [opDoubleBuffered], //use double bufferein to stop flickering
  147.                                 24,    //colour bits
  148.                                 1,    //stencil bits
  149.                                 32,  //accum bits
  150.                                 0,0);
  151.  
  152. //handle fail
  153.    If fHRC=0 Then
  154.    Begin
  155.      ReleaseDC(handle, fRenderDC);
  156.      Exit ;
  157.    end;
  158.  
  159.    ActivateRenderingContext(fRenderDC,fHRC); //activate the session
  160.  
  161.    glEnable(GL_DEPTH_TEST);
  162.    glEnable(GL_LINE_SMOOTH);
  163.    glEnable(GL_POLYGON_SMOOTH);
  164.    glDrawBuffer(GL_BACK);
  165. end;
  166.  
  167. Procedure TBasicOpenGL.ClearWindow;
  168. Begin
  169.   glClearColor(0,0,0,0);            //set to black
  170.   glClear(GL_COLOR_BUFFER_BIT or
  171.           GL_DEPTH_BUFFER_BIT);    //clear the depth and color buffers
  172. end;
  173.  
  174. procedure TBasicOpenGL.RenderWindow;
  175. begin
  176.   ClearWindow;            //clear the window
  177.   If Height=0 then exit;
  178.   glViewport(0,0,width,Height);    //set the viewport size
  179.   glMatrixMode(GL_PROJECTION);
  180.   glLoadIdentity;
  181.   gluperspective(fViewAngle,width/Height,1,500);  //set to perspective view
  182.   glMatrixMode(GL_MODELVIEW);
  183.   glLoadIdentity;
  184.   Case fViewPosition of
  185.     0:  glTranslatef(0,0,-50);          //move the viewer 50 units up the z axis looking down
  186.     1:  //above
  187.     Begin
  188.       glTranslatef(0,0,-50);
  189.       glRotatef(15,0,1,0);
  190.       glRotatef(25,1,0,0);
  191.     end;
  192.     2:     //side
  193.     Begin
  194.       glTranslatef(0,0,-50);
  195.       glRotatef(90,0,1,0);
  196.     end;
  197.     3:  //behind
  198.     Begin
  199.       glTranslatef(0,0,-50);
  200.       glRotatef(160,0,1,0);
  201.       glRotatef(35,1,0,0);
  202.     end;
  203.     else glTranslatef(0,0,-50);
  204.   end;//case
  205.  
  206.   If fRootObject<>Nil then
  207.      fRootObject.DoRender;
  208.   glFlush;                //flush the GL pipeline
  209.   SwapBuffers(fRenderDC); //swap the buffers
  210. end;
  211.  
  212. procedure TBasicOpenGL.WMPaint(var Message: TWMPaint);
  213. begin
  214.     ValidateRect(handle,nil);
  215.     ControlState:=ControlState+[csCustomPaint];
  216.     RenderWindow;
  217.     ControlState:=ControlState-[csCustomPaint];
  218.     Message.Result:=1;
  219. end;
  220. procedure TBasicOpenGL.DestroyWindowHandle;
  221. begin
  222.   GLShutDown;
  223.   inherited;
  224. end;
  225.  
  226. procedure TBasicOpenGL.WMEraseBkgnd(var Message: TWmEraseBkgnd);
  227. begin
  228.    If (fHRC<>0) Then
  229.       Message.Result:=1;
  230. end;
  231.  
  232. procedure TBasicOpenGL.GetSelectList(X, Y: Integer;
  233.   SelectMode: TSelectMode);
  234. Var
  235.    SelectArray  : Array[0..256] of TGLuint;
  236.    Hits         : Integer;
  237.    fviewport    : TVector4i;
  238.  
  239.     Procedure  ProcessHits;
  240.       Var I,ArrayCount:Integer;
  241.           aPtr:Pointer;
  242.  
  243.           Procedure ProcessHit;
  244.             Var HitCount,I:Integer;
  245.           Begin
  246.             HitCount:=SelectArray[ArrayCount];
  247.             Inc(ArrayCount);
  248.             If HitCount=0 then exit;
  249.             Inc(ArrayCount);//Z valu min
  250.             Inc(ArrayCount);//Z Value Max
  251.             For i:=1 to HitCount do
  252.             Begin
  253.               aPtr:=Ptr(SelectArray[ArrayCount]); Inc(ArrayCount);
  254.               If (aPtr<>Nil) and
  255.                  (TObject(aPtr) is TOpenGLObject) then
  256.                 Case SelectMode of
  257.                    tsMouseSelect: TOpenGLObject(aPtr).Selected:=True;
  258.                    tsWindowCull : TOpenGLObject(aPtr).ViewCulled:=False;
  259.                 end;//case
  260.             end;//hitcount loop
  261.           end;
  262.  
  263.       Begin
  264.         ArrayCount:=0;
  265.         For i:=1 to Hits do
  266.             ProcessHit;
  267.       end;
  268.  
  269. begin
  270.   If height<=0 then exit;
  271.   Hits:=0 ;
  272.   FillChar (SelectArray[0],SizeOf(SelectArray),0);
  273.  
  274.   glSelectBuffer(256,@SelectArray[0]);
  275.   glRenderMode(GL_Select);
  276.  
  277.   fviewport[0]:=0;
  278.   fviewport[1]:=0;
  279.   fviewport[2]:=Width;
  280.   fviewport[3]:=Height;
  281.  
  282.   If (SelectMode= tsMouseSelect) then
  283.   Begin
  284.     glMatrixMode(GL_PROJECTION);
  285.     glPushMatrix;
  286.     glLoadIdentity;
  287.     gluPickMatrix(X, Height-Y, 10, 10, fViewPort);
  288.     gluperspective(fViewAngle,width/height,1,500)
  289.   end;
  290.  
  291.   glInitNames;
  292.   glLoadName(0);
  293.  
  294.   glMatrixMode(GL_MODELVIEW);
  295.  
  296.   If SelectMode=tsWindowCull then
  297.      If fRootObject<>Nil then
  298.         fRootObject.CullAllObjects(false);
  299.  
  300.   If fRootObject<>Nil then
  301.      fRootObject.DoRender;
  302.  
  303. //get the hits data
  304.   Hits:= glRenderMode(GL_Render);
  305. //tidy up
  306.   If (SelectMode= tsMouseSelect) then
  307.   Begin
  308.     glMatrixMode(GL_PROJECTION);
  309.     glPopMatrix;
  310.     glMatrixMode(GL_MODELVIEW);
  311.   end;
  312.  
  313.   If SelectMode=tsMouseSelect then
  314.       If FRootObject<>Nil then
  315.          FRootObject.Selected:=False;
  316.  
  317.   If Hits>0 then
  318.   Begin
  319.     If SelectMode=tsWindowCull then
  320.        If fRootObject<>Nil then
  321.           fRootObject.CullAllObjects(True);
  322.     ProcessHits;
  323.   end;
  324.  
  325.   If Assigned(FOnUpdateTreeView) then
  326.      FOnUpdateTreeView;
  327.   Invalidate;
  328. end;
  329.  
  330. procedure TBasicOpenGL.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
  331.   Y: Integer);
  332. begin
  333.   inherited;
  334.   GetSelectList(X,Y,tsMouseSelect);
  335. end;
  336.  
  337. constructor TBasicOpenGL.Create(Owner: TComponent);
  338. begin
  339.   inherited;
  340.   fViewAngle:= 25;
  341. end;
  342.  
  343. procedure TBasicOpenGL.SetViewAngle(const Value: Single);
  344. begin
  345.   fViewAngle := Value;
  346.   If fViewAngle>179 then
  347.      fViewAngle:=179 ;  // limit the angle to less than 180
  348.   RenderWindow;
  349.   CullView;
  350.   If Assigned(FOnUpdateTreeView) then
  351.      FOnUpdateTreeView;
  352. end;
  353.  
  354. procedure TBasicOpenGL.CullView;
  355. begin
  356.   GetSelectList(0,0,tsWindowCull);
  357. end;
  358.  
  359. procedure TBasicOpenGL.WMSize(var Message: TWMSize);
  360. begin
  361.   Inherited;
  362.   If fHRC=0 then exit;
  363.   CullView;
  364.   If Assigned(FOnUpdateTreeView) then
  365.      FOnUpdateTreeView;
  366. end;
  367.  
  368. procedure TBasicOpenGL.WMSetFocus(var Message: TWMSetFocus);
  369. begin
  370.   Inherited;
  371.   If fHRC=0 then exit;
  372.   ActivateRenderingContext(fRenderDC,fHRC); //activate the session
  373. end;
  374.  
  375. { TOpenGLObject }
  376. function TOpenGLObject.AddChild: TOpenGLObject;
  377. begin
  378.   Result:=TOpenGLObject.Create;
  379.   Result.FParent:=self;
  380.   FChildrenList.Add(Result);
  381. end;
  382.  
  383. procedure TOpenGLObject.BuildTreeView(ATreeView: TTreeView;
  384.                                       ParentNode: TTreeNode);
  385. Var  Node:TTreeNode;
  386.      i:Integer;
  387. begin
  388.   If aTreeView=Nil then exit;
  389.   If ParentNode=nil then
  390.     Node:=aTreeView.Items.AddObject( ParentNode,Text,self)
  391.   else
  392.     Node:=aTreeView.Items.AddChildObject( ParentNode,Text,self);
  393.   If ChildCount>0 then
  394.     For i:=0 to ChildCount-1 do
  395.       Child[i].BuildTreeView(ATreeView, Node);
  396. end;
  397.  
  398. constructor TOpenGLObject.Create;
  399. begin
  400.   FParent       :=nil;                //parent in the scene
  401.   FChildrenList := TList.Create;       //holds all children
  402.   FScale.X:=1;
  403.   FScale.Y:=1;
  404.   FScale.Z:=1;
  405.   Inherited;
  406. end;
  407.  
  408. procedure TOpenGLObject.CullAllObjects(Value:Boolean);
  409. Var i:Integer;
  410. begin
  411.   FViewCulled:=Value;
  412.   If ChildCount=0 then exit;
  413.   For i:=0 to ChildCount-1 do
  414.     child[i].CullAllObjects(Value);
  415. end;
  416.  
  417. destructor TOpenGLObject.Destroy;
  418.  Var I:Integer;
  419. begin
  420.   If (FChildrenList.Count>0) then
  421.     For i:=0 to FChildrenList.count-1 do
  422.     Begin
  423.       TOpenGLObject(FChildrenList.Items[i]).Free;
  424.     end;
  425.   FChildrenList.Clear;
  426.   FChildrenList.Free;
  427.   inherited;
  428. end;
  429.  
  430. procedure TOpenGLObject.DoRender;
  431.  Var i:Integer;
  432. begin
  433.   If FViewCulled then exit;     // no need to render further
  434.   glPushMatrix;                 //copy current matrix
  435.   glTranslated(fTranslation.X,fTranslation.Y, fTranslation.Z);
  436.  
  437.   glRotated(fRotation.X,1,0,0);
  438.   glRotated(fRotation.Y,0,1,0);
  439.   glRotated(fRotation.Z,0,0,1);
  440.  
  441.   glPushMatrix;                 //copy current matrix
  442.   glScaled(fScale.X,fScale.Y,fScale.Z);//only scale the local object
  443.  
  444.   glPushName(Integer(self));    //push Self as Object name/locator
  445.  
  446.   Case fMode of
  447.     1: Begin
  448.          glColor3fv(@glRed);
  449.          glutSolidSphere(0.5,20,20);  //render as a sphere
  450.        end;
  451.     2: Begin
  452.          glColor3fv(@glGreen);
  453.          glutSolidCube(1);          //render as a cube
  454.        end;
  455.     3: Begin
  456.          glColor3fv(@glBlue);
  457.          glutSolidCylinder(0.5,1,10,10);   //render as a cylinder
  458.        end;
  459.   end; //case
  460.  
  461.   if FSelected then      // if the object tagged as selected then draw a bounding box
  462.   Begin
  463.     glColor3fv(@glGray);
  464.     glutWireCube(1.2);
  465.   end;
  466.  
  467.   glPopName;                  //pop name back of name stack
  468.   glPopMatrix;                //restore the original matrix
  469.  
  470.   If FChildrenList.Count>0 then          //if child count>0 then render the children
  471.   Begin
  472.     For i:=0 to FChildrenList.count-1 do
  473.         Child[i].DoRender;                       //recursive call down the tree
  474.   end;
  475.   glPopMatrix;                //restore the original matrix
  476.  
  477.  
  478. end;
  479.  
  480. function TOpenGLObject.GetChild(Index: Integer): TOpenGLObject;
  481. begin
  482.   Result:=nil;
  483.   If (Index<0) or
  484.      (Index>= FChildrenList.count) then exit;
  485.   Result:=TOpenGLObject(FChildrenList.Items[index]);
  486. end;
  487.  
  488. function TOpenGLObject.GetChildrenCount: Integer;
  489. begin
  490.   Result:= FChildrenList.count;
  491. end;
  492.  
  493. function TOpenGLObject.getText: String;
  494. begin
  495.   Result:=fText;
  496.   If fViewCulled then
  497.      Result:=Result+' (Not in View)';
  498.   If fSelected then
  499.   Result:=Result+' (Selected)';
  500. end;
  501.  
  502. procedure TOpenGLObject.setSelected(const Value: Boolean);
  503.  Var i:Integer;
  504. begin
  505.   //selection is passed down the tree
  506.   FSelected := Value;
  507.   If ChildCount>0 then
  508.      for i:=0 to ChildCount-1 do
  509.        Child[i].Selected:= FSelected;
  510. end;
  511.  
  512. procedure TOpenGLObject.settext(const Value: String);
  513. begin
  514.   fText:=Value;
  515. end;
  516.  
  517. procedure TOpenGLObject.setViewCulled(const Value: Boolean);
  518. begin
  519. //  View culling if false is passed back up the tree
  520.   FViewCulled := Value;
  521.   If fParent=nil then exit;
  522.   If fViewCulled then exit;
  523.   FParent.ViewCulled:=false;
  524. end;
  525.  
  526. end.
  527.