Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2010-12

Moving callbackfunctions to class

19 messages · 9 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Darius Blaszyk

Hi,

GLut defines callback functions, one of them is the display function, which is defined as:

TGlutVoidCallback = procedure; cdecl;
This is set by calling glutDisplayFunc(@MyDisplayFunc);

As these functions are needed per window, I would like to encapsulate each window in a class something like:

TMyGLutWindow = class
  private
    procedure MyDisplayFunc; cdecl;
  public
    constructor Create;
end;

In the constructor I would like to set the displayfunction. But doing this I get the error:

Error: Incompatible types: got "<procedure variable type of procedure of object;CDecl>" expected "<procedure variable type of procedure;CDecl>"

Though I understand the error, I do not know if there is a way to circumvent this?

Regards, Darius

Honza
to Darius Blaszyk

2010/12/30 Darius Blaszyk :

Though I understand the error, I do not know if there is a way to circumvent this?

I guess: In the callback you have to get the current window id using glutGetWindow, then dispatch the call to the right object instance using that id via some kind of mapping from window ids to instances.

cf: "Before the callback, the current window is set to the window needing to be redisplayed...", src:
http://www.opengl.org/resources/libraries/glut/spec3/node46.html

bflm freepascal-bits.blogspot.com
Michael Van Canneyt
to Darius Blaszyk: GLut defines callback functions, one of them is the display function, which is defined as:
Darius Blaszyk wrote 23 lines
Hi, GLut defines callback functions, one of them is the display function, which is defined as: TGlutVoidCallback = procedure; cdecl; This is set by calling glutDisplayFunc(@MyDisplayFunc);  As these functions are needed per window, I would like to encapsulate each window in a class something like: TMyGLutWindow = class   private     procedure MyDisplayFunc; cdecl;   public     constructor Create; end; In the constructor I would like to set the displayfunction. But doing this I get the error: Error: Incompatible types: got "<procedure variable type of procedure of object;CDecl>" expected "<procedure variable type of procedure;CDecl>" Though I understand the error, I do not know if there is a way to circumvent this?

No, there isn't.

Michael.

Unknown author
to Jonas Maebe: Maybe with a static class method? (they may require svn trunk to work though) You won't…
Jonas Maebe wrote 19 lines
On 30 Dec 2010, at 17:34, Darius Blaszyk wrote: > As these functions are needed per window, I would like to encapsulate each window in a class something like: > > TMyGLutWindow = class > private > procedure MyDisplayFunc; cdecl; > public > constructor Create; > end; > > In the constructor I would like to set the displayfunction. But doing this I get the error: > > Error: Incompatible types: got "<procedure variable type of procedure of object;CDecl>" expected "<procedure variable type of procedure;CDecl>" > > Though I understand the error, I do not know if there is a way to circumvent this? Maybe with a static class method? (they may require svn trunk to work though) You won't be able to access any fields from that one, of course.

That kind of defeats the purpose, if you want to create a wrapper around the window instance, which I understood to be the intention of Darius ?

Michael.

Jonas Maebe
to Darius Blaszyk: GLut defines callback functions, one of them is the display function, which is defined as:
Darius Blaszyk wrote 14 lines
As these functions are needed per window, I would like to encapsulate each window in a class something like: TMyGLutWindow = class private procedure MyDisplayFunc; cdecl; public constructor Create; end; In the constructor I would like to set the displayfunction. But doing this I get the error: Error: Incompatible types: got "<procedure variable type of procedure of object;CDecl>" expected "<procedure variable type of procedure;CDecl>" Though I understand the error, I do not know if there is a way to circumvent this?

Maybe with a static class method? (they may require svn trunk to work though) You won't be able to access any fields from that one, of course.

Jonas

Darius Blaszyk
to Unknown author: That kind of defeats the purpose, if you want to create a wrapper around the window…
Show quoted text 26 lines
On Thu, 30 Dec 2010, Jonas Maebe wrote: > > On 30 Dec 2010, at 17:34, Darius Blaszyk wrote: > >> As these functions are needed per window, I would like to encapsulate each window in a class something like: >> >> TMyGLutWindow = class >> private >> procedure MyDisplayFunc; cdecl; >> public >> constructor Create; >> end; >> >> In the constructor I would like to set the displayfunction. But doing this I get the error: >> >> Error: Incompatible types: got "<procedure variable type of procedure of object;CDecl>" expected "<procedure variable type of procedure;CDecl>" >> >> Though I understand the error, I do not know if there is a way to circumvent this? > > Maybe with a static class method? (they may require svn trunk to work though) You won't be able to access any fields from that one, of course. That kind of defeats the purpose, if you want to create a wrapper around the window instance, which I understood to be the intention of Darius ?

The intention is indeed to create a wrapper around the multiple callback functions that GLut provides and additionally add some other methods and properties. I have tried using a class method (FPC 2.4.2) but not static class methods, although I don't really understand what you mean with "you won't be able to access any fields from that one". Afaik class methods have a self, right? That would suggest you can access any method or property of self from a class method?

Regards, Darius

Jonas Maebe
to Darius Blaszyk
Darius Blaszyk wrote
The intention is indeed to create a wrapper around the multiple callback functions that GLut provides and additionally add some other methods and properties.

That is impossible since the callback does not offer any way to pass the self pointer.

I have tried using a class method (FPC 2.4.2) but not static class methods, although I don't really understand what you mean with "you won't be able to access any fields from that one". Afaik class methods have a self, right?

static class methods don't have a self pointer. And furthermore, the "self" parameter of class methods refers to the VMT of the class type, not to the "self" of an instance.

That would suggest you can access any method or property of self from a class method?

Not from a static class method. A static class method is basically a regular procedure/function declared in the scope of a class.

Jonas

Darius Blaszyk
to Jonas Maebe

I installed 2.5.1 just to test if it was possible to use static class methods or not. Apparently not so it seems. It was a good try, but it failed. Thanks anyway for the help and explanation Jonas.

It seems that GLut however offers a backdoor as was pointed out by honza. By using glutGetWindow, I can simply check in the main callback function which window paint method to handle. Thanks for the tip!

Regards, Darius

Jonas Maebe wrote 19 lines
On 30 Dec 2010, at 18:27, Darius Blaszyk wrote: > The intention is indeed to create a wrapper around the multiple callback functions that GLut provides and additionally add some other methods and properties. That is impossible since the callback does not offer any way to pass the self pointer. > I have tried using a class method (FPC 2.4.2) but not static class methods, although I don't really understand what you mean with "you won't be able to access any fields from that one". Afaik class methods have a self, right? static class methods don't have a self pointer. And furthermore, the "self" parameter of class methods refers to the VMT of the class type, not to the "self" of an instance. > That would suggest you can access any method or property of self from a class method? Not from a static class method. A static class method is basically a regular procedure/function declared in the scope of a class. Jonas_______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Paul Ishenin
to Darius Blaszyk
Darius Blaszyk wrote
I installed 2.5.1 just to test if it was possible to use static class methods or not. Apparently not so it seems. It was a good try, but it failed. Thanks anyway for the help and explanation Jonas.

Try {$mode delphi}.

Best regards,
Paul Ishenin

José Mejuto
to Darius Blaszyk: I installed 2.5.1 just to test if it was possible to use static class methods or not.…

Hello FPC-Pascal,

Friday, December 31, 2010, 1:53:31 AM, you wrote:

DB> I installed 2.5.1 just to test if it was possible to use DB> static class methods or not. Apparently not so it seems. It was a DB> good try, but it failed. Thanks anyway for the help and DB> explanation Jonas.
DB> It seems that GLut however offers a backdoor as was pointed DB> out by honza. By using glutGetWindow, I can simply check in the DB> main callback function which window paint method to handle. Thanks DB> for the tip!

You can create the same effect using trampolines, but unless fpc has a way to create trampolines you will be forced to use assembler (I was using them in assembler in the past with Delphi). With this trampolines you create a different callback pointer for each callback and in this callback the Self pointer is "hardcoded" and the "class callback" called, which creates the effect that the callback is connected with the class.

I do not know if all platforms support code execution in data memory :-?

Best regards, José
Darius Blaszyk
to Paul Ishenin: Try {$mode delphi}. Paul Ishenin
Paul Ishenin wrote
31.12.2010 7:53, Darius Blaszyk wrote: > I installed 2.5.1 just to test if it was possible to use static class methods or not. Apparently not so it seems. It was a good try, but it failed. Thanks anyway for the help and explanation Jonas. Try {$mode delphi}.

Thanks for the tip Paul. Unfortunately it did not help. See for the results below.

Delphi mode:

class -> Error: Incompatible types: got "class TfpgGLApplication.CDisplayFunc; CDecl;" expected "<procedure variable type of procedure;CDecl>" static -> Error: Incompatible types: got "class TfpgGLApplication.CDisplayFunc; CDecl; Static;" expected "<procedure variable type of procedure;CDecl>"

ObjFPC mode:

class -> Error: Incompatible types: got "<class method type of procedure of object;CDecl>" expected "<procedure variable type of procedure;CDecl>" static -> Error: Incompatible types: got "<class method type of procedure of object;CDecl>" expected "<procedure variable type of procedure;CDecl>"

