Initial text support implementation, pt. II.

Switch from fixed-function pipeline to shaders.
This commit is contained in:
Lucio Andrés Illanes Albornoz 2018-06-28 19:46:17 +02:00
parent f5dee0bf20
commit 22c4904c20
70 changed files with 150 additions and 33782 deletions

View File

@ -10,7 +10,7 @@
# 3) -s: effects: rotate, smash into bricks, swirl, wave, ... # 3) -s: effects: rotate, smash into bricks, swirl, wave, ...
# 4) XXX autodetect video width from widest mircart # 4) XXX autodetect video width from widest mircart
# 5) XXX convert TTF to texture PNG & coords TXT, render accordingly # 5) XXX convert TTF to texture PNG & coords TXT, render accordingly
# 6) XXX dont stall GPU w/ glReadPixels(), switch to asynchronous model w/ PBOs # 6) XXX dont stall GPU w/ glReadPixels(), switch to asynchronous model w/ FBO or PBO (http://www.songho.ca/opengl/gl_fbo.html, http://www.songho.ca/opengl/gl_pbo.html)
# 7) XXX render mircart as 3D blocks vs flat surface # 7) XXX render mircart as 3D blocks vs flat surface
# #
@ -91,8 +91,8 @@ class ENNToolApp(object):
MiRCART += ENNToolMiRCARTImporter(inFile).outMap MiRCART += ENNToolMiRCARTImporter(inFile).outMap
curY, rotateX, rotateY, translateY = 0, 0, 0, scrollRate curY, rotateX, rotateY, translateY = 0, 0, 0, scrollRate
artTextureId = panelGLCanvas.initTexture(texturePathName) artTextureId, artInfo = panelGLCanvas.initTexture(texturePathName)
artVbo, artVboLen, lastY, numVertices = panelGLCanvas.renderMiRCART(MiRCART, cubeSize=optdict["-R"]) artVbo, artVboLen, lastY, numVertices = panelGLCanvas.renderMiRCART(artInfo, MiRCART, cubeSize=optdict["-R"])
if "-v" in optdict: if "-v" in optdict:
print("{} vertices".format(numVertices)) print("{} vertices".format(numVertices))
w, h = panelGLCanvas.GetClientSize(); w, h = max(w, 1.0), max(h, 1.0); w, h = panelGLCanvas.GetClientSize(); w, h = max(w, 1.0), max(h, 1.0);
@ -121,7 +121,9 @@ class ENNToolApp(object):
videoFps, videoPath = int(optdict["-f"]), optdict["-o"] videoFps, videoPath = int(optdict["-f"]), optdict["-o"]
panelGLCanvas = ENNToolGLCanvasPanel(appPanelSkin, size=appFrameSize, videoPath=videoPath) panelGLCanvas = ENNToolGLCanvasPanel(appPanelSkin, size=appFrameSize, videoPath=videoPath)
panelGLCanvas.initOpenGL(); panelGLCanvas.initVideoWriter(fps=videoFps) panelGLCanvas.initOpenGL()
panelGLCanvas.initShaders()
panelGLCanvas.initVideoWriter(fps=videoFps)
if "-v" in optdict: if "-v" in optdict:
time0 = time.time() time0 = time.time()

View File

