"""Selection-buffer handling code
This code is resonsible for turning gluint *
arrays into structured representations for use
by Python-level code.
"""
def uintToLong( value ):
if value < 0:
# array type without a uint, so represented as an int
value = (value & 0x7fffffff) + 0x80000000
return value
class GLSelectRecord( object ):
"""Minimalist object for storing an OpenGL selection-buffer record
Provides near and far as *float* values by dividing by
self.DISTANCE_DIVISOR (2**32-1)
From the spec:
Depth values (which are in the range [0,1]) are multiplied by
2^32 - 1, before being placed in the hit record.
Names are unmodified, so normally are slices of the array passed in
to GLSelectRecord.fromArray( array )
"""
DISTANCE_DIVISOR = float((2L**32)-1)
__slots__ = ('near','far','names')
def fromArray( cls, array, total ):
"""Produce list with all records from the array"""
result = []
index = 0
arrayLength = len(array)
for item in xrange( total ):
if index + 2 >= arrayLength:
break
count = array[index]
near = array[index+1]
far = array[index+2]
names = map(uintToLong, array[index+3:index+3+count])
result.append( cls( near, far, names ) )
index += 3+count
return result
fromArray = classmethod( fromArray )
def __init__( self, near, far, names ):
"""Initialise/store the values"""
self.near = self.convertDistance( near )
self.far = self.convertDistance( far )
self.names = names
def convertDistance( self, value ):
"""Convert a distance value from array uint to 0.0-1.0 range float"""
return uintToLong( value ) / self.DISTANCE_DIVISOR
def __getitem__( self, key ):
"""Allow for treating the record as a three-tuple"""
if isinstance( key, (int,long)):
return (self.near,self.far,self.names)[key]
elif key in self.__slots__:
try:
return getattr( self, key )
except AttributeError, err:
raise KeyError( """Don't have an index/key %r for %s instant"""%(
key, self.__class__,
))
|