I was surprised that under objfpc there is no difference in error message.

Regards, Darius

Darius Blaszyk
to José Mejuto: DB> I installed 2.5.1 just to test if it was possible to use DB> static class methods or…
José Mejuto wrote 22 lines
Hello FPC-Pascal, Friday, December 31, 2010, 1:53:31 AM, you wrote: DB> I installed 2.5.1 just to test if it was possible to use DB> static class methods or not. Apparently not so it seems. It was a DB> good try, but it failed. Thanks anyway for the help and DB> explanation Jonas. DB> It seems that GLut however offers a backdoor as was pointed DB> out by honza. By using glutGetWindow, I can simply check in the DB> main callback function which window paint method to handle. Thanks DB> for the tip! You can create the same effect using trampolines, but unless fpc has a way to create trampolines you will be forced to use assembler (I was using them in assembler in the past with Delphi). With this trampolines you create a different callback pointer for each callback and in this callback the Self pointer is "hardcoded" and the "class callback" called, which creates the effect that the callback is connected with the class. I do not know if all platforms support code execution in data memory :-?

Unfortunately I need a platform independent method to handle this. So assembler is not really the way I want to go, unless it proves to be the only way.

Regards, Darius

Reimar Grabowski
to Darius Blaszyk: Unfortunately I need a platform independent method to handle this. So assembler is not…
Unfortunately I need a platform independent method to handle this. So assembler is not really the way I want to go, unless it proves to be the only way.

Now you know why I called glut a major PITA and using platform dependent assembler code to wrap a cross platform lib is just not right. Why don't you look at the context creation code of either TOpenGLContext from Lazarus or the equivalent component from GLScene (yes, it is more difficult than glut but not that difficult)? Glut is just not meant for the things you are doing with it and you are working around restrictions which other context creation mechanisms just don't have. But feel free to ignore my advice as it is your time you are wasting.

Happy new year and good luck.

R.

A: Because it messes up the order in which people normally read text. Q: Why is top-posting such a bad thing? A: Top-posting. Q: What is the most annoying thing in e-mail?
Michael Van Canneyt
to Darius Blaszyk: Thanks for the tip Paul. Unfortunately it did not help. See for the results below. Delphi…
Darius Blaszyk wrote 18 lines
On Dec 31, 2010, at 10:43 AM, Paul Ishenin wrote: > 31.12.2010 7:53, Darius Blaszyk wrote: >> I installed 2.5.1 just to test if it was possible to use static class methods or not. Apparently not so it seems. It was a good try, but it failed. Thanks anyway for the help and explanation Jonas. > Try {$mode delphi}. > Thanks for the tip Paul. Unfortunately it did not help. See for the results below. Delphi mode: class -> Error: Incompatible types: got "class TfpgGLApplication.CDisplayFunc; CDecl;" expected "<procedure variable type of procedure;CDecl>" static -> Error: Incompatible types: got "class TfpgGLApplication.CDisplayFunc; CDecl; Static;" expected "<procedure variable type of procedure;CDecl>" ObjFPC mode: class -> Error: Incompatible types: got "<class method type of procedure of object;CDecl>" expected "<procedure variable type of procedure;CDecl>" static -> Error: Incompatible types: got "<class method type of procedure of object;CDecl>" expected "<procedure variable type of procedure;CDecl>"

Even if they worked, it would do you no good: you would have no access to instance fields, or the VMT, since neither is passed when glut calls your callback:
- Class methods need 'self' (it will contain the VMT), and cannot access fields of an instance (since there is none to work with)
- Static methods do not need self, but they also cannot access fields of a class instance. Static methods are like regular procedures, but their name just contains a dot (.) character.

Conclusion: You can just as well use a regular procedure; the rest is a waste of your time.

Michael.

Darius Blaszyk
to Felipe Monteiro de Carvalho: On Fri, Dec 31, 2010 at 11:01 AM, Darius Blaszyk Using a correct type cast it should…
Felipe Monteiro de Carvalho wrote 5 lines
On Fri, Dec 31, 2010 at 11:01 AM, Darius Blaszyk wrote: > Thanks for the tip Paul. Unfortunately it did not help. See for the results below. Using a correct type cast it should work. Which line brings the errors?

Hi Felipe,

Casting works, but the app crashes (Michael get that smile from your face ;) Here's an example app for those that are curious:

Regards, Darius

program gluttest;
{$mode delphi}{$H+}
{$define ClassGLutWindow}
uses
  Classes, SysUtils, gl, glut;
{$IFDEF ClassGLutWindow}
type
  { TGLWindow }
  TGLWindow = class
  public
    constructor Create;
    class procedure DisplayFunc; cdecl;
  end;
var
  GLWindow: TGLWindow;
constructor TGLWindow.Create;
begin
  glutInitWindowSize(350, 200);
  glutInitWindowPosition(0, 0);
  glutCreateWindow(PChar('GLut window'));
  //GLut callback functions
  glutDisplayFunc(TGlutVoidCallback(DisplayFunc));
end;
class procedure TGLWindow.DisplayFunc; cdecl;
{$ELSE}
procedure DisplayFunc; cdecl;
{$ENDIF}
begin
  //clear background
  glClearColor(0.3, 0.3, 0.3, 1);
  glClear(GL_COLOR_BUFFER_BIT);
  //swap the buffer
  glutSwapBuffers;
end;
begin
  glutInit(@argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE or GLUT_RGBA);
  {$IFNDEF ClassGLutWindow}
  glutInitWindowSize(350, 200);
  glutInitWindowPosition(0, 0);
  glutCreateWindow(PChar('GLut window'));
  //GLut callback functions
  glutDisplayFunc(DisplayFunc);
  {$ENDIF}
  {$IFDEF ClassGLutWindow} GLWindow := TGLWindow.Create; {$ENDIF}
  glutMainLoop;
end.
Darius Blaszyk
to Reimar Grabowski: On Fri, 31 Dec 2010 14:03:27 +0100 Now you know why I called glut a major PITA and using…
Reimar Grabowski wrote 6 lines
On Fri, 31 Dec 2010 14:03:27 +0100 Darius Blaszyk wrote: > Unfortunately I need a platform independent method to handle this. So assembler is not really the way I want to go, unless it proves to be the only way. Now you know why I called glut a major PITA and using platform dependent assembler code to wrap a cross platform lib is just not right. Why don't you look at the context creation code of either TOpenGLContext from Lazarus or the equivalent component from GLScene (yes, it is more difficult than glut but not that difficult)? Glut is just not meant for the things you are doing with it and you are working around restrictions which other context creation mechanisms just don't have. But feel free to ignore my advice as it is your time you are wasting.

I know that GLut is inflexible and that creating your own context is the best way to go. I'm not ignorant to your advice and besides that it is my plan to do so from the beginning. However resolving the message loop for multiple windows is more or less my last obstacle to create an opengl fpgui. When I manage this, I will plead with Graeme to refactor the existing context handling code and create a new "context" layer in fpgui. This will open up the possibility to create multiple backends to fpgui eg cairo, sdl, etc.

Regards, Darius

José Mejuto
to Darius Blaszyk: Unfortunately I need a platform independent method to handle this. So assembler is not…

Hello FPC-Pascal,

you wrote 8 lines
> You can create the same effect using trampolines, but unless fpc has a > way to create trampolines you will be forced to use assembler (I was > using them in assembler in the past with Delphi). With this > trampolines you create a different callback pointer for each callback > and in this callback the Self pointer is "hardcoded" and the "class > callback" called, which creates the effect that the callback is > connected with the class. > I do not know if all platforms support code execution in data memory :-?

DB> Unfortunately I need a platform independent method to handle DB> this. So assembler is not really the way I want to go, unless it DB> proves to be the only way.

After thinking a bit in the problem, you do not need assembler, but you will need to write a wrapper for each callback call that setup some kind of trampoline different for each callback.

Just for the experiment I'll try to mockup something that should work ( if I'm able :) ).

Best regards, José
Paul Ishenin
to Darius Blaszyk: Thanks for the tip Paul. Unfortunately it did not help. See for the results below. Delphi…
Darius Blaszyk wrote 13 lines
On Dec 31, 2010, at 10:43 AM, Paul Ishenin wrote: > 31.12.2010 7:53, Darius Blaszyk wrote: >> I installed 2.5.1 just to test if it was possible to use static class methods or not. Apparently not so it seems. It was a good try, but it failed. Thanks anyway for the help and explanation Jonas. > Try {$mode delphi}. > Thanks for the tip Paul. Unfortunately it did not help. See for the results below. Delphi mode: class -> Error: Incompatible types: got "class TfpgGLApplication.CDisplayFunc; CDecl;" expected "<procedure variable type of procedure;CDecl>" static -> Error: Incompatible types: got "class TfpgGLApplication.CDisplayFunc; CDecl; Static;" expected "<procedure variable type of procedure;CDecl>"

You need to create a static class procedure. But I just checked with fpc
- it indeed fails to compile while delphi compiles fine.

Best regards,
Paul Ishenin