Exemple #1
0
flatsh = Shader("shaders/uv_flat")
defocus = Defocus()

#Create textures
shapeimg = Texture("textures/straw1.jpg")
shapebump = Texture("textures/floor_nm.jpg", True)
shapeshine = Texture("textures/pong3.png")

#Create shape
myshape = MergeShape(camera=persp_cam) #specify perspective view
asphere = Sphere(sides=16, slices=16)
myshape.radialCopy(asphere, step=72)
myshape.position(0.0, 0.0, 5.0)
myshape.set_draw_details(shader, [shapeimg, shapebump, shapeshine], 8.0, 0.1)

mysprite = Sprite(w=10.0, h=10.0, camera=persp_cam)
mysprite.position(0.0, 0.0, 15.0)
mysprite.set_draw_details(flatsh, [shapebump])

tick=0
next_time = time.time()+2.0

#load ttf font and set the font colour to 'raspberry'
arialFont = Ttffont("fonts/FreeMonoBoldOblique.ttf", "#dd00aa")
mystring = String(font=arialFont, string="blurring with distance!",
                  camera=ortho_cam, z=1.0, is_3d=False) # orthographic view
mystring.set_shader(flatsh)

# Fetch key presses.
mykeys = Keyboard()
Exemple #2
0
    def __init__(self,
                 font,
                 string,
                 camera=None,
                 color=(255, 255, 255, 255),
                 outline=(0, 0, 0, 255),
                 outline_size=0,
                 font_size=24,
                 margin=5.0,
                 justify='C',
                 background_color=None,
                 shader=None,
                 f_type='',
                 mipmap=True):
        """Arguments:

    *font*:
      File path/name to a TrueType font file.

    *string*:
      String to write.

    *camera*:
      Camera object passed on to constructor of sprite

    *color*:
      Color in format #RRGGBB, (255,0,0,255) etc (as accepted by PIL.ImageDraw)
      default (255, 255, 255, 255) i.e. white 100% alpha

    *font_size*:
      Point size for drawing the letters on the internal Texture. default 24

    *margin*:
      Offsets from the top left corner for the text and space on right
      and bottom. default 5.0

    *justify*:
      L(eft), C(entre), R(ight) default C

    *background_color*:
      filled background in ImageDraw format as above. default None i.e.
      transparent.

    *shader*:
      can be passed to init otherwise needs to be set in set_shader or
      draw. default None

    *f_type*:
      filter type. BUMP will generate a normal map (indented), EMBOSS,
      CONTOUR, BLUR and SMOOTH do what they sound like they will do.
    """
        super(FixedOutlineString, self).__init__(font, mipmap=mipmap)
        self.font = font
        try:
            imgfont = ImageFont.truetype(font, font_size)
        except IOError:
            abspath = os.path.abspath(font)
            msg = "Couldn't find font file '%s'" % font
            if font != abspath:
                msg = "%s - absolute path is '%s'" % (msg, abspath)
            raise Exception(msg)

        justify = justify.upper()
        f_type = f_type.upper()
        ascent, descent = imgfont.getmetrics()
        height = ascent + descent
        lines = string.split('\n')
        nlines = len(lines)
        maxwid = 0
        for l in lines:
            line_wid = imgfont.getsize(l)[0]
            if line_wid > maxwid:
                maxwid = line_wid
        maxwid += 2.0 * margin
        texture_wid = WIDTHS[0]
        for l in WIDTHS:
            if l > maxwid:
                texture_wid = l
                break
            texture_wid = l
        texture_hgt = int(nlines * height + 2 * margin)

        self.im = Image.new("RGBA", (texture_wid, texture_hgt),
                            background_color)
        self.alpha = True
        self.ix, self.iy = texture_wid, texture_hgt
        draw = ImageDraw.Draw(self.im)
        for i, line in enumerate(lines):
            line_len = imgfont.getsize(line)[0]
            if justify == "C":
                xoff = (maxwid - line_len) / 2.0
            elif justify == "L":
                xoff = margin
            else:
                xoff = maxwid - line_len

            # draw the outline by drawing the displaced text repeatedly
            if outline_size > 0:
                for xi in range(-outline_size, outline_size + 1):
                    for yi in range(-outline_size, outline_size + 1):
                        if xi != 0 and yi != 0:
                            draw.text((xoff + xi, margin + i * height + yi),
                                      line,
                                      font=imgfont,
                                      fill=outline)

            draw.text((xoff, margin + i * height),
                      line,
                      font=imgfont,
                      fill=color)

        if f_type == '':
            pass
        elif f_type == 'BUMP':
            self.im = self.make_bump_map()
        else:
            from PIL import ImageFilter
            if f_type == 'EMBOSS':
                self.im = self.im.filter(ImageFilter.EMBOSS)
            elif f_type == 'CONTOUR':
                self.im = self.im.filter(ImageFilter.CONTOUR)
            elif f_type == 'BLUR':
                self.im = self.im.filter(ImageFilter.BLUR)
            elif f_type == 'SMOOTH':
                self.im = self.im.filter(ImageFilter.SMOOTH_MORE)

        #self.image = self.im.convert('RGBA').tostring('raw', 'RGBA')
        self.im = self.im.convert('RGBA')
        self.image = np.array(self.im)
        self._tex = ctypes.c_int()

        bmedge = nlines * height + 2.0 * margin
        self.sprite = Sprite(camera=camera, w=maxwid, h=bmedge)
        buf = self.sprite.buf[0]  #convenience alias
        buf.textures = [self]
        if shader != None:
            self.sprite.shader = shader
            buf.shader = shader
        buf.unib[6] = float(maxwid / texture_wid)  #scale to fit
        buf.unib[7] = float(bmedge / texture_hgt)
Exemple #3
0
    def __init__(self,
                 font,
                 string,
                 camera=None,
                 color=(255, 255, 255, 255),
                 shadow=(0, 0, 0, 255),
                 shadow_radius=0,
                 font_size=24,
                 margin=5.0,
                 justify='C',
                 background_color=None,
                 shader=None,
                 f_type='',
                 mipmap=True):
        """Arguments:
    
    *font*:
      File path/name to a TrueType font file.

    *string*:
      String to write.
      
    *camera*:
      Camera object passed on to constructor of sprite
      
    *color*:
      Color in format '#RRGGBB', (255,0,0,255), 'orange' etc (as accepted 
      by PIL.ImageDraw) default (255, 255, 255, 255) i.e. white 100% alpha

    *shadow*:
      Color of shadow, default black.

    *shadow_radius*:
      Gaussian blur radius applied to shadow layer, default 0 (no shadow)

    *font_size*:
      Point size for drawing the letters on the internal Texture. default 24

    *margin*:
      Offsets from the top left corner for the text and space on right
      and bottom. default 5.0
      
    *justify*:
      L(eft), C(entre), R(ight) default C

    *background_color*:
      filled background in ImageDraw format as above. default None i.e.
      transparent. 
      
    *shader*:
      can be passed to init otherwise needs to be set in set_shader or
      draw. default None
      
    *f_type*:
      filter type. BUMP will generate a normal map (indented by default,
      +BUMP or BUMP+ will make it stick out), EMBOSS, CONTOUR, BLUR and 
      SMOOTH do what they sound like they will do.
    """
        super(FixedString, self).__init__(font, mipmap=mipmap)
        self.font = font
        try:
            imgfont = ImageFont.truetype(font, font_size)
        except IOError:
            abspath = os.path.abspath(font)
            msg = "Couldn't find font file '%s'" % font
            if font != abspath:
                msg = "%s - absolute path is '%s'" % (msg, abspath)
            raise Exception(msg)

        justify = justify.upper()
        f_type = f_type.upper()
        ascent, descent = imgfont.getmetrics()
        height = ascent + descent
        lines = string.split('\n')
        nlines = len(lines)
        maxwid = 0
        for l in lines:
            line_wid = imgfont.getsize(l)[0]
            if line_wid > maxwid:
                maxwid = line_wid
        maxwid += 2.0 * margin
        texture_wid = WIDTHS[0]
        for l in WIDTHS:
            if l > maxwid:
                texture_wid = l
                break
            texture_wid = l
        texture_hgt = int(nlines * height + 2 * margin)

        self.im = Image.new("RGBA", (texture_wid, texture_hgt),
                            background_color)
        self.ix, self.iy = texture_wid, texture_hgt
        draw = ImageDraw.Draw(self.im)
        if shadow_radius > 0:
            from PIL import ImageFilter
            self._render_text(lines, justify, margin, imgfont, maxwid, height,
                              shadow, draw)
            self.im = self.im.filter(
                ImageFilter.GaussianBlur(radius=shadow_radius))
            if background_color == None:
                im_arr = self._force_color(np.array(self.im), shadow)
                try:  # numpy not quite working fully in pypy so have to convert tobytes
                    self.im = Image.fromarray(im_arr)
                except:
                    h, w, c = im_arr.shape
                    rgb = 'RGB' if c == 3 else 'RGBA'
                    self.im = Image.frombytes(rgb, (w, h), im_arr.tobytes())

            draw = ImageDraw.Draw(self.im)

        self._render_text(lines, justify, margin, imgfont, maxwid, height,
                          color, draw)

        force_color = background_color is None and shadow_radius == 0
        if f_type == '':
            self.image = np.array(self.im)
        elif 'BUMP' in f_type:
            amount = -1.0 if '+' in f_type else 1.0
            self.image = self._normal_map(np.array(self.im, dtype=np.uint8),
                                          amount)
            force_color = False

        else:
            from PIL import ImageFilter
            if f_type == 'EMBOSS':
                self.im = self.im.filter(ImageFilter.EMBOSS)
            elif f_type == 'CONTOUR':
                self.im = self.im.filter(ImageFilter.CONTOUR)
            elif f_type == 'BLUR':
                self.im = self.im.filter(ImageFilter.BLUR)
            elif f_type == 'SMOOTH':
                self.im = self.im.filter(ImageFilter.SMOOTH_MORE)
            self.image = np.array(self.im)

        if force_color:
            self.image = self._force_color(self.image, color)

        self._tex = ctypes.c_uint()

        bmedge = nlines * height + 2.0 * margin
        self.sprite = Sprite(camera=camera, w=maxwid, h=bmedge)
        buf = self.sprite.buf[0]  #convenience alias
        buf.textures = [self]
        if shader != None:
            self.sprite.shader = shader
            buf.shader = shader
        buf.unib[6] = float(maxwid / texture_wid)  #scale to fit
        buf.unib[7] = float(bmedge / texture_hgt)
  def __init__(self, shader="uv_flat", mipmap=False, separation=0.4, interlace=0):
    """ calls Texture.__init__ but doesn't need to set file name as
    texture generated from the framebuffer. Keyword Arguments:

      *shader*
        to use when drawing sprite, defaults to uv_flat.

      *mipmap*
        can be set to True with slight cost to speed, or use fxaa shader

      *separation*
        distance between the two camera positions - how wide apart the
        eye views are.

      *interlace*
        if interlace > 0 then the images are not taken with glScissor and
        must be drawn with a special interlacing shader.
    """
    # load shader
    if interlace <= 0: # i.e. default side by side behaviour
      self.shader = Shader.create(shader)
    else:
      self.shader = Shader(vshader_source = """
precision mediump float;
attribute vec3 vertex;
attribute vec2 texcoord;
uniform mat4 modelviewmatrix[2];
varying vec2 texcoordout;
void main(void) {
  texcoordout = texcoord;
  gl_Position = modelviewmatrix[1] * vec4(vertex,1.0);
}
    """, fshader_source = """
precision mediump float;
uniform sampler2D tex0;
uniform sampler2D tex1;
varying vec2 texcoordout;
void main(void) {{
  vec4 texc0 = texture2D(tex0, texcoordout);
  vec4 texc1 = texture2D(tex1, texcoordout);
  vec2 coord = vec2(gl_FragCoord);
  gl_FragColor = mix(texc0, texc1, step(0.5, fract(coord.x / {:f})));
}}
    """.format(interlace * 2.0))

    self.camera_3d = Camera() # create 3d cam first so it becomes default instance
    self.forMtrx = np.identity(4, dtype='float32') # initially not rotated
    self.position = [0.0, 0.0, 0.0]
    self.camera_2d = Camera(is_3d=False)
    self.offs = separation / 2.0
    self.interlace = interlace
    self.textures = []
    self.sprites = []
    self.tex_list = []
    for i in range(2):
      self.textures.append(OffScreenTexture(name="stereo"))
      ix, iy = self.textures[i].ix, self.textures[i].iy
      #two sprites full width but moved so that they are centred on the
      #left and right edges. The offset values then move the uv mapping
      #so the image is on the right of the left sprite and left of the
      #right sprite
      self.sprites.append(Sprite(z=20.0, w=ix, h=iy, flip=True))
      if interlace <= 0:
        self.sprites[i].positionX(-ix/2.0 + i*ix)
        self.sprites[i].set_offset((i * 0.5 - 0.25, 0.0))
      else:
        self.sprites[i].set_2d_size(w=ix, h=iy)
      self.textures[i].blend = True
      self.textures[i].mipmap = mipmap
      self.tex_list.append(self.textures[i])
    opengles.glColorMask(1, 1, 1, 1)
