Porting Cocoa OpenGL sample code
Hello, I am trying to port the Cocoa OpenGL sample to MacRuby and encountered a few problems. First, I can't access some constants defined in an enum in GLTypes.h. Do I need to port those constants to ruby by hand ? Is that related to gen_bridge_metadata ? Second, I need to use CGLQueryRendererInfo and CGLDescribeRenderer functions. The first one requires a pointer to a CGLRendererInfoObj structure but the second requires the object to be passed directly. I tried some C style pointer arithmetic : info = Pointer.new_with_type("CGLRendererInfoObj") count = Pointer.new_with_type("l") CGLQueryRendererInfo(caps[:cgl_display_mask], info, count) <- works fine, but CGLRendererInfoObj is opaque so I can't check it in irb. CGLDescribeRenderer(info[0], 0, kCGLRPRendererCount, count) <- I naively tried to dereference the pointer, but it doesn't work. CGLDescribeRenderer(info, 0, kCGLRPRendererCount, count) <- No complaints, but the value for count[0] is not consistent (100468704 renderers). I see in MacIRB that there is a CGLRendererInfoObj class but I can't instantiate it. This is all new to me and I may be overlooking something obvious. If anyone has an idea, please help. Thanks, Julien Jassaud
CGLRendererInfo is a pointer to a struct: typedef struct _CGLRendererInfoObject *CGLRendererInfoObj; try creating a pointer to void or to the struct: info = Pointer.new_with_type("^v") # void *info; or info = Pointer.new_with_type("^{_CGLRendererInfoObject=}") # CGLRendererInfo *info I think the second one is effectively the same as what you were trying to do with: info = Pointer.new_with_type("CGLRendererInfoObj") except that the runtime doesn't know what to do with "CGLRendererInfo". The argument to Pointer.new_with_type must be a valid Objective-C type encoding[1]. [1]: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/A... If you are ever in doubt about what encoding to use, you can always compile a small Objective-C program that prints out the output of @encode(). For example: #import <Foundation/Foundation.h> #import <OpenGL/OpenGL.h> int main(int argc, char *argv[]) { char *encoding = @encode(CGLRendererInfoObj); printf("\nencoding => %s\n\n", encoding); return 0; } compile with: gcc -Wall -o encode encode.m -framework Foundation -framework OpenGL then run: ./encode Maybe there is an easier way to obtain the output of @encode(). I'm not sure. Brian On Wed, Feb 25, 2009 at 1:42 AM, Julien Jassaud <julien@collectapply.jp> wrote:
Hello, I am trying to port the Cocoa OpenGL sample to MacRuby and encountered a few problems.
First, I can't access some constants defined in an enum in GLTypes.h. Do I need to port those constants to ruby by hand ? Is that related to gen_bridge_metadata ?
Second, I need to use CGLQueryRendererInfo and CGLDescribeRenderer functions. The first one requires a pointer to a CGLRendererInfoObj structure but the second requires the object to be passed directly. I tried some C style pointer arithmetic : info = Pointer.new_with_type("CGLRendererInfoObj") count = Pointer.new_with_type("l") CGLQueryRendererInfo(caps[:cgl_display_mask], info, count) <- works fine, but CGLRendererInfoObj is opaque so I can't check it in irb. CGLDescribeRenderer(info[0], 0, kCGLRPRendererCount, count) <- I naively tried to dereference the pointer, but it doesn't work. CGLDescribeRenderer(info, 0, kCGLRPRendererCount, count) <- No complaints, but the value for count[0] is not consistent (100468704 renderers). I see in MacIRB that there is a CGLRendererInfoObj class but I can't instantiate it. This is all new to me and I may be overlooking something obvious. If anyone has an idea, please help. Thanks, Julien Jassaud _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
Brian, what's up with this syntax: info = Pointer.new_with_type("^{_CGLRendererInfoObject=}") Can you explain: "^{_CGLRendererInfoObject=}"? is that some secret incantation only known by the MacRuby/Obj overlords? Thanks, - Matt On Wed, Feb 25, 2009 at 10:13 AM, Brian Chapados <chapbr@gmail.com> wrote:
CGLRendererInfo is a pointer to a struct: typedef struct _CGLRendererInfoObject *CGLRendererInfoObj;
try creating a pointer to void or to the struct:
info = Pointer.new_with_type("^v") # void *info;
or
info = Pointer.new_with_type("^{_CGLRendererInfoObject=}") # CGLRendererInfo *info
I think the second one is effectively the same as what you were trying to do with: info = Pointer.new_with_type("CGLRendererInfoObj")
except that the runtime doesn't know what to do with "CGLRendererInfo". The argument to Pointer.new_with_type must be a valid Objective-C type encoding[1].
[1]: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/A...
If you are ever in doubt about what encoding to use, you can always compile a small Objective-C program that prints out the output of @encode(). For example:
#import <Foundation/Foundation.h> #import <OpenGL/OpenGL.h>
int main(int argc, char *argv[]) { char *encoding = @encode(CGLRendererInfoObj); printf("\nencoding => %s\n\n", encoding); return 0; }
compile with: gcc -Wall -o encode encode.m -framework Foundation -framework OpenGL
then run: ./encode
Maybe there is an easier way to obtain the output of @encode(). I'm not sure.
Brian
On Wed, Feb 25, 2009 at 1:42 AM, Julien Jassaud <julien@collectapply.jp> wrote:
Hello, I am trying to port the Cocoa OpenGL sample to MacRuby and encountered a few problems.
First, I can't access some constants defined in an enum in GLTypes.h. Do I need to port those constants to ruby by hand ? Is that related to gen_bridge_metadata ?
Second, I need to use CGLQueryRendererInfo and CGLDescribeRenderer functions. The first one requires a pointer to a CGLRendererInfoObj structure but the second requires the object to be passed directly. I tried some C style pointer arithmetic : info = Pointer.new_with_type("CGLRendererInfoObj") count = Pointer.new_with_type("l") CGLQueryRendererInfo(caps[:cgl_display_mask], info, count) <- works fine, but CGLRendererInfoObj is opaque so I can't check it in irb. CGLDescribeRenderer(info[0], 0, kCGLRPRendererCount, count) <- I naively tried to dereference the pointer, but it doesn't work. CGLDescribeRenderer(info, 0, kCGLRPRendererCount, count) <- No complaints, but the value for count[0] is not consistent (100468704 renderers). I see in MacIRB that there is a CGLRendererInfoObj class but I can't instantiate it. This is all new to me and I may be overlooking something obvious. If anyone has an idea, please help. Thanks, Julien Jassaud _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
Can you explain: "^{_CGLRendererInfoObject=}"? is that some secret incantation only known by the MacRuby/Obj overlords?
Yes, it is actually a 7th level spell: 'Encode Structure'. To learn it, you must study the ancient tome: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/A... If it makes you feel better, I usually need to look it up (or just run the Obj-C code sample), unless it is something simple (like '@'). I don't keep this spell in memory, as it is only required in special situations. Seriously though, that is actually how you encode a pointer to a struct. If you use the @encode(type) directive, the compiler will return the runtime encoding for 'type'. It's a bit cryptic, but not too bad once you know the syntax: '^type' encodes a pointer to type. '{name=<field1 type><field2 type><field3 type>...<fieldN type>}' encodes a struct with N fields. To break it down using 2 examples: (from the docs) typedef struct example { id anObject; // encoding = @ char *aString; // encoding = c int anInt; // enoding = i } Example; @encode(Example) = "^{example=@ci}" CGLRendererInfoObj is a pointer to an opaque struct (we don't know anything about the fields) named _CGLRendererInfoObject. All we know is: typedef struct _CGLRendererInfoObject *CGLRendererInfoObj; so it's just "^{_CGLRendererInfoObject=}" In practice (unless you're working with CoreFoundation C APIs) you usually just need a pointer to an object. The most common usage I run across is to retrieve NSError objects. The CoreFoundation C API uses pass-by-reference extensively. To use these functions with MacRuby, you need to create lots of pointer objects. In general, this is an area where interfacing ruby with C is just fugly. I'd personally avoid doing this in MacRuby. If you find yourself needing to use lots Pointer objects, it's probably better and less error-prone to write that code in C and expose it to MacRuby through an Objective-C interface. That said, for common things, I've used something like this extension to the Pointer class: ---- class Pointer def self.ptr new_with_type("@") end def self.to(type = :object) case type when :object new_with_type('@') when :int new_with_type('i') when :char when :bool when :BOOL new_with_type('c') when :unsigned new_with_type('I') end end def value self[0] end end ---- Need a pointer to an ObjC object? p = Pointer.ptr To a BOOL? p = Pointer.to(:BOOL) Need the value? p.value Those are the most common types I've needed. On Wed, Feb 25, 2009 at 11:11 AM, Matt Aimonetti <mattaimonetti@gmail.com> wrote:
Brian, what's up with this syntax: info = Pointer.new_with_type("^{_CGLRendererInfoObject=}") Can you explain: "^{_CGLRendererInfoObject=}"? is that some secret incantation only known by the MacRuby/Obj overlords? Thanks, - Matt
On Wed, Feb 25, 2009 at 10:13 AM, Brian Chapados <chapbr@gmail.com> wrote:
CGLRendererInfo is a pointer to a struct: typedef struct _CGLRendererInfoObject *CGLRendererInfoObj;
try creating a pointer to void or to the struct:
info = Pointer.new_with_type("^v") # void *info;
or
info = Pointer.new_with_type("^{_CGLRendererInfoObject=}") # CGLRendererInfo *info
I think the second one is effectively the same as what you were trying to do with: info = Pointer.new_with_type("CGLRendererInfoObj")
except that the runtime doesn't know what to do with "CGLRendererInfo". The argument to Pointer.new_with_type must be a valid Objective-C type encoding[1].
[1]: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/A...
If you are ever in doubt about what encoding to use, you can always compile a small Objective-C program that prints out the output of @encode(). For example:
#import <Foundation/Foundation.h> #import <OpenGL/OpenGL.h>
int main(int argc, char *argv[]) { char *encoding = @encode(CGLRendererInfoObj); printf("\nencoding => %s\n\n", encoding); return 0; }
compile with: gcc -Wall -o encode encode.m -framework Foundation -framework OpenGL
then run: ./encode
Maybe there is an easier way to obtain the output of @encode(). I'm not sure.
Brian
On Wed, Feb 25, 2009 at 1:42 AM, Julien Jassaud <julien@collectapply.jp> wrote:
Hello, I am trying to port the Cocoa OpenGL sample to MacRuby and encountered a few problems.
First, I can't access some constants defined in an enum in GLTypes.h. Do I need to port those constants to ruby by hand ? Is that related to gen_bridge_metadata ?
Second, I need to use CGLQueryRendererInfo and CGLDescribeRenderer functions. The first one requires a pointer to a CGLRendererInfoObj structure but the second requires the object to be passed directly. I tried some C style pointer arithmetic : info = Pointer.new_with_type("CGLRendererInfoObj") count = Pointer.new_with_type("l") CGLQueryRendererInfo(caps[:cgl_display_mask], info, count) <- works fine, but CGLRendererInfoObj is opaque so I can't check it in irb. CGLDescribeRenderer(info[0], 0, kCGLRPRendererCount, count) <- I naively tried to dereference the pointer, but it doesn't work. CGLDescribeRenderer(info, 0, kCGLRPRendererCount, count) <- No complaints, but the value for count[0] is not consistent (100468704 renderers). I see in MacIRB that there is a CGLRendererInfoObj class but I can't instantiate it. This is all new to me and I may be overlooking something obvious. If anyone has an idea, please help. Thanks, Julien Jassaud _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
Thanks Brian for the detailed explanation. I wonder if your Pointer extension shouldn't be merged into HotCocoa or MacRuby itself. What do you guys think? - Matt On Wed, Feb 25, 2009 at 12:43 PM, Brian Chapados <chapbr@gmail.com> wrote:
Can you explain: "^{_CGLRendererInfoObject=}"? is that some secret incantation only known by the MacRuby/Obj overlords?
Yes, it is actually a 7th level spell: 'Encode Structure'. To learn it, you must study the ancient tome: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/A...
If it makes you feel better, I usually need to look it up (or just run the Obj-C code sample), unless it is something simple (like '@'). I don't keep this spell in memory, as it is only required in special situations.
Seriously though, that is actually how you encode a pointer to a struct. If you use the @encode(type) directive, the compiler will return the runtime encoding for 'type'. It's a bit cryptic, but not too bad once you know the syntax:
'^type' encodes a pointer to type. '{name=<field1 type><field2 type><field3 type>...<fieldN type>}' encodes a struct with N fields.
To break it down using 2 examples:
(from the docs) typedef struct example { id anObject; // encoding = @ char *aString; // encoding = c int anInt; // enoding = i } Example;
@encode(Example) = "^{example=@ci}"
CGLRendererInfoObj is a pointer to an opaque struct (we don't know anything about the fields) named _CGLRendererInfoObject. All we know is: typedef struct _CGLRendererInfoObject *CGLRendererInfoObj;
so it's just "^{_CGLRendererInfoObject=}"
In practice (unless you're working with CoreFoundation C APIs) you usually just need a pointer to an object. The most common usage I run across is to retrieve NSError objects. The CoreFoundation C API uses pass-by-reference extensively. To use these functions with MacRuby, you need to create lots of pointer objects. In general, this is an area where interfacing ruby with C is just fugly. I'd personally avoid doing this in MacRuby. If you find yourself needing to use lots Pointer objects, it's probably better and less error-prone to write that code in C and expose it to MacRuby through an Objective-C interface.
That said, for common things, I've used something like this extension to the Pointer class:
---- class Pointer def self.ptr new_with_type("@") end
def self.to(type = :object) case type when :object new_with_type('@') when :int new_with_type('i') when :char when :bool when :BOOL new_with_type('c') when :unsigned new_with_type('I') end end
def value self[0] end end
----
Need a pointer to an ObjC object? p = Pointer.ptr
To a BOOL? p = Pointer.to(:BOOL)
Need the value? p.value
Those are the most common types I've needed.
On Wed, Feb 25, 2009 at 11:11 AM, Matt Aimonetti <mattaimonetti@gmail.com> wrote:
Brian, what's up with this syntax: info = Pointer.new_with_type("^{_CGLRendererInfoObject=}") Can you explain: "^{_CGLRendererInfoObject=}"? is that some secret incantation only known by the MacRuby/Obj overlords? Thanks, - Matt
On Wed, Feb 25, 2009 at 10:13 AM, Brian Chapados <chapbr@gmail.com> wrote:
CGLRendererInfo is a pointer to a struct: typedef struct _CGLRendererInfoObject *CGLRendererInfoObj;
try creating a pointer to void or to the struct:
info = Pointer.new_with_type("^v") # void *info;
or
info = Pointer.new_with_type("^{_CGLRendererInfoObject=}") # CGLRendererInfo *info
I think the second one is effectively the same as what you were trying to do with: info = Pointer.new_with_type("CGLRendererInfoObj")
except that the runtime doesn't know what to do with "CGLRendererInfo". The argument to Pointer.new_with_type must be a valid Objective-C type encoding[1].
[1]: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/A...
If you are ever in doubt about what encoding to use, you can always compile a small Objective-C program that prints out the output of @encode(). For example:
#import <Foundation/Foundation.h> #import <OpenGL/OpenGL.h>
int main(int argc, char *argv[]) { char *encoding = @encode(CGLRendererInfoObj); printf("\nencoding => %s\n\n", encoding); return 0; }
compile with: gcc -Wall -o encode encode.m -framework Foundation -framework OpenGL
then run: ./encode
Maybe there is an easier way to obtain the output of @encode(). I'm not sure.
Brian
On Wed, Feb 25, 2009 at 1:42 AM, Julien Jassaud <julien@collectapply.jp> wrote:
Hello, I am trying to port the Cocoa OpenGL sample to MacRuby and encountered a few problems.
First, I can't access some constants defined in an enum in GLTypes.h. Do I need to port those constants to ruby by hand ? Is that related to gen_bridge_metadata ?
Second, I need to use CGLQueryRendererInfo and CGLDescribeRenderer functions. The first one requires a pointer to a CGLRendererInfoObj structure but the second requires the object to be passed directly. I tried some C style pointer arithmetic : info = Pointer.new_with_type("CGLRendererInfoObj") count = Pointer.new_with_type("l") CGLQueryRendererInfo(caps[:cgl_display_mask], info, count) <- works fine, but CGLRendererInfoObj is opaque so I can't check it in irb. CGLDescribeRenderer(info[0], 0, kCGLRPRendererCount, count) <- I naively tried to dereference the pointer, but it doesn't work. CGLDescribeRenderer(info, 0, kCGLRPRendererCount, count) <- No complaints, but the value for count[0] is not consistent (100468704 renderers). I see in MacIRB that there is a CGLRendererInfoObj class but I can't instantiate it. This is all new to me and I may be overlooking something obvious. If anyone has an idea, please help. Thanks, Julien Jassaud _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
That's a pretty good idea. I tried to make the Pointer class as simple (and stupid) as possible but we might need some convenience APIs on top of it, for those not familiar with the Objective-C encoding types. Here is an API proposal based on Brian's snippet... thoughts? class Pointer def self.new(type='@') new_with_type(type) end TYPES = { :int => 'i', :uint => 'I', ... } def self.to(sym) new_with_type(TYPES[sym]) end def value self[0] end end # I'm pretty sure I already wrote something similar in RubyCocoa. Laurent On Feb 25, 2009, at 1:16 PM, Matt Aimonetti wrote:
Thanks Brian for the detailed explanation. I wonder if your Pointer extension shouldn't be merged into HotCocoa or MacRuby itself.
What do you guys think?
- Matt
On Wed, Feb 25, 2009 at 12:43 PM, Brian Chapados <chapbr@gmail.com> wrote:
Can you explain: "^{_CGLRendererInfoObject=}"? is that some secret incantation only known by the MacRuby/Obj overlords?
Yes, it is actually a 7th level spell: 'Encode Structure'. To learn it, you must study the ancient tome: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/A... /apple_ref/doc/uid/TP40008048-CH100-SW1
If it makes you feel better, I usually need to look it up (or just run the Obj-C code sample), unless it is something simple (like '@'). I don't keep this spell in memory, as it is only required in special situations.
Seriously though, that is actually how you encode a pointer to a struct. If you use the @encode(type) directive, the compiler will return the runtime encoding for 'type'. It's a bit cryptic, but not too bad once you know the syntax:
'^type' encodes a pointer to type. '{name=<field1 type><field2 type><field3 type>...<fieldN type>}' encodes a struct with N fields.
To break it down using 2 examples:
(from the docs) typedef struct example { id anObject; // encoding = @ char *aString; // encoding = c int anInt; // enoding = i } Example;
@encode(Example) = "^{example=@ci}"
CGLRendererInfoObj is a pointer to an opaque struct (we don't know anything about the fields) named _CGLRendererInfoObject. All we know is: typedef struct _CGLRendererInfoObject *CGLRendererInfoObj;
so it's just "^{_CGLRendererInfoObject=}"
In practice (unless you're working with CoreFoundation C APIs) you usually just need a pointer to an object. The most common usage I run across is to retrieve NSError objects. The CoreFoundation C API uses pass-by-reference extensively. To use these functions with MacRuby, you need to create lots of pointer objects. In general, this is an area where interfacing ruby with C is just fugly. I'd personally avoid doing this in MacRuby. If you find yourself needing to use lots Pointer objects, it's probably better and less error-prone to write that code in C and expose it to MacRuby through an Objective-C interface.
That said, for common things, I've used something like this extension to the Pointer class:
---- class Pointer def self.ptr new_with_type("@") end
def self.to(type = :object) case type when :object new_with_type('@') when :int new_with_type('i') when :char when :bool when :BOOL new_with_type('c') when :unsigned new_with_type('I') end end
def value self[0] end end
----
Need a pointer to an ObjC object? p = Pointer.ptr
To a BOOL? p = Pointer.to(:BOOL)
Need the value? p.value
Those are the most common types I've needed.
On Wed, Feb 25, 2009 at 11:11 AM, Matt Aimonetti <mattaimonetti@gmail.com> wrote:
Brian, what's up with this syntax: info = Pointer.new_with_type("^{_CGLRendererInfoObject=}") Can you explain: "^{_CGLRendererInfoObject=}"? is that some secret incantation only known by the MacRuby/Obj overlords? Thanks, - Matt
On Wed, Feb 25, 2009 at 10:13 AM, Brian Chapados <chapbr@gmail.com> wrote:
CGLRendererInfo is a pointer to a struct: typedef struct _CGLRendererInfoObject *CGLRendererInfoObj;
try creating a pointer to void or to the struct:
info = Pointer.new_with_type("^v") # void *info;
or
info = Pointer.new_with_type("^{_CGLRendererInfoObject=}") # CGLRendererInfo *info
I think the second one is effectively the same as what you were trying to do with: info = Pointer.new_with_type("CGLRendererInfoObj")
except that the runtime doesn't know what to do with "CGLRendererInfo". The argument to Pointer.new_with_type must be a valid Objective-C type encoding[1].
[1]: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/A... /apple_ref/doc/uid/TP40008048-CH100-SW1
If you are ever in doubt about what encoding to use, you can always compile a small Objective-C program that prints out the output of @encode(). For example:
#import <Foundation/Foundation.h> #import <OpenGL/OpenGL.h>
int main(int argc, char *argv[]) { char *encoding = @encode(CGLRendererInfoObj); printf("\nencoding => %s\n\n", encoding); return 0; }
compile with: gcc -Wall -o encode encode.m -framework Foundation -framework OpenGL
then run: ./encode
Maybe there is an easier way to obtain the output of @encode(). I'm not sure.
Brian
On Wed, Feb 25, 2009 at 1:42 AM, Julien Jassaud <julien@collectapply.jp
wrote:
Hello, I am trying to port the Cocoa OpenGL sample to MacRuby and encountered a few problems.
First, I can't access some constants defined in an enum in GLTypes.h. Do I need to port those constants to ruby by hand ? Is that related to gen_bridge_metadata ?
Second, I need to use CGLQueryRendererInfo and CGLDescribeRenderer functions. The first one requires a pointer to a CGLRendererInfoObj structure but the second requires the object to be passed directly. I tried some C style pointer arithmetic : info = Pointer.new_with_type("CGLRendererInfoObj") count = Pointer.new_with_type("l") CGLQueryRendererInfo(caps[:cgl_display_mask], info, count) <- works fine, but CGLRendererInfoObj is opaque so I can't check it in irb. CGLDescribeRenderer(info[0], 0, kCGLRPRendererCount, count) <- I naively tried to dereference the pointer, but it doesn't work. CGLDescribeRenderer(info, 0, kCGLRPRendererCount, count) <- No complaints, but the value for count[0] is not consistent (100468704 renderers). I see in MacIRB that there is a CGLRendererInfoObj class but I can't instantiate it. This is all new to me and I may be overlooking something obvious. If anyone has an idea, please help. Thanks, Julien Jassaud _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
Brian, Thanks for the very detailed answer. This tremendously helps. I am now having problems with arrays, though. I try to make a pointer to an array of 32 longs, like this :
p = Pointer.new_with_type('[32L]') => #<Pointer:0x80052af00> p[0] ArgumentError: can't convert C/Objective-C value `0x80052ae40' of type `[32i]' to Ruby object from (irb):49:in `[]' from (irb):49 from /usr/local/bin/macirb:12:in `<main>'
Am I not getting the syntax explained in the documentation page you mentioned ? Also, something is puzzling me. In C, arrays are pointers so I thought I could solve the problem (and it works) by doing :
p=Pointer.new_with_type('^L') => #<Pointer:0x800530380> p.assign([1,2,3]) => [1, 2, 3] p[0][1] => 2
Great ! I have a pointer to something that looks like an array of longs (and it seems to satisfy the CGGetActiveDisplayList function). But how is it possible when everything here is an object and not a series of neatly aligned bytes ? Anyway, you are right. The part of Cocoa OpenGL I am porting now probably doesn't need to and should be wrapped in an Objective-C object. Thanks, Julien Jassaud Le 26 févr. 09 à 05:43, Brian Chapados a écrit :
Can you explain: "^{_CGLRendererInfoObject=}"? is that some secret incantation only known by the MacRuby/Obj overlords?
Yes, it is actually a 7th level spell: 'Encode Structure'. To learn it, you must study the ancient tome: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/A... /apple_ref/doc/uid/TP40008048-CH100-SW1
If it makes you feel better, I usually need to look it up (or just run the Obj-C code sample), unless it is something simple (like '@'). I don't keep this spell in memory, as it is only required in special situations.
Seriously though, that is actually how you encode a pointer to a struct. If you use the @encode(type) directive, the compiler will return the runtime encoding for 'type'. It's a bit cryptic, but not too bad once you know the syntax:
'^type' encodes a pointer to type. '{name=<field1 type><field2 type><field3 type>...<fieldN type>}' encodes a struct with N fields.
To break it down using 2 examples:
(from the docs) typedef struct example { id anObject; // encoding = @ char *aString; // encoding = c int anInt; // enoding = i } Example;
@encode(Example) = "^{example=@ci}"
CGLRendererInfoObj is a pointer to an opaque struct (we don't know anything about the fields) named _CGLRendererInfoObject. All we know is: typedef struct _CGLRendererInfoObject *CGLRendererInfoObj;
so it's just "^{_CGLRendererInfoObject=}"
In practice (unless you're working with CoreFoundation C APIs) you usually just need a pointer to an object. The most common usage I run across is to retrieve NSError objects. The CoreFoundation C API uses pass-by-reference extensively. To use these functions with MacRuby, you need to create lots of pointer objects. In general, this is an area where interfacing ruby with C is just fugly. I'd personally avoid doing this in MacRuby. If you find yourself needing to use lots Pointer objects, it's probably better and less error-prone to write that code in C and expose it to MacRuby through an Objective-C interface.
That said, for common things, I've used something like this extension to the Pointer class:
---- class Pointer def self.ptr new_with_type("@") end
def self.to(type = :object) case type when :object new_with_type('@') when :int new_with_type('i') when :char when :bool when :BOOL new_with_type('c') when :unsigned new_with_type('I') end end
def value self[0] end end
----
Need a pointer to an ObjC object? p = Pointer.ptr
To a BOOL? p = Pointer.to(:BOOL)
Need the value? p.value
Those are the most common types I've needed.
On Wed, Feb 25, 2009 at 11:11 AM, Matt Aimonetti <mattaimonetti@gmail.com> wrote:
Brian, what's up with this syntax: info = Pointer.new_with_type("^{_CGLRendererInfoObject=}") Can you explain: "^{_CGLRendererInfoObject=}"? is that some secret incantation only known by the MacRuby/Obj overlords? Thanks, - Matt
On Wed, Feb 25, 2009 at 10:13 AM, Brian Chapados <chapbr@gmail.com> wrote:
CGLRendererInfo is a pointer to a struct: typedef struct _CGLRendererInfoObject *CGLRendererInfoObj;
try creating a pointer to void or to the struct:
info = Pointer.new_with_type("^v") # void *info;
or
info = Pointer.new_with_type("^{_CGLRendererInfoObject=}") # CGLRendererInfo *info
I think the second one is effectively the same as what you were trying to do with: info = Pointer.new_with_type("CGLRendererInfoObj")
except that the runtime doesn't know what to do with "CGLRendererInfo". The argument to Pointer.new_with_type must be a valid Objective-C type encoding[1].
[1]: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/A... /apple_ref/doc/uid/TP40008048-CH100-SW1
If you are ever in doubt about what encoding to use, you can always compile a small Objective-C program that prints out the output of @encode(). For example:
#import <Foundation/Foundation.h> #import <OpenGL/OpenGL.h>
int main(int argc, char *argv[]) { char *encoding = @encode(CGLRendererInfoObj); printf("\nencoding => %s\n\n", encoding); return 0; }
compile with: gcc -Wall -o encode encode.m -framework Foundation -framework OpenGL
then run: ./encode
Maybe there is an easier way to obtain the output of @encode(). I'm not sure.
Brian
On Wed, Feb 25, 2009 at 1:42 AM, Julien Jassaud <julien@collectapply.jp
wrote:
Hello, I am trying to port the Cocoa OpenGL sample to MacRuby and encountered a few problems.
First, I can't access some constants defined in an enum in GLTypes.h. Do I need to port those constants to ruby by hand ? Is that related to gen_bridge_metadata ?
Second, I need to use CGLQueryRendererInfo and CGLDescribeRenderer functions. The first one requires a pointer to a CGLRendererInfoObj structure but the second requires the object to be passed directly. I tried some C style pointer arithmetic : info = Pointer.new_with_type("CGLRendererInfoObj") count = Pointer.new_with_type("l") CGLQueryRendererInfo(caps[:cgl_display_mask], info, count) <- works fine, but CGLRendererInfoObj is opaque so I can't check it in irb. CGLDescribeRenderer(info[0], 0, kCGLRPRendererCount, count) <- I naively tried to dereference the pointer, but it doesn't work. CGLDescribeRenderer(info, 0, kCGLRPRendererCount, count) <- No complaints, but the value for count[0] is not consistent (100468704 renderers). I see in MacIRB that there is a CGLRendererInfoObj class but I can't instantiate it. This is all new to me and I may be overlooking something obvious. If anyone has an idea, please help. Thanks, Julien Jassaud _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
I'm not sure what's happening with the pointer to an array of longs in the first case. It looks like the Pointer is being created, but there is no way to assign/retrieve values? p = Pointer.new_with_type('^L') p.assign([1,2,3]) p[0][1] # => 2 I think the reason that this works is that rb_objc_rval_to_ocval seems to only handle assigning a ruby array to an ObjC pointer type ("^"). I guess you could just go with it, but if the function you are passing to will write to that address, then you need to ensure that the space has been allocated (see below). When you call assign with an array, it's like writing something like this in C: unsigned long *p[1]; unsigned long array[3] = {1,2,3}; *p = array; // same as p[0] = array; *p[1]; // => 2 Ideally you just want a real C array: unsigned long[10]; or the dynamically allocated equivalent. The issue here is that CGGetActiveDisplayList is going to write data to the pointer you pass it, and it is your responsibility to make sure that you own that memory. If you tell MacRuby that you want a pointer to "^L", it reserves space for the pointer, but not space to hold the data. When you assign a ruby array to the pointer, the Pointer class dynamically allocates space for each element in the array, so if you're going to use that method, I think you might need to assign a blank array of the proper size before you pass the pointer to function: p = Pointer.new_with_type('^L') p.assign(Array.new(count,0)) count_p = Pointer.new_with_type("L") CGGetActiveDisplayList(count, p[0], count_p) This is my understanding from reading through objc.m, someone please correct me if I'm wrong about this. Brian On Fri, Feb 27, 2009 at 8:57 AM, Julien Jassaud <sojastar07@gmail.com> wrote:
Brian, Thanks for the very detailed answer. This tremendously helps. I am now having problems with arrays, though. I try to make a pointer to an array of 32 longs, like this :
p = Pointer.new_with_type('[32L]') => #<Pointer:0x80052af00> p[0] ArgumentError: can't convert C/Objective-C value `0x80052ae40' of type `[32i]' to Ruby object from (irb):49:in `[]' from (irb):49 from /usr/local/bin/macirb:12:in `<main>' Am I not getting the syntax explained in the documentation page you mentioned ? Also, something is puzzling me. In C, arrays are pointers so I thought I could solve the problem (and it works) by doing : p=Pointer.new_with_type('^L') => #<Pointer:0x800530380> p.assign([1,2,3]) => [1, 2, 3] p[0][1] => 2 Great ! I have a pointer to something that looks like an array of longs (and it seems to satisfy the CGGetActiveDisplayList function). But how is it possible when everything here is an object and not a series of neatly aligned bytes ? Anyway, you are right. The part of Cocoa OpenGL I am porting now probably doesn't need to and should be wrapped in an Objective-C object. Thanks, Julien Jassaud Le 26 févr. 09 à 05:43, Brian Chapados a écrit :
Can you explain: "^{_CGLRendererInfoObject=}"? is that some secret
incantation only known by the MacRuby/Obj overlords?
Yes, it is actually a 7th level spell: 'Encode Structure'. To learn it, you must study the ancient tome: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/A...
If it makes you feel better, I usually need to look it up (or just run the Obj-C code sample), unless it is something simple (like '@'). I don't keep this spell in memory, as it is only required in special situations.
Seriously though, that is actually how you encode a pointer to a struct. If you use the @encode(type) directive, the compiler will return the runtime encoding for 'type'. It's a bit cryptic, but not too bad once you know the syntax:
'^type' encodes a pointer to type. '{name=<field1 type><field2 type><field3 type>...<fieldN type>}' encodes a struct with N fields.
To break it down using 2 examples:
(from the docs) typedef struct example { id anObject; // encoding = @ char *aString; // encoding = c int anInt; // enoding = i } Example;
@encode(Example) = "^{example=@ci}"
CGLRendererInfoObj is a pointer to an opaque struct (we don't know anything about the fields) named _CGLRendererInfoObject. All we know is: typedef struct _CGLRendererInfoObject *CGLRendererInfoObj;
so it's just "^{_CGLRendererInfoObject=}"
In practice (unless you're working with CoreFoundation C APIs) you usually just need a pointer to an object. The most common usage I run across is to retrieve NSError objects. The CoreFoundation C API uses pass-by-reference extensively. To use these functions with MacRuby, you need to create lots of pointer objects. In general, this is an area where interfacing ruby with C is just fugly. I'd personally avoid doing this in MacRuby. If you find yourself needing to use lots Pointer objects, it's probably better and less error-prone to write that code in C and expose it to MacRuby through an Objective-C interface.
That said, for common things, I've used something like this extension to the Pointer class:
---- class Pointer def self.ptr new_with_type("@") end
def self.to(type = :object) case type when :object new_with_type('@') when :int new_with_type('i') when :char when :bool when :BOOL new_with_type('c') when :unsigned new_with_type('I') end end
def value self[0] end end
----
Need a pointer to an ObjC object? p = Pointer.ptr
To a BOOL? p = Pointer.to(:BOOL)
Need the value? p.value
Those are the most common types I've needed.
On Wed, Feb 25, 2009 at 11:11 AM, Matt Aimonetti <mattaimonetti@gmail.com> wrote:
Brian, what's up with this syntax: info =
Pointer.new_with_type("^{_CGLRendererInfoObject=}")
Can you explain: "^{_CGLRendererInfoObject=}"? is that some secret
incantation only known by the MacRuby/Obj overlords?
Thanks,
- Matt
On Wed, Feb 25, 2009 at 10:13 AM, Brian Chapados <chapbr@gmail.com> wrote:
CGLRendererInfo is a pointer to a struct:
typedef struct _CGLRendererInfoObject *CGLRendererInfoObj;
try creating a pointer to void or to the struct:
info = Pointer.new_with_type("^v") # void *info;
or
info = Pointer.new_with_type("^{_CGLRendererInfoObject=}") #
CGLRendererInfo *info
I think the second one is effectively the same as what you were trying
to do with:
info = Pointer.new_with_type("CGLRendererInfoObj")
except that the runtime doesn't know what to do with
"CGLRendererInfo". The argument to Pointer.new_with_type must be a
valid Objective-C type encoding[1].
[1]:
http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/A...
If you are ever in doubt about what encoding to use, you can always
compile a small Objective-C program that prints out the output of
@encode(). For example:
#import <Foundation/Foundation.h>
#import <OpenGL/OpenGL.h>
int main(int argc, char *argv[])
{
char *encoding = @encode(CGLRendererInfoObj);
printf("\nencoding => %s\n\n", encoding);
return 0;
}
compile with:
gcc -Wall -o encode encode.m -framework Foundation -framework OpenGL
then run:
./encode
Maybe there is an easier way to obtain the output of @encode(). I'm not
sure.
Brian
On Wed, Feb 25, 2009 at 1:42 AM, Julien Jassaud <julien@collectapply.jp>
wrote:
Hello,
I am trying to port the Cocoa OpenGL sample to MacRuby and encountered a
few
problems.
First, I can't access some constants defined in an enum in GLTypes.h. Do
I
need to port those constants to ruby by hand ? Is that related
to gen_bridge_metadata ?
Second, I need to use CGLQueryRendererInfo
and CGLDescribeRenderer functions. The first one requires a pointer to
a CGLRendererInfoObj structure but the second requires the object to be
passed directly. I tried some C style pointer arithmetic :
info = Pointer.new_with_type("CGLRendererInfoObj")
count = Pointer.new_with_type("l")
CGLQueryRendererInfo(caps[:cgl_display_mask], info, count) <- works
fine,
but CGLRendererInfoObj is opaque so I can't check it in irb.
CGLDescribeRenderer(info[0], 0, kCGLRPRendererCount, count) <- I naively
tried to dereference the pointer, but it doesn't work.
CGLDescribeRenderer(info, 0, kCGLRPRendererCount, count) <- No
complaints,
but the value for count[0] is not consistent (100468704 renderers).
I see in MacIRB that there is a CGLRendererInfoObj class but I
can't instantiate it.
This is all new to me and I may be overlooking something obvious. If
anyone
has an idea, please help.
Thanks,
Julien Jassaud
_______________________________________________
MacRuby-devel mailing list
MacRuby-devel@lists.macosforge.org
http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________
MacRuby-devel mailing list
MacRuby-devel@lists.macosforge.org
http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________
MacRuby-devel mailing list
MacRuby-devel@lists.macosforge.org
http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
participants (5)
-
Brian Chapados
-
Julien Jassaud
-
Julien Jassaud
-
Laurent Sansonetti
-
Matt Aimonetti