Results 1 to 6 of 6

Thread: Use OpenGL from TThread with delphi2005?

  1. #1

    Use OpenGL from TThread with delphi2005?

    Delphi 2005 win32
    DGLOpenGL
    TThread
    -------------------------------------------------------------------------------------

    I am trying to use opengl from an thread. Unfortunately all i get is a black screen. All code seems to execute. Thanks for your help in advance.

    Code:
    unit OpenGLTemplateForm;
    
    interface
    
    uses
     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls, ExtCtrls, ComCtrls, DglOpenGL;
    
    type
      TDGLForm = class(TForm)
        procedure FormKeyPress(Sender: TObject; var Key: Char);
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
       TOpenGLRender = class(TThread)
       public
          destructor Destroy; override;
          procedure Init(aHandle: cardinal);
          procedure Draw;
          procedure Stop;
          procedure Execute; override;
       end;
    
    var
      DGLForm: TDGLForm;
      OpenGLRender: TOpenGLRender;
      DC:HDC;
      RC:HGLRC;
      angle: integer;
    
    
    implementation
    
    {$R *.DFM}
    
    function getNormal(p1,p2,p3:TGLArrayf3):TGLArrayf3;
    var a,b:TGLArrayf3;
    begin
     a[0]:=p2[0]-p1[0]; a[1]:=p2[1]-p1[1]; a[2]:=p2[2]-p1[2];
     b[0]:=p3[0]-p1[0]; b[1]:=p3[1]-p1[1]; b[2]:=p3[2]-p1[2];
     result[0]:=a[1]*b[2]-a[2]*b[1];
     result[1]:=a[2]*b[0]-a[0]*b[2];
     result[2]:=a[0]*b[1]-a[1]*b[0];
    end;
    
    //TOpenGLRender
    
    destructor TOpenGLRender.Destroy;
    begin
      inherited;
    end;
    
    procedure TOpenGLRender.Execute;
    begin
      while not terminated do
      begin
        Draw;
        sleep(1);
      end;
    end;
    
    procedure TOpenGLRender.Init(aHandle: cardinal);
    const
      light0_position:TGLArrayf4=( -8.0, 8.0, -16.0, 0.0);
      ambient:  TGLArrayf4=( 0.3, 0.3, 0.3, 0.3);
    begin
    
      InitOpenGL; // Initialize DglOpenGL
    
      DC := GetDC(aHandle);
      // Create RenderContext (32 Bit Pixel, 24 Bit DepthBuffer, Doublebuffering)
      RC := CreateRenderingContext(DC, [opDoubleBuffered], 32, 24, 0, 0, 0, 0);
      // Activate RenderContext
      ActivateRenderingContext(DC, RC);
    
      // set viewing projection
      glMatrixMode(GL_PROJECTION);
      glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0);
    
      // position viewer
      glMatrixMode(GL_MODELVIEW);
    
      // Active DepthBuffer
      glEnable(GL_DEPTH_TEST);
      glDepthFunc(GL_LESS);
    
      // Set lighting
      glEnable(GL_LIGHTING);
      glLightfv(GL_LIGHT0, GL_POSITION, @light0_position);
      glLightfv(GL_LIGHT0, GL_AMBIENT, @ambient);
      glEnable(GL_LIGHT0);
    
      // Set clear background color
      glClearColor(0,0,0,0);
    end;
    
    procedure TOpenGLRender.Draw;
    const
      D=1.5;
      H1=D/1.732;
      H2=D*1.732-H1; // D/H = tg(30) = 1/sqrt(3)
      HY=3.0;
      //vertexes
      a1:TGLArrayf3=(-D, 0, -H1);
      a2:TGLArrayf3=(D, 0, -H1);
      a3:TGLArrayf3=(0, 0, H2);
      a4:TGLArrayf3=(0, HY, 0);
    var
      n1, n2, n3, n4: TGLArrayf3;   //normals
    begin
      angle:=angle+1;
      n1 := getNormal(a1,a3,a2);
      n2 := getNormal(a1,a2,a4);
      n3 := getNormal(a2,a3,a4);
      n4 := getNormal(a3,a1,a4);
      glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
      glEnable(GL_NORMALIZE);
      glShadeModel(GL_FLAT);
      glCullFace(GL_BACK);
      glLoadIdentity;
      glTranslatef(0.0, 0.0, -12.0);
      glRotatef(angle, 0.0, 1.0, 0.0);
      glBegin(GL_TRIANGLES);
        glNormal3fv(@n1);
        glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a3);
        glNormal3fv(@n2);
        glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a4);
        glNormal3fv(@n3);
        glVertex3fv(@a2); glVertex3fv(@a3); glVertex3fv(@a4);
        glNormal3fv(@n4);
        glVertex3fv(@a3); glVertex3fv(@a1); glVertex3fv(@a4);
      glEnd;
      SwapBuffers(DC);
    end;
    
    procedure TOpenGLRender.Stop;
    begin
    end;
    
    //TDGLForm
    
    procedure TDGLForm.FormCreate(Sender: TObject);
    begin
      DecimalSeparator:='.'; //always use . as decimal seperator
      OpenGLRender := TOpenGLRender.Create(true);
      OpenGLRender.Init(Handle);
      OpenGLRender.Resume;
    end;
    
    procedure TDGLForm.FormDestroy(Sender: TObject);
    begin
      OpenGLRender.Suspend;
      OpenGLRender.Free;
      DeactivateRenderingContext; // Deactivate RenderContext
      wglDeleteContext(RC); //Delete RenderContext
      ReleaseDC(Handle, DC);
    end;
    
    procedure TDGLForm.FormKeyPress(Sender: TObject; var Key: Char);
    begin
      case Key of
        #27 : Close;
      end;
    end;
    
    end.
    http://3das.noeska.com - create adventure games without programming

  2. #2
    PGD Community Manager AthenaOfDelphi's Avatar
    Join Date
    Dec 2004
    Location
    South Wales, UK
    Posts
    1,245
    Blog Entries
    2

    Use OpenGL from TThread with delphi2005?

    Hi noeska,

    I'm not 100% sure of the reason why its not working as I haven't played around with multi-threaded rendering, but I think it has something to do with the creation of the rendering context.

    As your code is laid out at the moment, the init routine is called within the context of the main VCL thread, not the rendering thread.

    Maybe what you should do, is store the handle as a property and call Init as the first thing you do in the execute method. Then the rendering context will be created in the context of the thread thats trying to use it.

    Like I say, I'm not 100% sure as I haven't played around that much with multi-threaded rendering. At the very least, its worth a shot as its not a massive change.... if it doesn't work, then I'm wrong and you've not wasted too much time.

    If you do try this, please let me know how you get on.
    :: AthenaOfDelphi :: My Blog :: My Software ::

  3. #3
    PGD Community Manager AthenaOfDelphi's Avatar
    Join Date
    Dec 2004
    Location
    South Wales, UK
    Posts
    1,245
    Blog Entries
    2

    Use OpenGL from TThread with delphi2005?

    In fact... I've just tried it... dglOpenGL on BDS 2006, and making the changes I suggested seems to work.

    Here's the unit I ended up with....

    [pascal]
    unit unitOpenGLTemplateForm;

    interface

    uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    StdCtrls, ExtCtrls, ComCtrls, DglOpenGL;

    type
    TdglForm = class(TForm)
    procedure FormKeyPress(Sender: TObject; var Key: Char);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    private
    { Private declarations }
    public
    { Public declarations }
    end;

    TOpenGLRender = class(TThread)
    protected
    fTargetHandle : THandle;

    fDC : HDC;
    fRC : HGLRC;

    procedure Execute; override;

    procedure init;
    procedure deinit;
    public
    destructor Destroy; override;

    procedure Draw;

    property targetHandle:THandle read fTargetHandle write fTargetHandle;

    end;

    var
    dglForm: TdglForm;

    OpenGLRender: TOpenGLRender;
    angle: integer;


    implementation

    {$R *.DFM}

    function getNormal(p1,p2,p3:TGLArrayf3):TGLArrayf3;
    var a,b:TGLArrayf3;
    begin
    a[0]:=p2[0]-p1[0]; a[1]:=p2[1]-p1[1]; a[2]:=p2[2]-p1[2];
    b[0]:=p3[0]-p1[0]; b[1]:=p3[1]-p1[1]; b[2]:=p3[2]-p1[2];
    result[0]:=a[1]*b[2]-a[2]*b[1];
    result[1]:=a[2]*b[0]-a[0]*b[2];
    result[2]:=a[0]*b[1]-a[1]*b[0];
    end;

    //TOpenGLRender

    destructor TOpenGLRender.Destroy;
    begin
    inherited;
    end;

    procedure TOpenGLRender.Execute;
    begin
    init;

    while not terminated do
    begin
    Draw;
    sleep(1);
    end;

    deinit;
    end;

    procedure TOpenGLRender.deinit;
    begin
    DeactivateRenderingContext; // Deactivate RenderContext
    wglDeleteContext(fRC); //Delete RenderContext
    ReleaseDC(fTargetHandle, fDC);
    end;

    procedure TOpenGLRender.Init;
    const
    light0_position:TGLArrayf4=( -8.0, 8.0, -16.0, 0.0);
    ambient: TGLArrayf4=( 0.3, 0.3, 0.3, 0.3);
    begin

    InitOpenGL; // Initialize DglOpenGL

    fDC := GetDC(fTargetHandle);
    // Create RenderContext (32 Bit Pixel, 24 Bit DepthBuffer, Doublebuffering)
    fRC := CreateRenderingContext(fDC, [opDoubleBuffered], 32, 24, 0, 0, 0, 0);
    // Activate RenderContext
    ActivateRenderingContext(fDC, fRC);

    // set viewing projection
    glMatrixMode(GL_PROJECTION);
    glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0);

    // position viewer
    glMatrixMode(GL_MODELVIEW);

    // Active DepthBuffer
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

    // Set lighting
    glEnable(GL_LIGHTING);
    glLightfv(GL_LIGHT0, GL_POSITION, @light0_position);
    glLightfv(GL_LIGHT0, GL_AMBIENT, @ambient);
    glEnable(GL_LIGHT0);

    // Set clear background color
    glClearColor(0,0,0,0);
    end;

    procedure TOpenGLRender.Draw;
    const
    D=1.5;
    H1=D/1.732;
    H2=D*1.732-H1; // D/H = tg(30) = 1/sqrt(3)
    HY=3.0;
    //vertexes
    a1:TGLArrayf3=(-D, 0, -H1);
    a2:TGLArrayf3=(D, 0, -H1);
    a3:TGLArrayf3=(0, 0, H2);
    a4:TGLArrayf3=(0, HY, 0);
    var
    n1, n2, n3, n4: TGLArrayf3; //normals
    begin
    angle:=angle+1;
    n1 := getNormal(a1,a3,a2);
    n2 := getNormal(a1,a2,a4);
    n3 := getNormal(a2,a3,a4);
    n4 := getNormal(a3,a1,a4);
    glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
    glEnable(GL_NORMALIZE);
    glShadeModel(GL_FLAT);
    glCullFace(GL_BACK);
    glLoadIdentity;
    glTranslatef(0.0, 0.0, -12.0);
    glRotatef(angle, 0.0, 1.0, 0.0);
    glBegin(GL_TRIANGLES);
    glNormal3fv(@n1);
    glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a3);
    glNormal3fv(@n2);
    glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a4);
    glNormal3fv(@n3);
    glVertex3fv(@a2); glVertex3fv(@a3); glVertex3fv(@a4);
    glNormal3fv(@n4);
    glVertex3fv(@a3); glVertex3fv(@a1); glVertex3fv(@a4);
    glEnd;
    SwapBuffers(fDC);
    end;



    procedure TdglForm.FormCreate(Sender: TObject);
    begin
    DecimalSeparator:='.'; //always use . as decimal seperator
    OpenGLRender := TOpenGLRender.Create(true);
    OpenGLRender.targetHandle:=self.handle;
    OpenGLRender.Resume;
    end;

    procedure TdglForm.FormDestroy(Sender: TObject);
    begin
    OpenGLRender.Terminate;
    OpenGLRender.WaitFor;
    OpenGLRender.Free;
    end;

    procedure TdglForm.FormKeyPress(Sender: TObject; var Key: Char);
    begin
    case Key of
    #27 : Close;
    end;
    end;

    end.
    [/pascal]
    :: AthenaOfDelphi :: My Blog :: My Software ::

  4. #4

    Use OpenGL from TThread with delphi2005?

    Yes it works i just finished modifying my version the way you suggested and it works. Thanks.
    http://3das.noeska.com - create adventure games without programming

  5. #5

    Use OpenGL from TThread with delphi2005?

    Should i use:
    Code:
      OpenGLRender.Terminate;
      OpenGLRender.WaitFor;
      OpenGLRender.Free;
    or

    Code:
      OpenGLRender.Suspend;
      OpenGLRender.Free;
    http://3das.noeska.com - create adventure games without programming

  6. #6
    PGD Community Manager AthenaOfDelphi's Avatar
    Join Date
    Dec 2004
    Location
    South Wales, UK
    Posts
    1,245
    Blog Entries
    2

    Use OpenGL from TThread with delphi2005?

    There are a multitude of ways you can handle it. You can set the 'freeOnTerminate' property and then just terminate it... it will free it up itself. You can do what I've done... you can do what you've done (I think... the reason I say I think, is because I'm not sure how free handles suspended threads - whether it resumes them or not)

    I think its very much a personal preference... though having said that, I use different methods for different situations, so just tinker... you'll find a solution thats right for you and the situation you are using the threads in.
    :: AthenaOfDelphi :: My Blog :: My Software ::

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •