Esempio n. 1
0
    def reset(self):
        self.doReset = False

        self.width = self.size().width()
        self.height = self.size().height()

        #* Because I'm reeeeeally lazy
        self.s = self.width, self.height

        self.focusLoc = GLPoint(-1, -1, self.width, self.height)
        self.mouseLoc = TLPoint(0, 0, self.width, self.height)

        # debug(self.geometry(), color=2)

        # Vertex Buffered
        self.dots = genDotArrayPoints((self.width, self.height),
                                      self.dotSpread)
        #    startPoint=Pointi(-self.width / 2, -self.height / 2))
        self.centerPoint = TLPoint(
            min(self.dots,
                key=lambda p: dist(p, Pointf(self.width / 2, self.height / 2))
                ), None, self.width, self.height)

        # TLPoint(self.dots[0], None, self.width, self.height)
        # debug(self.centerPoint)

        # Not Vertex Buffered
        self.metaLines = []
        self.bounds = set()
        self.currentLine = None
        # An ordered list of Lines or tuples of Lines that hold the last lines to be added/removed
        #   Previously deleted and not drawn lines are included in this.
        #   Should have a limiter to stop it from getting too big.
        self.undoBuffer = []

        self.specificEraseBuffer = None

        # self.lineVboIndex = 0

        for line in self.lines:
            if line.label:
                line.label.hide()
                line.label = None

        self.currentDrawColor = (0, 0, 0)

        self.initializeGL()

        # self.resetLineVbo()

        self.update()
Esempio n. 2
0
    def initializeGL(self):
        # super().initializeGL()
        # glClearColor(*clampColor(*self.backgroundColor), 1)
        # self.initializeOpenGLFunctions()

        # self.context = QOpenGLContext(self)
        # assert self.context.create()
        # assert self.conte ().create() # QOpenGLContext(self)
        # debug(self.context().format())

        # npDots = np.array([np.array(i.start, i.end) for i in self.dots], dtype=np.float32)
        # self.dotCount = npDots.shape[0]
        # create a VBO, data is a Nx2 Numpy array
        # self.dotVbo = VBO(npDots)

        self.adjDots = [
            TLPoint(i, None, self.width, self.height).asGL().data()
            for i in genDotArrayPoints((self.width,
                                        self.height), self.dotSpread)
        ]
        # debug(self.adjDots)

        self.dotVbo = VBO(np.asarray(self.adjDots, dtype=np.float32))
        # self.lineVbo = VBO(np.array(self.lines, np.float32), size=16384)

        # s = self.width, self.height
        # self.lines = [Line(0, TLPoint(20, 20, *s), TLPoint(30, 35, *s), (0, 0, 255)),
        #               Line(0, TLPoint(30, 20, *s), TLPoint(30, 55, *s), (0, 255, 0)),
        #               Line(0, TLPoint(80, 50, *s), TLPoint(30, 35, *s), (255, 0, 0))]
        # lineData = ()
        # for i in self.lines:
        #     lineData += i.start.asGL(self.width, self.height).data() + i.end.asGL(self.width, self.height).data()

        self.lineVbo = VBO(np.asarray([], np.float32))
        self.colorVbo = VBO(np.asarray([], np.float32))
Esempio n. 3
0
class Paper(QOpenGLWidget):
    #* Static Settings
    # offscreenAmount = 0
    dotSpread = 16
    dotSize = 1
    focusRadius = 0.015
    dragDelay = 7
    exportThickness = 2
    aaSamples = 4

    background = (200, 160, 100, 255)
    # background = '/home/marvin/Media/Pictures/quiched my room meme.png'
    # background = Qt.transparent
    dotColor = (0, 0, 0, 255)
    focusColor = (0, 0, 255, 255)
    boundsColor = (30, 30, 30, 255)
    boundsLineColor = mirrorLineColor = (32, 45, 57, 255)
    # currentLineColor = (150, 44, 44)

    dotSpreadMeasure = 1
    dotSpreadUnit = 'dots'

    includeHalfsies = True
    overlap = (0, 0)

    rowSkip = 1
    rowSkipAmount = 0
    columnSkip = 1
    columnSkipAmount = 0

    flipRow = 1
    flipRowOrientation = 'Vertically'
    flipColumn = 1
    flipColumnOrientation = 'Vertically'

    savePath = "~/.GeoDoodle/saves/"
    exportPath = "~/.GeoDoodle/images/"
    loadDir = savePath

    mirroringStates = (0, 1, 2, 4)  # 1 is horizontal line only

    # _image = None

    #* Init functions
    def __init__(self, parent=None):
        super(Paper, self).__init__(parent)
        # QOpenGLFunctions_4_1_Core.__init__(self)

        # self.reset(width, height)
        self.doReset = True

        # mouseLoc is the 'normal' location of the cursor, focusLoc is the openGL location of the adjusted cursor.
        self.focusLoc = None  # GLPoint(self.width, self.height-1, -1)
        self.mouseLoc = None  # TLPoint(0, 0)

        self.dragButtons = [False] * 32

        self.lines = []
        self.lineColors = []

        self.setMouseTracking(True)
        self.installEventFilter(self)

        # self.setMinimumSize(100, 100)
        # self.getSize = lambda: (self.window().width(), self.window().height())

        # self.startingPoint = Pointi(self.width / 2, self.height / 2)
        # self.qp = QPainter()

        self.showLen = False

        self.lineVboIndex = 0

        # self.qp.pen().setWidth(1)

        # self.qp.font().setFamily('Times')
        # self.qp.font().setBold(False)
        # self.qp.font().setPointSize(40)

        # self.setStyleSheet("background-color: rgba(0,0,0,0)")
        # self.setWindowFlags(Qt.FramelessWindowHint)
        # self.setAttribute(Qt.WA_NoSystemBackground)
        # self.setAttribute(Qt.WA_TranslucentBackground)
        # self.setAttribute(Qt.WA_TransparentForMouseEvents)

        fmt = QSurfaceFormat()
        fmt.setSamples(self.aaSamples)
        # # fmt.setStereo(True)
        # fmt.setRenderableType(QSurfaceFormat.OpenGLES)
        # # fmt.setAlphaBufferSize(0)
        self.setFormat(fmt)

    def reset(self):
        self.doReset = False

        self.width = self.size().width()
        self.height = self.size().height()

        #* Because I'm reeeeeally lazy
        self.s = self.width, self.height

        self.focusLoc = GLPoint(-1, -1, self.width, self.height)
        self.mouseLoc = TLPoint(0, 0, self.width, self.height)

        # debug(self.geometry(), color=2)

        # Vertex Buffered
        self.dots = genDotArrayPoints((self.width, self.height),
                                      self.dotSpread)
        #    startPoint=Pointi(-self.width / 2, -self.height / 2))
        self.centerPoint = TLPoint(
            min(self.dots,
                key=lambda p: dist(p, Pointf(self.width / 2, self.height / 2))
                ), None, self.width, self.height)

        # TLPoint(self.dots[0], None, self.width, self.height)
        # debug(self.centerPoint)

        # Not Vertex Buffered
        self.metaLines = []
        self.bounds = set()
        self.currentLine = None
        # An ordered list of Lines or tuples of Lines that hold the last lines to be added/removed
        #   Previously deleted and not drawn lines are included in this.
        #   Should have a limiter to stop it from getting too big.
        self.undoBuffer = []

        self.specificEraseBuffer = None

        # self.lineVboIndex = 0

        for line in self.lines:
            if line.label:
                line.label.hide()
                line.label = None

        self.currentDrawColor = (0, 0, 0)

        self.initializeGL()

        # self.resetLineVbo()

        self.update()

        # self.boundsMode = False

    def initializeGL(self):
        # super().initializeGL()
        # glClearColor(*clampColor(*self.backgroundColor), 1)
        # self.initializeOpenGLFunctions()

        # self.context = QOpenGLContext(self)
        # assert self.context.create()
        # assert self.conte ().create() # QOpenGLContext(self)
        # debug(self.context().format())

        # npDots = np.array([np.array(i.start, i.end) for i in self.dots], dtype=np.float32)
        # self.dotCount = npDots.shape[0]
        # create a VBO, data is a Nx2 Numpy array
        # self.dotVbo = VBO(npDots)

        self.adjDots = [
            TLPoint(i, None, self.width, self.height).asGL().data()
            for i in genDotArrayPoints((self.width,
                                        self.height), self.dotSpread)
        ]
        # debug(self.adjDots)

        self.dotVbo = VBO(np.asarray(self.adjDots, dtype=np.float32))
        # self.lineVbo = VBO(np.array(self.lines, np.float32), size=16384)

        # s = self.width, self.height
        # self.lines = [Line(0, TLPoint(20, 20, *s), TLPoint(30, 35, *s), (0, 0, 255)),
        #               Line(0, TLPoint(30, 20, *s), TLPoint(30, 55, *s), (0, 255, 0)),
        #               Line(0, TLPoint(80, 50, *s), TLPoint(30, 35, *s), (255, 0, 0))]
        # lineData = ()
        # for i in self.lines:
        #     lineData += i.start.asGL(self.width, self.height).data() + i.end.asGL(self.width, self.height).data()

        self.lineVbo = VBO(np.asarray([], np.float32))
        self.colorVbo = VBO(np.asarray([], np.float32))
        # GLPoint(-1, -1, *s).data() * 600

        # debug(self.lineVbo.data)

        # self.lineVbo.bind()

        # newData = TLPoint(34, 511, *s).asGL().data() + \
        #           TLPoint(73, 471, *s).asGL().data() + \
        #           TLPoint(769, 513, *s).asGL().data() + \
        #           TLPoint(714, 472, *s).asGL().data()

        # glEnableClientState(GL_VERTEX_ARRAY)

        # #* BufferSubData
        # # glBufferSubData(GL_ARRAY_BUFFER, 12, 8 * 32, newData)

        # #* MapBuffer
        # # data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE)
        # # debug(pointer(data))
        # # debug(data)

        # #* BufferData
        # glBufferData(GL_ARRAY_BUFFER, np.asarray(lineData + newData, np.float32), GL_DYNAMIC_DRAW)

        # self.lines.append(Line(0, TLPoint(25, 275, *s), TLPoint(775, 275, *s), (0, 255, 0)))
        # self.lines.append(Line(0, TLPoint(25, 295, *s), TLPoint(775, 295, *s), (0, 255, 0)))

        # debug(self.lineVbo.data)

        # point = None
        # pointer = glGetBufferPointerv(GL_ARRAY_BUFFER, GL_BUFFER_MAP_POINTER, point)

        # debug(pointer)

        # self.lineVbo = None
        # self.lineVbo = QOpenGLBuffer()
        # assert self.lineVbo.create()
        # self.lineVbo.setUsagePattern(QOpenGLBuffer.DynamicDraw)
        # self.lineVbo.allocate(2048 ** 8)

        # self.lineVbo = VBO(np.asarray(self.lines, dtype=np.float32))
        # self.lineColorVbo = VBO(np.asarray(self.lineColors, dtype=np.float32))

        # glShadeModel(GL_SMOOTH)
        # glMatrixMode(GL_PROJECTION)
        # glLoadIdentity()
        # gluPerspective(45, -1.33, 1, 1)
        # glMatrixMode(GL_MODELVIEW)

#* Update Functions

    def updateFocus(self):
        self.focusLoc = GLPoint(
            min(self.adjDots,
                key=lambda p: abs(p[0] - self.mouseLoc.asGL().x))[0],
            min(self.adjDots,
                key=lambda p: abs(p[1] - self.mouseLoc.asGL().y))[1],
            self.width, self.height)

    def updateMouse(self, event):
        self.mouseLoc = TLPoint(event.pos(), None, self.width, self.height)
        self.updateFocus()
        if self.currentLine:
            self.currentLine.end = self.focusLoc

#* Event Functions

    def eventFilter(self, target, event):
        #* For some reason, this is the first point after initialization that the width/height are correct
        if self.doReset and self.size().width() != 100 and self.size().height(
        ) != 30:
            debug(showFunc=True)
            self.reset()

        if target == self:
            if event.type() in (QEvent.MouseMove, QEvent.DragMove,
                                QEvent.HoverMove):
                self.updateMouse(event)
                self.dragButtons[int(event.buttons())] = True
                self.update()

            if event.type() == QEvent.MouseButtonPress:
                if int(event.buttons()) == Qt.LeftButton:
                    self.createLine()

                elif int(event.buttons()) == Qt.RightButton:
                    self.createLine(True)

                elif int(event.buttons()) == Qt.MiddleButton:
                    self.deleteLine()
                    debug(self.mouseLoc, color=2)

            if event.type() == QEvent.MouseButtonRelease:
                if self.dragButtons[int(event.button())]:
                    self.dragButtons[int(event.button())] = False
                    if event.button() & (Qt.RightButton | Qt.LeftButton):
                        self.createLine(
                            linkAnother=int(event.button()) == Qt.RightButton)

            if event.type() == QEvent.MouseButtonDblClick:
                if int(event.buttons()) == Qt.LeftButton:
                    self.createLine(True)

                elif int(event.buttons()) == Qt.RightButton:
                    self.createLine(True)
        return super().eventFilter(target, event)

    def keyPressed(self, event):
        if event.key() == Qt.Key_Up or event.key() == Qt.Key_W:
            self.moveY(-1)

        elif event.key() == Qt.Key_Down or event.key() == Qt.Key_S:
            self.moveY(1)

        elif event.key() == Qt.Key_Left or event.key() == Qt.Key_A:
            self.moveX(-1)

        elif event.key() == Qt.Key_Right or event.key() == Qt.Key_D:
            self.moveX(1)

        elif event.key() == Qt.Key_Space:
            self.createLine()
            # self.update()

        elif event.key() == Qt.Key_C:
            self.createLine(True)
            # self.update()

        elif event.key() == Qt.Key_B:
            self.update()

        elif event.key() == Qt.Key_Q:
            self.deleteLine()

        else:
            event.ignore()
            return

        event.accept()

        # if event.key == 264 or event.key == pygame.K_HOME: # numpad up
        #     DOTSPREAD += 1
        #     self.dots = genDotArrayPoints((self.width, self.height), OFFSCREEN_AMOUNT, DOTSPREAD)
        # if event.key == 258 or event.key == pygame.K_END: # numpad down
        #     DOTSPREAD -= 1
        # self.dots = genDotArrayPoints((self.width, self.height), OFFSCREEN_AMOUNT, DOTSPREAD)

    def specificErase(self):
        todo('specificErase')
        # If there's nothing there, don't do anything
        if self.focusLoc in [i.end for i in self.lines
                             ] + [i.start for i in self.lines]:
            if self.specificEraseBuffer == None:
                self.specificEraseBuffer = self.focusLoc
            else:
                assert (type(self.specificEraseBuffer) == Pointi)
                for index, i in enumerate(self.lines):
                    if (i.start == self.focusLoc and i.end == self.specificEraseBuffer) or \
                    (i.start == self.specificEraseBuffer and i.end == self.focusLoc):
                        del self.lines[index]
                self.specificEraseBuffer = None
        else:
            self.specificEraseBuffer = None

    def fileDropped(self, event):
        with open(event.file, 'r') as f:
            self.lines = pickle.load(f)

    def moveX(self, dots):
        # I would think you should divide this by self.width instead, but that doesn't seem to work
        self.focusLoc.x += (self.dotSpread / (self.width / 2)) * dots
        if self.currentLine is not None:
            self.currentLine.end = self.focusLoc
            #* If the cursor is inside the window, move the cursor as well,
            #   That way, when you move it again, it goes from where it shows it is
        if self.window().rect().contains(toQPoint(self.focusLoc.asTL()),
                                         proper=True):
            self.cursor().setPos(
                self.mapToGlobal(toQPoint(self.focusLoc.asTL())))
        self.update()

    def moveY(self, dots):
        self.focusLoc.y += (self.dotSpread / (self.height / 2)) * dots
        if self.currentLine is not None:
            self.currentLine.end = self.focusLoc
            #* If the cursor is inside the window, move the cursor as well,
            #   That way, when you move it again, it goes from where it shows it is
        if self.window().rect().contains(toQPoint(self.focusLoc.asTL()),
                                         proper=True):
            self.cursor().setPos(
                self.mapToGlobal(toQPoint(self.focusLoc.asTL())))
        self.update()

#* Draw Functions

    def paintGL(self):
        if self.doReset:  # and not (self.size().width() == 100 and self.size().width() == 30):
            debug(showFunc=True)
            self.reset()
        # debug(self.size(), name='paper size', color=3)
        # Reset the background color
        # glClear(GL_COLOR_BUFFER_BIT)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        # debug(self.lines, showFile=True)

        # debug(self.focusLoc, self.lines, self.dots)
        self.drawBackground()
        self.drawDots()
        self.drawBounds()
        self.drawLines()
        self.drawCurrentLine()
        self.drawFocus()

        # glColor(*clampColor(self.boundsColor))
        # self.drawCircle(self.centerPoint.asGL(), self.focusRadius)

        #* Resets the current matrix
        # glLoadIdentity()
        glFlush()

    def paintEvent(self, event):

        # self.drawBackground()

        for line in self.lines:
            if self.showLen:
                line.createLabel(self, self.dotSpread, self.dotSpreadMeasure,
                                 self.dotSpreadUnit, self.background).show()
            elif line.label:
                line.label.hide()

        return super().paintEvent(event)

    def drawBackground(self):
        # self.qp.begin(self)
        # self.qp.setPen(QColor(255, 0, 0, 255))

        # self.qp.drawEllipse(*self.centerPoint.asTL().data(), 6, 6)
        # debug(self.background)
        if type(self.background) is tuple:
            # self.qp.fillRect(0, 0, self.width, self.height, QColor(*self.background))
            # return
            glColor(*clampColor(*self.background))
            glBegin(GL_QUADS)
            glVertex2f(1, 1)
            glVertex2f(1, -1)
            glVertex2f(-1, -1)
            glVertex2f(-1, 1)
            glEnd()

        elif type(self.background) is str:
            # if not self._image:
            # self._image = QLabel(self)
            # self._image.setPixmap(QPixmap(self.background))
            # self._image.setPixmap(QPixmap(QColor(255, 255, 255, 0)))
            # pixmap = QPixmap(self.background) #, 'Format_ARGB32_Premultiplied')
            image = QImage(
                self.background).mirrored()  #, 'Format_ARGB32_Premultiplied')
            texture = QOpenGLTexture(image)
            texture.bind()
            glDrawArrays(GL_TRIANGLE_FAN, 0, 4)

            # texture.bind()
            # for k, v in kwparams.items():
            # gl.glTexParameteri(gl.GL_TEXTURE_2D, getattr(gl, k), v)
            # texture.release()

            # qp = QPainter(pixmap)
            # qp.fillRect(pixmap.rect(), QColor(0, 0, 0, 150))
            # qp.end()
            # pixmap.transformed(QTransform())
            # self.window()._image.setPixmap(pixmap)

            # else:
            #     self._image.show()

            # self.imageimage = QImage(self.background)

            # QPainter painter(this)
            # self.qp.drawPixmap(0, 0, pixmap)

        elif type(self.background) is QGradient:
            todo('Drawing QGradient')

        elif type(self.background) is QImage:
            self.qp.drawImage(0, 0, self.background)

        # self.qp.end()

    def drawLines(self):
        # glColor(*clampColor(self.dotColor))
        # # Bind the VBO

        # lineData = ()
        # for i in self.lines:
        #     lineData += i.start.asGL(self.width, self.height).data() + i.end.asGL(self.width, self.height).data()
        # # lineData = np.asarray([i.data(self.width, self.height) for i in self.lines])
        # debug(lineData)
        # # self.lineVbo.set_array(lineData)
        # # self.lineVbo.bind()
        # # # tell OpenGL that the VBO contains an array of vertices
        # glEnableClientState(GL_VERTEX_ARRAY)
        # # # these vertices contain 2 single precision coordinates

        # # glVertexPointer(2, GL_FLOAT, 0, self.lineVbo)
        # glVertexPointer(2, GL_FLOAT, 0, np.asarray(lineData, np.float32))
        # # # draw "count" points from the VBO
        # glDrawArrays(GL_LINES, 0, len(self.lines) * 2)

        # glColor(*clampColor(self.dotColor))
        # bind the VBO
        self.lineVbo.bind()
        # self.colorVbo.bind()
        # tell OpenGL that the VBO contains an array of vertices
        glEnableClientState(GL_VERTEX_ARRAY)
        # glEnableClientState(GL_COLOR_ARRAY)
        # these vertices contain 2 single precision coordinates
        glVertexPointer(2, GL_FLOAT, 0, self.lineVbo)
        # glColorPointer(4, GL_FLOAT, 0, self.colorVbo)
        # glVertexPointer(2, GL_FLOAT, 2, self.lineVbo + 2)
        # draw "count" points from the VBO
        glDrawArrays(GL_LINES, 0, len(self.lines) * 2)

        # glBegin(GL_LINES)

        # for line in self.lines:
        #     line.draw(self.width, self.height)

        # glEnd()

        # glDrawArrays(GL_LINES, 0, len(self.lines) * 2)

    def drawCurrentLine(self):
        if self.currentLine is not None:
            glBegin(GL_LINES)
            # glColor(*clampColor(self.currentLineColor))
            glColor(*clampColor(self.currentDrawColor))
            glVertex(*self.currentLine.start.asGL().data())
            glVertex(*self.focusLoc.asGL().data())
            glEnd()

    def drawDots(self):
        glColor(*clampColor(self.dotColor))
        # bind the VBO
        self.dotVbo.bind()
        # tell OpenGL that the VBO contains an array of vertices
        glEnableClientState(GL_VERTEX_ARRAY)
        # these vertices contain 2 single precision coordinates
        glVertexPointer(2, GL_FLOAT, 0, self.dotVbo)
        # draw "count" points from the VBO
        glDrawArrays(GL_POINTS, 0, len(self.dots))

    def drawCircle(self, center, radius, filled=False, vertexCount=10):
        #* Create a buffer for vertex data
        # buffer = [] # = new float[vertexCount*2] # (x,y) for each vertex
        # buffer = np.array([0]*vertexCount*2, np.float32)
        glBegin(GL_LINE_LOOP)
        #* Center vertex for triangle fan
        # buffer.append(center.x)
        # buffer.append(center.y)

        #* Outer vertices of the circle
        outerVertexCount = vertexCount - 1

        for i in range(outerVertexCount):
            percent = i / (outerVertexCount - 1)
            rad = percent * 2 * math.pi

            #* Vertex position
            outer_x = center.x + radius * math.cos(rad)
            outer_y = center.y + radius * math.sin(rad) * 1.5

            glVertex(outer_x, outer_y)

        glEnd()

        #     buffer.append(outer_x)
        #     buffer.append(outer_y)

        # #* Create VBO from buffer with glBufferData()
        # if filled:
        #     glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount)
        # else:
        #     glDrawArrays(GL_LINE_LOOP, 2, debugged(outerVertexCount))

    def drawFocus(self):
        # self.qp.setPen(QColor(*self.focusColor))
        # self.qp.drawEllipse(*(self.focusLoc-6).datai(), self.focusRadius, self.focusRadius)

        glBegin(GL_LINES)

        glColor(*clampColor(self.focusColor))

        glVertex(self.focusLoc.x - self.focusRadius, self.focusLoc.y)
        glVertex(self.focusLoc.x + self.focusRadius, self.focusLoc.y)
        # I'm not sure why this direction is shorter than the other.
        glVertex(self.focusLoc.x, self.focusLoc.y - self.focusRadius * 1.5)
        glVertex(self.focusLoc.x, self.focusLoc.y + self.focusRadius * 1.5)

        # for offset in ((-2, -2), (2, 2), (-2, 2), (2, -2)):
        #     self.drawPoint(self.focusLoc + offset)

        glEnd()
        # self.drawCircle(self.focusLoc, self.focusRadius)

    def drawBounds(self):
        # Just for optimization's sake
        if len(self.bounds):
            glColor(*clampColor(self.boundsColor))
            for i in self.bounds:
                self.drawCircle(i, self.focusRadius * .75)

            if len(self.bounds) >= 2:
                glColor(*clampColor(self.boundsLineColor))
                # glBegin(GL_QUADS)
                glBegin(GL_LINE_LOOP)
                bounds = getLargestRect(self.bounds)
                glVertex(*Pointf(bounds.topLeft()).dataf())
                glVertex(*Pointf(bounds.topRight()).dataf())
                glVertex(*Pointf(bounds.bottomRight()).dataf())
                glVertex(*Pointf(bounds.bottomLeft()).dataf())
                glEnd()

    def drawMirroring(self):
        todo('mirroring')
        #* Add mirroring
        for i in self.lineBuffer:
            #* Check if there's already a line there (so it doesn't get bolder (because of anti-aliasing))
            dontDraw = False
            for k in self.lines:
                if i == k or (i.start == k.end and i.end == k.start):
                    dontDraw = True

            #* Check if the start and end are the same (no line would be drawn)
            if i.start != i.end and not dontDraw:
                self.lines.append(i)

            if self.mirroringStates[self.currentMirrorState] in [1, 4]:
                starty = self.startingPoint.y + (self.startingPoint.y -
                                                 i.start.y) + 2
                endy = self.startingPoint.y + (self.startingPoint.y -
                                               i.end.y) + 2
                vertStart = Pointi(i.start.x, starty)
                vertEnd = Pointi(i.end.x, endy)
                self.lines.append(Line(vertStart, vertEnd, i.color))

            if self.mirroringStates[self.currentMirrorState] >= 2:
                # self.startingPoint = Point(min(self.dots, key=lambda i:abs(i.x - (self.width / 2))).x + 1, min(self.dots, key=lambda i:abs(i.y - (self.height / 2))).y + 1)

                startx = self.startingPoint.x + (self.startingPoint.x -
                                                 i.start.x) + 2
                endx = self.startingPoint.x + (self.startingPoint.x -
                                               i.end.x) + 2
                horStart = Pointi(startx, i.start.y)
                horEnd = Pointi(endx, i.end.y)
                self.lines.append(Line(horStart, horEnd, i.color))

                if self.mirroringStates[self.currentMirrorState] >= 4:
                    corStart = Pointi(startx, starty)
                    corEnd = Pointi(endx, endy)
                    self.lines.append(Line(corStart, corEnd, i.color))

        self.lineBuffer = []

        #* Add mirrored current line
        if self.currentLine is not None and self.mirroringStates[
                self.currentMirrorState] in [1, 4]:
            curStarty = self.startingPoint.y + (self.startingPoint.y -
                                                self.currentLine.start.y) + 2
            curEndy = self.startingPoint.y + (self.startingPoint.y -
                                              self.currentLine.end.y) + 2
            Line(Pointi(self.currentLine.start.x, curStarty),
                 Pointi(self.currentLine.end.x, curEndy),
                 self.currentLine.color).draw(self.mainSurface)

        if self.currentLine is not None and self.mirroringStates[
                self.currentMirrorState] >= 2:
            curStartx = self.startingPoint.x + (self.startingPoint.x -
                                                self.currentLine.start.x) + 2
            curEndx = self.startingPoint.x + (self.startingPoint.x -
                                              self.currentLine.end.x) + 2
            Line(Pointi(curStartx, self.currentLine.start.y),
                 Pointi(curEndx, self.currentLine.end.y),
                 self.currentLine.color).draw(self.mainSurface)

            if self.currentLine is not None and self.mirroringStates[
                    self.currentMirrorState] >= 4:
                Line(Pointi(curStartx, curStarty), Pointi(curEndx, curEndy),
                     self.currentLine.color).draw(self.mainSurface)

    def resetLineVbo(self):
        lineData = ()
        for i in self.lines:
            lineData += i.data(self.width, self.height)

        self.lineVbo.bind()

        glEnableClientState(GL_VERTEX_ARRAY)

        #* BufferSubData
        # glBufferSubData(GL_ARRAY_BUFFER, 12, 8 * 32, newData)

        #* MapBuffer
        # data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE)
        # debug(pointer(data))
        # debug(data)

        #* BufferData
        glBufferData(GL_ARRAY_BUFFER, np.asarray(lineData, np.float32),
                     GL_DYNAMIC_DRAW)

