Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
How to use structures? setting GLKEffectPropertyLight.position, fails
-
I have been trying to impliment the majority of the GLKit library into my OpenGLES bindings however when I try to set the position variable of a GLKEffectPropertyLight it raises an TypeError.
PropLight = ObjCClass('GLKEffectPropertyLight') # I will rename it later. l = PropLight.new() # .alloc().init() print l.position # <objc_util.ObjCInstanceMethod object at [hex_value]> new_pos = GLKVector4() # Custom ctypes.Union l.setPosition_(new_pos) # Raises TypeError: expected 6 arguments. Got 1.
However I do not know what those 6 arguments should be.
Any help is well appreciatedThe GLKVector4 class.
class xyzw(ctypes.Structure): _fields_ = [ ('x', ctypes.c_float), ('y', ctypes.c_float), ('z', ctypes.c_float), ('w', ctypes.c_float) ] class rgba(ctypes.Structure): _fields_ = [ ('r', ctypes.c_float), ('g', ctypes.c_float), ('b', ctypes.c_float), ('a', ctypes.c_float) ] class stpq(ctypes.Structure): _fields_ = [ ('s', ctypes.c_float), ('t', ctypes.c_float), ('p', ctypes.c_float), ('q', ctypes.c_float) ] class float4(ctypes.Structure): _fields_ = [ ('v', (ctypes.c_float * 4)) ] class GLKVector4(ctypes.Union): _anonymous_ = [ ('s1'), ('s2'), ('s3'), ('s4'), ] _fields_ = [ ('s1', xyzw), ('s2', rgba), ('s3', stpq), ('s4', float4), ]
If it helps
-
i have seen something similar in the latest beta. I believe the intent is now that you would use l.position= rather than l.setPosition_. I have not dug into what is going wrong, but it seems like in some cases, for properties, it is missing the arguments.
you can always use l.setPosition_.encoding (i.e some objcinstancemethod)to check the encoding. The return type is first, followed by a pointer and a selector... then it is your own arguments. Check te objc utils source to understand the type encodings.
-
The type encoding parser doesn't support unions (which are pretty rare in Obj-C). You might need to pass
restype
andargtypes
explicitly. -
Thank you @JonB and @omz for your help
As @omz said the encoding parser does not support unions so for simplicity I have made a wrapper class for GLKEffectPropertyLight, and will be doing so probably for the majority of GLKit.
When I have the majority of it up and running I will update the GitHub repo.Thank you for the help
-
After further test this does not actually resolve the issue, as it now just returns a pointer to the structure (ie the first element of GLKVector4 is now the pointer)
Any ideas on how to fix this? -
Could a Python memoryview be used to serve similar purpose to an Objective C union?
-
I have never used a memoryview object before so I am not entirely sure how to implement/use it however I would assume that it would be the same way I did for a Structure or any other ctypes object (is this correct?)
I will look into it and see whether it helps.
Thanks for the info -
I have done a bit more testing and noticed that this is only an issue for GLKVector(2|3|4) and not for any of the GLKMatrix structures.
I have also updated the Github repo -
you should be able to cast the result as a POINTER(GLKVector3), then access the .contents().
I have been working on extending the objc utils to handle union encoding types, though it is not quite working yet (i can generate the structure from the type encoding, but using that as a restype seems to crash.)
-
Can you please elaborate on what you mean.
Using the current OpenGLES repo under GLKit/light.py
inGLKEffectPropertyLight.getPosition
I have tried both setting the return type and argtypes, but neither seem to work.def getPosition(self): p = GLKVector4() self._light.position(ctypes.byref(p), argtypes=[ctypes.POINTER(GLKVector4)], restype=None) res = self._light.position(argtypes=[], restype=ctypes.POINTER(GLKVector4)) print p return res.contents
-
Something strange seems to be happening in either ctypes, or objc with union return types. At least, on 32 bit, which uses objc_msgSend_stret. That function works by taking in a pointer to an existing structure, and modifying it in place.
It seems as if the size of the object returned is larger than what is passed in as the restype, causing a crash when the correct structure is used. Oddly, it seems like it does not always crash, for instance sometimes when calling l.position() with no left hand side, i was able to get a result.
A workaround is to pass in a larger structure for the return type, to ensure nothing gets overwritten. if you want to pass the struct back to objc, however, you must pass the right size, so you can use cast to cast to to correct type. This should work with your Union types as well. You must use the argtypes/restype input to override these.
from objc_util import * PropLight = ObjCClass('GLKEffectPropertyLight') # I will rename it later. l = PropLight.alloc().init() glk4 = parse_struct('{glkvec4=ffff}') glk4_union = parse_struct('{glkvec4union=fffff}') #union seems to have an extra field.... # test code: newpos=glk4() newpos.a=1. newpos.b=2. newpos.c=3. newpos.d=4. l.setPosition_(newpos,restype=ctypes.c_void_p, argtypes=[glk4]) # read back position, then cast to correct type retpos=l.position(restype=glk4_union, argtypes=[]) pos=ctypes.cast(ctypes.pointer(retpos),ctypes.POINTER(glk4)).contents print 'original', newpos.a,newpos.b, newpos.c, newpos.d print 'returned', retpos.a, retpos.b, retpos.c, retpos.d print 'cast', pos.a, pos.b, pos.c, pos.d
-
btw, if you are 64 bit, i suspect you can just use position() with restype= GLKVector4 and argtypes=[]. i suspect the extra size trick is needed only for 32 bit. Note you need to use setPosition_ to set.
-
Is it possible that you have discovered an overwrite condition in Apple's API that could be used as an exploit by a dishonest coder?
-
-
-
@JonB I am unable to get, I don't not if setting is working either. Using the example you provided I get
original 1.0 2.0 3.0 4.0 returned 9.45935362045e+19 1.40129846432e-45 2.80259692865e-45 0.0 cast 9.45935362045e+19 1.40129846432e-45 2.80259692865e-45 0.0
However
original
,returned
andcast
should all be the same, shouldn't they? -
-
@omz that seemed to fix it. Thanks