def __init__(self, filename, size, charset='abcdefghijklmnopqrstuvwxyz' +\ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +\ '1234567890;:,.!?%&"\' '): #filename = os.path.join('fonts', filename) self.filename = filename self.charset = charset self.charmap = {} font = pygame.font.Font(filename, size) self.descent = font.get_descent() self.w, self.h = font.size(self.charset) self.w += len(self.charset) * self.characterSpacing self.lineSize = self.h if self.w > self.maxTextureWidth: self.h = (self.w / self.maxTextureWidth + 1) * self.h self.w = self.maxTextureWidth self.tw, self.th = resource.pow2(self.w), resource.pow2(self.h) data = chr(0) * self.tw * self.th * 4 surface = pygame.image.fromstring(data, (self.tw, self.th), 'RGBA') x, y = 0.0, 0.0 for c in charset: render = font.render(c, True, (255, 255, 255)) render = pygame.transform.flip(render,False,True) # hack somehow my shit was upside down cw, ch = font.size(c) if x + cw >= self.tw: x = 0.0 y += self.lineSize surface.blit(render, (x, y)) self.charmap[c] = (x/self.tw, (self.th-y-self.lineSize)/self.th, (x+cw)/self.tw, (self.th-y)/self.th), cw x += cw + self.characterSpacing self.tex = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, self.tex) glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexImage2D(GL_TEXTURE_2D, 0, 4, self.tw, self.th, 0, GL_RGBA, GL_UNSIGNED_BYTE, pygame.image.tostring(surface, 'RGBA', True))
def __init__(self, filename, size, charset='abcdefghijklmnopqrstuvwxyz' +\ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +\ '1234567890;:,.!?%&"\' '): filename = os.path.join('fonts', filename) self.filename = filename self.charset = charset self.charmap = {} font = pygame.font.Font(filename, size) self.descent = font.get_descent() self.w, self.h = font.size(self.charset) self.w += len(self.charset) * self.characterSpacing self.lineSize = self.h if self.w > self.maxTextureWidth: self.h = (self.w / self.maxTextureWidth + 1) * self.h self.w = self.maxTextureWidth self.tw, self.th = res.pow2(self.w), res.pow2(self.h) data = chr(0) * self.tw * self.th * 4 surface = pygame.image.fromstring(data, (self.tw, self.th), 'RGBA') x, y = 0.0, 0.0 for c in charset: render = font.render(c, True, (255, 255, 255)) cw, ch = font.size(c) if x + cw >= self.tw: x = 0.0 y += self.lineSize surface.blit(render, (x, y)) self.charmap[c] = (x/self.tw, (self.th-y-self.lineSize)/self.th, (x+cw)/self.tw, (self.th-y)/self.th), cw x += cw + self.characterSpacing self.tex = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, self.tex) glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexImage2D(GL_TEXTURE_2D, 0, 4, self.tw, self.th, 0, GL_RGBA, GL_UNSIGNED_BYTE, pygame.image.tostring(surface, 'RGBA', True))
def _layout(self): """Generate indices, uvs and verts for the text.""" font = self.font_atlas.font descent = font.get_descent() n_chars = len(self._str) - self._str.count('\n') verts = np.ones((4 * n_chars, 3), dtype='f4') uvs = np.zeros((4 * n_chars, 2), dtype='f4') indices = np.zeros(n_chars * 6, dtype='u4') lines = self._str.split('\n') # We lay out based on 48px tex so line size is scaled later line_height = 48 * 1.3 curchar = 0 tex_ids = set() tex = None for lineno, line in enumerate(lines): if not line: continue # (min_x, max_x, min_y, max_y, horizontal_advance_x) metrics = np.array(font.metrics(line), dtype='f4') cx = np.cumsum(metrics[:, 4]) xpos = metrics[:, 0:2] + cx[::, np.newaxis] layout_width = cx[-1] #+ metrics[-1, 4] align_offset = ALIGNMENTS[self._align] * layout_width yoff = lineno * line_height for idx, char in enumerate(line): texregion = self.font_atlas.get(char) # TODO: this could break if tex is reallocated (eg. because it # grows) tex = texregion.tex.tex glyph_uvs = texregion.texcoords glyph_verts = texregion.get_verts(texregion.width, texregion.height) tex_ids.add(tex.glo) # The kerning seems pretty bad on Pygame fonts... # glyph_width = glyph_verts[1, 0] - glyph_verts[0, 0] # metrics_width = xpos[idx, 1] - xpos[idx, 0] # print(repr(char), glyph_width, metrics_width, metrics[idx, 4]) x = xpos[idx, 0] quadnum = idx + curchar start = quadnum * 4 glyph_slice = slice(start, start + 4) verts[glyph_slice] = glyph_verts + (x - align_offset, yoff - descent, 0) uvs[glyph_slice] = glyph_uvs indices[6 * quadnum:6 * quadnum + 6] = QUAD + 4 * quadnum curchar += len(line) # Scale coordinates resize = np.identity(3, dtype='f4') scale = self.fontsize / 48 resize[0, 0] = scale resize[1, 1] = scale # TODO: handle use of multiple textures. We will be able to handle # this eventually by selecting texture unit within the shader, or by # making multiple draw calls assert len(tex_ids) < 2, "Label got allocated over multiple textures" self.tex = tex self._verts = verts @ resize self._uvs = uvs self._indices = indices # TODO: update self.lst, set dirty OR reallocate self.lst for new size if self.tex is None: if self.lst: self.lst.free() self.lst = None self.vao = None elif self.lst: self.lst.realloc(len(self._verts), len(indices)) self.lst.indexbuf[:] = indices self.lst.indexbuf += self.lst.vertoff.start self.lst.vertbuf['in_uv'] = uvs self._update() elif self.tex and not self.vao: self._migrate(self.layer._text_vao(self.font_atlas))