#* File Functions

    def save(self):
        file = self.getFile(True)
        if len(file):
            with open(file, 'wb') as f:
                pickle.dump(self.lines, f)
            print('File Saved!')

    def saveAs(self):
        todo('saveAs')

    def open(self):
        file = self.getFile(False)
        if len(file):
            with open(file, 'rb') as f:
                self.lines = pickle.load(f)

    def export(self):
        image = Image.new('RGB', (self.width, self.height),
                          color=tuple(self.background))
        draw = ImageDraw.Draw(image)
        for line in self.lines:
            draw.line(line.start.data() + line.end.data(),
                      fill=tuple(line.color),
                      width=self.exportLineThickness)

        image.save(self.getFile(True))
        print('File Saved!')

    def new_(self):
        todo('_new')

    def getFile(self, save: bool):
        return QFileDialog.getSaveFileName(
        )[0] if save else QFileDialog.getOpenFileName()[0]

#* Repeat Functions

    def repeatPattern(self, pattern):
        self.lines = pattern.repeat(
            (Sizei(*self.s) / self.dotSpread) + 1,
            self.centerPoint,
            #  self.dotSpread / (self.height / 2),
            self.dotSpread,
            #  self.dots[0] % self.dotSpread,
            self.overlap,
            self.rowSkip,
            self.rowSkipAmount,
            self.columnSkip,
            self.columnSkipAmount,
            self.flipRow,
            self.flipRowOrientation,
            self.flipColumn,
            self.flipColumnOrientation,
            self.includeHalfsies)

        #* This does help, but not enough to make it worth it, I think
        # debug(self.lines)
        # for i, line in enumerate(self.lines):
        #     for point in (line.start, line.end):
        #         delete = False
        #         if not collidePoint(Pointf(-1, -1), (2, 2), point.asGL(*self.s)):
        #             delete = True
        #     if delete:
        #         del self.lines[i]
        # debug(self.lines)

        self.resetLineVbo()
        self.bounds = set()

    def getLinesWithinRect(self, bounds: QRectF):
        lines = []
        halfLines = []

        # debug(self.lines, color=3, showFile=True)

        for l in self.lines:
            #* You suck
            if bounds.contains(*l.start.asTL(
                    *self.s).data()) and bounds.contains(*l.end.asTL(
                        *self.s).data()):
                # if collidePoint(Pointf(bounds.topLeft()), (bounds.width(), bounds.height()), l.start) and \
                #    collidePoint(Pointf(bounds.topLeft()), (bounds.width(), bounds.height()), l.end):
                lines.append(l)
            elif bounds.contains(*l.start.asTL(
                    *self.s).data()) or bounds.contains(*l.end.asTL(
                        *self.s).data()):
                halfLines.append(l)

        return lines, halfLines

    def getPattern(self):
        if len(self.bounds) < 2:
            raise UserWarning('I\'m sorry Dave, but I can\'t do that.')

        bounds = getLargestRect([b.asTL(*self.s) for b in self.bounds])
        # return debugged(Pattern(self.getLinesWithinRect(bounds), self.getHalfLinesWithinRect(bounds), self.dotSpread / (self.height / 2), bounds))
        return Pattern(*self.getLinesWithinRect(bounds), self.dotSpread,
                       self.centerPoint, bounds)