Exemple #5
0
class FixedOutlineString(Texture):
    """
  A texture containing a simple string drawn using ImageDraw.

  The advantage over a standard String is that it only requires a simple
  Sprite shape for drawing so the gpu has to only draw two triangles
  rather than two triangles for each letter."""
    def __init__(self,
                 font,
                 string,
                 camera=None,
                 color=(255, 255, 255, 255),
                 outline=(0, 0, 0, 255),
                 outline_size=0,
                 font_size=24,
                 margin=5.0,
                 justify='C',
                 background_color=None,
                 shader=None,
                 f_type='',
                 mipmap=True):
        """Arguments:

    *font*:
      File path/name to a TrueType font file.

    *string*:
      String to write.

    *camera*:
      Camera object passed on to constructor of sprite

    *color*:
      Color in format #RRGGBB, (255,0,0,255) etc (as accepted by PIL.ImageDraw)
      default (255, 255, 255, 255) i.e. white 100% alpha

    *font_size*:
      Point size for drawing the letters on the internal Texture. default 24

    *margin*:
      Offsets from the top left corner for the text and space on right
      and bottom. default 5.0

    *justify*:
      L(eft), C(entre), R(ight) default C

    *background_color*:
      filled background in ImageDraw format as above. default None i.e.
      transparent.

    *shader*:
      can be passed to init otherwise needs to be set in set_shader or
      draw. default None

    *f_type*:
      filter type. BUMP will generate a normal map (indented), EMBOSS,
      CONTOUR, BLUR and SMOOTH do what they sound like they will do.
    """
        super(FixedOutlineString, self).__init__(font, mipmap=mipmap)
        self.font = font
        try:
            imgfont = ImageFont.truetype(font, font_size)
        except IOError:
            abspath = os.path.abspath(font)
            msg = "Couldn't find font file '%s'" % font
            if font != abspath:
                msg = "%s - absolute path is '%s'" % (msg, abspath)
            raise Exception(msg)

        justify = justify.upper()
        f_type = f_type.upper()
        ascent, descent = imgfont.getmetrics()
        height = ascent + descent
        lines = string.split('\n')
        nlines = len(lines)
        maxwid = 0
        for l in lines:
            line_wid = imgfont.getsize(l)[0]
            if line_wid > maxwid:
                maxwid = line_wid
        maxwid += 2.0 * margin
        texture_wid = WIDTHS[0]
        for l in WIDTHS:
            if l > maxwid:
                texture_wid = l
                break
            texture_wid = l
        texture_hgt = int(nlines * height + 2 * margin)

        self.im = Image.new("RGBA", (texture_wid, texture_hgt),
                            background_color)
        self.alpha = True
        self.ix, self.iy = texture_wid, texture_hgt
        draw = ImageDraw.Draw(self.im)
        for i, line in enumerate(lines):
            line_len = imgfont.getsize(line)[0]
            if justify == "C":
                xoff = (maxwid - line_len) / 2.0
            elif justify == "L":
                xoff = margin
            else:
                xoff = maxwid - line_len

            # draw the outline by drawing the displaced text repeatedly
            if outline_size > 0:
                for xi in range(-outline_size, outline_size + 1):
                    for yi in range(-outline_size, outline_size + 1):
                        if xi != 0 and yi != 0:
                            draw.text((xoff + xi, margin + i * height + yi),
                                      line,
                                      font=imgfont,
                                      fill=outline)

            draw.text((xoff, margin + i * height),
                      line,
                      font=imgfont,
                      fill=color)

        if f_type == '':
            pass
        elif f_type == 'BUMP':
            self.im = self.make_bump_map()
        else:
            from PIL import ImageFilter
            if f_type == 'EMBOSS':
                self.im = self.im.filter(ImageFilter.EMBOSS)
            elif f_type == 'CONTOUR':
                self.im = self.im.filter(ImageFilter.CONTOUR)
            elif f_type == 'BLUR':
                self.im = self.im.filter(ImageFilter.BLUR)
            elif f_type == 'SMOOTH':
                self.im = self.im.filter(ImageFilter.SMOOTH_MORE)

        #self.image = self.im.convert('RGBA').tostring('raw', 'RGBA')
        self.im = self.im.convert('RGBA')
        self.image = np.array(self.im)
        self._tex = ctypes.c_int()

        bmedge = nlines * height + 2.0 * margin
        self.sprite = Sprite(camera=camera, w=maxwid, h=bmedge)
        buf = self.sprite.buf[0]  #convenience alias
        buf.textures = [self]
        if shader != None:
            self.sprite.shader = shader
            buf.shader = shader
        buf.unib[6] = float(maxwid / texture_wid)  #scale to fit
        buf.unib[7] = float(bmedge / texture_hgt)

    def set_shader(self, shader):
        ''' wrapper for Shape.set_shader'''
        self.sprite.set_shader(shader)

    def draw(self,
             shader=None,
             txtrs=None,
             ntl=None,
             shny=None,
             camera=None,
             mlist=[]):
        '''wrapper for Shape.draw()'''
        self.sprite.draw(shader, txtrs, ntl, shny, camera, mlist)

    def make_bump_map(self):
        """ essentially just blurs the image then allocates R or G values
    according to the rate of change of grayscale in x and y directions
    """
        import numpy as np
        a = np.array(self.im, dtype=np.uint8)
        a = np.average(a, axis=2, weights=[1.0, 1.0, 1.0, 0.0]).astype(int)
        b = [[0.01, 0.025, 0.05, 0.025,
              0.01], [0.025, 0.05, 0.065, 0.05, 0.025],
             [0.05, 0.065, 0.1, 0.065,
              0.05], [0.025, 0.05, 0.065, 0.05, 0.025],
             [0.01, 0.025, 0.05, 0.025, 0.01]]
        c = np.zeros(a.shape, dtype=np.uint8)
        steps = [i - 2 for i in range(5)]
        for i, istep in enumerate(steps):
            for j, jstep in enumerate(steps):
                c += (np.roll(np.roll(a, istep, 0), jstep, 1) *
                      b[i][j]).astype(np.uint8)
        cx = np.roll(c, 1, 0)
        cy = np.roll(c, 1, 1)
        d = np.zeros((a.shape[0], a.shape[1], 4), dtype=np.uint8)
        d[:, :, 0] = ((c - cy) + 127).astype(int)
        d[:, :, 1] = ((c - cx) + 127).astype(int)
        d[:, :, 2] = (np.clip(
            (65025 - (127 - d[:, :, 0])**2 - (127 - d[:, :, 1])**2)**0.5, 0,
            255)).astype(int)
        d[:, :, 3] = 255
        return Image.fromarray(d)

    def _load_disk(self):
        """
Exemple #6
0
flatsh = Shader("shaders/uv_flat")
defocus = Defocus()

#Create textures
shapeimg = Texture("textures/straw1.jpg")
shapebump = Texture("textures/floor_nm.jpg", True)
shapeshine = Texture("textures/pong3.png")

#Create shape
myshape = MergeShape(camera=persp_cam)  #specify perspective view
asphere = Sphere(sides=16, slices=16)
myshape.radialCopy(asphere, step=72)
myshape.position(0.0, 0.0, 5.0)
myshape.set_draw_details(shader, [shapeimg, shapebump, shapeshine], 8.0, 0.1)

mysprite = Sprite(w=10.0, h=10.0, camera=persp_cam)
mysprite.position(0.0, 0.0, 15.0)
mysprite.set_draw_details(flatsh, [shapebump])

tick = 0
next_time = time.time() + 2.0

#load ttf font and set the font colour to 'raspberry'
arialFont = Ttffont("fonts/FreeMonoBoldOblique.ttf", "#dd00aa")
mystring = String(font=arialFont,
                  string="blurring with distance!",
                  camera=ortho_cam,
                  z=1.0,
                  is_3d=False)  # orthographic view
mystring.set_shader(flatsh)
Exemple #7
0
    def __init__(
        self,
        font,
        string,
        camera=None,
        color=(255, 255, 255, 255),
        font_size=24,
        margin=5.0,
        justify="C",
        background_color=None,
        shader=None,
        f_type="",
        mipmap=True,
    ):
        """Arguments:
    
    *font*:
      File path/name to a TrueType font file.

    *string*:
      String to write.
      
    *camera*:
      Camera object passed on to constructor of sprite
      
    *color*:
      Color in format '#RRGGBB', (255,0,0,255), 'orange' etc (as accepted 
      by PIL.ImageDraw) default (255, 255, 255, 255) i.e. white 100% alpha

    *font_size*:
      Point size for drawing the letters on the internal Texture. default 24

    *margin*:
      Offsets from the top left corner for the text and space on right
      and bottom. default 5.0
      
    *justify*:
      L(eft), C(entre), R(ight) default C

    *background_color*:
      filled background in ImageDraw format as above. default None i.e.
      transparent. 
      
    *shader*:
      can be passed to init otherwise needs to be set in set_shader or
      draw. default None
      
    *f_type*:
      filter type. BUMP will generate a normal map (indented by default,
      +BUMP or BUMP+ will make it stick out), EMBOSS, CONTOUR, BLUR and 
      SMOOTH do what they sound like they will do.
    """
        super(FixedString, self).__init__(font, mipmap=mipmap)
        self.font = font
        try:
            imgfont = ImageFont.truetype(font, font_size)
        except IOError:
            abspath = os.path.abspath(font)
            msg = "Couldn't find font file '%s'" % font
            if font != abspath:
                msg = "%s - absolute path is '%s'" % (msg, abspath)
            raise Exception(msg)

        justify = justify.upper()
        f_type = f_type.upper()
        ascent, descent = imgfont.getmetrics()
        height = ascent + descent
        lines = string.split("\n")
        nlines = len(lines)
        maxwid = 0
        for l in lines:
            line_wid = imgfont.getsize(l)[0]
            if line_wid > maxwid:
                maxwid = line_wid
        maxwid += 2.0 * margin
        texture_wid = WIDTHS[0]
        for l in WIDTHS:
            if l > maxwid:
                texture_wid = l
                break
            texture_wid = l
        texture_hgt = int(nlines * height + 2 * margin)

        self.im = Image.new("RGBA", (texture_wid, texture_hgt), background_color)
        self.ix, self.iy = texture_wid, texture_hgt
        draw = ImageDraw.Draw(self.im)
        for i, line in enumerate(lines):
            line_len = imgfont.getsize(line)[0]
            if justify == "C":
                xoff = (maxwid - line_len) / 2.0
            elif justify == "L":
                xoff = margin
            else:
                xoff = maxwid - line_len
            draw.text((xoff, margin + i * height), line, font=imgfont, fill=color)

        if f_type == "":
            self.image = np.array(self.im)
        elif "BUMP" in f_type:
            amount = -1.0 if "+" in f_type else 1.0
            self.image = self._normal_map(np.array(self.im, dtype=np.uint8), amount)
        else:
            from PIL import ImageFilter

            if f_type == "EMBOSS":
                self.im = self.im.filter(ImageFilter.EMBOSS)
            elif f_type == "CONTOUR":
                self.im = self.im.filter(ImageFilter.CONTOUR)
            elif f_type == "BLUR":
                self.im = self.im.filter(ImageFilter.BLUR)
            elif f_type == "SMOOTH":
                self.im = self.im.filter(ImageFilter.SMOOTH_MORE)
            self.image = np.array(self.im)
            if background_color is None:
                if isinstance(color, str):
                    from PIL import ImageColor

                    color = ImageColor.getrgb(color)
                self.image[:, :, :3] = color[:3]
        self._tex = ctypes.c_uint()

        bmedge = nlines * height + 2.0 * margin
        self.sprite = Sprite(camera=camera, w=maxwid, h=bmedge)
        buf = self.sprite.buf[0]  # convenience alias
        buf.textures = [self]
        if shader != None:
            self.sprite.shader = shader
            buf.shader = shader
        buf.unib[6] = float(maxwid / texture_wid)  # scale to fit
        buf.unib[7] = float(bmedge / texture_hgt)
class FixedOutlineString(Texture):
  """
  A texture containing a simple string drawn using ImageDraw.

  The advantage over a standard String is that it only requires a simple
  Sprite shape for drawing so the gpu has to only draw two triangles
  rather than two triangles for each letter."""

  def __init__(self, font, string, camera=None, color=(255,255,255,255),
               outline=(0,0,0,255), outline_size=0,
               font_size=24, margin=5.0, justify='C',
               background_color=None, shader=None, f_type='', mipmap=True):
    """Arguments:

    *font*:
      File path/name to a TrueType font file.

    *string*:
      String to write.

    *camera*:
      Camera object passed on to constructor of sprite

    *color*:
      Color in format #RRGGBB, (255,0,0,255) etc (as accepted by PIL.ImageDraw)
      default (255, 255, 255, 255) i.e. white 100% alpha

    *font_size*:
      Point size for drawing the letters on the internal Texture. default 24

    *margin*:
      Offsets from the top left corner for the text and space on right
      and bottom. default 5.0

    *justify*:
      L(eft), C(entre), R(ight) default C

    *background_color*:
      filled background in ImageDraw format as above. default None i.e.
      transparent.

    *shader*:
      can be passed to init otherwise needs to be set in set_shader or
      draw. default None

    *f_type*:
      filter type. BUMP will generate a normal map (indented), EMBOSS,
      CONTOUR, BLUR and SMOOTH do what they sound like they will do.
    """
    super(FixedOutlineString, self).__init__(font, mipmap=mipmap)
    self.font = font
    try:
      imgfont = ImageFont.truetype(font, font_size)
    except IOError:
      abspath = os.path.abspath(font)
      msg = "Couldn't find font file '%s'" % font
      if font != abspath:
        msg = "%s - absolute path is '%s'" % (msg, abspath)
      raise Exception(msg)

    justify = justify.upper()
    f_type = f_type.upper()
    ascent, descent = imgfont.getmetrics()
    height = ascent + descent
    lines = string.split('\n')
    nlines = len(lines)
    maxwid = 0
    for l in lines:
      line_wid = imgfont.getsize(l)[0]
      if line_wid > maxwid:
        maxwid = line_wid
    maxwid += 2.0 * margin
    texture_wid = WIDTHS[0]
    for l in WIDTHS:
      if l > maxwid:
        texture_wid = l
        break
      texture_wid = l
    texture_hgt = int(nlines * height + 2 * margin)

    self.im = Image.new("RGBA", (texture_wid, texture_hgt), background_color)
    self.alpha = True
    self.ix, self.iy = texture_wid, texture_hgt
    draw = ImageDraw.Draw(self.im)
    for i, line in enumerate(lines):
      line_len = imgfont.getsize(line)[0]
      if justify == "C":
        xoff = (maxwid - line_len) / 2.0
      elif justify == "L":
        xoff = margin
      else:
        xoff = maxwid - line_len

      # draw the outline by drawing the displaced text repeatedly
      if outline_size > 0:
          for xi in range(-outline_size, outline_size + 1):
              for yi in range(-outline_size, outline_size + 1):
                  if xi != 0 and yi != 0:
                      draw.text((xoff + xi, margin + i * height + yi), line, font=imgfont, fill=outline)

      draw.text((xoff, margin + i * height), line, font=imgfont, fill=color)

    if f_type == '':
      pass
    elif f_type == 'BUMP':
      self.im = self.make_bump_map()
    else:
      from PIL import ImageFilter
      if f_type == 'EMBOSS':
        self.im = self.im.filter(ImageFilter.EMBOSS)
      elif f_type == 'CONTOUR':
        self.im = self.im.filter(ImageFilter.CONTOUR)
      elif f_type == 'BLUR':
        self.im = self.im.filter(ImageFilter.BLUR)
      elif f_type == 'SMOOTH':
        self.im = self.im.filter(ImageFilter.SMOOTH_MORE)

    #self.image = self.im.convert('RGBA').tostring('raw', 'RGBA')
    self.im = self.im.convert('RGBA')
    self.image = np.array(self.im)
    self._tex = ctypes.c_int()

    bmedge = nlines * height + 2.0 * margin
    self.sprite = Sprite(camera=camera, w=maxwid, h=bmedge)
    buf = self.sprite.buf[0] #convenience alias
    buf.textures = [self]
    if shader != None:
      self.sprite.shader = shader
      buf.shader = shader
    buf.unib[6] = float(maxwid / texture_wid) #scale to fit
    buf.unib[7] = float(bmedge / texture_hgt)

  def set_shader(self, shader):
    ''' wrapper for Shape.set_shader'''
    self.sprite.set_shader(shader)

  def draw(self, shader=None, txtrs=None, ntl=None, shny=None, camera=None, mlist=[]):
    '''wrapper for Shape.draw()'''
    self.sprite.draw(shader, txtrs, ntl, shny, camera, mlist)

  def make_bump_map(self):
    """ essentially just blurs the image then allocates R or G values
    according to the rate of change of grayscale in x and y directions
    """
    import numpy as np
    a = np.array(self.im, dtype=np.uint8)
    a = np.average(a, axis=2, weights=[1.0, 1.0, 1.0, 0.0]).astype(int)
    b = [[0.01, 0.025, 0.05, 0.025, 0.01],
         [0.025,0.05,  0.065,0.05,  0.025],
         [0.05, 0.065, 0.1,  0.065, 0.05],
         [0.025,0.05,  0.065,0.05,  0.025],
         [0.01, 0.025, 0.05, 0.025, 0.01]]
    c = np.zeros(a.shape, dtype=np.uint8)
    steps = [i - 2 for i in range(5)]
    for i, istep in enumerate(steps):
      for j, jstep in enumerate(steps):
        c += (np.roll(np.roll(a, istep, 0), jstep, 1) * b[i][j]).astype(np.uint8)
    cx = np.roll(c, 1, 0)
    cy = np.roll(c, 1, 1)
    d = np.zeros((a.shape[0], a.shape[1], 4), dtype=np.uint8)
    d[:, :, 0] = ((c - cy) + 127).astype(int)
    d[:, :, 1] = ((c - cx) + 127).astype(int)
    d[:, :, 2] = (np.clip((65025 - (127 - d[:, :, 0]) ** 2 - (127 - d[:, :, 1]) ** 2) ** 0.5, 0, 255)).astype(int)
    d[:, :, 3] = 255
    return Image.fromarray(d)

  def _load_disk(self):
    """
  def __init__(self, font, string, camera=None, color=(255,255,255,255),
               outline=(0,0,0,255), outline_size=0,
               font_size=24, margin=5.0, justify='C',
               background_color=None, shader=None, f_type='', mipmap=True):
    """Arguments:

    *font*:
      File path/name to a TrueType font file.

    *string*:
      String to write.

    *camera*:
      Camera object passed on to constructor of sprite

    *color*:
      Color in format #RRGGBB, (255,0,0,255) etc (as accepted by PIL.ImageDraw)
      default (255, 255, 255, 255) i.e. white 100% alpha

    *font_size*:
      Point size for drawing the letters on the internal Texture. default 24

    *margin*:
      Offsets from the top left corner for the text and space on right
      and bottom. default 5.0

    *justify*:
      L(eft), C(entre), R(ight) default C

    *background_color*:
      filled background in ImageDraw format as above. default None i.e.
      transparent.

    *shader*:
      can be passed to init otherwise needs to be set in set_shader or
      draw. default None

    *f_type*:
      filter type. BUMP will generate a normal map (indented), EMBOSS,
      CONTOUR, BLUR and SMOOTH do what they sound like they will do.
    """
    super(FixedOutlineString, self).__init__(font, mipmap=mipmap)
    self.font = font
    try:
      imgfont = ImageFont.truetype(font, font_size)
    except IOError:
      abspath = os.path.abspath(font)
      msg = "Couldn't find font file '%s'" % font
      if font != abspath:
        msg = "%s - absolute path is '%s'" % (msg, abspath)
      raise Exception(msg)

    justify = justify.upper()
    f_type = f_type.upper()
    ascent, descent = imgfont.getmetrics()
    height = ascent + descent
    lines = string.split('\n')
    nlines = len(lines)
    maxwid = 0
    for l in lines:
      line_wid = imgfont.getsize(l)[0]
      if line_wid > maxwid:
        maxwid = line_wid
    maxwid += 2.0 * margin
    texture_wid = WIDTHS[0]
    for l in WIDTHS:
      if l > maxwid:
        texture_wid = l
        break
      texture_wid = l
    texture_hgt = int(nlines * height + 2 * margin)

    self.im = Image.new("RGBA", (texture_wid, texture_hgt), background_color)
    self.alpha = True
    self.ix, self.iy = texture_wid, texture_hgt
    draw = ImageDraw.Draw(self.im)
    for i, line in enumerate(lines):
      line_len = imgfont.getsize(line)[0]
      if justify == "C":
        xoff = (maxwid - line_len) / 2.0
      elif justify == "L":
        xoff = margin
      else:
        xoff = maxwid - line_len

      # draw the outline by drawing the displaced text repeatedly
      if outline_size > 0:
          for xi in range(-outline_size, outline_size + 1):
              for yi in range(-outline_size, outline_size + 1):
                  if xi != 0 and yi != 0:
                      draw.text((xoff + xi, margin + i * height + yi), line, font=imgfont, fill=outline)

      draw.text((xoff, margin + i * height), line, font=imgfont, fill=color)

    if f_type == '':
      pass
    elif f_type == 'BUMP':
      self.im = self.make_bump_map()
    else:
      from PIL import ImageFilter
      if f_type == 'EMBOSS':
        self.im = self.im.filter(ImageFilter.EMBOSS)
      elif f_type == 'CONTOUR':
        self.im = self.im.filter(ImageFilter.CONTOUR)
      elif f_type == 'BLUR':
        self.im = self.im.filter(ImageFilter.BLUR)
      elif f_type == 'SMOOTH':
        self.im = self.im.filter(ImageFilter.SMOOTH_MORE)

    #self.image = self.im.convert('RGBA').tostring('raw', 'RGBA')
    self.im = self.im.convert('RGBA')
    self.image = np.array(self.im)
    self._tex = ctypes.c_int()

    bmedge = nlines * height + 2.0 * margin
    self.sprite = Sprite(camera=camera, w=maxwid, h=bmedge)
    buf = self.sprite.buf[0] #convenience alias
    buf.textures = [self]
    if shader != None:
      self.sprite.shader = shader
      buf.shader = shader
    buf.unib[6] = float(maxwid / texture_wid) #scale to fit
    buf.unib[7] = float(bmedge / texture_hgt)
