From f17464f17329b740a15c9088670cbb0dd3deb03c Mon Sep 17 00:00:00 2001 From: Astatin3 <77305074+Astatin3@users.noreply.github.com> Date: Fri, 15 Mar 2024 15:08:37 -0600 Subject: [PATCH] Add moving keyframes --- src/buttonEditor.py | 155 ++++++++++++++++++++++++++++++++++---------- src/export.py | 1 - src/pathEditor.py | 12 ++-- src/render.py | 42 ++++++------ 4 files changed, 148 insertions(+), 62 deletions(-) diff --git a/src/buttonEditor.py b/src/buttonEditor.py index 8d294e5..8363077 100644 --- a/src/buttonEditor.py +++ b/src/buttonEditor.py @@ -15,11 +15,13 @@ matchTicks = 15 * 50 displayTickResolution = 4 displayTicks = round(matchTicks / displayTickResolution) -indicatorBarHeight = None - dragFrameIndex = -1 +ogDragFramePos = -1 + selFrame = -1 + + def getPosKeyframes(): frames = [] for keyFrame in keyFrames: @@ -27,18 +29,24 @@ def getPosKeyframes(): frames.append(keyFrame) return frames + + def getKeyframeAtPos(index): for frame in keyFrames: if frame["timeIndex"] == index: return frame return None + + def getPosKeyframeAtPos(index): for frame in keyFrames: if frame["timeIndex"] == index and frame['type'] == 'position': return frame return None + + def getBezierPointCounts(): counts = [] frames = getPosKeyframes() @@ -46,42 +54,59 @@ def getBezierPointCounts(): counts.append(frames[i]['timeIndex'] - frames[i-1]['timeIndex']) return counts + + def getPosKeyframeByIndex(index): for frame in keyFrames: if frame["index"] == index and frame['type'] == 'position': return frame return None + + +def getFrameIndex(frame): + if frame == None: + return -1 + return keyFrames.index(frame) + + + def getSurroundingPosFrames(index): prevFrame = None for i in range(index,-1,-1): - frame = getKeyframeAtPos(i) - if frame != None: + frame = getPosKeyframeAtPos(i) + if frame != None and (dragFrameIndex == -1 or not frame == keyFrames[dragFrameIndex]): prevFrame = frame break nextFrame = None for i in range(index,displayTicks,1): - frame = getKeyframeAtPos(i) - if frame != None: + frame = getPosKeyframeAtPos(i) + if frame != None and (dragFrameIndex == -1 or not frame == keyFrames[dragFrameIndex]): nextFrame = frame break if nextFrame == None and prevFrame == None: return prevFrame, nextFrame - elif nextFrame == None: - return prevFrame, prevFrame - elif prevFrame == None: - return nextFrame, nextFrame + # elif nextFrame == None: + # return prevFrame, prevFrame + # elif prevFrame == None: + # return nextFrame, nextFrame return prevFrame, nextFrame + + def getRobotAtIndex(index): prevFrame, nextFrame = getSurroundingPosFrames(index) - if prevFrame['timeIndex'] - nextFrame['timeIndex'] == 0: + if prevFrame == None: + return nextFrame['position'], nextFrame['rotation'] + elif nextFrame == None: + return prevFrame['position'], prevFrame['rotation'] + elif nextFrame['timeIndex'] - prevFrame['timeIndex'] == 0: return prevFrame['position'], prevFrame['rotation'] - relPos = -((prevFrame['timeIndex'] - index)/(nextFrame['timeIndex'] - prevFrame['timeIndex']-1)) + relPos = -((prevFrame['timeIndex'] - index)/(nextFrame['timeIndex'] - prevFrame['timeIndex'])) pos = calcBezierPoint(prevFrame['position'], ogCtrlNodes[prevFrame['index']], nextFrame['position'], relPos) @@ -91,10 +116,20 @@ def getRobotAtIndex(index): rot = ((nextFrame['rotation']-prevFrame['rotation']+math.pi*2)*relPos) + prevFrame['rotation'] else: rot = ((nextFrame['rotation']-prevFrame['rotation'])*relPos) + prevFrame['rotation'] + + # diff = (nextFrame['rotation']-prevFrame['rotation']) + # if diff >= math.pi: + # rot = ((nextFrame['rotation']-prevFrame['rotation']-math.pi*2)*relPos) + prevFrame['rotation'] + # elif diff <= math.pi: + # rot = ((nextFrame['rotation']-prevFrame['rotation']+math.pi*2)*relPos) + prevFrame['rotation'] + # else: + # rot = ((nextFrame['rotation']-prevFrame['rotation'])*relPos) + prevFrame['rotation'] return pos, rot + + def getTimeBarColor(index): frame = getKeyframeAtPos(index) if frame == None: @@ -102,28 +137,20 @@ def getTimeBarColor(index): if frame['type'] == 'position': return (127,127,0) elif frame['type'] == 'controller': - return (0,127,0) + return (127,0,127) return (16,16,32) -# def renderSelectIndicator(i): -# if i == selFrame: -# x1 = i * (render.width/(displayTicks)) -# x2 = (render.width/(displayTicks)) - -# # render.drawrect((255,0,0), (x1, bottomBarRect[1], x2, indicatorBarHeight)) -# # render.drawrect((255,0,0), (x1, render.screen.get_height()-indicatorBarHeight, x2, indicatorBarHeight)) - -# render.drawrect((255,0,0), (x1, bottomBarRect[1]+((bottomBarRect[3]-indicatorBarHeight)/2), x2, indicatorBarHeight)) - -# # render.drawrect((255,0,0), rect) - + + def calcBezierPoint(p0, p1, p2, t): px = p0[0]*(1-t)**2 + 2*(1-t)*t*p1[0] + p2[0]*t**2 py = p0[1]*(1-t)**2 + 2*(1-t)*t*p1[1] + p2[1]*t**2 return (px, py) + + def reloadBar(pos): toggle = False for i in range(displayTicks): @@ -135,9 +162,26 @@ def reloadBar(pos): if i == selFrame: color = (color[0]+64,color[1]+64,color[2]+64) - if render.isInRect(pos, rect): color = (color[0]+64,color[1]+64,color[2]+64) + if dragFrameIndex != -1 and getKeyframeAtPos(i) == None: + if keyFrames[dragFrameIndex]['type'] == 'position': + prevFrame, nextFrame = getSurroundingPosFrames(ogDragFramePos) + + # print(prevFrame['timeIndex'] == nextFrame['timeIndex']) + if prevFrame == nextFrame: + pass + elif prevFrame == None: + if i < nextFrame['timeIndex']: + keyFrames[dragFrameIndex]['timeIndex'] = i + elif nextFrame == None: + if i > prevFrame['timeIndex']: + keyFrames[dragFrameIndex]['timeIndex'] = i + elif i > prevFrame['timeIndex'] and i < nextFrame['timeIndex']: + keyFrames[dragFrameIndex]['timeIndex'] = i + + else: + keyFrames[dragFrameIndex]['timeIndex'] = i else: color = (color[0]+16+(toggle*16),color[1]+16+(toggle*16),color[2]+32+(toggle*16)) @@ -147,7 +191,9 @@ def reloadBar(pos): # renderSelectIndicator(i) render.update() -def clickBar(pos): + + +def clickBar(pos, doubleClick): for i in range(displayTicks): x1 = i * (render.width/(displayTicks)) x2 = (render.width/(displayTicks)) @@ -155,7 +201,17 @@ def clickBar(pos): if render.isInRect(pos, rect): global selFrame + global dragFrameIndex + global ogDragFramePos selFrame = i + if not doubleClick and dragFrameIndex == -1: + dragFrameIndex = getFrameIndex(getKeyframeAtPos(i)) + ogDragFramePos = i + if doubleClick and getKeyframeAtPos(i) == None: + keyFrames.append({ + 'type': 'controller', + 'timeIndex': i + }) return class buttonEditor: @@ -173,6 +229,8 @@ class buttonEditor: global bottomBarRect bottomBarRect = (0, (render.screen.get_height()-render.bottomBarHeight), render.screen.get_width(), render.bottomBarHeight) + + def refresh(self): global ogNodes global ogCtrlNodes @@ -191,21 +249,40 @@ class buttonEditor: reloadBar((0,0)) render.update() - + + + def mouseDown(self, pos): if pos[1] > bottomBarRect[1]: - clickBar(pos) + clickBar(pos, False) self.refresh() - pass + + def mouseUp(self, pos): - pass + global dragFrameIndex + if dragFrameIndex != -1: + dragFrameIndex = -1 + ogDragFramePos = -1 + self.refresh() + reloadBar((0, 0)) + + def mouseMove(self, pos): - reloadBar(pos) + global dragFrameIndex + if dragFrameIndex != -1 or pos[1] > bottomBarRect[1]: + reloadBar(pos) + # if pos[1] > bottomBarRect[1]: + + def doubleClick(self, pos): - pass + if pos[1] > bottomBarRect[1]: + clickBar(pos, True) + self.refresh() + + def keyDown(self, key): global selFrame @@ -215,7 +292,9 @@ class buttonEditor: elif key == render.pg.K_RIGHT and selFrame < displayTicks-1: selFrame += 1 self.refresh() - + + + def updateNodes(self, loadKeyframes): global ogNodes global ogCtrlNodes @@ -232,6 +311,8 @@ class buttonEditor: frame['position'] = ogNodes[i] frame['rotation'] = ogRotNodes[i] + + def load(self): global selFrame selFrame = -1 @@ -248,9 +329,13 @@ class buttonEditor: self.updateNodes(False) for i in range(len(ogNodes)): + if len(ogNodes) == 1: + timeIndex = 0 + else: + timeIndex = round((i)/(len(ogNodes)-1) * (displayTicks-1)) keyFrames.append({ "type": "position", - "timeIndex": round((i)/(len(ogNodes)-1) * (displayTicks-1)), + "timeIndex": timeIndex, "index": i, "position": ogNodes[i], "rotation": ogRotNodes[i] diff --git a/src/export.py b/src/export.py index 3e86928..0dce9bd 100644 --- a/src/export.py +++ b/src/export.py @@ -1,6 +1,5 @@ pg = None render = None -bottomBarHeight = 0 class export: name = "Export" diff --git a/src/pathEditor.py b/src/pathEditor.py index ffd0373..cb03f2f 100644 --- a/src/pathEditor.py +++ b/src/pathEditor.py @@ -38,8 +38,8 @@ def refresh(): render.circle(curveEditPointColor, curveEditPoints[i], curveEditPointRadius) for i in range(0,len(nodeRotations)): - posX = (math.sin(nodeRotations[i])*rotNodeDist) + nodes[i][0] - posY = (math.cos(nodeRotations[i])*rotNodeDist) + nodes[i][1] + posX = (math.sin(nodeRotations[i])*rotNodeDist/render.offsetSize) + nodes[i][0] + posY = (math.cos(nodeRotations[i])*rotNodeDist/render.offsetSize) + nodes[i][1] render.circle(rotNodeColor, (posX, posY), rotNodeRadius) render.robotSquare(nodes[i], nodeRotations[i]) for pos in nodes: @@ -52,8 +52,8 @@ def getElemAt(pos): if getDist(pos, nodes[i], nodeRadius): return 0, i for i in range(0,len(nodeRotations)): - posX = (math.sin(nodeRotations[i])*rotNodeDist) + nodes[i][0] - posY = (math.cos(nodeRotations[i])*rotNodeDist) + nodes[i][1] + posX = (math.sin(nodeRotations[i])*rotNodeDist/render.offsetSize) + nodes[i][0] + posY = (math.cos(nodeRotations[i])*rotNodeDist/render.offsetSize) + nodes[i][1] if getDist(pos, (posX, posY), nodeRadius): return 2, i for i in range(0,len(curveEditPoints)): @@ -120,14 +120,14 @@ class pathEditor: if clickType == 1: curveEditPoints[clickIndex] = pos if clickType == 2: - nodeRotations[clickIndex] = points2rad(nodes[clickIndex], nearestCirclePoint(nodes[clickIndex], pos, rotNodeDist)) + nodeRotations[clickIndex] = points2rad(nodes[clickIndex], nearestCirclePoint(nodes[clickIndex], pos, rotNodeDist/render.offsetSize)) refresh() def doubleClick(self, pos): clickType, clickIndex = getElemAt(pos) if clickType == -1: pass - if clickType == 0: + elif clickType == 0: if clickIndex > 0: if clickIndex < len(nodes)-1: newPos = (nodes[clickIndex-1][0]+nodes[clickIndex][0])/2,(nodes[clickIndex-1][1]+nodes[clickIndex][1])/2 diff --git a/src/render.py b/src/render.py index 3cef231..d589f97 100644 --- a/src/render.py +++ b/src/render.py @@ -50,35 +50,37 @@ class render(): pos[1] <= rect[1]+rect[3] def robotSquare(self, pos, rot): - pos1 = ((math.sin(rot + math.pi*-0.25)*nodeSquareRadius) + pos[0], - (math.cos(rot + math.pi*-0.25)*nodeSquareRadius) + pos[1]) - pos2 = ((math.sin(rot + math.pi*0.25)*nodeSquareRadius) + pos[0], - (math.cos(rot + math.pi*0.25)*nodeSquareRadius) + pos[1]) - pos3 = ((math.sin(rot + math.pi*0.75)*nodeSquareRadius) + pos[0], - (math.cos(rot + math.pi*0.75)*nodeSquareRadius) + pos[1]) - pos4 = ((math.sin(rot + math.pi*1.25)*nodeSquareRadius) + pos[0], - (math.cos(rot + math.pi*1.25)*nodeSquareRadius) + pos[1]) + pos1 = ((math.sin(rot + math.pi*-0.25)*nodeSquareRadius/self.offsetSize) + pos[0], + (math.cos(rot + math.pi*-0.25)*nodeSquareRadius/self.offsetSize) + pos[1]) + pos2 = ((math.sin(rot + math.pi*0.25)*nodeSquareRadius/self.offsetSize) + pos[0], + (math.cos(rot + math.pi*0.25)*nodeSquareRadius/self.offsetSize) + pos[1]) + pos3 = ((math.sin(rot + math.pi*0.75)*nodeSquareRadius/self.offsetSize) + pos[0], + (math.cos(rot + math.pi*0.75)*nodeSquareRadius/self.offsetSize) + pos[1]) + pos4 = ((math.sin(rot + math.pi*1.25)*nodeSquareRadius/self.offsetSize) + pos[0], + (math.cos(rot + math.pi*1.25)*nodeSquareRadius/self.offsetSize) + pos[1]) - pos5 = ((math.sin(rot)*(nodeSquareRadius+nodeTickLength)) + pos[0], - (math.cos(rot)*(nodeSquareRadius+nodeTickLength)) + pos[1]) - pos6 = ((math.sin(rot)*(nodeSquareRadius-nodeTickLength)) + pos[0], - (math.cos(rot)*(nodeSquareRadius-nodeTickLength)) + pos[1]) + pos5 = ((math.sin(rot)*(nodeSquareRadius+nodeTickLength)/self.offsetSize) + pos[0], + (math.cos(rot)*(nodeSquareRadius+nodeTickLength)/self.offsetSize) + pos[1]) + pos6 = ((math.sin(rot)*(nodeSquareRadius-nodeTickLength)/self.offsetSize) + pos[0], + (math.cos(rot)*(nodeSquareRadius-nodeTickLength)/self.offsetSize) + pos[1]) - self.line(nodeSquareColor, pos1, pos2, nodeSquareWidth) - self.line(nodeSquareColor, pos2, pos3, nodeSquareWidth) - self.line(nodeSquareColor, pos3, pos4, nodeSquareWidth) - self.line(nodeSquareColor, pos4, pos1, nodeSquareWidth) + self.line(nodeSquareColor, pos1, pos2, nodeSquareWidth*self.offsetSize) + self.line(nodeSquareColor, pos2, pos3, nodeSquareWidth*self.offsetSize) + self.line(nodeSquareColor, pos3, pos4, nodeSquareWidth*self.offsetSize) + self.line(nodeSquareColor, pos4, pos1, nodeSquareWidth*self.offsetSize) - self.line(nodeSquareColor, pos5, pos6, nodeSquareWidth) + self.line(nodeSquareColor, pos5, pos6, nodeSquareWidth*self.offsetSize) def bezier(self, p0, p1, p2, curvePointCount): #for p in [p0, p1, p2]: # pg.draw.circle(self.screen, (255, 255, 255), p, 5) for t in np.arange(0, 1, 1/curvePointCount): - px = p0[0]*(1-t)**2 + 2*(1-t)*t*p1[0] + p2[0]*t**2 - py = p0[1]*(1-t)**2 + 2*(1-t)*t*p1[1] + p2[1]*t**2 - self.circle(curvePointColor, (px, py), curvePointRadius) + px = p0[0]*(1-t)**2 + 2*(1-t)*t*p1[0] + p2[0]*t**2 + py = p0[1]*(1-t)**2 + 2*(1-t)*t*p1[1] + p2[1]*t**2 + self.circle(curvePointColor, (px, py), curvePointRadius) + self.circle(curvePointColor, p2, curvePointRadius) + #self.drawrect(curvePointColor, (round(px+0.5), round(py+0.5), curvePointRadius, curvePointRadius)) def clear(self): self.pg.draw.rect(self.screen, (0, 0, 0), self.rect)