def get_image_data(self, z=0, fmt='RGBA', gl_format=gl.GL_RGBA): """Get the image data of this texture. Changes to the returned instance will not be reflected in this texture. :Parameters: `z` : int For 3D textures, the image slice to retrieve. :rtype: :py:class:`~pyglet.image.ImageData` """ gl.glBindTexture(self.target, self.id) # # Always extract complete RGBA data. Could check internalformat # # to only extract used channels. XXX # fmt = 'RGBA' # gl_format = gl.GL_RGBA gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1) buffer = (gl.GLubyte * (self.width * self.height * self.images * len(fmt)))() gl.glGetTexImage(self.target, self.level, gl_format, gl.GL_UNSIGNED_BYTE, buffer) data = pyglet.image.ImageData(self.width, self.height, fmt, buffer) if self.images > 1: data = data.get_region(0, z * self.height, self.width, self.height) return data
def _drawLUTtoScreen(self): """(private) Used to set the LUT in Bits++ mode. Should not be needed by user if attached to a ``psychopy.visual.Window()`` since this will automatically draw the LUT as part of the screen refresh. """ #push the projection matrix and set to orthorgaphic GL.glMatrixMode(GL.GL_PROJECTION) GL.glPushMatrix() GL.glLoadIdentity() GL.glOrtho( 0, self.win.size[0],self.win.size[1], 0, 0, 1 ) #this also sets the 0,0 to be top-left #but return to modelview for rendering GL.glMatrixMode(GL.GL_MODELVIEW) GL.glLoadIdentity() #draw the pixels GL.glActiveTextureARB(GL.GL_TEXTURE0_ARB) GL.glEnable(GL.GL_TEXTURE_2D) GL.glBindTexture(GL.GL_TEXTURE_2D, 0) GL.glActiveTextureARB(GL.GL_TEXTURE1_ARB) GL.glEnable(GL.GL_TEXTURE_2D) GL.glBindTexture(GL.GL_TEXTURE_2D, 0) GL.glRasterPos2i(0,1) GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1) GL.glDrawPixels(len(self._HEADandLUT),1, GL.GL_RGB,GL.GL_UNSIGNED_BYTE, self._HEADandLUTstr) #GL.glDrawPixels(524,1, GL.GL_RGB,GL.GL_UNSIGNED_BYTE, self._HEADandLUTstr) #return to 3D mode (go and pop the projection matrix) GL.glMatrixMode( GL.GL_PROJECTION ) GL.glPopMatrix() GL.glMatrixMode( GL.GL_MODELVIEW )
def __init__(self, size: Tuple[int, int], component: int, data): self.width, self.height = size sized_format = (gl.GL_R8, gl.GL_RG8, gl.GL_RGB8, gl.GL_RGBA8)[component - 1] self.format = (gl.GL_R, gl.GL_RG, gl.GL_RGB, gl.GL_RGBA)[component - 1] gl.glActiveTexture(gl.GL_TEXTURE0 + 0) # If we need other texture unit... self.texture_id = texture_id = gl.GLuint() gl.glGenTextures(1, byref(self.texture_id)) if self.texture_id.value == 0: raise ShaderException("Cannot create Texture.") gl.glBindTexture(gl.GL_TEXTURE_2D, self.texture_id) gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) try: gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, sized_format, self.width, self.height, 0, self.format, gl.GL_UNSIGNED_BYTE, data) except gl.GLException: raise gl.GLException( f"Unable to create texture. {gl.GL_MAX_TEXTURE_SIZE} {size}") gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR) gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR) weakref.finalize(self, Texture.release, texture_id)
def _drawLUTtoScreen(self): """(private) Used to set the LUT in 'bits++' mode. Should not be needed by user if attached to a ``psychopy.visual.Window()`` since this will automatically draw the LUT as part of the screen refresh. """ # push the projection matrix and set to orthorgaphic GL.glMatrixMode(GL.GL_PROJECTION) GL.glPushMatrix() GL.glLoadIdentity() # this also sets the 0,0 to be top-left GL.glOrtho(0, self.win.size[0], self.win.size[1], 0, 0, 1) # but return to modelview for rendering GL.glMatrixMode(GL.GL_MODELVIEW) GL.glLoadIdentity() # draw the pixels GL.glActiveTextureARB(GL.GL_TEXTURE0_ARB) GL.glEnable(GL.GL_TEXTURE_2D) GL.glBindTexture(GL.GL_TEXTURE_2D, 0) GL.glActiveTextureARB(GL.GL_TEXTURE1_ARB) GL.glEnable(GL.GL_TEXTURE_2D) GL.glBindTexture(GL.GL_TEXTURE_2D, 0) GL.glRasterPos2i(0, 1) GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1) GL.glDrawPixels(len(self._HEADandLUT), 1, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, self._HEADandLUTstr) # GL.glDrawPixels(524,1, GL.GL_RGB,GL.GL_UNSIGNED_BYTE, # self._HEADandLUTstr) # return to 3D mode (go and pop the projection matrix) GL.glMatrixMode(GL.GL_PROJECTION) GL.glPopMatrix() GL.glMatrixMode(GL.GL_MODELVIEW)
def set_data(self, arr): arr = np.asarray(arr) self.src_format, self.dst_format = fmts_from_shape(arr.shape, self._texture_dim) # Float is default type if arr.dtype == np.uint8: arr = np.ascontiguousarray(arr) self.src_type = gl.GL_UNSIGNED_BYTE elif arr.dtype == np.float32: arr = np.ascontiguousarray(arr) self.src_type = gl.GL_FLOAT else: arr = np.astype(np.float32) self.src_type = gl.GL_FLOAT self._arr = arr if self._id: gl.glDeleteTextures(1, gl.byref(self._id)) id = gl.GLuint() gl.glGenTextures(1, gl.byref(id)) self._id = id gl.glPixelStorei (gl.GL_UNPACK_ALIGNMENT, 1) gl.glPixelStorei (gl.GL_PACK_ALIGNMENT, 1) gl.glBindTexture (self.target, self._id) gl.glTexParameterf (self.target, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST) gl.glTexParameterf (self.target, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST) gl.glTexParameterf (self.target, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP) gl.glTexParameterf (self.target, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP) self._setup_tex() self.update()
def _texture_2d(self, data): """Create a 2D texture""" # Make sure we unpack the pixel data with correct alignment # or we'll end up with corrupted textures gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, self._alignment) gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, self._alignment) # Create depth 2d texture if self._depth: gl.glTexImage2D( self._target, 0, # level gl.GL_DEPTH_COMPONENT24, self._width, self._height, 0, gl.GL_DEPTH_COMPONENT, gl.GL_FLOAT, data, ) self.compare_func = "<=" # Create normal 2d texture else: try: format_info = pixel_formats[self._dtype] except KeyError: raise ValueError( f"dype '{self._dtype}' not support. Supported types are : {tuple(pixel_formats.keys())}" ) try: ( _format, _internal_format, self._type, self._component_size, ) = format_info self._format = _format[self._components] self._internal_format = _internal_format[self._components] gl.glTexImage2D( self._target, # target 0, # level self._internal_format, # internal_format self._width, # width self._height, # height 0, # border self._format, # format self._type, # type data, # data ) except gl.GLException as ex: raise gl.GLException( ( f"Unable to create texture: {ex} : dtype={self._dtype} size={self.size} components={self._components} " "MAX_TEXTURE_SIZE = {self.ctx.limits.MAX_TEXTURE_SIZE}" ) )
def _updateFrameTexture(self): if self._nextFrameT is None: # movie has no current position, need to reset the clock # to zero in order to have the timing logic work # otherwise the video stream would skip frames until the # time since creating the movie object has passed self._videoClock.reset() self._nextFrameT = 0 #only advance if next frame (half of next retrace rate) if self._nextFrameT > self.duration: self._onEos() elif (self._numpyFrame is not None) and \ (self._nextFrameT > (self._videoClock.getTime()-self._retraceInterval/2.0)): return None self._numpyFrame = self._mov.get_frame(self._nextFrameT) useSubTex=self.useTexSubImage2D if self._texID is None: self._texID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._texID)) useSubTex=False #bind the texture in openGL GL.glEnable(GL.GL_TEXTURE_2D) GL.glBindTexture(GL.GL_TEXTURE_2D, self._texID)#bind that name to the target GL.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_WRAP_S,GL.GL_REPEAT) #makes the texture map wrap (this is actually default anyway) GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1) # data from PIL/numpy is packed, but default for GL is 4 bytes #important if using bits++ because GL_LINEAR #sometimes extrapolates to pixel vals outside range if self.interpolate: GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR) if useSubTex is False: GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB8, self._numpyFrame.shape[1],self._numpyFrame.shape[0], 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, self._numpyFrame.ctypes) else: GL.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, self._numpyFrame.shape[1], self._numpyFrame.shape[0], GL.GL_RGB, GL.GL_UNSIGNED_BYTE, self._numpyFrame.ctypes) else: GL.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_MAG_FILTER,GL.GL_NEAREST) GL.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_MIN_FILTER,GL.GL_NEAREST) if useSubTex is False: GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB8, self._numpyFrame.shape[1],self._numpyFrame.shape[0], 0, GL.GL_BGR, GL.GL_UNSIGNED_BYTE, self._numpyFrame.ctypes) else: GL.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, self._numpyFrame.shape[1], self._numpyFrame.shape[0], GL.GL_BGR, GL.GL_UNSIGNED_BYTE, self._numpyFrame.ctypes) GL.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE)#?? do we need this - think not! if not self.status==PAUSED: self._nextFrameT += self._frameInterval
def attach_input(in_data, in_size): # Load input gl.glBindTexture(gl.GL_TEXTURE_3D, input_texture) glTypeFromNp = { np.dtype('uint8'): gl.GL_UNSIGNED_BYTE, np.dtype('uint16'): gl.GL_UNSIGNED_SHORT, np.dtype('uint32'): gl.GL_UNSIGNED_INT, np.dtype('float32'): gl.GL_FLOAT } gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) gl.glTexImage3D(gl.GL_TEXTURE_3D, 0, gl.GL_RED, in_size[0], in_size[1], in_size[2], 0, gl.GL_RED, glTypeFromNp[in_data.dtype], ctypes.c_void_p(in_data.ctypes.data))
def read(self, level: int = 0, alignment: int = 1) -> bytearray: """ Read the contents of the texture. :param int level: The texture level to read :param int alignment: Alignment of the start of each row in memory in number of bytes. Possible values: 1,2,4 :rtype: bytearray """ gl.glBindTexture(self._target, self._glo) gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, alignment) buffer = (gl.GLubyte * (self.width * self.height * self._component_size * self._components))() gl.glGetTexImage(gl.GL_TEXTURE_2D, level, self._format, self._type, buffer) return bytearray(buffer)
def get_layer_preview_texture(self, layer, colors, size=(32, 32)): w, h = layer.size size = w, h texture = Texture(size, params={gl.GL_TEXTURE_MIN_FILTER: gl.GL_LINEAR}) texture.clear() data = as_rgba(layer.get_data(self.drawing.frame), colors) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 4) gl.glTextureSubImage2D( texture.name, 0, 0, 0, w, h, # min(w, bw), min(w, bh), gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, data.tobytes("F")) return texture
def build_kernel(size=256): # From GPU Gems # Chapter 24. High-Quality Filtering # Kevin Bjorke, NVIDIA # http://http.developer.nvidia.com/GPUGems/gpugems_ch24.html # # Mitchell Netravali Reconstruction Filter # a = 1.0, b = 0.0 - cubic B-spline # B = 1/3, b = 1/3 - recommended # a = 0.5, b = 0.0 - Catmull-Rom spline def MitchellNetravali(x, a=1, b=0): x = math.fabs(x) if x < 1.0: return ((12-9*a-6*b) *x*x*x + (-18+12*a+6*b)*x*x + (6-2*a))/6.0 elif x < 2.0: return ((-a-6*b)*x*x*x + (6*a+30*b)*x*x + (-12*a-48*b)*x + (8*a+24*b))/6.0 else: return 0 data = (gl.GLfloat*(4*size))() for i in range(size): x = i/float(size-1) data[i*4+0] = MitchellNetravali(x+1) data[i*4+1] = MitchellNetravali(x) data[i*4+2] = MitchellNetravali(1-x) data[i*4+3] = MitchellNetravali(2-x) texid = gl.GLuint() gl.glGenTextures(1, ctypes.byref(texid)) kernel = texid.value gl.glPixelStorei (gl.GL_UNPACK_ALIGNMENT, 1) gl.glPixelStorei (gl.GL_PACK_ALIGNMENT, 1) gl.glBindTexture (gl.GL_TEXTURE_1D, texid) gl.glTexParameterf (gl.GL_TEXTURE_1D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST) gl.glTexParameterf (gl.GL_TEXTURE_1D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST) gl.glTexParameterf (gl.GL_TEXTURE_1D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP) gl.glTexParameterf (gl.GL_TEXTURE_1D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP) gl.glTexImage1D (gl.GL_TEXTURE_1D, 0, gl.GL_RGBA16, size, 0, gl.GL_RGBA, gl.GL_FLOAT, data) return kernel
def get_brush_preview_texture(self, brush, colors=None, size=(8, 8)): colors = colors or self.drawing.palette.as_tuple() bw, bh = brush.size w, h = size w, h = size = max(w, bw), max(h, bh) texture = Texture(size) texture.clear() data = as_rgba(brush.data, colors).tobytes("F") gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 4) gl.glTextureSubImage2D( texture.name, 0, max(0, w // 2 - bw // 2), max(0, h // 2 - bh // 2), bw, bh, # min(w, bw), min(w, bh), gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, data) return texture
def write(self, data: Union[bytes, Buffer], level: int = 0, viewport=None) -> None: """Write byte data to the texture. This can be bytes or a :py:class:`~arcade.gl.Buffer`. :param Union[bytes,Buffer] data: bytes or a Buffer with data to write :param int level: The texture level to write :param tuple viewport: The are of the texture to write. 2 or 4 component tuple """ # TODO: Support writing to layers using viewport + alignment if self._samples > 0: raise ValueError("Writing to multisample textures not supported") x, y, w, h = 0, 0, self._width, self._height if viewport: if len(viewport) == 2: w, h = viewport elif len(viewport) == 4: x, y, w, h = viewport else: raise ValueError("Viewport must be of length 2 or 4") if isinstance(data, Buffer): gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, data.glo) gl.glActiveTexture(gl.GL_TEXTURE0) gl.glBindTexture(self._target, self._glo) gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) gl.glTexSubImage2D(self._target, level, x, y, w, h, self._format, self._type, 0) gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, 0) else: byte_size, data = data_to_ctypes(data) gl.glActiveTexture(gl.GL_TEXTURE0) gl.glBindTexture(self._target, self._glo) gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) gl.glTexSubImage2D( self._target, # target level, # level x, # x offset y, # y offset w, # width h, # height self._format, # format self._type, # type data, # pixel data )
def create_point_texture(size, feather=0): """Create and load a circular grayscale image centered in a square texture with a width and height of size. The radius of the circle is size / 2. Since size is used as the texture width and height, it should typically be a power of two. Feather determines the softness of the edge of the circle. The default, zero, creates a hard edged circle. Larger feather values create softer edges for blending. The point at the center of the texture is always white. Return the OpenGL texture name (id) for the resulting texture. This value can be passed directy to a texturizer or glBindTexture """ from pyglet import gl assert feather >= 0, 'Expected feather value >= 0' coords = range(size) texel = (gl.GLfloat * size**2)() r = size / 2.0 c = feather + 1.0 for y in coords: col = y * size for x in coords: d = math.sqrt((x - r)**2 + (y - r)**2) if d < r and (1.0 - 1.0 / (d / r - 1.0)) < 100: texel[x + col] = c**2 / c**(1.0 - 1.0 / (d / r - 1.0)) else: texel[x + col] = 0 id = gl.GLuint() gl.glGenTextures(1, ctypes.byref(id)) gl.glBindTexture(gl.GL_TEXTURE_2D, id.value) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 4) gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_LUMINANCE, size, size, 0, gl.GL_LUMINANCE, gl.GL_FLOAT, ctypes.byref(texel)) gl.glFlush() return id.value
def create_texobject(self, color_table, format=gl.GL_RGB, internalformat=gl.GL_RGB): k = (tuple(color_table), format, internalformat) texobj = self._texobjects.get(k) if texobj: return texobj width = { gl.GL_RGB: 3, gl.GL_RGBA: 4, gl.GL_LUMINANCE: 1, gl.GL_LUMINANCE_ALPHA: 2}[format] texobj = gl.GLuint() gl.glGenTextures( 1, ctypes.byref(texobj) ) gl.glEnable( gl.GL_TEXTURE_1D ) gl.glBindTexture( gl.GL_TEXTURE_1D, texobj ) gl.glTexEnvi( gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_DECAL ) gl.glTexParameteri( gl.GL_TEXTURE_1D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST ) gl.glTexParameteri( gl.GL_TEXTURE_1D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST ) gl.glTexParameteri( gl.GL_TEXTURE_1D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP ) gl.glPixelStorei( gl.GL_UNPACK_ALIGNMENT, 1 ) gl.glTexImage1D( gl.GL_TEXTURE_1D, 0, internalformat, width, 0, format, gl.GL_UNSIGNED_BYTE, color_table ) group = TextureBindGroup(texobj, target=gl.GL_TEXTURE_1D, parent=tex_enable_group_1D(target=gl.GL_TEXTURE_1D)) #group = CellShaderGroup(texobj, color_table, width, # format, internalformat) self._texobjects[k] = texobj self._defaultgroups[texobj.value] = group return texobj
def load_textures(file_name: str, image_location_list: PointList, mirrored: bool=False, flipped: bool=False, scale: float=1) -> List['Texture']: """ Load a set of textures off of a single image file. Note, if the code is to load only part of the image, the given x, y coordinates will start with the origin (0, 0) in the upper left of the image. When drawing, Arcade uses (0, 0) in the lower left corner when drawing. Be careful about this reversal. For a longer explanation of why computers sometimes start in the upper left, see: http://programarcadegames.com/index.php?chapter=introduction_to_graphics&lang=en#section_5 Args: :file_name: Name of the file. :image_location_list: List of image locations. Each location should be a list of four floats. ``[x, y, width, height]``. :mirrored=False: If set to true, the image is mirrored left to right. :flipped=False: If set to true, the image is flipped upside down. Returns: :list: List of textures loaded. Raises: :SystemError: """ source_image = PIL.Image.open(file_name) source_image_width, source_image_height = source_image.size texture_info_list = [] for image_location in image_location_list: x, y, width, height = image_location if width <= 0: raise ValueError("Texture has a width of {}, must be > 0." .format(width)) if x > source_image_width: raise ValueError("Can't load texture starting at an x of {} " "when the image is only {} across." .format(x, source_image_width)) if y > source_image_height: raise ValueError("Can't load texture starting at an y of {} " "when the image is only {} high." .format(y, source_image_height)) if x + width > source_image_width: raise ValueError("Can't load texture ending at an x of {} " "when the image is only {} wide." .format(x + width, source_image_width)) if y + height > source_image_height: raise ValueError("Can't load texture ending at an y of {} " "when the image is only {} high." .format(y + height, source_image_height)) image = source_image.crop((x, y, x + width, y + height)) # image = _trim_image(image) if mirrored: image = PIL.ImageOps.mirror(image) if flipped: image = PIL.ImageOps.flip(image) image_width, image_height = image.size texture = gl.GLuint(0) gl.glGenTextures(1, ctypes.byref(texture)) gl.glBindTexture(gl.GL_TEXTURE_2D, texture) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_REPEAT) gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_REPEAT) gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR) gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR_MIPMAP_LINEAR) image_width *= scale image_height *= scale texture_info_list.append(Texture(texture, width, height, image_location)) return texture_info_list
def main(): t = time.time() parser = argparse.ArgumentParser() parser.add_argument('--tex', help='input tiff file (*.tiff for sequence)', default='') parser.add_argument('--in_box', help='--insize x y z w h d', type=int, nargs=6, default=[0, 0, 0, 0, 0, 0]) parser.add_argument('--code', help='--code "return texture(tex,p).r;"', default='return texture(tex,p).r;') parser.add_argument('--size', help='--size w h d', nargs=3, type=int, default=[0, 0, 0]) parser.add_argument('--seam', help='--seam dd', nargs=1, type=int, default=10) parser.add_argument('--compress', help='compression level', type=int, default=2) parser.add_argument('out_tiff', help='output tiff file', type=str) args = parser.parse_args() seam = args.seam if '*' in args.tex: import os dr = os.path.split(args.tex)[0] + '/' print(dr, os.path.isdir(dr)) seq = tifffile.TiffSequence(args.tex) in_data = seq.asarray() print(in_data.shape, in_data.dtype) print(in_data[0][0][0]) # in_data = in_data.astype(np.uint32) # print(in_data[0][0][0]) elif os.path.isfile(args.tex): in_data = tifffile.imread(args.tex) else: in_data = np.zeros((1, 1, 1), dtype=np.uint32) if len(in_data.shape) != 3: print('Not a 3D grayscale tiff:', in_data.shape) # if len(in_data.shape)==4: # print('Using red channel') in_d, in_h, in_w = in_data.shape in_size = in_w, in_h, in_d bx, by, bz, bw, bh, bd = args.in_box bw = in_w - bx if bw == 0 or bx + bw > in_w else bw bh = in_h - by if bh == 0 or by + bh > in_h else bh bd = in_d - bz if bd == 0 or bz + bd > in_d else bd time_loaded = time.time() print('Loading input {} took {:.2f} seconds'.format( in_size, time_loaded - t)) if (bw, bh, bd) != in_size: print('Clipping to [{},{})x[{},{})x[{},{})'.format( bx, bx + bw, by, by + bh, bz, bz + bd)) in_size = (bw, bh, bd) in_w, in_h, in_d = in_size in_data = in_data[bz:bz + bd, by:by + bh, bx:bx + bw] out_w, out_h, out_d = args.size out_w = in_w if out_w <= 0 else out_w out_h = in_h if out_h <= 0 else out_h out_d = in_d if out_d <= 0 else out_d out_size = (out_w, out_h, out_d) pixPerZ = in_w * in_h zPerBatch = SAFE_TEX_SIZE // pixPerZ - 2 * seam batches = [(i, i + zPerBatch) for i in range(0, in_d, zPerBatch)] setup_framebuffer() setup_render_program(args.code) setup_render_vertexbuffer() time_setup = time.time() print('Setup took {:.2f} seconds'.format(time_setup - time_loaded)) time_buffered = time_setup warned = False out_batches = [] for z0, z1 in batches: z0 = max(0, z0) z1 = min(in_d, z1) z0s = max(0, z0 - seam) z1s = min(in_d, z1 + seam) batch_out_d = out_d * (z1 - z0) / in_d if not warned and batch_out_d != int(batch_out_d) and len(batches) > 1: warned = True print( 'Warning: input/output Z-dimension mismatch while using multiple batches' ) batch_out_d = int(batch_out_d) batch_in_size = (in_w, in_h, z1s - z0s) batch_out_size = (out_w, out_h, batch_out_d) attach_input(in_data[z0s:z1s], batch_in_size) attach_output(batch_out_size) time_transfer = time.time() print('Texture transfer {} took {:.2f} seconds'.format( (z0s, z0, z1, z1s), time_transfer - time_buffered)) render_to_texture(batch_in_size, batch_out_size, (z0 - z0s, z1 - z0s)) time_rendered = time.time() print('Rendering took {:.2f} seconds'.format(time_rendered - time_transfer)) buf = (gl.GLubyte * (out_w * out_h * batch_out_d))() gl.glBindTexture(gl.GL_TEXTURE_3D, rendered_texture) gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1) gl.glGetTexImage(gl.GL_TEXTURE_3D, 0, gl.GL_RED, gl.GL_UNSIGNED_BYTE, buf) out_batches.append( np.frombuffer(buf, dtype=np.uint8).reshape( (batch_out_d, out_h, out_w))) time_buffered = time.time() print('Buffering took {:.2f} seconds'.format(time_buffered - time_rendered)) out_data = np.concatenate(out_batches) time_cat = time.time() print('Concatenating took {:.2f} seconds'.format(time_cat - time_buffered)) # export t = time.time() tifffile.imwrite(args.out_tiff, out_data, bigtiff=True, compress=args.compress, photometric='minisblack', metadata={ 'title': str(out_data.shape), 'code': str(args.code) }) time_exported = time.time() print('Exporting took {:.2f} seconds; size {:.2f} MB'.format( time_exported - t, os.path.getsize(args.out_tiff) / 1024**2))
def render_drawing(drawing, highlighted_layer=None): """ This function has the job of rendering a drawing to a framebuffer. """ offscreen_buffer = _get_offscreen_buffer(drawing.size) colors = _get_colors(drawing.palette.as_tuple()) with vao, offscreen_buffer, draw_program: w, h = offscreen_buffer.size gl.glViewport(0, 0, w, h) gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glClearBufferfv(gl.GL_COLOR, 0, EMPTY_COLOR) overlay = drawing.overlay overlay_texture = _get_overlay_texture(overlay.size) if overlay.dirty.get(0) and overlay.lock.acquire(timeout=0.01): # Since we're drawing in a separate thread, we need to be very careful # when accessing the overlay, otherwise we can get nasty problems. # While we have the lock, the thread won't draw, so we can safely copy data. # The acquire timeout is a compromise; on one hand, we don't wait # so long that the user feels stutter, on the other hand, # if we never wait, and the draw thread is very busy, we might # not get to update for a long time. rect = overlay.dirty[0] subimage = overlay.get_subimage(rect) data = subimage.tobytes("F") # TODO Is this making another copy? # Now update the texture with the changed part of the layer. try: gl.glTextureSubImage2D(overlay_texture.name, 0, *rect.points, gl.GL_RGBA_INTEGER, gl.GL_UNSIGNED_BYTE, data) overlay.dirty.pop(0) overlay.lock.release() # Allow layer to change again. except gl.lib.GLException as e: logging.error(str(e)) frame = drawing.frame for layer in drawing.layers: if highlighted_layer and highlighted_layer != layer: continue # TODO might be a good optimization to draw the layers above and # above into two separate textures, so we don't have # to iterate over them all every frame. Also cuts down on the # number of textures in GPU memory. # Assumes the non-current textures don't change though. layer_texture = _get_layer_texture(layer, frame) if layer.dirty.get(frame) and layer.lock.acquire(timeout=0.03): rect = layer.dirty[frame] subimage = layer.get_subimage(rect, frame) data = subimage.tobytes("F") gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) # Needed for writing 8bit data gl.glTextureSubImage2D(layer_texture.name, 0, *rect.points, gl.GL_RED_INTEGER, gl.GL_UNSIGNED_BYTE, data) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 4) layer.dirty.pop(frame) layer.lock.release() if not layer.visible and highlighted_layer != layer: continue with layer_texture: if layer == drawing.current: # The overlay is combined with the layer with overlay_texture: # TODO is it possible to send the palette without converting # to float first? gl.glUniform1f(1, 1) gl.glUniform4fv(2, 256, colors) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) else: with _get_empty_texture(drawing.size): gl.glUniform1f(1, 1) gl.glUniform4fv(2, 256, colors) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) gl.glDisable(gl.GL_BLEND) return offscreen_buffer
def createTexImage2D(width, height, target=GL.GL_TEXTURE_2D, level=0, internalFormat=GL.GL_RGBA8, pixelFormat=GL.GL_RGBA, dataType=GL.GL_FLOAT, data=None, unpackAlignment=4, texParameters=()): """Create a 2D texture in video memory. This can only create a single 2D texture with targets GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE. Parameters ---------- width : :obj:`int` Texture width in pixels. height : :obj:`int` Texture height in pixels. target : :obj:`int` The target texture should only be either GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE. level : :obj:`int` LOD number of the texture, should be 0 if GL_TEXTURE_RECTANGLE is the target. internalFormat : :obj:`int` Internal format for texture data (e.g. GL_RGBA8, GL_R11F_G11F_B10F). pixelFormat : :obj:`int` Pixel data format (e.g. GL_RGBA, GL_DEPTH_STENCIL) dataType : :obj:`int` Data type for pixel data (e.g. GL_FLOAT, GL_UNSIGNED_BYTE). data : :obj:`ctypes` or :obj:`None` Ctypes pointer to image data. If None is specified, the texture will be created but pixel data will be uninitialized. unpackAlignment : :obj:`int` Alignment requirements of each row in memory. Default is 4. texParameters : :obj:`list` of :obj:`tuple` of :obj:`int` Optional texture parameters specified as a list of tuples. These values are passed to 'glTexParameteri'. Each tuple must contain a parameter name and value. For example, texParameters=[(GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR), (GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR)] Returns ------- :obj:`TexImage2D` A TexImage2D descriptor. Notes ----- The 'userData' field of the returned descriptor is a dictionary that can be used to store arbitrary data associated with the texture. Previous textures are unbound after calling 'createTexImage2D'. Examples -------- import pyglet.gl as GL # using Pyglet for now # empty texture textureDesc = createTexImage2D(1024, 1024, internalFormat=GL.GL_RGBA8) # load texture data from an image file using Pillow and NumPy from PIL import Image import numpy as np im = Image.open(imageFile) # 8bpp! im = im.transpose(Image.FLIP_TOP_BOTTOM) # OpenGL origin is at bottom im = im.convert("RGBA") pixelData = np.array(im).ctypes # convert to ctypes! width = pixelData.shape[1] height = pixelData.shape[0] textureDesc = gltools.createTexImage2D( texture_array.shape[1], texture_array.shape[0], internalFormat=GL.GL_RGBA, pixelFormat=GL.GL_RGBA, dataType=GL.GL_UNSIGNED_BYTE, data=texture_array.ctypes, unpackAlignment=1, texParameters=[(GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR), (GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR)]) GL.glBindTexture(GL.GL_TEXTURE_2D, textureDesc.id) """ width = int(width) height = int(height) if width <= 0 or height <= 0: raise ValueError("Invalid image dimensions {} x {}.".format( width, height)) if target == GL.GL_TEXTURE_RECTANGLE: if level != 0: raise ValueError("Invalid level for target GL_TEXTURE_RECTANGLE, " "must be 0.") GL.glEnable(GL.GL_TEXTURE_RECTANGLE) colorTexId = GL.GLuint() GL.glGenTextures(1, ctypes.byref(colorTexId)) GL.glBindTexture(target, colorTexId) GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, int(unpackAlignment)) GL.glTexImage2D(target, level, internalFormat, width, height, 0, pixelFormat, dataType, data) # apply texture parameters if texParameters: for pname, param in texParameters: GL.glTexParameteri(target, pname, param) GL.glBindTexture(target, 0) return TexImage2D(colorTexId, target, width, height, internalFormat, pixelFormat, dataType, unpackAlignment, 1, False, dict())
def _updateFrameTexture(self): """Update texture pixel store to contain the present frame. Decoded frame image samples are streamed to the texture buffer. """ if self._nextFrameT is None or self._nextFrameT < 0: # movie has no current position (or invalid position -JK), # need to reset the clock to zero in order to have the # timing logic work otherwise the video stream would skip # frames until the time since creating the movie object has passed self._videoClock.reset() self._nextFrameT = 0.0 # only advance if next frame (half of next retrace rate) if self._nextFrameT > self.duration: self._onEos() elif self._numpyFrame is not None: if self._nextFrameT > (self._videoClock.getTime() - self._retraceInterval / 2.0): return None while self._nextFrameT <= (self._videoClock.getTime() - self._frameInterval * 2): self.nDroppedFrames += 1 if self.nDroppedFrames <= reportNDroppedFrames: logging.warning( "{}: Video catchup needed, advancing self._nextFrameT from" " {} to {}".format(self._videoClock.getTime(), self._nextFrameT, self._nextFrameT + self._frameInterval)) if self.nDroppedFrames == reportNDroppedFrames: logging.warning( "Max reportNDroppedFrames reached, will not log any more dropped frames" ) self._nextFrameT += self._frameInterval try: self._numpyFrame = self._mov.get_frame(self._nextFrameT) except OSError: if self.autoLog: logging.warning( "Frame {} not found, moving one frame and trying again". format(self._nextFrameT), obj=self) self._nextFrameT += self._frameInterval self._updateFrameTexture() useSubTex = self.useTexSubImage2D if self._texID is None: self._texID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._texID)) useSubTex = False GL.glActiveTexture(GL.GL_TEXTURE0) # bind that name to the target GL.glBindTexture(GL.GL_TEXTURE_2D, self._texID) # bind the texture in openGL GL.glEnable(GL.GL_TEXTURE_2D) # makes the texture map wrap (this is actually default anyway) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP) # data from PIL/numpy is packed, but default for GL is 4 bytes GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1) # important if using bits++ because GL_LINEAR # sometimes extrapolates to pixel vals outside range if self.interpolate: GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR) if useSubTex is False: GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB8, self._numpyFrame.shape[1], self._numpyFrame.shape[0], 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, self._numpyFrame.ctypes) else: GL.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, self._numpyFrame.shape[1], self._numpyFrame.shape[0], GL.GL_RGB, GL.GL_UNSIGNED_BYTE, self._numpyFrame.ctypes) else: GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST) if useSubTex is False: GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB8, self._numpyFrame.shape[1], self._numpyFrame.shape[0], 0, GL.GL_BGR, GL.GL_UNSIGNED_BYTE, self._numpyFrame.ctypes) else: GL.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, self._numpyFrame.shape[1], self._numpyFrame.shape[0], GL.GL_BGR, GL.GL_UNSIGNED_BYTE, self._numpyFrame.ctypes) GL.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE) # ?? do we need this - think not! if self.status == PLAYING: self._nextFrameT += self._frameInterval
def load_textures(file_name: str, image_location_list: PointList, mirrored: bool = False, flipped: bool = False, scale: float = 1) -> List['Texture']: """ Load a set of textures off of a single image file. Args: :file_name: Name of the file. :image_location_list: List of image locations. Each location should be a list of four floats. ``[x, y, width, height]``. :mirrored=False: If set to true, the image is mirrored left to right. :flipped=False: If set to true, the image is flipped upside down. Returns: :list: List of textures loaded. Raises: :SystemError: """ source_image = PIL.Image.open(file_name) source_image_width, source_image_height = source_image.size texture_info_list = [] for image_location in image_location_list: x, y, width, height = image_location if width <= 0: raise ValueError( "Texture has a width of {}, must be > 0.".format(width)) if x > source_image_width: raise ValueError("Can't load texture starting at an x of {} " "when the image is only {} across.".format( x, source_image_width)) if y > source_image_height: raise ValueError("Can't load texture starting at an y of {} " "when the image is only {} high.".format( y, source_image_height)) if x + width > source_image_width: raise ValueError("Can't load texture ending at an x of {} " "when the image is only {} wide.".format( x + width, source_image_width)) if y + height > source_image_height: raise ValueError("Can't load texture ending at an y of {} " "when the image is only {} high.".format( y + height, source_image_height)) image = source_image.crop((x, y, x + width, y + height)) # image = _trim_image(image) if mirrored: image = PIL.ImageOps.mirror(image) if flipped: image = PIL.ImageOps.flip(image) image_width, image_height = image.size texture = gl.GLuint(0) gl.glGenTextures(1, ctypes.byref(texture)) gl.glBindTexture(gl.GL_TEXTURE_2D, texture) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_REPEAT) gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_REPEAT) gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR) gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR_MIPMAP_LINEAR) image_width *= scale image_height *= scale texture_info_list.append(Texture(texture, width, height)) return texture_info_list
def load_texture(file_name: str, x: float = 0, y: float = 0, width: float = 0, height: float = 0, mirrored: bool = False, flipped: bool = False, scale: float = 1) -> arcade.Texture: """ Load image from disk and create a texture. Args: :filename (str): Name of the file to that holds the texture. :x (float): X position of the crop area of the texture. :y (float): Y position of the crop area of the texture. :width (float): Width of the crop area of the texture. :height (float): Height of the crop area of the texture. :scale (float): Scale factor to apply on the new texture. Returns: The new texture. Raises: None >>> import arcade >>> arcade.open_window(800,600,"Drawing Example") >>> name = "arcade/examples/images/meteorGrey_big1.png" >>> texture1 = load_texture(name, 1, 1, 50, 50) >>> texture2 = load_texture(name, 1, 1, 50, 50) >>> texture = load_texture(name, 200, 1, 50, 50) Traceback (most recent call last): ... ValueError: Can't load texture starting at an x of 200 when the image is only 101 across. >>> texture = load_texture(name, 1, 50, 50, 50) Traceback (most recent call last): ... ValueError: Can't load texture ending at an y of 100 when the image is only 84 high. >>> texture = load_texture(name, 1, 150, 50, 50) Traceback (most recent call last): ... ValueError: Can't load texture starting at an y of 150 when the image is only 84 high. >>> texture = load_texture(name, 0, 0, 400, 50) Traceback (most recent call last): ... ValueError: Can't load texture ending at an x of 400 when the image is only 101 wide. >>> arcade.close_window() """ # See if we already loaded this file, and we can just use a cached version. cache_name = "{}{}{}{}{}{}{}{}".format(file_name, x, y, width, height, scale, flipped, mirrored) if cache_name in load_texture.texture_cache: return load_texture.texture_cache[cache_name] source_image = PIL.Image.open(file_name) source_image_width, source_image_height = source_image.size if x != 0 or y != 0 or width != 0 or height != 0: if x > source_image_width: raise ValueError("Can't load texture starting at an x of {} " "when the image is only {} across.".format( x, source_image_width)) if y > source_image_height: raise ValueError("Can't load texture starting at an y of {} " "when the image is only {} high.".format( y, source_image_height)) if x + width > source_image_width: raise ValueError("Can't load texture ending at an x of {} " "when the image is only {} wide.".format( x + width, source_image_width)) if y + height > source_image_height: raise ValueError("Can't load texture ending at an y of {} " "when the image is only {} high.".format( y + height, source_image_height)) image = source_image.crop((x, y, x + width, y + height)) else: image = source_image # image = _trim_image(image) if mirrored: image = PIL.ImageOps.mirror(image) if flipped: image = PIL.ImageOps.flip(image) image_width, image_height = image.size image_bytes = image.convert("RGBA").tobytes("raw", "RGBA", 0, -1) texture = gl.GLuint(0) gl.glGenTextures(1, ctypes.byref(texture)) gl.glBindTexture(gl.GL_TEXTURE_2D, texture) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_REPEAT) gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_REPEAT) gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST) gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST) glu.gluBuild2DMipmaps(gl.GL_TEXTURE_2D, gl.GL_RGBA, image_width, image_height, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, image_bytes) image_width *= scale image_height *= scale result = Texture(texture, image_width, image_height) load_texture.texture_cache[cache_name] = result return result
def blit_to_texture(self, target, level, x, y, z, internalformat=None): '''Draw this image to to the currently bound texture at `target`. If `internalformat` is specified, glTexImage is used to initialise the texture; otherwise, glTexSubImage is used to update a region. ''' data_format = self.format data_pitch = abs(self._current_pitch) # Determine pixel format from format string matrix = None format, type = self._get_gl_format_and_type(data_format) if format is None: if (len(data_format) in (3, 4) and gl.gl_info.have_extension('GL_ARB_imaging')): # Construct a color matrix to convert to GL_RGBA def component_column(component): try: pos = 'RGBA'.index(component) return [0] * pos + [1] + [0] * (3 - pos) except ValueError: return [0, 0, 0, 0] # pad to avoid index exceptions lookup_format = data_format + 'XXX' matrix = (component_column(lookup_format[0]) + component_column(lookup_format[1]) + component_column(lookup_format[2]) + component_column(lookup_format[3])) format = {3: gl.GL_RGB, 4: gl.GL_RGBA}.get(len(data_format)) type = gl.GL_UNSIGNED_BYTE gl.glMatrixMode(gl.GL_COLOR) gl.glPushMatrix() gl.glLoadMatrixf((gl.GLfloat * 16)(*matrix)) else: # Need to convert data to a standard form data_format = { 1: 'L', 2: 'LA', 3: 'RGB', 4: 'RGBA' }.get(len(data_format)) format, type = self._get_gl_format_and_type(data_format) # Workaround: don't use GL_UNPACK_ROW_LENGTH if gl.current_context._workaround_unpack_row_length: data_pitch = self.width * len(data_format) # Get data in required format (hopefully will be the same format it's # already in, unless that's an obscure format, upside-down or the # driver is old). data = self._convert(data_format, data_pitch) if data_pitch & 0x1: alignment = 1 elif data_pitch & 0x2: alignment = 2 else: alignment = 4 row_length = data_pitch / len(data_format) gl.glPushClientAttrib(gl.GL_CLIENT_PIXEL_STORE_BIT) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, alignment) gl.glPixelStorei(gl.GL_UNPACK_ROW_LENGTH, row_length) self._apply_region_unpack() gl.glTexParameteri(target, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE) gl.glTexParameteri(target, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE) gl.glTexParameteri(target, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR) gl.glTexParameteri(target, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR) if target == gl.GL_TEXTURE_3D: assert not internalformat gl.glTexSubImage3D(target, level, x, y, z, self.width, self.height, 1, format, type, data) elif internalformat: gl.glTexImage2D(target, level, internalformat, self.width, self.height, 0, format, type, data) else: gl.glTexSubImage2D(target, level, x, y, self.width, self.height, format, type, data) gl.glPopClientAttrib() if matrix: gl.glPopMatrix() gl.glMatrixMode(gl.GL_MODELVIEW)
def _updateFrameTexture(self): if self._nextFrameT is None: # movie has no current position, need to reset the clock # to zero in order to have the timing logic work # otherwise the video stream would skip frames until the # time since creating the movie object has passed self._videoClock.reset() self._nextFrameT = 0 # only advance if next frame (half of next retrace rate) if self._nextFrameT > self.duration: self._onEos() elif self._numpyFrame is not None: if self._nextFrameT > (self._videoClock.getTime() - old_div(self._retraceInterval, 2.0)): return None self._numpyFrame = self._mov.get_frame(self._nextFrameT) useSubTex = self.useTexSubImage2D if self._texID is None: self._texID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._texID)) useSubTex = False # bind the texture in openGL GL.glEnable(GL.GL_TEXTURE_2D) # bind that name to the target GL.glBindTexture(GL.GL_TEXTURE_2D, self._texID) # makes the texture map wrap (this is actually default anyway) GL.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT) # data from PIL/numpy is packed, but default for GL is 4 bytes GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1) # important if using bits++ because GL_LINEAR # sometimes extrapolates to pixel vals outside range if self.interpolate: GL.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR) GL.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR) if useSubTex is False: GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB8, self._numpyFrame.shape[1], self._numpyFrame.shape[0], 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, self._numpyFrame.ctypes) else: GL.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, self._numpyFrame.shape[1], self._numpyFrame.shape[0], GL.GL_RGB, GL.GL_UNSIGNED_BYTE, self._numpyFrame.ctypes) else: GL.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST) GL.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST) if useSubTex is False: GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB8, self._numpyFrame.shape[1], self._numpyFrame.shape[0], 0, GL.GL_BGR, GL.GL_UNSIGNED_BYTE, self._numpyFrame.ctypes) else: GL.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, self._numpyFrame.shape[1], self._numpyFrame.shape[0], GL.GL_BGR, GL.GL_UNSIGNED_BYTE, self._numpyFrame.ctypes) GL.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE) # ?? do we need this - think not! if not self.status == PAUSED: self._nextFrameT += self._frameInterval
def __init__(self, ctx: 'Context', size: Tuple[int, int], *, components: int = 4, dtype: str = 'f1', data: Any = None, filter: Tuple[gl.GLuint, gl.GLuint] = None, wrap_x: gl.GLuint = None, wrap_y: gl.GLuint = None): """ A texture can be created with or without initial data. NOTE: Currently does not support multisample textures even thought ``samples`` is exposed. :param Context ctx: The context the object belongs to :param Tuple[int, int] size: The size of the texture :param int components: The number of components (1: R, 2: RG, 3: RGB, 4: RGBA) :param str dtype: The data type of each component: f1, f2, f4 / i1, i2, i4 / u1, u2, u4 :param Any data: The byte data of the texture. bytes or anything supporting the buffer protocol. :param Tuple[gl.GLuint, gl.GLuint] filter: The minification/magnification filter of the texture :param gl.GLuint wrap_s :param data: The texture data (optional) """ self._ctx = ctx self._width, self._height = size self._dtype = dtype self._components = components self._target = gl.GL_TEXTURE_2D self._samples = 0 # Default filters for float and integer textures if 'f' in self.dtype: self._filter = gl.GL_LINEAR, gl.GL_LINEAR else: self._filter = gl.GL_NEAREST, gl.GL_NEAREST self._wrap_x = gl.GL_REPEAT self._wrap_y = gl.GL_REPEAT if components not in [1, 2, 3, 4]: raise ValueError("Components must be 1, 2, 3 or 4") try: format_info = self._formats[self._dtype] except KeyError: raise ValueError( f"dype '{dtype}' not support. Supported types are : {tuple(self._formats.keys())}" ) gl.glActiveTexture( gl.GL_TEXTURE0) # Create textures in the default channel (0) self._glo = glo = gl.GLuint() gl.glGenTextures(1, byref(self._glo)) if self._glo.value == 0: raise RuntimeError( "Cannot create Texture. OpenGL failed to generate a texture id" ) gl.glBindTexture(self._target, self._glo) gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) if data is not None: byte_length, data = data_to_ctypes(data) try: _format, _internal_format, self._type, self._component_size = format_info self._format = _format[components] self._internal_format = _internal_format[components] gl.glTexImage2D( self._target, # target 0, # level self._internal_format, # internal_format self._width, # width self._height, # height 0, # border self._format, # format self._type, # type data # data ) except gl.GLException as ex: raise gl.GLException(( f"Unable to create texture: {ex} : dtype={dtype} size={size} components={components} " "MAX_TEXTURE_SIZE = {self.ctx.limits.MAX_TEXTURE_SIZE}")) self.filter = filter or self._filter self.wrap_x = wrap_x or self._wrap_x self.wrap_y = wrap_y or self._wrap_y self.ctx.stats.incr('texture') weakref.finalize(self, Texture.release, self._ctx, glo)
def load_texture(file_name, x=0, y=0, width=0, height=0, scale=1): """ Load image from disk and create a texture. Args: :filename (str): Name of the file to that holds the texture. Returns: Integer identifier for the new texture. Raises: None >>> import arcade >>> arcade.open_window("Drawing Example", 800, 600) >>> name = "examples/images/meteorGrey_big1.png" >>> texture = load_texture(name, 1, 1, 50, 50) >>> arcade.close_window() """ # See if we already loaded this file, and we can just use a cached version. if file_name in load_texture.texture_cache: return load_texture.texture_cache[file_name] source_image = PIL.Image.open(file_name) source_image_width, source_image_height = source_image.size if x != 0 or y != 0 or width != 0 or height != 0: if x > source_image_width: raise SystemError("Can't load texture starting at an x of {} " "when the image is only {} across." .format(x, source_image_width)) if y > source_image_height: raise SystemError("Can't load texture starting at an y of {} " "when the image is only {} high." .format(y, source_image_height)) if x + width > source_image_width: raise SystemError("Can't load texture ending at an x of {} " "when the image is only {} wide." .format(x + width, source_image_width)) if y + height > source_image_height: raise SystemError("Can't load texture ending at an y of {} " "when the image is only {} high." .format(y + height, source_image_height)) image = source_image.crop((x, y, x + width, y + height)) else: image = source_image # image = _trim_image(image) image_width, image_height = image.size image_bytes = image.convert("RGBA").tobytes("raw", "RGBA", 0, -1) texture = GL.GLuint(0) GL.glGenTextures(1, ctypes.byref(texture)) GL.glBindTexture(GL.GL_TEXTURE_2D, texture) GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1) # Appveyor work-around appveyor = True if not appveyor: GL.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_BORDER) GL.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_BORDER) else: GL.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT) GL.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR) GLU.gluBuild2DMipmaps(GL.GL_TEXTURE_2D, GL.GL_RGBA, image_width, image_height, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, image_bytes) image_width *= scale image_height *= scale result = Texture(texture, image_width, image_height) load_texture.texture_cache[file_name] = result return result
def render_view(window): """ Render the current view to a texture. """ drawing = window.drawing view = window.view changed = False # Update the overlay with the current stroke overlay = view.overlay w, h, d = view.shape size = w, h overlay_texture = _get_overlay_texture(size) if overlay.dirty and overlay.lock.acquire(timeout=0.01): rect = overlay.dirty x0, y0, x1, y1 = rect.box() overlay_data = overlay.data[x0:x1, y0:y1].tobytes("F") gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) # Needed for writing 8bit data gl.glTextureSubImage2D(overlay_texture.name, 0, *rect.position, *rect.size, gl.GL_RGBA_INTEGER, gl.GL_UNSIGNED_BYTE, overlay_data) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 4) overlay.dirty = None overlay.lock.release() changed = True # Update the image texture data = drawing.data drawing_texture = _get_3d_texture(data.shape) if drawing.dirty: with drawing.lock: update_data = data[drawing.dirty].tobytes(order="F") sx, sy, sz = drawing.dirty drawing.dirty = None sw = sx.stop - sx.start sh = sy.stop - sy.start sd = sz.stop - sz.start gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) # Needed for writing 8bit data gl.glTextureSubImage3D(drawing_texture.name, 0, sx.start, sy.start, sz.start, sw, sh, sd, gl.GL_RED_INTEGER, gl.GL_UNSIGNED_BYTE, update_data) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 4) changed = True # Render everything to the offscreen buffer # TODO we actually should not have to redraw the offscreen_buffer unless something has changed # (e.g. drawing, overlay, palette or cursor) offscreen_buffer = _get_offscreen_buffer(size) colors = _get_colors(drawing.palette.colors) vao = _get_vao() draw_program = _get_program() empty_texture = _get_empty_texture(size) cursor_pos = d - view.index - 1 # TODO why? other_layer_alpha = 0.3 if view.show_only_current_layer or view.layer_being_switched else 1.0 T = _get_transform(view.rotation) with vao, offscreen_buffer: gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glViewport(0, 0, w, h) gl.glClearBufferfv(gl.GL_COLOR, 0, EMPTY_COLOR) with draw_program, drawing_texture: gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, (gl.GLfloat * 16)(*T)) gl.glUniform3f(1, *view.direction) gl.glUniform4fv(5, 256, colors) # Draw the layers below the current one if cursor_pos < d - 1: with empty_texture: gl.glUniform1f(2, other_layer_alpha) gl.glUniform2i(3, cursor_pos + 1, d) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) # Draw the current layer + overlay with overlay_texture: gl.glUniform1f(2, 1) gl.glUniform2i(3, cursor_pos, cursor_pos + 1) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) # Draw the layers on top if cursor_pos > 0: with empty_texture: gl.glUniform1f(2, other_layer_alpha) gl.glUniform2i(3, 0, cursor_pos) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) return offscreen_buffer
def blit_to_texture(self, target, level, x, y, z, internalformat=None): '''Draw this image to to the currently bound texture at `target`. If `internalformat` is specified, glTexImage is used to initialise the texture; otherwise, glTexSubImage is used to update a region. ''' data_format = self.format data_pitch = abs(self._current_pitch) # Determine pixel format from format string matrix = None format, type = self._get_gl_format_and_type(data_format) if format is None: if (len(data_format) in (3, 4) and gl.gl_info.have_extension('GL_ARB_imaging')): # Construct a color matrix to convert to GL_RGBA def component_column(component): try: pos = 'RGBA'.index(component) return [0] * pos + [1] + [0] * (3 - pos) except ValueError: return [0, 0, 0, 0] # pad to avoid index exceptions lookup_format = data_format + 'XXX' matrix = (component_column(lookup_format[0]) + component_column(lookup_format[1]) + component_column(lookup_format[2]) + component_column(lookup_format[3])) format = { 3: gl.GL_RGB, 4: gl.GL_RGBA}.get(len(data_format)) type = gl.GL_UNSIGNED_BYTE gl.glMatrixMode(gl.GL_COLOR) gl.glPushMatrix() gl.glLoadMatrixf((gl.GLfloat * 16)(*matrix)) else: # Need to convert data to a standard form data_format = { 1: 'L', 2: 'LA', 3: 'RGB', 4: 'RGBA'}.get(len(data_format)) format, type = self._get_gl_format_and_type(data_format) # Workaround: don't use GL_UNPACK_ROW_LENGTH if gl.current_context._workaround_unpack_row_length: data_pitch = self.width * len(data_format) # Get data in required format (hopefully will be the same format it's # already in, unless that's an obscure format, upside-down or the # driver is old). data = self._convert(data_format, data_pitch) if data_pitch & 0x1: alignment = 1 elif data_pitch & 0x2: alignment = 2 else: alignment = 4 row_length = data_pitch / len(data_format) gl.glPushClientAttrib(gl.GL_CLIENT_PIXEL_STORE_BIT) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, alignment) gl.glPixelStorei(gl.GL_UNPACK_ROW_LENGTH, row_length) self._apply_region_unpack() gl.glTexParameteri(target, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE) gl.glTexParameteri(target, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE) gl.glTexParameteri(target, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR) gl.glTexParameteri(target, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR) if target == gl.GL_TEXTURE_3D: assert not internalformat gl.glTexSubImage3D(target, level, x, y, z, self.width, self.height, 1, format, type, data) elif internalformat: gl.glTexImage2D(target, level, internalformat, self.width, self.height, 0, format, type, data) else: gl.glTexSubImage2D(target, level, x, y, self.width, self.height, format, type, data) gl.glPopClientAttrib() if matrix: gl.glPopMatrix() gl.glMatrixMode(gl.GL_MODELVIEW)
def load_texture(file_name: str, x: float=0, y: float=0, width: float=0, height: float=0, mirrored: bool=False, flipped: bool=False, scale: float=1) -> Texture: """ Load image from disk and create a texture. Note, if the code is to load only part of the image, the given x, y coordinates will start with the origin (0, 0) in the upper left of the image. When drawing, Arcade uses (0, 0) in the lower left corner when drawing. Be careful about this reversal. For a longer explanation of why computers sometimes start in the upper left, see: http://programarcadegames.com/index.php?chapter=introduction_to_graphics&lang=en#section_5 Args: :filename (str): Name of the file to that holds the texture. :x (float): X position of the crop area of the texture. :y (float): Y position of the crop area of the texture. :width (float): Width of the crop area of the texture. :height (float): Height of the crop area of the texture. :scale (float): Scale factor to apply on the new texture. Returns: The new texture. Raises: None >>> import arcade >>> arcade.open_window(800,600,"Drawing Example") >>> name = "arcade/examples/images/meteorGrey_big1.png" >>> texture1 = load_texture(name, 1, 1, 50, 50) >>> texture2 = load_texture(name, 1, 1, 50, 50) >>> texture = load_texture(name, 200, 1, 50, 50) Traceback (most recent call last): ... ValueError: Can't load texture starting at an x of 200 when the image is only 101 across. >>> texture = load_texture(name, 1, 50, 50, 50) Traceback (most recent call last): ... ValueError: Can't load texture ending at an y of 100 when the image is only 84 high. >>> texture = load_texture(name, 1, 150, 50, 50) Traceback (most recent call last): ... ValueError: Can't load texture starting at an y of 150 when the image is only 84 high. >>> texture = load_texture(name, 0, 0, 400, 50) Traceback (most recent call last): ... ValueError: Can't load texture ending at an x of 400 when the image is only 101 wide. >>> arcade.close_window() """ # See if we already loaded this file, and we can just use a cached version. cache_name = "{}{}{}{}{}{}{}{}".format(file_name, x, y, width, height, scale, flipped, mirrored) if cache_name in load_texture.texture_cache: return load_texture.texture_cache[cache_name] source_image = PIL.Image.open(file_name) source_image_width, source_image_height = source_image.size if x != 0 or y != 0 or width != 0 or height != 0: if x > source_image_width: raise ValueError("Can't load texture starting at an x of {} " "when the image is only {} across." .format(x, source_image_width)) if y > source_image_height: raise ValueError("Can't load texture starting at an y of {} " "when the image is only {} high." .format(y, source_image_height)) if x + width > source_image_width: raise ValueError("Can't load texture ending at an x of {} " "when the image is only {} wide." .format(x + width, source_image_width)) if y + height > source_image_height: raise ValueError("Can't load texture ending at an y of {} " "when the image is only {} high." .format(y + height, source_image_height)) image = source_image.crop((x, y, x + width, y + height)) else: image = source_image # image = _trim_image(image) if mirrored: image = PIL.ImageOps.mirror(image) if flipped: image = PIL.ImageOps.flip(image) image_width, image_height = image.size # image_bytes = image.convert("RGBA").tobytes("raw", "RGBA", 0, -1) texture = gl.GLuint(0) gl.glGenTextures(1, ctypes.byref(texture)) gl.glBindTexture(gl.GL_TEXTURE_2D, texture) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_REPEAT) gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_REPEAT) gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR) gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR_MIPMAP_LINEAR) # glu.gluBuild2DMipmaps(gl.GL_TEXTURE_2D, gl.GL_RGBA, # image_width, image_height, # gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, image_bytes) image_width *= scale image_height *= scale result = Texture(texture, image_width, image_height, file_name) load_texture.texture_cache[cache_name] = result return result
def load_textures(file_name, image_location_list, mirrored=False, flipped=False): """ Load a set of textures off of a single image file. Args: :file_name: Name of the file. :image_location_list: List of image locations. Each location should be a list of four numbers. ``[x, y, width, height]``. :mirrored=False: If set to true, the image is mirrored left to right. :flipped=False: If set to true, the image is flipped upside down. Returns: :list: List of textures loaded. Raises: :SystemError: >>> import arcade >>> arcade.open_window("Drawing Example", 800, 600) >>> image_location_list = [[591, 5, 64, 93], ... [655, 10, 75, 88], ... [730, 7, 54, 91], ... [784, 3, 59, 95], ... [843, 6, 56, 92]] >>> texture_info_list = arcade.load_textures( \ "examples/images/character_sheet.png", image_location_list) >>> arcade.close_window() """ source_image = PIL.Image.open(file_name) source_image_width, source_image_height = source_image.size texture_info_list = [] for image_location in image_location_list: x, y, width, height = image_location if x > source_image_width: raise SystemError("Can't load texture starting at an x of {} " "when the image is only {} across." .format(x, source_image_width)) if y > source_image_height: raise SystemError("Can't load texture starting at an y of {} " "when the image is only {} high." .format(y, source_image_height)) if x + width > source_image_width: raise SystemError("Can't load texture ending at an x of {} " "when the image is only {} wide." .format(x + width, source_image_width)) if y + height > source_image_height: raise SystemError("Can't load texture ending at an y of {} " "when the image is only {} high." .format(y + height, source_image_height)) image = source_image.crop((x, y, x + width, y + height)) # image = _trim_image(image) if mirrored: image = PIL.ImageOps.mirror(image) if flipped: image = PIL.ImageOps.flip(image) image_width, image_height = image.size image_bytes = image.convert("RGBA").tobytes("raw", "RGBA", 0, -1) texture = GL.GLuint(0) GL.glGenTextures(1, ctypes.byref(texture)) GL.glBindTexture(GL.GL_TEXTURE_2D, texture) GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1) # Appveyor work-around appveyor = True if not appveyor: GL.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_BORDER) GL.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_BORDER) else: GL.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT) GL.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR) GLU.gluBuild2DMipmaps(GL.GL_TEXTURE_2D, GL.GL_RGBA, image_width, image_height, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, image_bytes) texture_info_list.append(Texture(texture, width, height)) return texture_info_list