Skip to content

Commit

Permalink
update high-level api
Browse files Browse the repository at this point in the history
Signed-off-by: George Lemon <georgelemon@protonmail.com>
  • Loading branch information
georgelemon committed Oct 19, 2024
1 parent 26a6b7b commit 1702c86
Show file tree
Hide file tree
Showing 9 changed files with 330 additions and 64 deletions.
35 changes: 29 additions & 6 deletions src/blend2d/bindings/bl_context.nim
Original file line number Diff line number Diff line change
Expand Up @@ -91,22 +91,45 @@ type
BL_CLIP_MODE_COUNT ## Count of clip modes.

BLCompOp* {.size:sizeof(uint32).} = enum
BL_COMP_OP_SRC_OVER ## Source-over [default].
BL_COMP_OP_SRC_OVER
## Source-over [default]
## The source is composited over the destination. this is the default
## alpha blending compose method, when neither the compose setting is
## set, nor is set in the image meta-data.
BL_COMP_OP_SRC_COPY ## Source-copy.
BL_COMP_OP_SRC_IN ## Source-in.
BL_COMP_OP_SRC_IN
## Source-in.
## The destination is composited over the source and the
## result replaces the destination.
BL_COMP_OP_SRC_OUT ## Source-out.
BL_COMP_OP_SRC_ATOP ## Source-atop.
BL_COMP_OP_SRC_ATOP
## Source-atop.
## The part of the source lying inside of the destination
## is composited onto the destination
BL_COMP_OP_DST_OVER ## Destination-over.
BL_COMP_OP_DST_COPY ## Destination-copy [nop].
BL_COMP_OP_DST_IN ## Destination-in.
BL_COMP_OP_DST_OUT ## Destination-out.
BL_COMP_OP_DST_ATOP ## Destination-atop.
BL_COMP_OP_XOR ## Xor.
BL_COMP_OP_DST_ATOP
## Destination-atop.
## The part of the destination lying inside of the source is
## composited over the source and replaces the destination.
## Areas not overlaid are cleared
BL_COMP_OP_XOR
## The part of the source that lies outside of the destination
## is combined with the part of the destination that lies outside
## of the source. Source or Destination, but not both
BL_COMP_OP_CLEAR ## Clear.
BL_COMP_OP_PLUS ## Plus.
BL_COMP_OP_MINUS ## Minus.
BL_COMP_OP_MODULATE ## Modulate.
BL_COMP_OP_MULTIPLY ## Multiply.
BL_COMP_OP_MULTIPLY
## Multiply.
## The source is multiplied by the destination and replaces the
## destination. The resultant color is always at least as dark
## as either of the two constituent colors. Multiplying any
## color with black produces black. Multiplying any color
## with white leaves the original color unchanged.
BL_COMP_OP_SCREEN ## Screen.
BL_COMP_OP_OVERLAY ## Overlay.
BL_COMP_OP_DARKEN ## Darken.
Expand Down
29 changes: 29 additions & 0 deletions src/blend2d/bindings/bl_filesystem.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,33 @@
# Copyright (c) 2017-2024 The Blend2D Authors
#
# This software is provided 'as-is', without any express or
# implied warranty. In no event will the authors be held liable
# for any damages arising from the use of this software.
#
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
#
# The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software. If you use this software in
# a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
#
# Altered source versions must be plainly marked as such, and must not
# be misrepresented as being the original software.
#
# This notice may not be removed or altered from any source distribution.
#
#
# blend2d-nim is a Nim wrapper for the libblend2d library
# providing low-level & high-level API for rendering 2D graphics.
#
# (c) 2024 George Lemon | ZLib License
# Made by Humans from OpenPeeps
# https://github.com/openpeeps/blend2d-nim

import ./bl_globals

{.push importc, header: blend2dHeader.}

type
Expand Down
3 changes: 1 addition & 2 deletions src/blend2d/bindings/bl_geometry.nim
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,7 @@ type

BLSizeI* {.bycopy.} = object
## Size specified as [w, h] using int as a storage type.
w*: cint
h*: cint
w*, h*: cint