@ -10,13 +10,20 @@
# Wed, 27 Jun 2018 16:02:12 +0200 [3] <https://www.khronos.org/opengl/wiki/How_lighting_works#Good_Settings.> # Wed, 27 Jun 2018 16:02:12 +0200 [3] <https://www.khronos.org/opengl/wiki/How_lighting_works#Good_Settings.>
# Wed, 27 Jun 2018 16:02:13 +0200 [4] <https://www.khronos.org/opengl/wiki/Common_Mistakes> # Wed, 27 Jun 2018 16:02:13 +0200 [4] <https://www.khronos.org/opengl/wiki/Common_Mistakes>
# Wed, 27 Jun 2018 16:02:14 +0200 [5] <https://www.khronos.org/opengl/wiki/Pixel_Transfer#Pixel_layout> # Wed, 27 Jun 2018 16:02:14 +0200 [5] <https://www.khronos.org/opengl/wiki/Pixel_Transfer#Pixel_layout>
# Thu, 28 Jun 2018 17:03:16 +0200 [6] <https://stackoverflow.com/questions/384759/how-to-convert-a-pil-image-into-a-numpy-array>
# Thu, 28 Jun 2018 17:04:59 +0200 [7] <https://www.khronos.org/opengl/wiki/Common_Mistakes#y-axis>
# Thu, 28 Jun 2018 18:32:50 +0200 [8] <https://stackoverflow.com/questions/18935203/shader-position-vec4-or-vec3>
# #
from OpenGL.GL import * from OpenGL.GL import *
from OpenGL.GL import shaders
from PIL import Image from PIL import Image
import cv2, numpy import cv2, numpy
import ctypes, sys import ctypes, os, sys, time
import wx, wx.glcanvas import wx, wx.glcanvas
import yaml
from ENNToolMiRCARTColours import ENNToolMiRCARTColoursFloat
class ENNToolGLCanvasPanel(wx.glcanvas.GLCanvas, wx.Panel): class ENNToolGLCanvasPanel(wx.glcanvas.GLCanvas, wx.Panel):
"""XXX""" """XXX"""
@ -34,22 +41,56 @@ class ENNToolGLCanvasPanel(wx.glcanvas.GLCanvas, wx.Panel):
glEnable(GL_DEPTH_TEST) glEnable(GL_DEPTH_TEST)
glClearColor(0, 0, 0, 1); glClearDepth(1); glClearColor(0, 0, 0, 1); glClearDepth(1);
glTranslatef(-5.0, 3.0, -5) glTranslatef(-5.0, 3.0, -5)
# [3]
glLight(GL_LIGHT0, GL_AMBIENT, (0, 0, 0, 1))
glLight(GL_LIGHT0, GL_DIFFUSE, (1, 1, 1, 1))
glLight(GL_LIGHT0, GL_POSITION, (1, 1, 0+2, 0))
glLight(GL_LIGHT0, GL_SPECULAR, (1, 1, 1, 1))
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (0.2, 0.2, 0.2, 1))
glEnable(GL_LIGHTING); glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL)
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)
# }}} # }}}
# {{{ initTexture(self, pathName): XXX # {{{ initShaders(self): XXX
def initTexture(self, pathName): def initShaders(self):
fs = shaders.compileShader("""
#version 330 core
in vec4 bgColour;
in vec2 fgTexCoord;
uniform sampler2D texture;
void main() {
vec4 texel = texture2D(texture, fgTexCoord);
if (texel.a > 0.0) {
gl_FragColor = vec4(texel.r, texel.g, texel.b, 1.0);
} else {
gl_FragColor = bgColour;
}
}
""", GL_FRAGMENT_SHADER)
vs = shaders.compileShader("""
#version 330 core
layout(location = 0) in vec4 vertex;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec4 colour;
layout(location = 3) in vec2 texcoord;
out vec4 bgColour;
out vec2 fgTexCoord;
uniform mat4 model;
uniform mat4 projection;
void main() {
gl_Position = projection * model * vertex;
bgColour = colour;
fgTexCoord = texcoord;
}
""", GL_VERTEX_SHADER)
self.shader = shaders.compileProgram(vs, fs)
# }}}
# {{{ initTexture(self, pathName, infoPathName=os.path.join("assets", "textures.yaml")): XXX
def initTexture(self, pathName, infoPathName=os.path.join("assets", "textures.yaml")):
with open(infoPathName, "r") as fileObject:
artInfo = yaml.load(fileObject)
# [6], [7]
artTextureId = glGenTextures(1) artTextureId = glGenTextures(1)
artTextureImage = Image.open(pathName) artTextureImage = Image.open(pathName).transpose(Image.FLIP_TOP_BOTTOM)
artTextureImageData = numpy.array(list(artTextureImage.getdata()), numpy.uint8) artTextureImageData = numpy.array(artTextureImage)
glBindTexture(GL_TEXTURE_2D, artTextureId) glBindTexture(GL_TEXTURE_2D, artTextureId)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1) glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
@ -61,11 +102,11 @@ class ENNToolGLCanvasPanel(wx.glcanvas.GLCanvas, wx.Panel):
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
# [4][5] # [4][5]
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
artTextureImage.size[0], artTextureImage.size[1], artTextureImage.size[0], artTextureImage.size[1],
0, GL_RGBA, GL_UNSIGNED_BYTE, artTextureImageData) 0, GL_RGBA, GL_UNSIGNED_BYTE, artTextureImageData)
glBindTexture(GL_TEXTURE_2D, artTextureId) glBindTexture(GL_TEXTURE_2D, artTextureId)
return artTextureId return artTextureId, artInfo
# }}} # }}}
# {{{ initVideoWriter(self): XXX # {{{ initVideoWriter(self): XXX
def initVideoWriter(self, fourcc="XVID", fps=25): def initVideoWriter(self, fourcc="XVID", fps=25):
@ -76,54 +117,94 @@ class ENNToolGLCanvasPanel(wx.glcanvas.GLCanvas, wx.Panel):
def renderFrame(self, artTextureId, artVbo, artVboLen): def renderFrame(self, artTextureId, artVbo, artVboLen):
glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_NORMAL_ARRAY) glEnableClientState(GL_NORMAL_ARRAY)
glEnableClientState(GL_COLOR_ARRAY)
glEnableClientState(GL_TEXTURE_COORD_ARRAY) glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glEnable(GL_TEXTURE_2D) glEnable(GL_TEXTURE_2D)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glBindTexture(GL_TEXTURE_2D, artTextureId) glBindTexture(GL_TEXTURE_2D, artTextureId)
glBindBuffer(GL_ARRAY_BUFFER, artVbo) glBindBuffer(GL_ARRAY_BUFFER, artVbo)
glVertexPointer(3, GL_FLOAT, 32, ctypes.c_void_p(0))
glNormalPointer(GL_FLOAT, 32, ctypes.c_void_p(12)) glUseProgram(self.shader)
glTexCoordPointer(2, GL_FLOAT, 32, ctypes.c_void_p(24)) model = (GLfloat * 16)()
glGetFloatv(GL_MODELVIEW_MATRIX, model)
projection = (GLfloat * 16)()
glGetFloatv(GL_PROJECTION_MATRIX, projection)
glUniformMatrix4fv(glGetUniformLocation(self.shader, "model"), 1, GL_FALSE, model)
glUniformMatrix4fv(glGetUniformLocation(self.shader, "projection"), 1, GL_FALSE, projection)
glUniform1i(glGetUniformLocation(self.shader, "texture"), 0)
# [8]
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 3, GL_FLOAT, False, 48, ctypes.c_void_p(0))
glEnableVertexAttribArray(1)
glVertexAttribPointer(1, 3, GL_FLOAT, False, 48, ctypes.c_void_p(12))
glEnableVertexAttribArray(2)
glVertexAttribPointer(2, 4, GL_FLOAT, False, 48, ctypes.c_void_p(24))
glEnableVertexAttribArray(3)
glVertexAttribPointer(3, 2, GL_FLOAT, False, 48, ctypes.c_void_p(40))
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glVertexPointer(3, GL_FLOAT, 48, ctypes.c_void_p(0))
glNormalPointer(GL_FLOAT, 48, ctypes.c_void_p(12))
glColorPointer(4, GL_FLOAT, 48, ctypes.c_void_p(24))
glTexCoordPointer(2, GL_FLOAT, 48, ctypes.c_void_p(40))
glDrawArrays(GL_QUADS, 0, artVboLen) glDrawArrays(GL_QUADS, 0, artVboLen)
glDisableVertexAttribArray(0)
glDisable(GL_BLEND)
glDisable(GL_TEXTURE_2D) glDisable(GL_TEXTURE_2D)
glDisableClientState(GL_TEXTURE_COORD_ARRAY) glDisableClientState(GL_TEXTURE_COORD_ARRAY)
glDisableClientState(GL_COLOR_ARRAY)
glDisableClientState(GL_NORMAL_ARRAY) glDisableClientState(GL_NORMAL_ARRAY)
glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_VERTEX_ARRAY)
# }}} # }}}
# {{{ renderMiRCART(self, artMap, centre=True, canvasCols=100, cubeSize=(0.1, 0.2), texelHeight=0.0625, texelWidth=0.0625): XXX # {{{ renderMiRCART(self, artInfo, artMap, centre=True, canvasCols=100, cubeSize=(0.1, 0.2)): XXX
def renderMiRCART(self, artMap, centre=True, canvasCols=100, cubeSize=(0.1, 0.2), texelHeight=0.0625, texelWidth=0.0625): def renderMiRCART(self, artInfo, artMap, centre=True, canvasCols=100, cubeSize=(0.1, 0.2)):
curPos = [0, 0, 0]; vertices = []; numVertices = 0; curPos = [0, 0, 0]; vertices = []; numVertices = 0;
for numRow in range(len(artMap)): for numRow in range(len(artMap)):
if centre and (len(artMap[numRow]) < canvasCols): if centre and (len(artMap[numRow]) < canvasCols):
curPos[0] += (((canvasCols - len(artMap[numRow])) * cubeSize[0]) / 2) curPos[0] += (((canvasCols - len(artMap[numRow])) * cubeSize[0]) / 2)
for numCol in range(len(artMap[numRow])): for numCol in range(len(artMap[numRow])):
cubeColour = artMap[numRow][numCol][1] * texelWidth cubeColour = [*ENNToolMiRCARTColoursFloat[artMap[numRow][numCol][1]], 1.0]
if artMap[numRow][numCol][0] != artMap[numRow][numCol][1]:
colColour = artMap[numRow][numCol][0]
cubeChar = artMap[numRow][numCol][3]
if ord(cubeChar) >= 128:
print("dont have {}".format(cubeChar))
cubeChar = " "
else:
colColour = artMap[numRow][numCol][1]
cubeChar = " "
# Top Right # Top Right
vertices += curPos vertices += curPos
vertices += [0.0, 0.0, 1.0] vertices += [0.0, 0.0, 1.0]
vertices += [cubeColour+texelWidth, texelHeight] vertices += cubeColour
vertices += [float(((ord(cubeChar) + 1) * artInfo["rowWidth"]) / artInfo["texWidth"]), ((colColour + 1) * artInfo["rowHeight"]) / float(artInfo["texHeight"])]
numVertices += 1 numVertices += 1
# Top Left # Top Left
vertices += [curPos[0]-cubeSize[0], curPos[1], curPos[2]] vertices += [curPos[0]-cubeSize[0], curPos[1], curPos[2]]
vertices += [0.0, 0.0, 1.0] vertices += [0.0, 0.0, 1.0]
vertices += [cubeColour, texelHeight] vertices += cubeColour
vertices += [float(((ord(cubeChar) + 0) * artInfo["rowWidth"]) / artInfo["texWidth"]), ((colColour + 1) * artInfo["rowHeight"]) / float(artInfo["texHeight"])]
numVertices += 1 numVertices += 1
# Bottom Left # Bottom Left
vertices += [curPos[0]-cubeSize[0], curPos[1]-cubeSize[1], curPos[2]] vertices += [curPos[0]-cubeSize[0], curPos[1]-cubeSize[1], curPos[2]]
vertices += [0.0, 0.0, 1.0] vertices += [0.0, 0.0, 1.0]
vertices += [cubeColour, 0.0] vertices += cubeColour
vertices += [float(((ord(cubeChar) + 0) * artInfo["rowWidth"]) / artInfo["texWidth"]), ((colColour) * artInfo["rowHeight"]) / float(artInfo["texHeight"])]
numVertices += 1 numVertices += 1
# Bottom Right # Bottom Right
vertices += [curPos[0], curPos[1]-cubeSize[1], curPos[2]] vertices += [curPos[0], curPos[1]-cubeSize[1], curPos[2]]
vertices += [0.0, 0.0, 1.0] vertices += [0.0, 0.0, 1.0]
vertices += [cubeColour+texelWidth, 0.0] vertices += cubeColour
vertices += [float(((ord(cubeChar) + 1) * artInfo["rowWidth"]) / artInfo["texWidth"]), ((colColour) * artInfo["rowHeight"]) / float(artInfo["texHeight"])]
numVertices += 1 numVertices += 1
curPos[0] += cubeSize[0] curPos[0] += cubeSize[0]

