mirror of
https://github.com/lalbornoz/roar.git
synced 2024-11-22 15:26:37 +00:00
Initial FFmpeg & {GIF,MP4,WEBM,...} support for -o.
ENNToolGLCanvasPanel.py: minor cleanup regarding deprecated calls.
This commit is contained in:
parent
e656f549ff
commit
eff72be6ef
48
ENNTool.py
48
ENNTool.py
@ -6,14 +6,12 @@
|
|||||||
#
|
#
|
||||||
# TODO:
|
# TODO:
|
||||||
# 1) -A: render frame #1, render frame #2, ...
|
# 1) -A: render frame #1, render frame #2, ...
|
||||||
# 2) -o: support at least {GIF,MP4,WEBM}
|
# 2) -s: effects: rotate, smash into bricks, swirl, wave, ...
|
||||||
# 3) -s: effects: rotate, smash into bricks, swirl, wave, ...
|
# 3) Feature: include ETA @ progress bar
|
||||||
# 4) Feature: include ETA @ progress bar
|
# 4) Feature: autodetect video width from widest mircart
|
||||||
# 5) Feature: autodetect video width from widest mircart
|
# 5) Feature: render mircart as 3D blocks vs flat surface
|
||||||
# 6) Feature: render mircart as 3D blocks vs flat surface
|
# 6) Optimisation: 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) Optimisation: 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) OpenGL: use VAOs + glVertexAttribFormat + glVertexAttribBinding
|
||||||
# 8) OpenGL: use VAOs + glVertexAttribFormat + glVertexAttribBinding
|
|
||||||
# 9) OpenGL: use glEnable(GL_BLEND) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) & multiply texel * bgcolour (https://learnopengl.com/Advanced-OpenGL/Blending)
|
|
||||||
#
|
#
|
||||||
|
|
||||||
from getopt import getopt, GetoptError
|
from getopt import getopt, GetoptError
|
||||||
@ -24,6 +22,7 @@ import wx
|
|||||||
|
|
||||||
from ENNToolGLCanvasPanel import ENNToolGLCanvasPanel
|
from ENNToolGLCanvasPanel import ENNToolGLCanvasPanel
|
||||||
from ENNToolGLTTFTexture import ENNToolGLTTFTexture
|
from ENNToolGLTTFTexture import ENNToolGLTTFTexture
|
||||||
|
from ENNToolGLVideoWriter import ENNToolGLVideoWriter
|
||||||
from ENNToolMiRCARTImporter import ENNToolMiRCARTImporter
|
from ENNToolMiRCARTImporter import ENNToolMiRCARTImporter
|
||||||
|
|
||||||
class ENNToolApp(object):
|
class ENNToolApp(object):
|
||||||
@ -33,31 +32,30 @@ class ENNToolApp(object):
|
|||||||
def parseArgv(self, argv):
|
def parseArgv(self, argv):
|
||||||
def usage(argv0):
|
def usage(argv0):
|
||||||
print("usage: {}".format(os.path.basename(argv0)), file=sys.stderr)
|
print("usage: {}".format(os.path.basename(argv0)), file=sys.stderr)
|
||||||
print(" [-A] [-f fps] [-h] [-o pname]".format(os.path.basename(argv0)), file=sys.stderr)
|
print(" [-A] [-f fps] [-h] [-o fname]".format(os.path.basename(argv0)), file=sys.stderr)
|
||||||
print(" [-p] [-r WxH] [-R WxH] [-s pname]", file=sys.stderr)
|
print(" [-p] [-r WxH] [-R WxH] [-s fname]", file=sys.stderr)
|
||||||
print(" [-S] [-t pname] [-v] [--] pname..", file=sys.stderr)
|
print(" [-S] [-v] [--] fname..", file=sys.stderr)
|
||||||
print("", file=sys.stderr)
|
print("", file=sys.stderr)
|
||||||
print(" -a........: select animation mode", file=sys.stderr)
|
print(" -a........: select animation mode", file=sys.stderr)
|
||||||
print(" -f fps....: set video FPS; defaults to 25", file=sys.stderr)
|
print(" -f fps....: set video FPS; defaults to 25", file=sys.stderr)
|
||||||
print(" -h........: show this screen", file=sys.stderr)
|
print(" -h........: show this screen", file=sys.stderr)
|
||||||
print(" -o pname..: output video pathname", file=sys.stderr)
|
print(" -o fname..: output video filename; extension determines video type", file=sys.stderr)
|
||||||
print(" -p........: play video after rendering", file=sys.stderr)
|
print(" -p........: play video after rendering", file=sys.stderr)
|
||||||
print(" -r WxH....: set video resolution; defaults to 1152x864", file=sys.stderr)
|
print(" -r WxH....: set video resolution; defaults to 1152x864", file=sys.stderr)
|
||||||
print(" -R WxH....: set MiRCART cube resolution; defaults to 0.1x0.2", file=sys.stderr)
|
print(" -R WxH....: set MiRCART cube resolution; defaults to 0.1x0.2", file=sys.stderr)
|
||||||
print(" -s pname..: input script pathname", file=sys.stderr)
|
print(" -s fname..: input script filename", file=sys.stderr)
|
||||||
print(" -S........: select scrolling mode", file=sys.stderr)
|
print(" -S........: select scrolling mode", file=sys.stderr)
|
||||||
print(" -t pname..: set MiRCART texture pathname; defaults to {}".format(os.path.join("assets", "texture.png")), file=sys.stderr)
|
|
||||||
print(" -v........: be verbose", file=sys.stderr)
|
print(" -v........: be verbose", file=sys.stderr)
|
||||||
try:
|
try:
|
||||||
optlist, argv = getopt(argv[1:], "Af:ho:pr:R:s:St:v")
|
optlist, argv = getopt(argv[1:], "Af:ho:pr:R:s:Sv")
|
||||||
optdict = dict(optlist)
|
optdict = dict(optlist)
|
||||||
|
|
||||||
if "-h" in optdict:
|
if "-h" in optdict:
|
||||||
usage(sys.argv[0]); exit(0);
|
usage(sys.argv[0]); exit(0);
|
||||||
elif not "-o" in optdict:
|
elif not "-o" in optdict:
|
||||||
raise GetoptError("-o pname must be specified")
|
raise GetoptError("-o fname must be specified")
|
||||||
elif not len(argv):
|
elif not len(argv):
|
||||||
raise GetoptError("at least one MiRCART input pname must be specified")
|
raise GetoptError("at least one MiRCART input fname must be specified")
|
||||||
|
|
||||||
if not "-f" in optdict:
|
if not "-f" in optdict:
|
||||||
optdict["-f"] = "25"
|
optdict["-f"] = "25"
|
||||||
@ -65,8 +63,6 @@ class ENNToolApp(object):
|
|||||||
optdict["-r"] = "1152x864"
|
optdict["-r"] = "1152x864"
|
||||||
if not "-R" in optdict:
|
if not "-R" in optdict:
|
||||||
optdict["-R"] = "0.1x0.2"
|
optdict["-R"] = "0.1x0.2"
|
||||||
if not "-t" in optdict:
|
|
||||||
optdict["-t"] = os.path.join("assets", "texture.png")
|
|
||||||
|
|
||||||
if "-r" in optdict:
|
if "-r" in optdict:
|
||||||
optdict["-r"] = [int(r) for r in optdict["-r"].split("x")][0:2]
|
optdict["-r"] = [int(r) for r in optdict["-r"].split("x")][0:2]
|
||||||
@ -86,8 +82,8 @@ class ENNToolApp(object):
|
|||||||
print("\r[{:<50}] {}%".format(
|
print("\r[{:<50}] {}%".format(
|
||||||
("=" * int(progressDiv * 50)), int(progressDiv * 100)), end=endChar)
|
("=" * int(progressDiv * 50)), int(progressDiv * 100)), end=endChar)
|
||||||
# }}}
|
# }}}
|
||||||
# {{{ modeScroll(self, argv, optdict, panelGLCanvas, texturePathName, fps=25, scrollRate=0.25): XXX
|
# {{{ modeScroll(self, argv, optdict, GLVideoWriter, panelGLCanvas, fps=25, scrollRate=0.25): XXX
|
||||||
def modeScroll(self, argv, optdict, panelGLCanvas, texturePathName, fps=25, scrollRate=0.25):
|
def modeScroll(self, argv, optdict, GLVideoWriter, panelGLCanvas, fps=25, scrollRate=0.25):
|
||||||
MiRCART = []
|
MiRCART = []
|
||||||
for inFileArg in argv:
|
for inFileArg in argv:
|
||||||
for inFile in sorted(glob(inFileArg)):
|
for inFile in sorted(glob(inFileArg)):
|
||||||
@ -110,9 +106,11 @@ class ENNToolApp(object):
|
|||||||
glRotatef(rotateX * (180.0/w), 0.0, 1.0, 0.0)
|
glRotatef(rotateX * (180.0/w), 0.0, 1.0, 0.0)
|
||||||
if rotateY:
|
if rotateY:
|
||||||
glRotatef(rotateY * (180.0/h), 1.0, 0.0, 0.0)
|
glRotatef(rotateY * (180.0/h), 1.0, 0.0, 0.0)
|
||||||
panelGLCanvas.saveFrame()
|
GLVideoWriter.saveFrame()
|
||||||
if curY >= lastY:
|
if curY >= lastY:
|
||||||
self.printProgress(curY, lastY); break;
|
self.printProgress(curY, lastY); break;
|
||||||
|
|
||||||
|
GLVideoWriter.saveVideo()
|
||||||
# }}}
|
# }}}
|
||||||
# {{{ __init__(self, argv): XXX
|
# {{{ __init__(self, argv): XXX
|
||||||
def __init__(self, argv):
|
def __init__(self, argv):
|
||||||
@ -123,14 +121,14 @@ class ENNToolApp(object):
|
|||||||
appPanelSkin = wx.Panel(appFrame, wx.ID_ANY)
|
appPanelSkin = wx.Panel(appFrame, wx.ID_ANY)
|
||||||
|
|
||||||
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)
|
||||||
panelGLCanvas.initOpenGL()
|
panelGLCanvas.initOpenGL()
|
||||||
panelGLCanvas.initShaders()
|
panelGLCanvas.initShaders()
|
||||||
panelGLCanvas.initVideoWriter(fps=videoFps)
|
GLVideoWriter = ENNToolGLVideoWriter(videoPath, panelGLCanvas.GetClientSize(), videoFps=videoFps)
|
||||||
|
|
||||||
if "-v" in optdict:
|
if "-v" in optdict:
|
||||||
time0 = time.time()
|
time0 = time.time()
|
||||||
self.modeScroll(argv, optdict, panelGLCanvas, fps=videoFps, texturePathName=optdict["-t"])
|
self.modeScroll(argv, optdict, GLVideoWriter, panelGLCanvas, fps=videoFps)
|
||||||
if "-v" in optdict:
|
if "-v" in optdict:
|
||||||
print("delta {}s".format(time.time() - time0))
|
print("delta {}s".format(time.time() - time0))
|
||||||
if "-p" in optdict:
|
if "-p" in optdict:
|
||||||
|
@ -11,15 +11,12 @@
|
|||||||
# 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 18:32:50 +0200 [6] <https://stackoverflow.com/questions/18935203/shader-position-vec4-or-vec3>
|
# Thu, 28 Jun 2018 18:32:50 +0200 [6] <https://stackoverflow.com/questions/18935203/shader-position-vec4-or-vec3>
|
||||||
|
# Tue, 03 Jul 2018 14:34:57 +0200 [7] <https://gamedev.stackexchange.com/questions/107793/binding-and-unbinding-what-would-you-do>
|
||||||
#
|
#
|
||||||
|
|
||||||
from OpenGL.GL import *
|
from OpenGL.GL import *
|
||||||
from OpenGL.GL import shaders
|
from OpenGL.GL import shaders
|
||||||
import cv2, numpy
|
import ctypes, wx, wx.glcanvas
|
||||||
import ctypes, os, sys, time
|
|
||||||
import wx, wx.glcanvas
|
|
||||||
|
|
||||||
from ENNToolMiRCARTColours import ENNToolMiRCARTColoursFloat
|
|
||||||
|
|
||||||
class ENNToolGLCanvasPanel(wx.glcanvas.GLCanvas, wx.Panel):
|
class ENNToolGLCanvasPanel(wx.glcanvas.GLCanvas, wx.Panel):
|
||||||
"""XXX"""
|
"""XXX"""
|
||||||
@ -40,10 +37,10 @@ class ENNToolGLCanvasPanel(wx.glcanvas.GLCanvas, wx.Panel):
|
|||||||
# }}}
|
# }}}
|
||||||
# {{{ initShaders(self): XXX
|
# {{{ initShaders(self): XXX
|
||||||
def initShaders(self):
|
def initShaders(self):
|
||||||
|
# Fragment shader
|
||||||
fs = shaders.compileShader("""
|
fs = shaders.compileShader("""
|
||||||
#version 330 core
|
#version 330 core
|
||||||
|
|
||||||
in vec4 bgColour;
|
|
||||||
in vec2 fgTexCoord;
|
in vec2 fgTexCoord;
|
||||||
uniform sampler2D texture;
|
uniform sampler2D texture;
|
||||||
|
|
||||||
@ -52,125 +49,83 @@ class ENNToolGLCanvasPanel(wx.glcanvas.GLCanvas, wx.Panel):
|
|||||||
gl_FragColor = vec4(texel.r, texel.g, texel.b, 1.0);
|
gl_FragColor = vec4(texel.r, texel.g, texel.b, 1.0);
|
||||||
}
|
}
|
||||||
""", GL_FRAGMENT_SHADER)
|
""", GL_FRAGMENT_SHADER)
|
||||||
|
|
||||||
|
# Vertex shader
|
||||||
vs = shaders.compileShader("""
|
vs = shaders.compileShader("""
|
||||||
#version 330 core
|
#version 330 core
|
||||||
|
|
||||||
layout(location = 0) in vec4 vertex;
|
layout(location = 0) in vec4 vertex;
|
||||||
layout(location = 1) in vec3 normal;
|
layout(location = 1) in vec2 texcoord;
|
||||||
layout(location = 2) in vec4 colour;
|
|
||||||
layout(location = 3) in vec2 texcoord;
|
|
||||||
|
|
||||||
out vec4 bgColour;
|
|
||||||
out vec2 fgTexCoord;
|
out vec2 fgTexCoord;
|
||||||
|
|
||||||
uniform mat4 model;
|
uniform mat4 modelview;
|
||||||
uniform mat4 projection;
|
uniform mat4 projection;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = projection * model * vertex;
|
gl_Position = projection * modelview * vertex;
|
||||||
bgColour = colour;
|
|
||||||
fgTexCoord = texcoord;
|
fgTexCoord = texcoord;
|
||||||
}
|
}
|
||||||
""", GL_VERTEX_SHADER)
|
""", GL_VERTEX_SHADER)
|
||||||
self.shader = shaders.compileProgram(vs, fs)
|
self.shader = shaders.compileProgram(vs, fs)
|
||||||
# }}}
|
# }}}
|
||||||
# {{{ initVideoWriter(self): XXX
|
|
||||||
def initVideoWriter(self, fourcc="XVID", fps=25):
|
|
||||||
fourcc = cv2.VideoWriter_fourcc(*list(fourcc))
|
|
||||||
self.videoWriter = cv2.VideoWriter(self.videoPath, fourcc, fps, (self.width, self.height), True)
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
# {{{ renderFrame(self, artTextureId, artVbo, artVboLen): XXX
|
# {{{ renderFrame(self, artTextureId, artVbo, artVboLen): XXX
|
||||||
def renderFrame(self, artTextureId, artVbo, artVboLen):
|
def renderFrame(self, artTextureId, artVbo, artVboLen):
|
||||||
glEnableClientState(GL_VERTEX_ARRAY)
|
# Bind VBO and named texture & install shader program object
|
||||||
glEnableClientState(GL_NORMAL_ARRAY)
|
|
||||||
glEnableClientState(GL_COLOR_ARRAY)
|
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
|
|
||||||
glEnable(GL_TEXTURE_2D)
|
|
||||||
|
|
||||||
glEnable(GL_BLEND)
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, artTextureId)
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, artVbo)
|
glBindBuffer(GL_ARRAY_BUFFER, artVbo)
|
||||||
|
glBindTexture(GL_TEXTURE_2D, artTextureId)
|
||||||
glUseProgram(self.shader)
|
glUseProgram(self.shader)
|
||||||
model = (GLfloat * 16)()
|
|
||||||
glGetFloatv(GL_MODELVIEW_MATRIX, model)
|
# Specify modelview and projection matrix & texture unit uniforms for shader programs
|
||||||
projection = (GLfloat * 16)()
|
modelview, projection = (GLfloat * 16)(), (GLfloat * 16)()
|
||||||
|
glGetFloatv(GL_MODELVIEW_MATRIX, modelview)
|
||||||
glGetFloatv(GL_PROJECTION_MATRIX, projection)
|
glGetFloatv(GL_PROJECTION_MATRIX, projection)
|
||||||
glUniformMatrix4fv(glGetUniformLocation(self.shader, "model"), 1, GL_FALSE, model)
|
glUniformMatrix4fv(glGetUniformLocation(self.shader, "modelview"), 1, GL_FALSE, modelview)
|
||||||
glUniformMatrix4fv(glGetUniformLocation(self.shader, "projection"), 1, GL_FALSE, projection)
|
glUniformMatrix4fv(glGetUniformLocation(self.shader, "projection"), 1, GL_FALSE, projection)
|
||||||
glUniform1i(glGetUniformLocation(self.shader, "texture"), 0)
|
glUniform1i(glGetUniformLocation(self.shader, "texture"), 0)
|
||||||
|
|
||||||
# [6]
|
# VBO vertices location
|
||||||
glEnableVertexAttribArray(0)
|
glEnableVertexAttribArray(0)
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, False, 48, ctypes.c_void_p(0))
|
glVertexAttribPointer(0, 3, GL_FLOAT, False, 20, ctypes.c_void_p(0))
|
||||||
|
glVertexPointer(3, GL_FLOAT, 20, ctypes.c_void_p(0))
|
||||||
|
|
||||||
|
# VBO texture coordinates
|
||||||
glEnableVertexAttribArray(1)
|
glEnableVertexAttribArray(1)
|
||||||
glVertexAttribPointer(1, 3, GL_FLOAT, False, 48, ctypes.c_void_p(12))
|
glVertexAttribPointer(1, 2, GL_FLOAT, False, 20, ctypes.c_void_p(12))
|
||||||
glEnableVertexAttribArray(2)
|
glTexCoordPointer(2, GL_FLOAT, 20, ctypes.c_void_p(12))
|
||||||
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))
|
|
||||||
|
|
||||||
|
# Clear colour and depth buffer, draw quads from VBO & clear state
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
|
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)
|
glDisableVertexAttribArray(0)
|
||||||
glDisable(GL_BLEND)
|
glBindTexture(GL_TEXTURE_2D, 0)
|
||||||
glDisable(GL_TEXTURE_2D)
|
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY)
|
|
||||||
glDisableClientState(GL_COLOR_ARRAY)
|
|
||||||
glDisableClientState(GL_NORMAL_ARRAY)
|
|
||||||
glDisableClientState(GL_VERTEX_ARRAY)
|
|
||||||
# }}}
|
# }}}
|
||||||
# {{{ renderMiRCART(self, artInfo, artMap, centre=True, canvasCols=100, cubeSize=(0.1, 0.2)): XXX
|
# {{{ renderMiRCART(self, artInfo, artMap, centre=True, canvasCols=100, cubeSize=(0.1, 0.2)): XXX
|
||||||
def renderMiRCART(self, artInfo, artMap, centre=True, canvasCols=100, cubeSize=(0.1, 0.2)):
|
def renderMiRCART(self, artInfo, artMap, centre=True, canvasCols=100, cubeSize=(0.1, 0.2)):
|
||||||
curPos = [0, 0, 0]; vertices = []; numVertices = 0;
|
curPos, vertices, numVertices = [0, 0, 0], [], 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])):
|
||||||
cubeFg = artMap[numRow][numCol][0]
|
cubeFg = artMap[numRow][numCol][0]
|
||||||
cubeBg = artMap[numRow][numCol][1]
|
cubeBg = artMap[numRow][numCol][1]
|
||||||
cubeBgFloat = [*ENNToolMiRCARTColoursFloat[cubeBg], 1.0]
|
|
||||||
cubeAttrs = artMap[numRow][numCol][2]
|
cubeAttrs = artMap[numRow][numCol][2]
|
||||||
cubeChar = artMap[numRow][numCol][3]
|
cubeChar = artMap[numRow][numCol][3]
|
||||||
artCell = artInfo[cubeFg][cubeBg][cubeAttrs][cubeChar]
|
artCell = artInfo[cubeFg][cubeBg][cubeAttrs][cubeChar]
|
||||||
|
|
||||||
# Top Right
|
# Top Right, Top Left
|
||||||
vertices += curPos
|
vertices += curPos
|
||||||
vertices += [0.0, 0.0, 1.0]
|
|
||||||
vertices += cubeBgFloat
|
|
||||||
vertices += artCell[0:2]
|
vertices += artCell[0:2]
|
||||||
numVertices += 1
|
|
||||||
|
|
||||||
# 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 += cubeBgFloat
|
|
||||||
vertices += artCell[2:4]
|
vertices += artCell[2:4]
|
||||||
numVertices += 1
|
|
||||||
|
|
||||||
# Bottom Left
|
# Bottom Left, Bottom Right
|
||||||
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 += cubeBgFloat
|
|
||||||
vertices += artCell[4:6]
|
vertices += artCell[4:6]
|
||||||
numVertices += 1
|
|
||||||
|
|
||||||
# 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 += cubeBgFloat
|
|
||||||
vertices += artCell[6:8]
|
vertices += artCell[6:8]
|
||||||
numVertices += 1
|
|
||||||
|
|
||||||
curPos[0] += cubeSize[0]
|
curPos[0], numVertices = curPos[0] + cubeSize[0], numVertices + 4
|
||||||
curPos[0], curPos[1] = 0, curPos[1] - cubeSize[1]
|
curPos[0], curPos[1] = 0, curPos[1] - cubeSize[1]
|
||||||
|
|
||||||
artVbo = glGenBuffers(1)
|
artVbo = glGenBuffers(1)
|
||||||
@ -180,22 +135,10 @@ class ENNToolGLCanvasPanel(wx.glcanvas.GLCanvas, wx.Panel):
|
|||||||
GL_STATIC_DRAW)
|
GL_STATIC_DRAW)
|
||||||
return artVbo, len(vertices), -curPos[1], numVertices
|
return artVbo, len(vertices), -curPos[1], numVertices
|
||||||
# }}}
|
# }}}
|
||||||
# {{{ saveFrame(self): XXX
|
# {{{ __init__(self, parent, size, defaultPos=(24,24)): initialisation method
|
||||||
def saveFrame(self):
|
def __init__(self, parent, size, defaultPos=(24,24)):
|
||||||
if sys.byteorder == "little":
|
|
||||||
screenshot = glReadPixels(0, 0, self.width, self.height, GL_BGR, GL_UNSIGNED_BYTE)
|
|
||||||
else:
|
|
||||||
screenshot = glReadPixels(0, 0, self.width, self.height, GL_RGB, GL_UNSIGNED_BYTE)
|
|
||||||
screenshot = numpy.flipud(numpy.frombuffer(screenshot, numpy.uint8).reshape((self.height, self.width, 3)))
|
|
||||||
self.videoWriter.write(screenshot)
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
# {{{ __init__(self, parent, size, defaultPos=(24,24), videoPath=None): initialisation method
|
|
||||||
def __init__(self, parent, size, defaultPos=(24,24), videoPath=None):
|
|
||||||
super().__init__(parent, pos=defaultPos, size=size)
|
super().__init__(parent, pos=defaultPos, size=size)
|
||||||
self.curPos = list(defaultPos); self.curSize = list(size);
|
self.curPos = list(defaultPos); self.curSize = list(size);
|
||||||
self.width, self.height = self.GetClientSize()
|
|
||||||
self.videoPath = videoPath
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
|
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
|
||||||
|
@ -17,7 +17,6 @@ from OpenGL.GL import *
|
|||||||
from PIL import Image, ImageDraw, ImageFont
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
import numpy
|
import numpy
|
||||||
import os, string, sys
|
import os, string, sys
|
||||||
|
|
||||||
from ENNToolMiRCARTColours import ENNToolMiRCARTColours
|
from ENNToolMiRCARTColours import ENNToolMiRCARTColours
|
||||||
from ENNToolMiRCARTImporter import ENNToolMiRCARTImporter
|
from ENNToolMiRCARTImporter import ENNToolMiRCARTImporter
|
||||||
|
|
||||||
@ -34,7 +33,6 @@ class ENNToolGLTTFTexture(object):
|
|||||||
def _nestedDict():
|
def _nestedDict():
|
||||||
return defaultdict(ENNToolGLTTFTexture._nestedDict)
|
return defaultdict(ENNToolGLTTFTexture._nestedDict)
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
# {{{ _drawCharList(self, artInfo, charList, pilFontBold, pilFontNormal, pilFontSize, pilImageDraw, pilImageSize): XXX
|
# {{{ _drawCharList(self, artInfo, charList, pilFontBold, pilFontNormal, pilFontSize, pilImageDraw, pilImageSize): XXX
|
||||||
def _drawCharList(self, artInfo, charList, pilFontBold, pilFontNormal, pilFontSize, pilImageDraw, pilImageSize):
|
def _drawCharList(self, artInfo, charList, pilFontBold, pilFontNormal, pilFontSize, pilImageDraw, pilImageSize):
|
||||||
curPos = [0, 0]
|
curPos = [0, 0]
|
||||||
@ -119,9 +117,9 @@ class ENNToolGLTTFTexture(object):
|
|||||||
0, GL_RGBA, GL_UNSIGNED_BYTE, artTextureImageData)
|
0, GL_RGBA, GL_UNSIGNED_BYTE, artTextureImageData)
|
||||||
glGenerateMipmap(GL_TEXTURE_2D)
|
glGenerateMipmap(GL_TEXTURE_2D)
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0)
|
||||||
return artTextureId
|
return artTextureId
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
# {{{ getParams(self): XXX
|
# {{{ getParams(self): XXX
|
||||||
def getParams(self):
|
def getParams(self):
|
||||||
return self.artTextureId, self.artInfo
|
return self.artTextureId, self.artInfo
|
||||||
|
44
ENNToolGLVideoWriter.py
Normal file
44
ENNToolGLVideoWriter.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# ENNTool -- mIRC art animation tool (for EFnet #MiRCART) (WIP)
|
||||||
|
# Copyright (c) 2018 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
||||||
|
# This project is licensed under the terms of the MIT license.
|
||||||
|
#
|
||||||
|
|
||||||
|
from OpenGL.GL import *
|
||||||
|
import numpy, subprocess
|
||||||
|
|
||||||
|
class ENNToolGLVideoWriter(object):
|
||||||
|
"""XXX"""
|
||||||
|
|
||||||
|
# {{{ saveFrame(self): XXX
|
||||||
|
def saveFrame(self):
|
||||||
|
frameBuffer = glReadPixels(0, 0, self.videoSize[0], self.videoSize[1], GL_RGB, GL_UNSIGNED_BYTE)
|
||||||
|
frameBuffer = numpy.frombuffer(frameBuffer, numpy.uint8)
|
||||||
|
frameBuffer = frameBuffer.reshape((self.videoSize[1], self.videoSize[0], 3))
|
||||||
|
frameBuffer = numpy.flipud(frameBuffer)
|
||||||
|
self.videoFrames += [frameBuffer]
|
||||||
|
# }}}
|
||||||
|
# {{{ saveVideo(self): XXX
|
||||||
|
def saveVideo(self):
|
||||||
|
with subprocess.Popen([
|
||||||
|
"FFmpeg.exe",
|
||||||
|
"-pix_fmt", "rgb24",
|
||||||
|
"-r", str(self.videoFps),
|
||||||
|
"-s", "x".join([str(r) for r in self.videoSize]),
|
||||||
|
"-vcodec", "rawvideo",
|
||||||
|
"-f", "rawvideo",
|
||||||
|
"-i", "-",
|
||||||
|
"-an",
|
||||||
|
"-y",
|
||||||
|
self.videoPath], stdin=subprocess.PIPE) as procObject:
|
||||||
|
for videoFrame in self.videoFrames:
|
||||||
|
procObject.stdin.write(videoFrame.tobytes())
|
||||||
|
# }}}
|
||||||
|
# {{{ __init__(self, videoPath, videoSize, videoFps=25): XXX
|
||||||
|
def __init__(self, videoPath, videoSize, videoFps=25):
|
||||||
|
self.videoFps, self.videoPath, self.videoSize = videoFps, videoPath, videoSize
|
||||||
|
self.videoFrames = []
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
|
@ -26,7 +26,6 @@ class ENNToolMiRCARTImporter(object):
|
|||||||
PS_COLOUR_DIGIT0 = 2
|
PS_COLOUR_DIGIT0 = 2
|
||||||
PS_COLOUR_DIGIT1 = 3
|
PS_COLOUR_DIGIT1 = 3
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
# {{{ _flipCellStateBit(self, cellState, bit): XXX
|
# {{{ _flipCellStateBit(self, cellState, bit): XXX
|
||||||
def _flipCellStateBit(self, cellState, bit):
|
def _flipCellStateBit(self, cellState, bit):
|
||||||
if cellState & bit:
|
if cellState & bit:
|
||||||
|
@ -2,4 +2,5 @@
|
|||||||
Copyright (c) 2018 Lucio Andrés Illanes Albornoz <<lucio@lucioillanes.de>>
|
Copyright (c) 2018 Lucio Andrés Illanes Albornoz <<lucio@lucioillanes.de>>
|
||||||
This project is licensed under the terms of the MIT licence.
|
This project is licensed under the terms of the MIT licence.
|
||||||
* Prerequisites on Windows: install Python v3.5.x and script dependencies w/ the following elevated command prompt command line:
|
* Prerequisites on Windows: install Python v3.5.x and script dependencies w/ the following elevated command prompt command line:
|
||||||
`pip install chardet numpy opencv-python Pillow PyOpenGL wxPython`
|
`pip install chardet numpy Pillow PyOpenGL wxPython`
|
||||||
|
* Additionally, FFmpeg.exe must be present in the current working directory and/or %PATH%.
|
||||||
|
Loading…
Reference in New Issue
Block a user