BLBox* {.bycopy.} = object
## Box specified as [x0, y0, x1, y1] using double as a storage type.
Expand Down
17 changes: 13 additions & 4 deletions src/blend2d/bindings/bl_text.nim
Original file line number Diff line number Diff line change
Expand Up @@ -592,10 +592,19 @@ proc blFontApplyKerning*(self: ptr BLFontCore; gb: ptr BLGlyphBufferCore): BLRes
proc blFontApplyGSub*(self: ptr BLFontCore; gb: ptr BLGlyphBufferCore; lookups: ptr BLBitArrayCore): BLResult
proc blFontApplyGPos*(self: ptr BLFontCore; gb: ptr BLGlyphBufferCore; lookups: ptr BLBitArrayCore): BLResult
proc blFontGetTextMetrics*(self: ptr BLFontCore; gb: ptr BLGlyphBufferCore; `out`: ptr BLTextMetrics): BLResult
proc blFontGetGlyphBounds*(self: ptr BLFontCore; glyphData: ptr uint32; glyphAdvance: ptr int; `out`: ptr BLBoxI; count: uint): BLResult
proc blFontGetGlyphAdvances*(self: ptr BLFontCore; glyphData: ptr uint32; glyphAdvance: ptr int; `out`: ptr BLGlyphPlacement; count: uint): BLResult
proc blFontGetGlyphOutlines*(self: ptr BLFontCore; glyphId: BLGlyphId; userTransform: ptr BLMatrix2D; `out`: ptr BLPathCore; sink: BLPathSinkFunc; userData: pointer): BLResult
proc blFontGetGlyphRunOutlines*(self: ptr BLFontCore; glyphRun: ptr BLGlyphRun; userTransform: ptr BLMatrix2D; `out`: ptr BLPathCore; sink: BLPathSinkFunc; userData: pointer): BLResult
proc blFontGetGlyphBounds*(self: ptr BLFontCore; glyphData: ptr uint32;
glyphAdvance: ptr int; `out`: ptr BLBoxI; count: uint): BLResult

proc blFontGetGlyphAdvances*(self: ptr BLFontCore; glyphData: ptr uint32;
glyphAdvance: ptr int; `out`: ptr BLGlyphPlacement; count: uint): BLResult

proc blFontGetGlyphOutlines*(self: ptr BLFontCore; glyphId: BLGlyphId;
userTransform: ptr BLMatrix2D; `out`: ptr BLPathCore;
sink: BLPathSinkFunc; userData: pointer): BLResult

proc blFontGetGlyphRunOutlines*(self: ptr BLFontCore; glyphRun: ptr BLGlyphRun;
userTransform: ptr BLMatrix2D; `out`: ptr BLPathCore;
sink: BLPathSinkFunc; userData: pointer): BLResult

#
# BLFontFeatureSettings API
Expand Down
40 changes: 26 additions & 14 deletions src/blend2d/color.nim
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
# https://github.com/openpeeps/blend2d-nim
import ./bindings/[bl_globals, bl_style]

from ./bindings import `!`

proc rgba*(r, g, b, a: float32): BLRgba =
result = BLRgba(r: r, g: g, b: b, a: a)

Expand Down Expand Up @@ -333,22 +335,32 @@ const
colYellow* = ColorHex(0xFFFFFF00)
colYellowGreen* = ColorHex(0xFF9ACD32)

type
Gradient* = ptr BLGradientCore

#
# Gradients
#
proc newLinearGradient*(x1, y1: cdouble; x0, y0: cdouble = 0): ptr BLGradientCore =
## Create a new `BLGradientCore`
var gradient = create(BLGradientCore)
var values = BLLinearGradientValues(x0: x0, y0: y0, x1: x1, y1: y1)
assert blGradientInitAs(gradient,
BLGradientType.BL_GRADIENT_TYPE_LINEAR, values.addr,
BLExtendMode.BL_EXTEND_MODE_PAD, nil, 0, nil).code == BL_SUCCESS
gradient
proc linearGradient*(x1, y1: cdouble; x0, y0: cdouble = 0): Gradient =
## Create a new linear `Gradient` pointer of `BLGradientCore`
result = create(BLGradientCore)
var v = BLLinearGradientValues(x0: x0, y0: y0, x1: x1, y1: y1)
!blGradientInitAs(result,
BLGradientType.BL_GRADIENT_TYPE_LINEAR, v.addr,
BLExtendMode.BL_EXTEND_MODE_PAD, nil, 0, nil)

proc radialGradient*(x1, y1, x0, y0, r0: float): Gradient =
## Create a new radial `Gradient` pointer of `BLGradientCore`
result = create(BLGradientCore)
var v = BLRadialGradientValues(x0: x0, y0: y0, x1: x1, y1: y1, r0: r0)
!blGradientInitAs(result,
BLGradientType.BL_GRADIENT_TYPE_RADIAL, v.addr,
BLExtendMode.BL_EXTEND_MODE_PAD, nil, 0, nil)

proc add*(gradient: ptr BLGradientCore, offset: float32, color: uint32) =
## Add a new stop color to `gradient` using `offset` and `color`
assert gradient.blGradientAddStopRgba32(offset, color).code == BL_SUCCESS
proc add*(gr: Gradient, offset: float32, color: uint32) =
## Add a new stop color to `Gradient` using `offset` and `color`
!blGradientAddStopRgba32(gr, offset, color)