View File

@ -16,75 +16,61 @@ from ENNToolMiRCARTImporter import ENNToolMiRCARTImporter
def main(*argv): def main(*argv):
fontNormalPathName = os.path.join("assets", "DejaVuSansMono.ttf") fontNormalPathName = os.path.join("assets", "DejaVuSansMono.ttf")
fontBoldPathName = os.path.join("assets", "DejaVuSansMono-Bold.ttf") fontBoldPathName = os.path.join("assets", "DejaVuSansMono-Bold.ttf")
fontSize = int("11") fontSize = int("26")
outInfoFileName = os.path.join("assets", "textures.yaml") outInfoFileName = os.path.join("assets", "textures.yaml")
outPathName = os.path.join("assets", "textures") outFileName = os.path.join("assets", "DejaVuSansMono.png")
if not os.path.exists(os.path.dirname(outInfoFileName)): if not os.path.exists(os.path.dirname(outInfoFileName)):
os.makedirs(os.path.dirname(outInfoFileName)) os.makedirs(os.path.dirname(outInfoFileName))
if not os.path.exists(outPathName): if not os.path.exists(os.path.dirname(outFileName)):
os.makedirs(outPathName) os.makedirs(os.path.dirname(outFileName))
pilFontNormal = ImageFont.truetype(fontNormalPathName, fontSize) pilFontNormal = ImageFont.truetype(fontNormalPathName, fontSize)
pilFontBold = ImageFont.truetype(fontBoldPathName, fontSize) pilFontBold = ImageFont.truetype(fontBoldPathName, fontSize)
pilFontSize = list(pilFontNormal.getsize(" ")) pilFontSize = list(pilFontNormal.getsize(" "))
pilFontSize[0] += (8 - (pilFontSize[0] % 8)) pilFontSize[0] += (8 - (pilFontSize[0] % 8))
pilFontSize[1] = pilFontSize[0] * 2 pilFontSize[1] = pilFontSize[0] * 2
pilImageSize = (pilFontSize[0] * 128, pilFontSize[1]) pilImageSize = (pilFontSize[0] * 128, (pilFontSize[1] * 16 * 4))
print("font size: {}, image size: {}".format(pilFontSize, pilImageSize)) print("font size: {}, image size: {}".format(pilFontSize, pilImageSize))
charMap = {} curPos = [0, 0]
for fontAttrs in [[ENNToolMiRCARTImporter._CellState.CS_NONE], pilImage = Image.new("RGBA", pilImageSize, (0, 0, 0, 0))
[ENNToolMiRCARTImporter._CellState.CS_BOLD], pilImageDraw = ImageDraw.Draw(pilImage)
[ENNToolMiRCARTImporter._CellState.CS_UNDERLINE],
[ENNToolMiRCARTImporter._CellState.CS_BOLD, ENNToolMiRCARTImporter._CellState.CS_UNDERLINE]]: pilImageTmp = Image.new("RGBA", pilFontSize, (0, 0, 0, 0))
for fontColour in range(16): pilImageTmpDraw = ImageDraw.Draw(pilImageTmp)
curPos = [0, 0]
pilImage = Image.new("RGBA", pilImageSize, (0, 0, 0, 0)) for fontAttr in [ENNToolMiRCARTImporter._CellState.CS_BOLD | ENNToolMiRCARTImporter._CellState.CS_UNDERLINE,
pilImageDraw = ImageDraw.Draw(pilImage) ENNToolMiRCARTImporter._CellState.CS_UNDERLINE,
ENNToolMiRCARTImporter._CellState.CS_BOLD,
ENNToolMiRCARTImporter._CellState.CS_NONE]:
for fontColour in reversed(range(16)):
for fontChar in [chr(n) for n in range(128)]: for fontChar in [chr(n) for n in range(128)]:
pilFont, underLine = None, False pilFont, underLine = pilFontNormal, False
for fontAttr in fontAttrs: if fontAttr & ENNToolMiRCARTImporter._CellState.CS_BOLD:
if fontAttr == ENNToolMiRCARTImporter._CellState.CS_NONE: pilFont = pilFontBold
pilFont = pilFontNormal if fontAttr & ENNToolMiRCARTImporter._CellState.CS_UNDERLINE:
elif fontAttr == ENNToolMiRCARTImporter._CellState.CS_BOLD: underLine = True
pilFont = pilFontBold
elif fontAttr == ENNToolMiRCARTImporter._CellState.CS_UNDERLINE:
underLine = True
else:
raise ValueError
if fontChar in string.printable: if fontChar in string.printable:
pilImageDraw.text(curPos, fontChar, pilImageTmpDraw.text((0, 0), fontChar,
(*ENNToolMiRCARTColours[fontColour], 255), pilFont) (*ENNToolMiRCARTColours[fontColour], 255), pilFont)
pilImage.paste(pilImageTmp, tuple(curPos))
pilImageTmpDraw.rectangle((0, 0, pilFontSize[0], pilFontSize[1]),
fill=(0, 0, 0, 0))
if underLine: if underLine:
pilImageDraw.line( pilImageDraw.line(
xy=(curPos[0], curPos[1] + (pilFontSize[1] - 2), xy=(curPos[0], curPos[1] + (pilFontSize[1] - 2),
curPos[0] + pilFontSize[0], curPos[1] + (pilFontSize[1] - 2)), curPos[0] + pilFontSize[0], curPos[1] + (pilFontSize[1] - 2)),
fill=(*ENNToolMiRCARTColours[fontColour], 255)) fill=(*ENNToolMiRCARTColours[fontColour], 255))
if not fontChar in charMap:
charMap[fontChar] = {}
if not fontColour in charMap[fontChar]:
charMap[fontChar][fontColour] = []
charMap[fontChar][fontColour] \
+= [{"attrs":fontAttrs,
"bl":[float((curPos[0])/pilImageSize[0]), float((curPos[1])/pilImageSize[1])],
"br":[float((curPos[0] + pilFontSize[0])/pilImageSize[0]), float((curPos[1])/pilImageSize[1])],
"tl":[float((curPos[0])/pilImageSize[0]), float((curPos[1] + pilFontSize[1])/pilImageSize[1])],
"tr":[float((curPos[0] + pilFontSize[0])/pilImageSize[0]), float((curPos[1] + pilFontSize[1])/pilImageSize[1])]}]
curPos[0] += pilFontSize[0] curPos[0] += pilFontSize[0]
fontAttrName = "" curPos[0], curPos[1] = 0, curPos[1] + pilFontSize[1]
for fontAttr in fontAttrs: pilImage.save(outFileName)
if fontAttr == ENNToolMiRCARTImporter._CellState.CS_NONE: artInfo = {}
fontAttrName += "Normal" artInfo["rowHeight"] = pilFontSize[1]
elif fontAttr == ENNToolMiRCARTImporter._CellState.CS_BOLD: artInfo["rowWidth"] = pilFontSize[0]
fontAttrName += "Bold" artInfo["texHeight"] = pilImageSize[1]
elif fontAttr == ENNToolMiRCARTImporter._CellState.CS_UNDERLINE: artInfo["texWidth"] = pilImageSize[0]
fontAttrName += "Underline"
else:
raise ValueError
pilImage.save(os.path.join(outPathName, "{}Fg{:02d}.png".format(fontAttrName, fontColour)))
with open(outInfoFileName, "w") as fileObject: with open(outInfoFileName, "w") as fileObject:
yaml.dump(charMap, fileObject) yaml.dump(artInfo, fileObject)
if __name__ == "__main__": if __name__ == "__main__":
main(*sys.argv) main(*sys.argv)

BIN
assets/DejaVuSansMono.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 18 B

1
assets/texture.png Symbolic link
View File

@ -0,0 +1 @@
DejaVuSansMono.png

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 18 B

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB