예제 #1
0
class Canvas:
    '''Canvas Class'''
    width = int
    height = int
    referenceX = int
    referenceY = int
    windowWidth = int
    windowHeight = int
    

    layers = []
    order = []
    
    name = ""
    filepath = "unnamed.cobra"
    
    def __init__(self, width, height, name, path):
        '''Constructor'''

        #Get size from parent
        self.width = width
        self.height = height

        self.name = name
        self.filepath = path

        self.referenceX = 0
        self.referenceY = 0
        self.windowWidth = 800
        self.windowHeight = 600

        self.curStroke = []
        self.brush = Brush(2,"brush",110)
        self.eraser = Brush(2,"eraser",255)
        self.eraserMode = False
        self.his = History()

        self.pointQueue = deque([])
        self.batch = graphics.Batch()
        self.background = graphics.OrderedGroup(0)
        self.drawingLayer = graphics.OrderedGroup(2)
        self.layer1 = graphics.OrderedGroup(1)
        
        self.canvas = self.batch.add(self.width*self.height,
                                     gl.GL_POINTS, self.background,
                                     ('v2i'), ('c3B'))
        self.swap = self.batch.add(self.width*self.height,
                                     gl.GL_POINTS, self.drawingLayer,
                                     ('v2i'), ('c3B'))
        
        self._buildCanvas(self.canvas)
        self._buildSwap(self.swap)

        self.layers.append(Layer(self.width,self.height,self.batch,self.layer1,0))
        
        self.currentLayer = self.layers[0]
        self.order.append(1)
        
        self.layerAction = Action()
        self.layerAction.layer = self.currentLayer
        self.layerAction.name = self.currentLayer.name
        self.his.addAction(self.layerAction)

    def draw(self):
        '''Updates the canvas, drawing all layers'''
        self.batch.draw()

    def _buildCanvas(self, canvas):
        for x in range(self.width):
            for y in range(self.height):
                '''We have to convert our 2d coordinates into a 1d array index'''
                i = self._2dTo1d(x, y)
                canvas.vertices[i*2:i*2+2] = [x, y]
                canvas.colors[i*3:i*3+3] = [255, 255, 255]
                
    def _buildSwap(self, swap):
        for i in range(self.width*self.height):
            '''We have to convert our 2d coordinates into a 1d array index'''
            swap.vertices[i*2:i*2+2] = [0,0]
            swap.colors[i*3:i*3+3] = [0,0,0]

    def setBrushSize(self, command):
        if(command == 'Increase Brush Size'):
            self._incBrush()
        else:
            self._decBrush()
    def _incBrush(self):
        if(self.brush.size < 10):
            self.brush.size = self.brush.size + 2

    def _decBrush(self):
        if(self.brush.size > 2):
            self.brush.size = self.brush.size - 2

    def setPencil(self):
        self.eraserMode = False

    def setEraser(self):
        self.eraserMode = True

    def addLayer(self):
        self._addLayer()

    def setCurrentLayer(self, index):
        self.currentLayer = self.layers[index]

    def _addLayer(self, name="Untitled Layer"):
        '''Adds a new layer to the canvas, and selects it as the current canvas'''
        newGroup = graphics.OrderedGroup(len(self.layers)+1)
        self.order.append(len(self.layers)+1)
        self.layers.append(Layer(self.width, self.height, self.batch,newGroup,len(self.layers)))
        self.currentLayer = self.layers[len(self.layers)-1]
        #Adds the new layer to history
        self.layerAction = self.currentLayer
        self.layerAction.name = self.currentLayer.name
        self.his.addAction(self.layerAction)

    def setLayer(self, layerIndex, orderValue):
        '''Sets the drawing order of a layer to the selected orderValue (0-Background, 1+Foreground)'''
        newGroup = graphics.OrderedGroup(orderValue)
        self.order[layerIndex] = orderValue
        self.layers[layerIndex].group = newGroup
        self.layers[layerIndex].index = orderValue

    def deleteLayer(self, layerIndex):
        '''Deletes a layer from the canvas'''
        if(layerIndex > 0 and layerIndex < len(self.layers)):
            for layer in self.layers[layerIndex:len(self.layers)]:
                layer.index = layer.index -1            
            self.order.pop(layerIndex)
            self.layers.pop(layerIndex)

    def incrementLayer(self, layerIndex):
        '''Increments a layer's drawing order by swapping it's position in the hierarchy with the one above it, if any'''
        if(layerIndex-1 < len(self.order)):
            oldLayer = self.order[layerIndex-1]
            newLayer = self.order[layerIndex]
            self.setLayer(layerIndex-1, newLayer)
            self.setLayer(layerIndex, oldLayer)

    def decrementLayer(self, layerIndex):
        '''Decrements a layer's drawing order by one'''
        if(layerIndex < len(self.layers) and layerIndex > 0):
            oldLayer = self.order[layerIndex]
            newLayer = self.order[layerIndex-1]
            self.setLayer(layerIndex, newLayer)
            self.setLayer(layerIndex-1, oldLayer)
        
    def addPoint(self, x, y):
        '''Adds a point to the current stroke list and calls drawPoint to draw it on the canvas'''
        if(self.currentLayer.visible):
            self.pointQueue.append((x, y))
            if (len(self.pointQueue) > 2):
                curPoint = self.pointQueue.popleft()
                lineS = self._interpolate(curPoint[0], curPoint[1],
                                          self.pointQueue[0][0],
                                          self.pointQueue[0][1],
                                          self.pointQueue[1][0],
                                          self.pointQueue[1][1])
                for point in lineS:
                    self.curStroke.append(point)
                    self.drawPoint(point[0], point[1])
                self.curStroke.append(curPoint)                
                self.drawPoint(curPoint[0], curPoint[1])

    def endLine(self, x, y):
        '''Saves the end of a stroke to the current layer'''
        if(self.currentLayer.visible):
            while(len(self.pointQueue) > 0):
                curPoint = self.pointQueue.popleft()
                self.drawPoint(curPoint[0], curPoint[1])
                self.curStroke.append(curPoint)
            
            #Add the current stroke to the history and the layer
            newAction = Action()
            newAction.name = 'Stroke'
            finalStroke = Stroke(self.curStroke,255)
            if(not self.eraserMode):
                self.currentLayer.addStroke(finalStroke,self.brush)
            else:
                self.currentLayer.addStroke(finalStroke,self.eraser)
                
            newAction.stroke = finalStroke
            self.his.addAction(newAction)

            #Clear the canvas and the temporary stroke
            self.swap.colors = [255,255,255]*self.width*self.height
            self.swap.vertices = [0,0]*self.width*self.height
            self.curStroke = []

    def drawPoint(self, x, y):
        '''Draws a point directly on the swap canvas'''
        for i in range(0, self.brush.size):
            colorRow = []
            vertRow = []
            for q in range(0, self.brush.size):
                vertRow.append(x+q)
                vertRow.append(y+i)
            if(not self.eraserMode):
                colorRow = [self.brush.shade]* 3 * self.brush.size
                self.swap.vertices[((y+i)*self.width+x)*2:((y+i)*self.width+x)*2+2*self.brush.size] = vertRow
                self.swap.colors[((y+i)*self.width+x)*3:((y+i)*self.width+x)*3+3*self.brush.size] = colorRow
            else:
                colorRow = [self.eraser.shade]* 3 * self.brush.size
                self.swap.vertices[((y+i)*self.width+x)*2:((y+i)*self.width+x)*2+2*self.brush.size] = vertRow
                self.swap.colors[((y+i)*self.width+x)*3:((y+i)*self.width+x)*3+3*self.brush.size] = colorRow
            

                
    def _2dTo1d(self, x, y):
        '''_2dTo1d converts the coordinates for a 2d array to a corresponding
        1d array index'''
        return y*self.width+x

    def _interpolate(self, x0, y0, x1, y1, x2, y2):
        t = 0.0
        pointList = []
        #B(t) = (1-t)^2P0 + 2(1-t)tP1 + t^2P2, t E [0,1]
        while t <= 1.0:
            ty = int(pow((1-t), 2) * y0 + 2*(1-t)*t*y1 + (t*t) * y2)
            tx = int(pow((1-t), 2) * x0 + 2*(1-t)*t*x1 + (t*t) * x2)
            t += .01
            pointList.append((tx, ty))
        return pointList

    def resizeCanvas(self, top, right, bottom, left):
        '''Changes the size of the canvas'''
        width = width + right + left
        height = height + top + bottom

        if(top > 0):
            #If adding space to the top, show the extra space
            referenceY = 0 
        else:
            #otherwise move the screen down to show the extra space on the bottom
            referenceY = referenceY + bottom

        if(left > 0):
            #If adding space to the left, show the extra space
            referenceX = 0
        else:
            #Otherwise move the screen right to show the extra space added
            referenceX = referenceX + right

    def export(self):
        '''Passes an array of [R G B] * Pixels to CobraSketch for storing'''
        out = [255] * (self.height * self.width)
        for layer in self.layers:
            cIndex = 0
            for i in range(0,int(len(layer.canvas.vertices)/2)):
                x = layer.canvas.vertices[i*2]
                y = layer.canvas.vertices[i*2+1]
                r = layer.canvas.colors[cIndex]
                g = layer.canvas.colors[cIndex+1]
                b = layer.canvas.colors[cIndex+2]
                out[self._2dTo1d(x,y)] = r
                
                cIndex = cIndex + 3
        print("done exporting")
        return out

    def load(self, pixels):
        '''Recieves the appropriate information from Sketch for loading'''
        print("loading")
        print(len(pixels),len(self.canvas.colors))
        for i in range(0,len(self.canvas.colors)):
            self.canvas.colors[i:i+3] = pixels[i:i+3]

        self.layers = []
        self.order = []
        
        self.drawingLayer = graphics.OrderedGroup(2)
        self.layer1 = graphics.OrderedGroup(1)
        self.layers.append(Layer(self.width,self.height,self.batch,self.layer1,0))        
        self.currentLayer = self.layers[0]
        self.order.append(1)
        

    def newStroke(self, points, brush):
        '''Applys the given points using brush to the current layer'''

    def newLayer(self, position):
        '''Creates a new layer at the given position'''