Skip to content

Commit

Permalink
FFMpeg rendering, Initial Pattern Creation & tests
Browse files Browse the repository at this point in the history
FFMpeg rendering will now be done by piping every frame into a
subprocess. There seems, however, to be some error with the subprocess
stdin buffer being filled and it hanging resulting in me having to flush
it, close the process and start a new one. A bunch of movies are created
and then concatenated at the end. This is still better than a data.txt
which easily goes above 100s if gigabytes in size, but not still not
nice. Bug in osproc?

Inside drawing.nim there has been some initial work on pattern creation.
Patterns ends the current frame and saves the pixels written by nanovg.
It then clears a portion of the screen, draws a pattern, creates an
Image and a Pain from those pixels, resets the screen to its original
state and returns the Paint/Pattern. Simple patterns are cached.

Initial unittests have been setup. Workflows works out fo the box? Probs
not...
  • Loading branch information
EriKWDev committed Mar 29, 2021
1 parent 8c810c6 commit df057e4
Showing 13 changed files with 513 additions and 242 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/unittests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Run nimble test

on: push

jobs:
nimble-test:
runs-on: ubuntu-latest

strategy:
matrix:
nim: [ '1.4.0', 'stable', 'devel' ]
name: Nimble test with nim version ${{ matrix.nim }}
steps:
- uses: actions/checkout@v2

- name: Setup nim
uses: jiro4989/setup-nim-action@v1
with:
nim-version: ${{ matrix.nim }}

- run: nimble test
29 changes: 15 additions & 14 deletions examples/example_001.nim
Original file line number Diff line number Diff line change
@@ -11,14 +11,12 @@ proc testScene(): Scene =
var text = newText("Hello, World!", font="montserrat-thin")
var rect = newSquare()

scene.add(circle1, circle2, text, rect, engon1)
scene.add(circle1, circle2, rect, engon1, text)

discard circle1.move(150, 150)
discard text.move(150, 150)
discard engon1.move(10, 20)

scene.wait(5500)

scene.wait(500)
scene.showAllEntities()
scene.wait(500)
@@ -42,32 +40,35 @@ proc testScene(): Scene =

scene.play(rect.setTension(0.6))

# scene.startHere() # ! start animation here
scene.wait(500)

scene.play(circle1.pscale(1/5),
circle2.scale(1/2),
rect.pscale(1/3))

# scene.startHere() # ! start animation here

scene.play(rect.setTension(0), rect.rotate(360*2), rect.pscale(4))

for i in 0..5:
scene.wait(500)
scene.play(engon1.move(100, 200))
scene.play(engon1.rotate(180))
scene.wait(500)
scene.play(engon1.pstretch(4, 1))
scene.play(engon1.rotate(180))
scene.play(engon1.pstretch(1/8, 1/2))

scene.play(rect.move(600), rect.setCornerRadius(30))
scene.play(rect.move(600), rect.setCornerRadius(30))

for i in 0..15:
scene.play(rect.move(-20),
rect.rotate(-300),
rect.pscale(if i mod 2 == 0: 1.0/10.0 else: 10.0))
for i in 0..5:
scene.play(rect.move(-20),
rect.rotate(-300),
rect.pscale(if i mod 2 == 0: 1.0/10.0 else: 10.0))

scene.wait(500)

return scene


when isMainModule:
render(testScene, defined(video))
when defined(release):
render1440p(testScene)
else:
render(testScene)
2 changes: 2 additions & 0 deletions examples/renders/parts/parts.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
file 'D:\Documents\Coding\GitHub\nanim\examples\renders\parts\scene_0.mp4'
file 'D:\Documents\Coding\GitHub\nanim\examples\renders\parts\scene_242.mp4'
54 changes: 42 additions & 12 deletions src/nanim/animation/easings.nim
Original file line number Diff line number Diff line change
@@ -13,24 +13,31 @@ type Easing* = proc(t: float): float

func linear*(t: float): float = return t


