From 55597d0486e26dae98ee962a12c5d2400a214d99 Mon Sep 17 00:00:00 2001 From: EriKWDev Date: Tue, 6 Apr 2021 13:53:44 +0200 Subject: [PATCH] Fixes #3. Adds Entity Style. Begins work on #6 --- .github/workflows/unittests.yaml | 3 +- src/nanim.nim | 8 +-- src/nanim/core.nim | 103 ++++++++++++++++++++++++++++--- src/nanim/drawing.nim | 67 ++++++++++++-------- src/nanim/entities.nim | 10 +++ src/nanim/entities/text.nim | 10 +-- src/nanim/rendering.nim | 10 ++- 7 files changed, 157 insertions(+), 54 deletions(-) create mode 100644 src/nanim/entities.nim diff --git a/.github/workflows/unittests.yaml b/.github/workflows/unittests.yaml index aeab07e..3e33b47 100644 --- a/.github/workflows/unittests.yaml +++ b/.github/workflows/unittests.yaml @@ -37,4 +37,5 @@ jobs: with: nim-version: ${{ matrix.nim }} - - run: nimble test -Y \ No newline at end of file + - name: Run nimble test + run: nimble test -Y diff --git a/src/nanim.nim b/src/nanim.nim index 0e5de23..b761d6c 100644 --- a/src/nanim.nim +++ b/src/nanim.nim @@ -22,18 +22,14 @@ import nanim/rendering, # Entities - nanim/entities/circle, - nanim/entities/rectangle, - nanim/entities/text, - nanim/entities/engon, - nanim/entities/scene_entity + nanim/entities export core, animation, rendering, - circle, rectangle, text, engon, scene_entity + entities # exporting these doesn't make sense in a normal library, but I can't bother importing them in every scene import lenientops, glm diff --git a/src/nanim/core.nim b/src/nanim/core.nim index dcdff17..e83606c 100644 --- a/src/nanim/core.nim +++ b/src/nanim/core.nim @@ -17,11 +17,30 @@ type AngleMode* = enum amDegrees, amRadians + StyleMode* = enum + smSolidColor, smPaintPattern, smNone + + Style* = ref tuple + fillMode: StyleMode + fillColor: Color + fillPattern: proc(context: NVGContext): Paint + + strokeMode: StyleMode + strokeColor: Color + strokePattern: proc(context: NVGContext): Paint + strokeWidth: float + + winding: PathWinding + lineCap: LineCapJoin + lineJoin: LineCapJoin + compositeOperation: CompositeOperation + Entity* = ref object of RootObj points*: seq[Vec3[float]] tension*: float cornerRadius*: float + style*: Style position*: Vec3[float] rotation*: float @@ -73,24 +92,72 @@ proc `$`*(entity: Entity): string = " tension: " & $(entity.tension) +func newStyle*(): Style = + new(result) + result.fillMode = smPaintPattern + result.fillColor = rgb(255, 56, 116) + result.fillPattern = defaultPattern + + result.strokeMode = smSolidColor + result.strokeColor = rgb(230, 26, 94) + result.strokePattern = defaultPattern + result.strokeWidth = 2.0 + + result.winding = pwCCW + result.lineCap = lcjRound + result.lineJoin = lcjMiter + result.compositeOperation = coSourceOver + + +proc setStyle*(context: NVGContext, style: Style) = + case style.fillMode: + of smSolidColor: + context.fillColor(style.fillColor) + of smPaintPattern: + context.fillPaint(style.fillPattern(context)) + of smNone: discard + + context.strokeWidth(style.strokeWidth) + case style.strokeMode: + of smSolidColor: + context.strokeColor(style.strokeColor) + of smPaintPattern: + context.strokePaint(style.strokePattern(context)) + of smNone: context.strokeWidth(0.0) + + context.pathWinding(style.winding) + context.lineJoin(style.lineJoin) + context.lineCap(style.lineCap) + context.globalCompositeOperation(style.compositeOperation) + + +proc executeStyle*(context: NVGContext, style: Style) = + case style.fillMode: + of smSolidColor, smPaintPattern: + context.fill() + of smNone: discard + + case style.strokeMode: + of smSolidColor, smPaintPattern: + context.stroke() + of smNone: discard + + +proc applyStyle*(context: NVGContext, style: Style) = + context.setStyle(style) + context.executeStyle(style) + + method draw*(entity: Entity, scene: Scene) {.base.} = let context = scene.context context.beginPath() - if entity.tension > 0: context.drawPointsWithTension(entity.points, entity.tension) else: context.drawPointsWithRoundedCornerRadius(entity.points, entity.cornerRadius) - context.closePath() - # context.fillColor(rgb(255, 56, 116)) - context.fillPaint(context.gridPattern()) - context.fill() - - context.strokeColor(rgb(230, 26, 94)) - context.strokeWidth(5) - context.stroke() + context.applyStyle(entity.style) func init*(entity: Entity) = @@ -98,6 +165,7 @@ func init*(entity: Entity) = entity.children = @[] entity.tension = 0.0 entity.cornerRadius = 20.0 + entity.style = newStyle() entity.position = vec3(0.0, 0.0, 0.0) entity.rotation = 0.0 entity.scaling = vec3(1.0, 1.0, 1.0) @@ -343,6 +411,17 @@ proc setCornerRadius*(entity: Entity, cornerRadius: float = 0.0): Tween = result = newTween(interpolators) +proc fill*(context: NVGContext, width: cfloat, height: cfloat, color: Color = rgb(255, 255, 255)) = + context.save() + context.fillColor(color) + context.beginPath() + context.resetTransform() + context.rect(0, 0, width, height) + context.closePath() + context.fill() + context.restore() + + proc init(scene: Scene) = scene.time = 0.0 scene.restartTime = 0.0 @@ -356,7 +435,11 @@ proc init(scene: Scene) = vec4[float](0,0,1,0), vec4[float](0,0,0,1)) scene.done = false - scene.background = proc(scene: Scene) = clearWithColor(rgb(255, 255, 255)) + + scene.background = + proc(scene: Scene) = + scene.context.fill(scene.width.cfloat, scene.height.cfloat, rgb(255, 255, 255)) + scene.foreground = proc(scene: Scene) = discard diff --git a/src/nanim/drawing.nim b/src/nanim/drawing.nim index 82fe60e..38936f7 100644 --- a/src/nanim/drawing.nim +++ b/src/nanim/drawing.nim @@ -57,58 +57,71 @@ proc drawPointsWithRoundedCornerRadius*(context: NVGContext, points: seq[Vec], c context.arcTo(p1.x, p1.y, midPoint.x, midPoint.y, cornerRadius) -proc defaultPattern(context: NVGContext) = +proc defaultPatternDrawer*(context: NVGContext, width: float, height: float) = context.beginPath() - context.circle(5, 1440-5, 3) + context.circle(width/2, height/2, width/2) context.closePath() context.fillColor(rgb(20, 20, 20)) context.fill() +proc offset(some: pointer; b: int): pointer {.inline.} = + result = cast[pointer](cast[int](some) + b) + + 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: +proc gridPattern*(context: NVGContext, + patternDrawer: proc(context: NVGContext, width: float, height: float) = defaultPatternDrawer, + width: cint = 10, + height: cint = 10): Paint = + + # Impure, but worth it for the performance benefit... + if hasGatheredPattern and false: return patternPaint let - bufferSize = width*height*4 - oldTransformMatrix = context.currentTransform() + bufferSize = width * height * 4 + tempContext = nvgCreateContext({nifStencilStrokes, nifDebug}) - var - oldData = alloc0(bufferSize) - imageData = alloc0(bufferSize) + var imageData = alloc0(bufferSize) - context.endFrame() - - glPixelStorei(GL_PACK_ALIGNMENT, 1) - glReadBuffer(GL_BACK) - - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, oldData) + # clear the region glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, imageData) - context.beginFrame(2880.cfloat, 1440.cfloat, 1) - patternDrawer(context) - context.endFrame() + # draw the pattern + let (frameBufferWidth, frameBufferHeight) = (2560, 1440) + + tempContext.beginFrame(frameBufferWidth.cfloat, frameBufferHeight.cfloat, 1) + clearWithColor() + tempContext.translate(0, frameBufferHeight.float - height.float) + patternDrawer(tempContext, width.float, height.float) + tempContext.endFrame() + # read the region glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, imageData) - var pixels: seq[uint8] = newSeq[uint8](bufferSize) - copyMem(pixels[0].unsafeAddr, imageData, bufferSize) + + var pixels = newSeq[uint8](bufferSize) + + # Flip the image + for y in 0..