#!/usr/bin/env python3 # # ENNTool -- mIRC art animation tool (for EFnet #MiRCART) (WIP) # Copyright (c) 2018 Lucio Andrés Illanes Albornoz # This project is licensed under the terms of the MIT license. # # References: # Wed, 27 Jun 2018 16:02:10 +0200 [1] # Wed, 27 Jun 2018 16:02:11 +0200 [2] # Wed, 27 Jun 2018 16:02:12 +0200 [3] # Wed, 27 Jun 2018 16:02:13 +0200 [4] # Wed, 27 Jun 2018 16:02:14 +0200 [5] # Thu, 28 Jun 2018 18:32:50 +0200 [6] # Tue, 03 Jul 2018 14:34:57 +0200 [7] # from ENNToolMiRCARTColours import ENNToolMiRCARTColoursFloat from OpenGL.GL import * from OpenGL.GL import shaders import ctypes, wx, wx.glcanvas class ENNToolGLCanvas(wx.glcanvas.GLCanvas): # {{{ initOpenGL(self, cameraPos=(-5.0, 3.0, -5)): XXX def initOpenGL(self, cameraPos=(-5.0, 3.0, -5)): self.glContext = wx.glcanvas.GLContext(self) self.SetCurrent(self.glContext) # [1] glViewport(0, 0, *self.curSize) glMatrixMode(GL_PROJECTION) glLoadIdentity(); glFrustum(-1, 1, -1, 1, 1, 100); glMatrixMode(GL_MODELVIEW) glEnable(GL_DEPTH_TEST) glTranslatef(*cameraPos) # }}} # {{{ initShaders(self): XXX def initShaders(self): # Fragment shader fs = shaders.compileShader(""" #version 330 core in vec2 frgTexCoord; in vec3 frgFgColour; in vec3 frgBgColour; uniform sampler2D texture; layout(location = 0) out vec4 fragColour; void main() { vec4 texel = texture2D(texture, frgTexCoord); if (texel.r == 0.0 && texel.g == 0.0 && texel.b == 0.0 && texel.a == 0.0) { fragColour = vec4(frgBgColour.r, frgBgColour.g, frgBgColour.b, 1.0); } else { fragColour = vec4(frgFgColour.r, frgFgColour.g, frgFgColour.b, 1.0); } } """, GL_FRAGMENT_SHADER) # Vertex shader vs = shaders.compileShader(""" #version 330 core layout(location = 0) in vec4 vertex; layout(location = 1) in vec2 texcoord; layout(location = 2) in vec3 vexFgColour; layout(location = 3) in vec3 vexBgColour; out vec2 frgTexCoord; out vec3 frgFgColour; out vec3 frgBgColour; uniform mat4 modelview; uniform mat4 projection; void main() { gl_Position = projection * modelview * vertex; frgTexCoord = texcoord; frgFgColour = vexFgColour; frgBgColour = vexBgColour; } """, GL_VERTEX_SHADER) self.shader = shaders.compileProgram(vs, fs) # }}} # {{{ renderFrame(self, artTextureId, artVbo, artVboLen): XXX def renderFrame(self, artTextureId, artVbo, artVboLen): # Bind VBO and named texture & install shader program object glBindBuffer(GL_ARRAY_BUFFER, artVbo) glBindTexture(GL_TEXTURE_2D, artTextureId) glUseProgram(self.shader) # Specify modelview and projection matrix & texture unit uniforms for shader programs modelview, projection = (GLfloat * 16)(), (GLfloat * 16)() glGetFloatv(GL_MODELVIEW_MATRIX, modelview) glGetFloatv(GL_PROJECTION_MATRIX, projection) glUniformMatrix4fv(glGetUniformLocation(self.shader, "modelview"), 1, GL_FALSE, modelview) glUniformMatrix4fv(glGetUniformLocation(self.shader, "projection"), 1, GL_FALSE, projection) glUniform1i(glGetUniformLocation(self.shader, "texture"), 0) # VBO vertices location glEnableVertexAttribArray(0) glVertexAttribPointer(0, 3, GL_FLOAT, False, 44, ctypes.c_void_p(0)) glVertexPointer(3, GL_FLOAT, 44, ctypes.c_void_p(0)) # VBO texture coordinates glEnableVertexAttribArray(1) glVertexAttribPointer(1, 2, GL_FLOAT, False, 44, ctypes.c_void_p(12)) glTexCoordPointer(2, GL_FLOAT, 44, ctypes.c_void_p(12)) # VBO foreground colours glEnableVertexAttribArray(2) glVertexAttribPointer(2, 3, GL_FLOAT, False, 44, ctypes.c_void_p(20)) glTexCoordPointer(3, GL_FLOAT, 44, ctypes.c_void_p(20)) # VBO background colours glEnableVertexAttribArray(3) glVertexAttribPointer(3, 3, GL_FLOAT, False, 44, ctypes.c_void_p(32)) glTexCoordPointer(3, GL_FLOAT, 44, ctypes.c_void_p(32)) # Clear colour and depth buffer, draw quads from VBO & clear state glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glDrawArrays(GL_QUADS, 0, artVboLen) glDisableVertexAttribArray(0) glBindTexture(GL_TEXTURE_2D, 0) # }}} # {{{ 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)): curPos, vertices, numVertices = [0, 0, 0], [], 0 for numRow in range(len(artMap)): if centre and (len(artMap[numRow]) < canvasCols): curPos[0] += (((canvasCols - len(artMap[numRow])) * cubeSize[0]) / 2) for numCol in range(len(artMap[numRow])): cubeFg = artMap[numRow][numCol][0] cubeBg = artMap[numRow][numCol][1] cubeAttrs = artMap[numRow][numCol][2] cubeChar = artMap[numRow][numCol][3] artCell = artInfo[cubeAttrs][cubeChar] # Top Right, Top Left vertices += curPos vertices += artCell[0:2] vertices += [*ENNToolMiRCARTColoursFloat[cubeFg]] vertices += [*ENNToolMiRCARTColoursFloat[cubeBg]] vertices += [curPos[0] - cubeSize[0], curPos[1], curPos[2]] vertices += artCell[2:4] vertices += ENNToolMiRCARTColoursFloat[cubeFg] vertices += ENNToolMiRCARTColoursFloat[cubeBg] # Bottom Left, Bottom Right vertices += [curPos[0] - cubeSize[0], curPos[1] - cubeSize[1], curPos[2]] vertices += artCell[4:6] vertices += [*ENNToolMiRCARTColoursFloat[cubeFg]] vertices += [*ENNToolMiRCARTColoursFloat[cubeBg]] vertices += [curPos[0], curPos[1] - cubeSize[1], curPos[2]] vertices += artCell[6:8] vertices += ENNToolMiRCARTColoursFloat[cubeFg] vertices += ENNToolMiRCARTColoursFloat[cubeBg] curPos[0], numVertices = curPos[0] + cubeSize[0], numVertices + 4 curPos[0], curPos[1] = 0, curPos[1] - cubeSize[1] artVbo = glGenBuffers(1) glBindBuffer(GL_ARRAY_BUFFER, artVbo) glBufferData(GL_ARRAY_BUFFER, (ctypes.c_float*len(vertices))(*vertices), GL_STATIC_DRAW) return artVbo, len(vertices), -curPos[1], numVertices # }}} # {{{ __init__(self, parentCanvas, size): initialisation method def __init__(self, parentCanvas, size): super().__init__(parentCanvas, size=size) self.curSize = list(size) self.parentCanvas = parentCanvas # }}} class ENNToolGLPanel(wx.Panel): """XXX""" # {{{ onPaint(self, event): XXX def onPaint(self, event): eventDc = wx.PaintDC(self) eventUpdates = wx.RegionIterator(self.GetUpdateRegion()) paintFlag = True if eventUpdates.HaveRects() else False if self.frameFun != None: self.frameFun() # }}} # {{{ onTimer(self, event): XXX def onTimer(self, event): if self.frameFun != None: if not self.frameFun(): event.GetTimer().Stop() event.GetTimer().Destroy() # }}} # {{{ __init__(self, parent, size, defaultPos=(24,24), parentFrame=None): initialisation method def __init__(self, parent, size, defaultPos=(24,24), parentFrame=None): super().__init__(parent, pos=defaultPos, size=size) self.curPos = list(defaultPos); self.curSize = list(size); self.Bind(wx.EVT_PAINT, self.onPaint) self.frameFun = None self.timerTimer = wx.Timer(self, 1) self.timerTimer.Start(40) self.Bind(wx.EVT_TIMER, self.onTimer, self.timerTimer) # }}} # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120