func inQuad*(t: float): float = return pow(t, 4.0)
func outQuad*(t: float): float = return 1.0 - inQuad(t - 1.0)

func inOutQuad*(t: float): float =
return if t < 0.5: inQuad(4.0*t) else: outQuad(4.0*t)


func sigmoid*(t: float): float =
return 1.0/(1.0 + exp(-t))
func inExpo*(t: float): float = return pow(t, 2.0)
func outExpo*(t: float): float = return 1.0 - inExpo(t - 1.0)

# from https://stats.stackexchange.com/questions/214877/is-there-a-formula-for-an-s-shaped-curve-with-domain-and-range-0-1
func sigmoid*(t: float, n: float): float = return 1.0/(1.0 + pow(t/(1.0 - t), -abs(n)))

func expo*(t: float): float =
return t^2
func sigmoid2*(t: float): float = sigmoid(t, 2.0)
func sigmoid3*(t: float): float = sigmoid(t, 3.0)
func sigmoid4*(t: float): float = sigmoid(t, 4.0)
func sigmoid5*(t: float): float = sigmoid(t, 5.0)

func bounceOut*(t: float): float =
if t < 4/11.0:
return (121 * t * t)/16.0
elif t < 8/11.0:
return (363/40.0 * t * t) - (99/10.0 * t) + 17/5.0
elif t < 9/10.0:
return (4356/361.0 * t * t) - (35442/1805.0 * t) + 16061/1805.0
else:
return (54/5.0 * t * t) - (513/25.0 * t) + 268/25.0

const defaultEasing* = outQuad

func bounceIn*(t: float): float = return 1.0 - bounceOut(1.0 - t)

# General interpolation
proc interpolate*[V](fromValue: V,
@@ -39,8 +46,31 @@ proc interpolate*[V](fromValue: V,
return fromValue + t * (toValue - fromValue)


# Can use https://cubic-bezier.com/ to create nice curves
func cubicBezier*(t: float = 0.0, cpx1, cpy1, cpx2, cpy2: float): float =
let
controlPoint1 = vec2(min(1.0, max(0.0, cpx1)), cpy1)
controlPoint2 = vec2(min(1.0, max(0.0, cpx2)), cpy2)
startPoint = vec2(0.0, 0.0)
endPoint = vec2(1.0, 1.0)

let
p1 = interpolate(startPoint, controlPoint1, t)
p2 = interpolate(controlPoint1, controlPoint2, t)
p3 = interpolate(controlPoint2, endPoint, t)
p12 = interpolate(p1, p2, t)
p23 = interpolate(p2, p3, t)
finalPoint = interpolate(p12, p23, t)

return finalPoint.y

func smoothOvershoot*(t: float): float = cubicBezier(t, 1.0, -0.3, 0.12, 1.22)

const defaultEasing* = bounceIn


# Interpolation of sequence of points
# TODO: Make sequences of differing size interpolate well too
# TODO: Make sequences of differing size interpolate well too (somehow...)
proc interpolate*(fromValue: seq[Vec3[float]],
toValue: seq[Vec3[float]],
t: float): seq[Vec3[float]] =
2 changes: 1 addition & 1 deletion src/nanim/animation/tween.nim
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ type
easing*: Easing


const defaultDuration*: float = 1200.0
const defaultDuration*: float = 1100.0


proc evaluate*(tween: Tween, t: float) =
111 changes: 111 additions & 0 deletions src/nanim/drawing.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@

import
nanovg,
opengl,
glm


proc clearWithColor*(color: Color = rgba(0, 0, 0, 0)) =
glClearColor(color.r, color.g, color.b, color.a)
glClear(GL_COLOR_BUFFER_BIT or
GL_DEPTH_BUFFER_BIT or
GL_STENCIL_BUFFER_BIT)


proc drawPointsWithTension*(context: NVGContext, points: seq[Vec], tension: float = 0.5) =
if len(points) < 2: return

context.moveTo(points[0].x, points[0].y)

let controlScale = tension / 0.5 * 0.175
let numberOfPoints = len(points)

for i in 0..high(points):
let points_before = points[(i - 1 + numberOfPoints) mod numberOfPoints]
let point = points[i]

let pointAfter = points[(i + 1) mod numberOfPoints]
let pointAfter2 = points[(i + 2) mod numberOfPoints]

let p4 = pointAfter

let di = vec2(pointAfter.x - points_before.x, pointAfter.y - points_before.y)
let p2 = vec2(point.x + controlScale * di.x, point.y + controlScale * di.y)

let diPlus1 = vec2(pointAfter2.x - points[i].x, pointAfter2.y - points[i].y)

let p3 = vec2(pointAfter.x - controlScale * diPlus1.x, pointAfter.y - controlScale * diPlus1.y)

context.bezierTo(p2.x, p2.y, p3.x, p3.y, p4.x, p4.y)


proc drawPointsWithRoundedCornerRadius*(context: NVGContext, points: seq[Vec], cornerRadius: float = 20) =
if len(points) < 2: return

var p1 = points[0]

let lastPoint = points[high(points)]
let midPoint = vec2((p1.x + lastPoint.x) / 2.0, (p1.y + lastPoint.y) / 2.0)

context.moveTo(midPoint.x, midPoint.y)
for i in 1..high(points):
let p2 = points[i]

context.arcTo(p1.x, p1.y, p2.x, p2.y, cornerRadius)
p1 = p2

context.arcTo(p1.x, p1.y, midPoint.x, midPoint.y, cornerRadius)


proc defaultPattern(context: NVGContext) =
context.beginPath()
context.circle(5, 1440-5, 3)
context.closePath()

context.fillColor(rgb(20, 20, 20))
context.fill()


var
patternPaint: Paint
hasGatheredPattern = false

proc gridPattern*(context: NVGContext, patternDrawer: proc(context: NVGContext) = defaultPattern, width: cint = 10, height: cint = 10): Paint =
# Impure, but worth it for the performance benefit...
if hasGatheredPattern:
return patternPaint

let
bufferSize = width*height*4
oldTransformMatrix = context.currentTransform()

var
oldData = alloc0(bufferSize)
imageData = alloc0(bufferSize)

context.endFrame()

glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, oldData)
glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, imageData)

