DGL
https://delphigl.com/forum/

Render From Thread
https://delphigl.com/forum/viewtopic.php?f=19&t=7389
Seite 1 von 1

Autor:  noeska [ Fr Apr 04, 2008 18:18 ]
Betreff des Beitrags:  Render From Thread

I am trying to do rendering from an thread. Unfortunately all i get is a black screen. I post my code below. Thank for your help in advance.

Code:
  1.  
  2. unit OpenGLTemplateForm;
  3.  
  4. interface
  5.  
  6. uses
  7.  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  8.   StdCtrls, ExtCtrls, ComCtrls, DglOpenGL;
  9.  
  10. type
  11.   TDGLForm = class(TForm)
  12.     procedure FormKeyPress(Sender: TObject; var Key: Char);
  13.     procedure FormCreate(Sender: TObject);
  14.     procedure FormDestroy(Sender: TObject);
  15.   private
  16.     { Private declarations }
  17.   public
  18.     { Public declarations }
  19.   end;
  20.  
  21.    TOpenGLRender = class(TThread)
  22.    public
  23.       destructor Destroy; override;
  24.       procedure Init(aHandle: cardinal);
  25.       procedure Draw;
  26.       procedure Stop;
  27.       procedure Execute; override;
  28.    end;
  29.  
  30. var
  31.   DGLForm: TDGLForm;
  32.   OpenGLRender: TOpenGLRender;
  33.   DC:HDC;
  34.   RC:HGLRC;
  35.   angle: integer;
  36.  
  37.  
  38. implementation
  39.  
  40. {$R *.DFM}
  41.  
  42. function getNormal(p1,p2,p3:TGLArrayf3):TGLArrayf3;
  43. var a,b:TGLArrayf3;
  44. begin
  45.  a[0]:=p2[0]-p1[0]; a[1]:=p2[1]-p1[1]; a[2]:=p2[2]-p1[2];
  46.  b[0]:=p3[0]-p1[0]; b[1]:=p3[1]-p1[1]; b[2]:=p3[2]-p1[2];
  47.  result[0]:=a[1]*b[2]-a[2]*b[1];
  48.  result[1]:=a[2]*b[0]-a[0]*b[2];
  49.  result[2]:=a[0]*b[1]-a[1]*b[0];
  50. end;
  51.  
  52. //TOpenGLRender
  53.  
  54. destructor TOpenGLRender.Destroy;
  55. begin
  56.   inherited;
  57. end;
  58.  
  59. procedure TOpenGLRender.Execute;
  60. begin
  61.   while not terminated do
  62.   begin
  63.     Draw;
  64.     sleep(1);
  65.   end;
  66. end;
  67.  
  68. procedure TOpenGLRender.Init(aHandle: cardinal);
  69. const
  70.   light0_position:TGLArrayf4=( -8.0, 8.0, -16.0, 0.0);
  71.   ambient:  TGLArrayf4=( 0.3, 0.3, 0.3, 0.3);
  72. begin
  73.  
  74.   InitOpenGL; // Initialize DglOpenGL
  75.  
  76.   DC := GetDC(aHandle);
  77.   // Create RenderContext (32 Bit Pixel, 24 Bit DepthBuffer, Doublebuffering)
  78.   RC := CreateRenderingContext(DC, [opDoubleBuffered], 32, 24, 0, 0, 0, 0);
  79.   // Activate RenderContext
  80.   ActivateRenderingContext(DC, RC);
  81.  
  82.   // set viewing projection
  83.   glMatrixMode(GL_PROJECTION);
  84.   glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0);
  85.  
  86.   // position viewer
  87.   glMatrixMode(GL_MODELVIEW);
  88.  
  89.   // Active DepthBuffer
  90.   glEnable(GL_DEPTH_TEST);
  91.   glDepthFunc(GL_LESS);
  92.  
  93.   // Set lighting
  94.   glEnable(GL_LIGHTING);
  95.   glLightfv(GL_LIGHT0, GL_POSITION, @light0_position);
  96.   glLightfv(GL_LIGHT0, GL_AMBIENT, @ambient);
  97.   glEnable(GL_LIGHT0);
  98.  
  99.   // Set clear background color
  100.   glClearColor(0,0,0,0);
  101. end;
  102.  
  103. procedure TOpenGLRender.Draw;
  104. const
  105.   D=1.5;
  106.   H1=D/1.732;
  107.   H2=D*1.732-H1; // D/H = tg(30) = 1/sqrt(3)
  108.   HY=3.0;
  109.   //vertexes
  110.   a1:TGLArrayf3=(-D, 0, -H1);
  111.   a2:TGLArrayf3=(D, 0, -H1);
  112.   a3:TGLArrayf3=(0, 0, H2);
  113.   a4:TGLArrayf3=(0, HY, 0);
  114. var
  115.   n1, n2, n3, n4: TGLArrayf3;   //normals
  116. begin
  117.   angle:=angle+1;
  118.   n1 := getNormal(a1,a3,a2);
  119.   n2 := getNormal(a1,a2,a4);
  120.   n3 := getNormal(a2,a3,a4);
  121.   n4 := getNormal(a3,a1,a4);
  122.   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  123.   glEnable(GL_NORMALIZE);
  124.   glShadeModel(GL_FLAT);
  125.   glCullFace(GL_BACK);
  126.   glLoadIdentity;
  127.   glTranslatef(0.0, 0.0, -12.0);
  128.   glRotatef(angle, 0.0, 1.0, 0.0);
  129.   glBegin(GL_TRIANGLES);
  130.     glNormal3fv(@n1);
  131.     glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a3);
  132.     glNormal3fv(@n2);
  133.     glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a4);
  134.     glNormal3fv(@n3);
  135.     glVertex3fv(@a2); glVertex3fv(@a3); glVertex3fv(@a4);
  136.     glNormal3fv(@n4);
  137.     glVertex3fv(@a3); glVertex3fv(@a1); glVertex3fv(@a4);
  138.   glEnd;
  139.   SwapBuffers(DC);
  140. end;
  141.  
  142. procedure TOpenGLRender.Stop;
  143. begin
  144. end;
  145.  
  146. //TDGLForm
  147.  
  148. procedure TDGLForm.FormCreate(Sender: TObject);
  149. begin
  150.   DecimalSeparator:='.'; //always use . as decimal seperator
  151.   OpenGLRender := TOpenGLRender.Create(true);
  152.   OpenGLRender.Init(Handle);
  153.   OpenGLRender.Resume;
  154. end;
  155.  
  156. procedure TDGLForm.FormDestroy(Sender: TObject);
  157. begin
  158.   OpenGLRender.Suspend;
  159.   OpenGLRender.Free;
  160.   DeactivateRenderingContext; // Deactivate RenderContext
  161.   wglDeleteContext(RC); //Delete RenderContext
  162.   ReleaseDC(Handle, DC);
  163. end;
  164.  
  165. procedure TDGLForm.FormKeyPress(Sender: TObject; var Key: Char);
  166. begin
  167.   case Key of
  168.     #27 : Close;
  169.   end;
  170. end;
  171.  
  172. end.
  173.  

Autor:  Stucuk [ Fr Apr 04, 2008 18:55 ]
Betreff des Beitrags: 

don't you need to setup a viewport?

Code:
  1. if (Height = 0) then                // prevent divide by zero exception
  2.     Height := 1;
  3.   glViewport(0, 0, Width, Height);    // Set the viewport for the OpenGL window
  4.   glMatrixMode(GL_PROJECTION);        // Change Matrix Mode to Projection
  5.   glLoadIdentity();                   // Reset View
  6.   gluPerspective(FOV, Width/Height, 4.0, Depth_Of_View);  // Do the perspective calculations. Last value = max clipping depth
  7.  
  8.   glMatrixMode(GL_MODELVIEW);         // Return to the modelview matrix
  9.   glLoadIdentity();                   // Reset View

Autor:  noeska [ Fr Apr 04, 2008 19:06 ]
Betreff des Beitrags: 

The code worked before i implemented the threading part. But you are right a proper glviewport needs to be added. But adding it did not solve the problem.

Autor:  Lord Horazont [ Fr Apr 04, 2008 19:32 ]
Betreff des Beitrags: 

Hmm... Interesting problem. Since you created the rendering context in your thread there should be no problem. I am quite sure that you can use a handle of another thread for drawing on it, since some applications draw even on windows of other processes.

What disturbes me is that you call the following in your FormDestroy:
Code:
  1.   DeactivateRenderingContext; // Deactivate RenderContext
  2.   wglDeleteContext(RC); //Delete RenderContext
  3.   ReleaseDC(Handle, DC);

You should call this at the end of your Execute method, since all this stuff has been created in the thread.

To check that all is working well, you could create a simple environment in the thread, with an glOrtho-Projection and a quad that should fill the whole viewport. If you see something then, there might be a slight difference in your code you didn't see yet.

greetings Lord Horazont

Autor:  noeska [ Fr Apr 04, 2008 19:45 ]
Betreff des Beitrags: 

Solved.

I should have called the init from within the procedure TOpenGLRender.Execute. Not from withing the form create. Now it works. Thans go to AthenaOfDelphi on the PascalGameDevelopment forum for pointing this out.

Here is the modified code. (needs a cleanup):
Code:
  1.  
  2. unit OpenGLTemplateForm;
  3.  
  4. interface
  5.  
  6. uses
  7.  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  8.   StdCtrls, ExtCtrls, ComCtrls, DglOpenGL;
  9.  
  10. type
  11.   TDGLForm = class(TForm)
  12.     procedure FormKeyPress(Sender: TObject; var Key: Char);
  13.     procedure FormCreate(Sender: TObject);
  14.     procedure FormDestroy(Sender: TObject);
  15.   private
  16.     { Private declarations }
  17.   public
  18.     { Public declarations }
  19.   end;
  20.  
  21.   TOpenGLRender = class(TThread)
  22.   private
  23.     DC:HDC;
  24.     RC:HGLRC;
  25.     angle: integer;
  26.     initialized: boolean;
  27.   public
  28.     destructor Destroy; override;
  29.     procedure Init(aHandle: cardinal);
  30.     procedure Draw;
  31.     procedure Stop;
  32.     procedure Execute; override;
  33.   end;
  34.  
  35. var
  36.   DGLForm: TDGLForm;
  37.   OpenGLRender: TOpenGLRender;
  38.  
  39. implementation
  40.  
  41. {$R *.DFM}
  42.  
  43. function getNormal(p1,p2,p3:TGLArrayf3):TGLArrayf3;
  44. var a,b:TGLArrayf3;
  45. begin
  46.  a[0]:=p2[0]-p1[0]; a[1]:=p2[1]-p1[1]; a[2]:=p2[2]-p1[2];
  47.  b[0]:=p3[0]-p1[0]; b[1]:=p3[1]-p1[1]; b[2]:=p3[2]-p1[2];
  48.  result[0]:=a[1]*b[2]-a[2]*b[1];
  49.  result[1]:=a[2]*b[0]-a[0]*b[2];
  50.  result[2]:=a[0]*b[1]-a[1]*b[0];
  51. end;
  52.  
  53. //TOpenGLRender
  54.  
  55. destructor TOpenGLRender.Destroy;
  56. begin
  57.   inherited;
  58. end;
  59.  
  60. procedure TOpenGLRender.Execute;
  61. begin
  62.   Init(0);
  63.   while not terminated do
  64.   begin
  65.     Draw;
  66.     sleep(1);
  67.   end;
  68. end;
  69.  
  70. procedure TOpenGLRender.Init(aHandle: cardinal);
  71. const
  72.   light0_position:TGLArrayf4=( -8.0, 8.0, -16.0, 0.0);
  73.   ambient:  TGLArrayf4=( 0.3, 0.3, 0.3, 0.3);
  74. begin
  75.  
  76. //  InitOpenGL;
  77.  
  78.   DC := GetDC(DGLForm.Handle);
  79.   // Create RenderContext (32 Bit Pixel, 24 Bit DepthBuffer, Doublebuffering)
  80.   RC := CreateRenderingContext(DC, [opDoubleBuffered], 32, 24, 0, 0, 0, 0);
  81.   // Activate RenderContext
  82.   ActivateRenderingContext(DC, RC);
  83.  
  84.   // set viewing projection
  85.   glMatrixMode(GL_PROJECTION);
  86.   glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0);
  87.  
  88.   // position viewer
  89.   glMatrixMode(GL_MODELVIEW);
  90.  
  91.   // Active DepthBuffer
  92.   glEnable(GL_DEPTH_TEST);
  93.   glDepthFunc(GL_LESS);
  94.  
  95.   // Set lighting
  96.   glEnable(GL_LIGHTING);
  97.   glLightfv(GL_LIGHT0, GL_POSITION, @light0_position);
  98.   glLightfv(GL_LIGHT0, GL_AMBIENT, @ambient);
  99.   glEnable(GL_LIGHT0);
  100.  
  101.   // Set clear background color
  102.   glClearColor(0,0,0,0);
  103. end;
  104.  
  105. procedure TOpenGLRender.Draw;
  106. const
  107.   D=1.5;
  108.   H1=D/1.732;
  109.   H2=D*1.732-H1; // D/H = tg(30) = 1/sqrt(3)
  110.   HY=3.0;
  111.   //vertexes
  112.   a1:TGLArrayf3=(-D, 0, -H1);
  113.   a2:TGLArrayf3=(D, 0, -H1);
  114.   a3:TGLArrayf3=(0, 0, H2);
  115.   a4:TGLArrayf3=(0, HY, 0);
  116. var
  117.   n1, n2, n3, n4: TGLArrayf3;   //normals
  118. begin
  119.   angle:=angle+1;
  120.   n1 := getNormal(a1,a3,a2);
  121.   n2 := getNormal(a1,a2,a4);
  122.   n3 := getNormal(a2,a3,a4);
  123.   n4 := getNormal(a3,a1,a4);
  124.   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  125.   glEnable(GL_NORMALIZE);
  126.   glShadeModel(GL_FLAT);
  127.   glCullFace(GL_BACK);
  128.   glLoadIdentity;
  129.   glTranslatef(0.0, 0.0, -12.0);
  130.   glRotatef(angle, 0.0, 1.0, 0.0);
  131.   glBegin(GL_TRIANGLES);
  132.     glNormal3fv(@n1);
  133.     glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a3);
  134.     glNormal3fv(@n2);
  135.     glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a4);
  136.     glNormal3fv(@n3);
  137.     glVertex3fv(@a2); glVertex3fv(@a3); glVertex3fv(@a4);
  138.     glNormal3fv(@n4);
  139.     glVertex3fv(@a3); glVertex3fv(@a1); glVertex3fv(@a4);
  140.   glEnd;
  141.   SwapBuffers(DC);
  142. end;
  143.  
  144. procedure TOpenGLRender.Stop;
  145. begin
  146.   OpenGLRender.Suspend;
  147.   DeactivateRenderingContext; // Deactivate RenderContext
  148.   wglDeleteContext(RC); //Delete RenderContext
  149.   ReleaseDC(Handle, DC);
  150. end;
  151.  
  152. //TDGLForm
  153.  
  154. procedure TDGLForm.FormCreate(Sender: TObject);
  155. begin
  156.   DecimalSeparator:='.'; //always use . as decimal seperator
  157.   //InitOpenGL; // Initialize DglOpenGL
  158.   OpenGLRender := TOpenGLRender.Create(true);
  159.   //OpenGLRender.Init(Handle);
  160.   OpenGLRender.Resume;
  161. end;
  162.  
  163. procedure TDGLForm.FormDestroy(Sender: TObject);
  164. begin
  165.   OpenGLRender.Stop;
  166.   OpenGLRender.Free;
  167. end;
  168.  
  169. procedure TDGLForm.FormKeyPress(Sender: TObject; var Key: Char);
  170. begin
  171.   case Key of
  172.     #27 : Close;
  173.   end;
  174. end;
  175.  
  176. end.
  177.  

Autor:  Lord Horazont [ Fr Apr 04, 2008 19:48 ]
Betreff des Beitrags: 

An Idea:
You could write a constructor to pass the handle on to the thread and save it in a local variable to avoid the access to the Form-Object from within the thread.

And you should also move the call to Stop from your FormDestroy to the end of the Execute method.

greetings Lord Horazont

Autor:  noeska [ Fr Apr 04, 2008 20:22 ]
Betreff des Beitrags: 

OK

I added an property to pass the handle.
I now call stop at the end of the execute method.

Now should i use
Code:
  1.  
  2.   OpenGLRender.Terminate;
  3.   OpenGLRender.WaitFor;
  4.   OpenGLRender.Free;
  5.  


Code:
  1.  
  2.  OpenGLRender.Suspend;
  3.  OpenGLRender.Free;
  4.  

in the formdestroy.

Autor:  Lossy eX [ Fr Apr 04, 2008 20:41 ]
Betreff des Beitrags: 

Suspend: Suspended the Thread but it's still alive an can resumed every time you want.
WaitFor: Blocks the calling thread until the running thread is terminated. WaitFor is also called in destructor of the threadclass.
Terminate: Sets an internal value of the thread. This value will be quered with terminated inside the thread. Terminate also will be called in the destuctor.

So to terminate the thread its enough if you only call Free. But i think you will generate an deadlock in your application if your thread dosn't quits the execute method.


PS: If you create an Thread suspended and free them before you have resumed it the destructor resume it for you. The Thread always getting called. Instead there will be some issues inside windows i think.

Seite 1 von 1 Alle Zeiten sind UTC + 1 Stunde
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/