Exemple #10
0
cloudTex = []
cloudTex.append(Texture("textures/cloud2.png", True))
cloudTex.append(Texture("textures/cloud3.png", True))
cloudTex.append(Texture("textures/cloud4.png", True))
cloudTex.append(Texture("textures/cloud5.png", True))
cloudTex.append(Texture("textures/cloud6.png", True))

# Setup cloud positions and cloud image refs
cz = 0.0
clouds = []  # an array for the clouds
for b in range(0, cloudno):
    size = 0.5 + random.random() / 2.0
    cloud = Sprite(w=size * widex,
                   h=size * widey,
                   x=150.0 * (random.random() - 0.5),
                   y=0.0,
                   z=cloud_depth - cz)
    cloud.set_draw_details(shader, [cloudTex[int(random.random() * 4.99999)]],
                           0.0, 0.0)
    clouds.append(cloud)
    cz = cz + zd

CAMERA = Camera.instance()
CAMERA.position((0.0, 0.0, 50.0))
CAMERA.was_moved = False
# Fetch key presses
mykeys = Keyboard()

while DISPLAY.loop_running():
    # the z position of each cloud is held in clouds[i].unif[2] returned by cloud.z()
Exemple #11
0
class FixedString(Texture):
  """
  A texture containing a simple string drawn using ImageDraw.
  
  The advantage over a standard String is that it only requires a simple
  Sprite shape for drawing so the gpu has to only draw two triangles
  rather than two triangles for each letter."""

  def __init__(self, font, string, camera=None, color=(255,255,255,255),
               font_size=24, margin=5.0, justify='C',
               background_color=None, shader=None, f_type='', mipmap=True):
    """Arguments:
    
    *font*:
      File path/name to a TrueType font file.

    *string*:
      String to write.
      
    *camera*:
      Camera object passed on to constructor of sprite
      
    *color*:
      Color in format '#RRGGBB', (255,0,0,255), 'orange' etc (as accepted 
      by PIL.ImageDraw) default (255, 255, 255, 255) i.e. white 100% alpha

    *font_size*:
      Point size for drawing the letters on the internal Texture. default 24

    *margin*:
      Offsets from the top left corner for the text and space on right
      and bottom. default 5.0
      
    *justify*:
      L(eft), C(entre), R(ight) default C

    *background_color*:
      filled background in ImageDraw format as above. default None i.e.
      transparent. 
      
    *shader*:
      can be passed to init otherwise needs to be set in set_shader or
      draw. default None
      
    *f_type*:
      filter type. BUMP will generate a normal map (indented by default,
      +BUMP or BUMP+ will make it stick out), EMBOSS, CONTOUR, BLUR and 
      SMOOTH do what they sound like they will do.
    """
    super(FixedString, self).__init__(font, mipmap=mipmap)
    self.font = font
    try:
      imgfont = ImageFont.truetype(font, font_size)
    except IOError:
      abspath = os.path.abspath(font)
      msg = "Couldn't find font file '%s'" % font
      if font != abspath:
        msg = "%s - absolute path is '%s'" % (msg, abspath)
      raise Exception(msg)

    justify = justify.upper()
    f_type = f_type.upper()
    ascent, descent = imgfont.getmetrics()
    height = ascent + descent
    lines = string.split('\n')
    nlines = len(lines)
    maxwid = 0
    for l in lines:
      line_wid = imgfont.getsize(l)[0]
      if line_wid > maxwid:
        maxwid = line_wid
    maxwid += 2.0 * margin
    texture_wid = WIDTHS[0]
    for l in WIDTHS:
      if l > maxwid:
        texture_wid = l
        break
      texture_wid = l
    texture_hgt = int(nlines * height + 2 * margin)
    
    self.im = Image.new("RGBA", (texture_wid, texture_hgt), background_color)
    self.ix, self.iy = texture_wid, texture_hgt
    draw = ImageDraw.Draw(self.im)
    for i, line in enumerate(lines):
      line_len = imgfont.getsize(line)[0] 
      if justify == "C":
        xoff = (maxwid - line_len) / 2.0
      elif justify == "L":
        xoff = margin
      else:
        xoff = maxwid - line_len
      draw.text((xoff, margin + i * height), line, font=imgfont, fill=color)

    if f_type == '':
      pass
    elif 'BUMP' in f_type:
      amount = -1.0 if '+' in f_type else 1.0
      self.image = self._normal_map(np.array(self.im, dtype=np.uint8), amount)
    else:
      from PIL import ImageFilter
      if f_type == 'EMBOSS':
        self.im = self.im.filter(ImageFilter.EMBOSS)
      elif f_type == 'CONTOUR':
        self.im = self.im.filter(ImageFilter.CONTOUR)
      elif f_type == 'BLUR':
        self.im = self.im.filter(ImageFilter.BLUR)
      elif f_type == 'SMOOTH':
        self.im = self.im.filter(ImageFilter.SMOOTH_MORE)
      self.image = np.array(self.im)
      if background_color is None:
        if isinstance(color, str):
          from PIL import ImageColor
          color = ImageColor.getrgb(color)
        self.image[:,:,:3] = color[:3]
    self._tex = ctypes.c_int()
    
    bmedge = nlines * height + 2.0 * margin
    self.sprite = Sprite(camera=camera, w=maxwid, h=bmedge)
    buf = self.sprite.buf[0] #convenience alias
    buf.textures = [self]
    if shader != None:
      self.sprite.shader = shader
      buf.shader = shader
    buf.unib[6] = float(maxwid / texture_wid) #scale to fit
    buf.unib[7] = float(bmedge / texture_hgt)
    
  def set_shader(self, shader):
    ''' wrapper for Shape.set_shader'''
    self.sprite.set_shader(shader)
    
  def draw(self, shader=None, txtrs=None, ntl=None, shny=None, camera=None, mlist=[]):
    '''wrapper for Shape.draw()'''
    self.sprite.draw(shader, txtrs, ntl, shny, camera, mlist)
    
  def _load_disk(self):
    """
Exemple #12
0
  def __init__(self, font, string, camera=None, color=(255,255,255,255),
               shadow=(0,0,0,255), shadow_radius=0,
               font_size=24, margin=5.0, justify='C',
               background_color=None, shader=None, f_type='', mipmap=True):
    """Arguments:
    
    *font*:
      File path/name to a TrueType font file.

    *string*:
      String to write.
      
    *camera*:
      Camera object passed on to constructor of sprite
      
    *color*:
      Color in format '#RRGGBB', (255,0,0,255), 'orange' etc (as accepted 
      by PIL.ImageDraw) default (255, 255, 255, 255) i.e. white 100% alpha

    *shadow*:
      Color of shadow, default black.

    *shadow_radius*:
      Gaussian blur radius applied to shadow layer, default 0 (no shadow)

    *font_size*:
      Point size for drawing the letters on the internal Texture. default 24

    *margin*:
      Offsets from the top left corner for the text and space on right
      and bottom. default 5.0
      
    *justify*:
      L(eft), C(entre), R(ight) default C

    *background_color*:
      filled background in ImageDraw format as above. default None i.e.
      transparent. 
      
    *shader*:
      can be passed to init otherwise needs to be set in set_shader or
      draw. default None
      
    *f_type*:
      filter type. BUMP will generate a normal map (indented by default,
      +BUMP or BUMP+ will make it stick out), EMBOSS, CONTOUR, BLUR and 
      SMOOTH do what they sound like they will do.
    """
    super(FixedString, self).__init__(font, mipmap=mipmap)
    self.font = font
    try:
      imgfont = ImageFont.truetype(font, font_size)
    except IOError:
      abspath = os.path.abspath(font)
      msg = "Couldn't find font file '%s'" % font
      if font != abspath:
        msg = "%s - absolute path is '%s'" % (msg, abspath)
      raise Exception(msg)

    justify = justify.upper()
    f_type = f_type.upper()
    ascent, descent = imgfont.getmetrics()
    height = ascent + descent
    lines = string.split('\n')
    nlines = len(lines)
    maxwid = 0
    for l in lines:
      line_wid = imgfont.getsize(l)[0]
      if line_wid > maxwid:
        maxwid = line_wid
    maxwid += 2.0 * margin
    texture_wid = WIDTHS[0]
    for l in WIDTHS:
      if l > maxwid:
        texture_wid = l
        break
      texture_wid = l
    texture_hgt = int(nlines * height + 2 * margin)
    
    self.im = Image.new("RGBA", (texture_wid, texture_hgt), background_color)
    self.ix, self.iy = texture_wid, texture_hgt
    draw = ImageDraw.Draw(self.im)
    if shadow_radius > 0:
      from PIL import ImageFilter
      self._render_text(lines, justify, margin, imgfont, maxwid, height, shadow, draw)
      self.im = self.im.filter(ImageFilter.GaussianBlur(radius=shadow_radius))
      if background_color == None:
        im_arr = self._force_color(np.array(self.im), shadow)
        try: # numpy not quite working fully in pypy so have to convert tobytes
          self.im = Image.fromarray(im_arr)
        except:
          h, w, c = im_arr.shape
          rgb = 'RGB' if c == 3 else 'RGBA'
          self.im = Image.frombytes(rgb, (w, h), im_arr.tobytes())
        
      draw = ImageDraw.Draw(self.im)

    self._render_text(lines, justify, margin, imgfont, maxwid, height, color, draw)

    force_color = background_color is None and shadow_radius == 0
    if f_type == '':
      self.image = np.array(self.im)
    elif 'BUMP' in f_type:
      amount = -1.0 if '+' in f_type else 1.0
      self.image = self._normal_map(np.array(self.im, dtype=np.uint8), amount)
      force_color = False

    else:
      from PIL import ImageFilter
      if f_type == 'EMBOSS':
        self.im = self.im.filter(ImageFilter.EMBOSS)
      elif f_type == 'CONTOUR':
        self.im = self.im.filter(ImageFilter.CONTOUR)
      elif f_type == 'BLUR':
        self.im = self.im.filter(ImageFilter.BLUR)
      elif f_type == 'SMOOTH':
        self.im = self.im.filter(ImageFilter.SMOOTH_MORE)
      self.image = np.array(self.im)

    if force_color:
      self.image = self._force_color(self.image, color)

    self._tex = ctypes.c_uint()
    
    bmedge = nlines * height + 2.0 * margin
    self.sprite = Sprite(camera=camera, w=maxwid, h=bmedge)
    buf = self.sprite.buf[0] #convenience alias
    buf.textures = [self]
    if shader != None:
      self.sprite.shader = shader
      buf.shader = shader
    buf.unib[6] = float(maxwid / texture_wid) #scale to fit
    buf.unib[7] = float(bmedge / texture_hgt)
Exemple #13
0
shader = Shader("shaders/uv_flat")
#############################

cloudTex = []
cloudTex.append(Texture("textures/cloud2.png",True))
cloudTex.append(Texture("textures/cloud3.png",True))
cloudTex.append(Texture("textures/cloud4.png",True))
cloudTex.append(Texture("textures/cloud5.png",True))
cloudTex.append(Texture("textures/cloud6.png",True))

# Setup cloud positions and cloud image refs
cz = 0.0
clouds = [] # an array for the clouds
for b in range (0, cloudno):
  size = 0.5 + random.random()/2.0
  cloud = Sprite(w=size * widex, h=size * widey, 
          x=150.0 * (random.random() - 0.5), y=0.0, z=cloud_depth - cz)
  cloud.set_draw_details(shader, [cloudTex[int(random.random() * 4.99999)]], 0.0, 0.0)
  clouds.append(cloud)
  cz = cz + zd

CAMERA = Camera.instance()
CAMERA.position((0.0, 0.0, 50.0))
CAMERA.was_moved = False
# Fetch key presses
mykeys = Keyboard()

while DISPLAY.loop_running():
  # the z position of each cloud is held in clouds[i].unif[2] returned by cloud.z()
  # it stops the clouds being drawn behind nearer clouds and pixels being 
  # discarded by the shader! that should be blended.
  # first go through the clouds to find index of furthest away
Exemple #14
0
class FixedString(Texture):
    """
  A texture containing a simple string drawn using ImageDraw.
  
  The advantage over a standard String is that it only requires a simple
  Sprite shape for drawing so the gpu has to only draw two triangles
  rather than two triangles for each letter."""
    def __init__(self,
                 font,
                 string,
                 camera=None,
                 color=(255, 255, 255, 255),
                 shadow=(0, 0, 0, 255),
                 shadow_radius=0,
                 font_size=24,
                 margin=5.0,
                 justify='C',
                 background_color=None,
                 shader=None,
                 f_type='',
                 mipmap=True,
                 width=None):
        """Arguments:

    *font*:
      File path/name to a TrueType font file.

    *string*:
      String to write.

    *camera*:
      Camera object passed on to constructor of sprite

    *color*:
      Color in format '#RRGGBB', (255,0,0,255), 'orange' etc (as accepted 
      by PIL.ImageDraw) default (255, 255, 255, 255) i.e. white 100% alpha

    *shadow*:
      Color of shadow, default black.

    *shadow_radius*:
      Gaussian blur radius applied to shadow layer, default 0 (no shadow)

    *font_size*:
      Point size for drawing the letters on the internal Texture. default 24

    *margin*:
      Offsets from the top left corner for the text and space on right
      and bottom. default 5.0

    *justify*:
      L(eft), C(entre), R(ight) default C

    *background_color*:
      filled background in ImageDraw format as above. default None i.e.
      transparent. 

    *shader*:
      can be passed to init otherwise needs to be set in set_shader or
      draw. default None

    *f_type*:
      filter type. BUMP will generate a normal map (indented by default,
      +BUMP or BUMP+ will make it stick out), EMBOSS, CONTOUR, BLUR and 
      SMOOTH do what they sound like they will do.
    """
        super(FixedString, self).__init__(font, mipmap=mipmap)
        self.font = font
        try:
            imgfont = ImageFont.truetype(font, font_size)
        except IOError:
            abspath = os.path.abspath(font)
            msg = "Couldn't find font file '%s'" % font
            if font != abspath:
                msg = "%s - absolute path is '%s'" % (msg, abspath)
            raise Exception(msg)

        justify = justify.upper()
        f_type = f_type.upper()
        ascent, descent = imgfont.getmetrics()
        height = ascent + descent
        lines = string.split('\n')
        new_lines = []
        maxwid = 0
        for l in lines:
            line_wid = imgfont.getsize(l)[0]
            if width is not None and line_wid > width:
                new_line = ""
                space = ""
                words = l.split(" ")
                for word in words:
                    check_line = "{}{}{}".format(new_line, space, word)
                    if imgfont.getsize(check_line)[0] <= width:
                        new_line = check_line
                    else:  # wrap before this word TODO cope with lines with no spaces
                        if "-" in word:  # TODO make this a function to split first on " " then "-" then on
                            split_word = word.split("-")
                            pre = split_word[0]
                            post = "-".join(split_word[1:])
                            check_line = "{} {}-".format(new_line, pre)
                            if imgfont.getsize(check_line)[0] <= width:
                                new_line = check_line
                                word = post
                        new_lines.append(new_line)
                        new_line = word
                    space = " "
                new_lines.append(new_line)
            else:
                new_lines.append(l)
        lines = new_lines
        for l in lines:
            line_wid = imgfont.getsize(l)[0]
            if line_wid > maxwid:
                maxwid = line_wid
        maxwid += 2.0 * margin
        if Display.INSTANCE is not None:
            max_size = Display.INSTANCE.opengl.max_texture_size.value
        else:
            max_size = MAX_SIZE
        texture_wid = min(int(maxwid / 4) * 4, max_size)
        nlines = len(lines)
        texture_hgt = int(nlines * height + 2 * margin)

        self.im = Image.new("RGBA", (texture_wid, texture_hgt),
                            background_color)
        self.ix, self.iy = texture_wid, texture_hgt
        draw = ImageDraw.Draw(self.im)
        if shadow_radius > 0:
            from PIL import ImageFilter
            self._render_text(lines, justify, margin, imgfont, maxwid, height,
                              shadow, draw)
            self.im = self.im.filter(
                ImageFilter.GaussianBlur(radius=shadow_radius))
            if background_color == None:
                im_arr = self._force_color(np.array(self.im), shadow)
                try:  # numpy not quite working fully in pypy so have to convert tobytes
                    self.im = Image.fromarray(im_arr)
                except:
                    h, w, c = im_arr.shape
                    rgb = 'RGB' if c == 3 else 'RGBA'
                    self.im = Image.frombytes(rgb, (w, h), im_arr.tobytes())

            draw = ImageDraw.Draw(self.im)

        self._render_text(lines, justify, margin, imgfont, maxwid, height,
                          color, draw)

        force_color = background_color is None and shadow_radius == 0
        if f_type == '':
            self.image = np.array(self.im)
        elif 'BUMP' in f_type:
            amount = -1.0 if '+' in f_type else 1.0
            self.image = self._normal_map(np.array(self.im, dtype=np.uint8),
                                          amount)
            force_color = False

        else:
            from PIL import ImageFilter
            if f_type == 'EMBOSS':
                self.im = self.im.filter(ImageFilter.EMBOSS)
            elif f_type == 'CONTOUR':
                self.im = self.im.filter(ImageFilter.CONTOUR)
            elif f_type == 'BLUR':
                self.im = self.im.filter(ImageFilter.BLUR)
            elif f_type == 'SMOOTH':
                self.im = self.im.filter(ImageFilter.SMOOTH_MORE)
            self.image = np.array(self.im)

        if force_color:
            self.image = self._force_color(self.image, color)

        self._tex = ctypes.c_uint()

        bmedge = nlines * height + 2.0 * margin
        self.sprite = Sprite(camera=camera, w=maxwid, h=bmedge)
        buf = self.sprite.buf[0]  #convenience alias
        buf.textures = [self]
        if shader != None:
            self.sprite.shader = shader
            buf.shader = shader
        buf.unib[6] = float(maxwid / texture_wid)  #scale to fit
        buf.unib[7] = float(bmedge / texture_hgt)

    def _render_text(self, lines, justify, margin, imgfont, maxwid, height,
                     color, draw):
        for i, line in enumerate(lines):
            line_len = imgfont.getsize(line)[0]
            if justify == "C":
                xoff = (maxwid - line_len) / 2.0
            elif justify == "L":
                xoff = margin
            else:
                xoff = maxwid - line_len

            draw.text((xoff, margin + i * height),
                      line,
                      font=imgfont,
                      fill=color)

    def set_shader(self, shader):
        ''' wrapper for Shape.set_shader'''
        self.sprite.set_shader(shader)

    def draw(self, shader=None, txtrs=None, ntl=None, shny=None, camera=None):
        '''wrapper for Shape.draw()'''
        self.sprite.draw(shader, txtrs, ntl, shny, camera)

    def _force_color(self, im_array, color):
        """
    Overwrite color of all pixels as PIL renders text incorrectly when drawing on transparent backgrounds
    http://nedbatchelder.com/blog/200801/truly_transparent_text_with_pil.html
    """
        if isinstance(color, str):
            from PIL import ImageColor
            color = ImageColor.getrgb(color)
        im_array[:, :, :3] = color[:3]
        return im_array

    def _load_disk(self):
        """