context.beginFrame(2880.cfloat, 1440.cfloat, 1)
patternDrawer(context)
context.endFrame()

glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, imageData)
var pixels: seq[uint8] = newSeq[uint8](bufferSize)
copyMem(pixels[0].unsafeAddr, imageData, bufferSize)
let image = context.createImageRGBA(width, height, {ifRepeatX, ifRepeatY, ifFlipY}, pixels)

patternPaint = context.imagePattern(0, 0, width.cfloat, height.cfloat, 0, image, 1.0)
hasGatheredPattern = true
result = patternPaint

context.beginFrame(2880.cfloat, 1440.cfloat, 1)
glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, oldData)

dealloc(oldData)
dealloc(imageData)

context.transform(oldTransformMatrix.m[0], oldTransformMatrix.m[1], oldTransformMatrix.m[2],
oldTransformMatrix.m[3], oldTransformMatrix.m[4], oldTransformMatrix.m[5])
1 change: 1 addition & 0 deletions src/nanim/entities/engon.nim
Original file line number Diff line number Diff line change
@@ -33,5 +33,6 @@ proc newEngon*(n: float, radius: float = 100.0): Engon =
proc newRegularTriangle*(radius: float = 100.0): Engon = newEngon(3, radius)
proc newPentagon*(radius: float = 100.0): Engon = newEngon(5, radius)
proc newHexagon*(radius: float = 100.0): Engon = newEngon(6, radius)
proc newBestagon*(radius: float = 100.0): Engon = newEngon(6, radius)
proc newHeptagon*(radius: float = 100.0): Engon = newEngon(7, radius)
proc newOctagon*(radius: float = 100.0): Engon = newEngon(8, radius)
Loading

0 comments on commit df057e4

Please sign in to comment.