proc add*(gradient: ptr BLGradientCore, stop: BLGradientStop) =
## Add a new `BLGradientStop` stop color to `gradient`
assert gradient.blGradientAssignStops(stop.addr, 0'u).code == BL_SUCCESS
proc add*(gr: Gradient, stop: BLGradientStop) =
## Add a new `BLGradientStop` stop color to `Gradient`
!blGradientAssignStops(gr, stop.addr, 0'u)
141 changes: 115 additions & 26 deletions src/blend2d/context.nim
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,19 @@ export BLPoint, BLPointI, context
type
Context* = ptr BLContextCore

proc newContext*(img: Image, compOp: BLCompOp = BL_COMP_OP_SRC_COPY): Context =
proc setCompOp*(ctx: Context, compOp: BLCompOp) {.inline.} =
!blContextSetCompOp(ctx, compOp)

proc clearAll*(ctx: Context) {.inline.} =
!blContextClearAll(ctx)

proc newContext*(img: Image, compOp: BLCompOp = BL_COMP_OP_SRC_OVER): Context =
## Creates a new Context
result = create(BLContextCore)
var cci = create(BLContextCreateInfo)
!blContextInitAs(result, img, cci)
!blContextClearAll(result)
!blContextSetCompOp(result, compOp)
result.clearAll()
result.setCompOp(compOp)

proc opacity*(ctx: Context, alpha: range[0.0..1.0]): Context {.discardable.} =
## Applies `blContextSetGlobalAlpha` using `alpha`
Expand All @@ -56,10 +62,10 @@ template opacity*(alpha: range[0.0..1.0], stmts: untyped) {.dirty.} =
stmts
this.opacity(1)

proc fillStyle*(ctx: Context): Context {.discardable.} =
## Fill `ctx` Context with Color
proc fillStyle*(ctx: Context, color: ColorHex = colWhite): Context {.discardable.} =
## Fill Context with ColorHex
!blContextSetCompOp(ctx, BLCompOp.BL_COMP_OP_SRC_COPY)
!blContextSetFillStyleRgba32(ctx, 0xFFFFFFFF'u32)
!blContextSetFillStyleRgba32(ctx, color)
!blContextFillAll(ctx)
ctx

Expand All @@ -68,21 +74,11 @@ proc fill*(ctx: Context, rgba: BLRgba): Context {.discardable.} =
!blContextFillAllExt(ctx, rgba.addr)
ctx

# proc fillAllC*(impl: ptr BLContextImpl): BLResult {.cdecl.} =
# blContextFillAllExt(impl[], gradient)

proc fill*(ctx: Context, gradient: ptr BLGradientCore): Context {.discardable.} =
## Fills the entire Context with the `gradient` color
!blContextFillAllExt(ctx, gradient)
ctx

proc add*(ctx: Context, font: Font, content: string, x, y: int32 = 0,
color: ColorHex = colWhite): Context {.discardable.} =
## Add a new text to Context
let origin = point(x, y)
!blContextFillUtf8TextIRgba32(ctx, origin.addr, font,
content.cstring, content.len.uint, color)

#
# Context Transformers
#
Expand All @@ -107,7 +103,7 @@ proc resetTransform*(ctx: Context) =
!ctx.blContextApplyTransformOp(BlTransformOpReset, nil)

#
# Blendings
# Blending Modes
#
proc blend*(ctx: Context, img: Image,
p: ptr BLPointI, r: ptr BLRectI,
Expand All @@ -124,23 +120,24 @@ macro genBlendingModes(blendModes: static seq[string]) =
let id = ident("blend" & blendMode)
let mode = ident("BLCompOp" & blendMode)
add result, quote do:
# Generate blending mode handles that calls `blContextSetCompOp`.
# A `blendClear` call is required to stop blending handle.
# Generate blend mode handles that calls `blContextSetCompOp`.
# A `blendSrcOver` call is required after this in order
# to clear the previously applied blending.
proc `id`*(ctx: Context): Context {.discardable.} =
!ctx.blContextSetCompOp(`mode`)
ctx
let handleId = "blend" & blendMode
let macroHandleID = ident("apply" & id.strVal.capitalizeAscii)
add result, quote do:
# Generate macro-based blending mode handles that injects
# a `blendClear` call at the end of the statement.
# These macros can be used only inside a `ctx` macro
# Generate macro-based blend mode handles that auto-injects
# a `blendSrcOver` call at the end of the statement to switch
# to default composition mode.
macro `macroHandleID`*(stmts: untyped): untyped =
result = newStmtList()
result.add(
newCall(ident(`handleId`), ident"this"),
stmts,
newCall(ident"blendClear", ident"this")
newCall(ident"blendSrcOver", ident"this")
)

genBlendingModes @["Clear", "SrcOver", "SrcCopy", "SrcIn", "SrcOut", "SrcAtop",
Expand All @@ -149,17 +146,109 @@ genBlendingModes @["Clear", "SrcOver", "SrcCopy", "SrcIn", "SrcOut", "SrcAtop",
"Darken", "Lighten", "ColorDodge", "ColorBurn", "LinearBurn", "LinearLight",
"PinLight", "HardLight", "SoftLight", "Difference", "Exclusion"]

proc add*(ctx: Context, img: Image, p: ptr BLPointI, r: ptr BLRectI): Context {.discardable.} =
!ctx.blContextBlitImageI(p, img, r)
#
# Context - Add font
#
proc add*(ctx: Context, font: Font, content: string, x, y: int32 = 0,
color: ColorHex = colWhite): Context {.discardable.} =
## Add a new text to Context
let origin = point(x, y)
!blContextFillUtf8TextIRgba32(ctx, origin.addr, font,
content.cstring, content.len.uint, color)

#
# Context - Add Geometry
#
proc add*(ctx: Context, r: BLRectI) =
## Add a `BLRectI` to Context
!blContextFillRectI(ctx, r.addr)

proc add*(ctx: Context, circle: Circle) =
## Add a `Circle` pointer to current `Context`
!blContextFillGeometry(ctx, BL_GEOMETRY_TYPE_CIRCLE, circle)

proc add*(ctx: Context, c: Circle, color: ColorHex) =
## Add a colored `Circle` pointer to current `Context`
!blContextFillGeometryRgba32(ctx, BL_GEOMETRY_TYPE_CIRCLE, c, color)

proc add*(ctx: Context, rr: RoundRect, color: ColorHex) =
## Add a colored `BLRoundRect` to current `Context`
!blContextFillGeometryRgba32(ctx, BL_GEOMETRY_TYPE_ROUND_RECT, rr, color)

#
# Context - Blit Image with BLPointI
#
proc add*(ctx: Context, img: Image): Context {.discardable.} =
## Add an Image to current Context
var p = point(0, 0)
var r = rect(img.width, img.height)
!ctx.blContextBlitImageI(p.addr, img, r.addr)
ctx

proc add*(ctx: Context, img: Image,
p: sink BLPointI, r: sink BLRectI): Context {.discardable.} =
## Add an Image to current Context using `BLPointI` as
## position origin and `BLRectI` as image area
!ctx.blContextBlitImageI(p.addr, img, r.addr)
ctx

proc add*(ctx: Context, img: Image,
p: sink BLPointI): Context {.discardable.} =
## Add an Image to current Context using `BLPointI` position origin
var r = rect(img.width, img.height)
!ctx.blContextBlitImageI(p.addr, img, r.addr)
ctx

#
# Context - Blit Image with BLPoint
#
proc add*(ctx: Context, img: Image,
p: sink BLPoint, r: sink BLRectI): Context {.discardable.} =
## Add an Image to current Context using `BLPointI` as
## position origin and `BLRectI` as image area
!ctx.blContextBlitImageD(p.addr, img, r.addr)
ctx

proc add*(ctx: Context, img: Image,
p: sink BLPoint): Context {.discardable.} =
## Add an Image to current Context using `BLPointI` position origin
var r = rect(img.width, img.height)
!ctx.blContextBlitImageD(p.addr, img, r.addr)
ctx

proc add*(ctx: Context, img: Image, r: sink BLRectI): Context {.discardable.} =
## Add an Image to current Context using `BLRectI` image area
var p = point(0.0, 0.0)
!ctx.blContextBlitImageD(p.addr, img, r.addr)
ctx

#
# Context - Masks
#
proc mask*(ctx: Context, origin: PointI,
mask: Image, maskArea: RectI): Context {.discardable.} =
!blContextFillMaskI(ctx, origin, mask, maskArea)
ctx

proc mask*(ctx: Context, text: tuple[f: BLFontCore, textContent: string, x: int32, y: int32], img: BLImageCore) =
!blContextSetCompOp(ctx, BLCompOp.BL_COMP_OP_SRC_COPY)
ctx.add(text[0].addr, text[1], 0, 0)
var p = point(0, 0)
var r = rect(300, 300)
!blContextSetCompOp(ctx, BLCompOp.BL_COMP_OP_SRC_IN)
!ctx.blContextBlitImageI(p.addr, img.addr, r.addr)

proc endContext*(ctx: Context) =
!blContextEnd(ctx)

#
# Macro Utils
#
macro ctx*(img: typed, contextStmt: untyped) =
macro ctx*(img: typed, contextStmt: untyped): untyped =
## Macro utility to create a new nestable context.
##
## Use `this` identifier to access the Context pointer.
## An `endContext` call is injected at the end of the statement.
result = nnkBlockStmt.newTree()
add result, newEmptyNode() # unamed block
add result,
Expand Down
Loading

0 comments on commit 1702c86

Please sign in to comment.