#* Other Functions

    def createLine(self, linkAnother=False):
        if self.currentLine is None:
            self.currentLine = Line(self.lineVboIndex,
                                    deepcopy(self.focusLoc),
                                    color=self.currentDrawColor)
            self.lineVboIndex += Line.vboSize
        else:
            if self.currentLine.start == self.focusLoc:
                self.currentLine = None
            else:
                self.currentLine.finish(self.focusLoc.copy(), self.width,
                                        self.height, self.lineVbo,
                                        self.colorVbo, self.lines)
                self.lines.append(self.currentLine)
                self.currentLine = Line(
                    self.lineVboIndex,
                    deepcopy(self.focusLoc),
                    color=self.currentDrawColor) if linkAnother else None
                self.lineVboIndex += Line.vboSize

    def deleteLine(self, at=None):
        todo('optimize deleteLine with glBufferSubData()')

        if at is None:
            at = self.focusLoc.asGL(*self.s)

        #* If there's a bound there, don't delete all the lines under it as well
        removedBound = False

        # You can't change the size of a set while iterating through it for some reason
        #   Hence, copy().
        for i in self.bounds.copy():
            if i == at:
                self.bounds.remove(i)
                removedBound = True

        if not removedBound:
            #* This should not be nessicarry, I have no idea why the 3 lines don't work by themselves.
            linesStillAtFocus = True
            while linesStillAtFocus:
                linesStillAtFocus = False

                for i in self.lines:
                    if i.start == at or i.end == at:
                        self.lines.remove(i)

                for i in self.lines:
                    if i.start == at or i.end == at:
                        linesStillAtFocus = True

        self.currentLine = None

        self.resetLineVbo()
        self.update()

    def resizeGL(self, width, height):
        """Called upon window resizing: reinitialize the viewport.
        """
        # update the window size
        # self.width, self.height = width, height
        # paint within the whole window
        glViewport(0, 0, width, height)
        # set orthographic projection (2D only)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        # the window corner OpenGL coordinates are (-+1, -+1)
        glOrtho(-1, 1, 1, -1, -1, 1)

        # side = min(width, height)
        # glViewport((width - side) / 2, (height - side) / 2, side, side)

    def mirror(self):
        self.metaLines = []

        self.currentMirrorState += 1
        if self.currentMirrorState >= len(self.mirroringStates):
            self.currentMirrorState = 0

        # print(self.mirroringStates[self.currentMirrorState])

        if self.mirroringStates[self.currentMirrorState] in [1, 4]:
            starth = Pointi(-self.offScreenAmount, self.startingPoint.y)
            endh = Pointi(self.width + self.offScreenAmount,
                          self.startingPoint.y)
            self.metaLines.append(Line(starth, endh, MIRROR_LINE_COLOR))

        if self.mirroringStates[self.currentMirrorState] >= 2:
            startv = Pointi(self.startingPoint.x, -self.offScreenAmount)
            endv = Pointi(self.startingPoint.x,
                          self.height + self.offScreenAmount)
            self.metaLines.append(Line(startv, endv, MIRROR_LINE_COLOR))

    def toggleBoundsMode(self):
        # todo('toggleBoundsMode')
        # self.boundsMode = not self.boundsMode
        self.addBound()

    def undo(self):
        todo('undo')
        if self.currentLine == None and len(self.lines) > 0:
            del self.lines[-1]
            if self.mirroringStates[self.currentMirrorState] >= 2 and len(
                    self.lines) > 0:
                self.lines.pop()
                if self.mirroringStates[self.currentMirrorState] >= 4 and len(
                        self.lines) > 0:
                    self.lines.pop()
                    if len(self.lines) > 1:
                        self.lines.pop()
        elif self.currentLine != None:
            self.currentLine = None

    def redo(self):
        todo('redo')

    def clearAll(self):
        self.lines = []
        self.bounds = set()
        self.currentLine = None
        self.metaLines = []

    def addBound(self):
        self.bounds.add(self.focusLoc.copy())
        self.update()

    def updateSettings(self, settings):
        # keyRepeatDelay
        # keyIntervalDealy

        # shortcutBox
        # shortcutSelect
        # setShortcut

        self.dotSpread = settings.dotSpread.value()
        self.dotSpreadMeasure = settings.dotSpreadMeasure.value()
        self.dotSpreadUnit = settings.dotSpreadUnit.text()

        self.background = settings.backgroundColor.getColor()
        self.dotColor = settings.dotColor.getColor()
        self.focusColor = settings.focusColor.getColor()

        self.exportThickness = settings.exportThickness.value()
        self.savePath = settings.savePath.text()
        self.exportPath = settings.exportPath.text()

        self.doReset = True
        # glClearColor(*clampColor(*self.backgroundColor), 1)
        # debug(glGetFloatv(GL_COLOR_CLEAR_VALUE), name='background color', color=2)
        self.update()

    def setCurrentDrawColor(self, color):
        self.currentDrawColor = color

    def setShowLen(self, val):
        self.showLen = val
        self.update()

    def exit(self):
        self.close()
Esempio n. 4
0
 def updateMouse(self, event):
     self.mouseLoc = TLPoint(event.pos(), None, self.width, self.height)
     self.updateFocus()
     if self.currentLine:
         self.currentLine.end = self.focusLoc