Merge pull request #230 from guzba/master
2.0.5 bugfix + more improvements
This commit is contained in:
commit
5d3fed368c
7 changed files with 131 additions and 57 deletions
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
|
@ -13,5 +13,6 @@ jobs:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: jiro4989/setup-nim-action@v1
|
- uses: jiro4989/setup-nim-action@v1
|
||||||
- run: nimble test -d:release -y
|
- run: nimble test -d:release -y
|
||||||
|
- run: nimble test -d:release -d:pixieNoSimd -y
|
||||||
- run: nimble test --gc:orc -d:release -y
|
- run: nimble test --gc:orc -d:release -y
|
||||||
- run: nim cpp -d:release -r tests/all.nim
|
- run: nim cpp -d:release -r tests/all.nim
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
version = "2.0.4"
|
version = "2.0.5"
|
||||||
author = "Andre von Houck and Ryan Oldenburg"
|
author = "Andre von Houck and Ryan Oldenburg"
|
||||||
description = "Full-featured 2d graphics library for Nim."
|
description = "Full-featured 2d graphics library for Nim."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
@ -753,71 +753,72 @@ proc drawUber(a, b: Image | Mask, mat = mat3(), blendMode = bmNormal) =
|
||||||
)
|
)
|
||||||
x += 16
|
x += 16
|
||||||
|
|
||||||
for _ in x ..< xMax:
|
var srcPos = p + dx * x.float32 + dy * y.float32
|
||||||
let
|
srcPos = vec2(max(0, srcPos.x), max(0, srcPos.y))
|
||||||
srcPos = p + dx * x.float32 + dy * y.float32
|
|
||||||
xFloat = srcPos.x - h
|
for x in x ..< xMax:
|
||||||
yFloat = srcPos.y - h
|
let samplePos = ivec2((srcPos.x - h).int32, (srcPos.y - h).int32)
|
||||||
|
|
||||||
when type(a) is Image:
|
when type(a) is Image:
|
||||||
let backdrop = a.getRgbaUnsafe(x, y)
|
let backdrop = a.getRgbaUnsafe(x, y)
|
||||||
when type(b) is Image:
|
when type(b) is Image:
|
||||||
let
|
let
|
||||||
sample = b.getRgbaUnsafe(xFloat.int, yFloat.int)
|
sample = b.getRgbaUnsafe(samplePos.x, samplePos.y)
|
||||||
blended = blender(backdrop, sample)
|
blended = blender(backdrop, sample)
|
||||||
else: # b is a Mask
|
else: # b is a Mask
|
||||||
let
|
let
|
||||||
sample = b.getValueUnsafe(xFloat.int, yFloat.int)
|
sample = b.getValueUnsafe(samplePos.x, samplePos.y)
|
||||||
blended = blender(backdrop, rgbx(0, 0, 0, sample))
|
blended = blender(backdrop, rgbx(0, 0, 0, sample))
|
||||||
a.setRgbaUnsafe(x, y, blended)
|
a.setRgbaUnsafe(x, y, blended)
|
||||||
else: # a is a Mask
|
else: # a is a Mask
|
||||||
let backdrop = a.getValueUnsafe(x, y)
|
let backdrop = a.getValueUnsafe(x, y)
|
||||||
when type(b) is Image:
|
when type(b) is Image:
|
||||||
let sample = b.getRgbaUnsafe(xFloat.int, yFloat.int).a
|
let sample = b.getRgbaUnsafe(samplePos.x, samplePos.y).a
|
||||||
else: # b is a Mask
|
else: # b is a Mask
|
||||||
let sample = b.getValueUnsafe(xFloat.int, yFloat.int)
|
let sample = b.getValueUnsafe(samplePos.x, samplePos.y)
|
||||||
a.setValueUnsafe(x, y, masker(backdrop, sample))
|
a.setValueUnsafe(x, y, masker(backdrop, sample))
|
||||||
inc x
|
|
||||||
|
srcPos += dx
|
||||||
|
|
||||||
if blendMode == bmIntersectMask:
|
if blendMode == bmIntersectMask:
|
||||||
if a.width - xMax > 0:
|
if a.width - xMax > 0:
|
||||||
zeroMem(a.data[a.dataIndex(xMax, y)].addr, 4 * (a.width - xMax))
|
zeroMem(a.data[a.dataIndex(xMax, y)].addr, 4 * (a.width - xMax))
|
||||||
|
|
||||||
proc draw*(a, b: Image, mat: Mat3, blendMode = bmNormal) {.inline.} =
|
proc draw*(
|
||||||
|
a, b: Image, transform: Vec2 | Mat3 = vec2(), blendMode = bmNormal
|
||||||
|
) {.inline.} =
|
||||||
## Draws one image onto another using matrix with color blending.
|
## Draws one image onto another using matrix with color blending.
|
||||||
a.drawUber(b, mat, blendMode)
|
when type(transform) is Vec2:
|
||||||
|
a.drawUber(b, translate(transform), blendMode)
|
||||||
proc draw*(a, b: Image, pos = vec2(0, 0), blendMode = bmNormal) {.inline.} =
|
else:
|
||||||
## Draws one image onto another using a position offset with color blending.
|
a.drawUber(b, transform, blendMode)
|
||||||
a.draw(b, translate(pos), blendMode)
|
|
||||||
|
|
||||||
proc draw*(image: Image, mask: Mask, mat: Mat3, blendMode = bmMask) {.inline.} =
|
|
||||||
## Draws a mask onto an image using a matrix with color blending.
|
|
||||||
image.drawUber(mask, mat, blendMode)
|
|
||||||
|
|
||||||
proc draw*(
|
proc draw*(
|
||||||
image: Image, mask: Mask, pos = vec2(0, 0), blendMode = bmMask
|
a, b: Mask, transform: Vec2 | Mat3 = vec2(), blendMode = bmMask
|
||||||
) {.inline.} =
|
) {.inline.} =
|
||||||
## Draws a mask onto an image using a position offset with color blending.
|
|
||||||
image.drawUber(mask, translate(pos), blendMode)
|
|
||||||
|
|
||||||
proc draw*(a, b: Mask, mat: Mat3, blendMode = bmMask) {.inline.} =
|
|
||||||
## Draws a mask onto a mask using a matrix with color blending.
|
## Draws a mask onto a mask using a matrix with color blending.
|
||||||
a.drawUber(b, mat, blendMode)
|
when type(transform) is Vec2:
|
||||||
|
a.drawUber(b, translate(transform), blendMode)
|
||||||
proc draw*(a, b: Mask, pos = vec2(0, 0), blendMode = bmMask) {.inline.} =
|
else:
|
||||||
## Draws a mask onto a mask using a position offset with color blending.
|
a.drawUber(b, transform, blendMode)
|
||||||
a.draw(b, translate(pos), blendMode)
|
|
||||||
|
|
||||||
proc draw*(mask: Mask, image: Image, mat: Mat3, blendMode = bmMask) {.inline.} =
|
|
||||||
## Draws a image onto a mask using a matrix with color blending.
|
|
||||||
mask.drawUber(image, mat, blendMode)
|
|
||||||
|
|
||||||
proc draw*(
|
proc draw*(
|
||||||
mask: Mask, image: Image, pos = vec2(0, 0), blendMode = bmMask
|
image: Image, mask: Mask, transform: Vec2 | Mat3 = vec2(), blendMode = bmMask
|
||||||
) {.inline.} =
|
) {.inline.} =
|
||||||
## Draws a image onto a mask using a position offset with color blending.
|
## Draws a mask onto an image using a matrix with color blending.
|
||||||
mask.draw(image, translate(pos), blendMode)
|
when type(transform) is Vec2:
|
||||||
|
image.drawUber(mask, translate(transform), blendMode)
|
||||||
|
else:
|
||||||
|
image.drawUber(mask, transform, blendMode)
|
||||||
|
|
||||||
|
proc draw*(
|
||||||
|
mask: Mask, image: Image, transform: Vec2 | Mat3 = vec2(), blendMode = bmMask
|
||||||
|
) {.inline.} =
|
||||||
|
## Draws a image onto a mask using a matrix with color blending.
|
||||||
|
when type(transform) is Vec2:
|
||||||
|
mask.drawUber(image, translate(transform), blendMode)
|
||||||
|
else:
|
||||||
|
mask.drawUber(image, transform, blendMode)
|
||||||
|
|
||||||
proc drawTiled*(dest, src: Image, mat: Mat3, blendMode = bmNormal) =
|
proc drawTiled*(dest, src: Image, mat: Mat3, blendMode = bmNormal) =
|
||||||
dest.drawCorrect(src, mat, true, blendMode)
|
dest.drawCorrect(src, mat, true, blendMode)
|
||||||
|
|
|
@ -73,17 +73,80 @@ proc minifyBy2*(mask: Mask, power = 1): Mask =
|
||||||
if power == 0:
|
if power == 0:
|
||||||
return mask.copy()
|
return mask.copy()
|
||||||
|
|
||||||
|
var src = mask
|
||||||
for i in 1 .. power:
|
for i in 1 .. power:
|
||||||
result = newMask(mask.width div 2, mask.height div 2)
|
result = newMask(mask.width div 2, mask.height div 2)
|
||||||
for y in 0 ..< result.height:
|
for y in 0 ..< result.height:
|
||||||
for x in 0 ..< result.width:
|
var x: int
|
||||||
|
when defined(amd64) and not defined(pixieNoSimd):
|
||||||
|
let
|
||||||
|
oddMask = mm_set1_epi16(cast[int16](0xff00))
|
||||||
|
first8 = cast[M128i]([uint8.high, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
||||||
|
for _ in countup(0, result.width - 16, 8):
|
||||||
|
let
|
||||||
|
top = mm_loadu_si128(src.data[src.dataIndex(x * 2, y * 2 + 0)].addr)
|
||||||
|
btm = mm_loadu_si128(src.data[src.dataIndex(x * 2, y * 2 + 1)].addr)
|
||||||
|
topShifted = mm_srli_si128(top, 1)
|
||||||
|
btmShifted = mm_srli_si128(btm, 1)
|
||||||
|
|
||||||
|
topEven = mm_andnot_si128(oddMask, top)
|
||||||
|
topOdd = mm_srli_epi16(mm_and_si128(top, oddMask), 8)
|
||||||
|
btmEven = mm_andnot_si128(oddMask, btm)
|
||||||
|
btmOdd = mm_srli_epi16(mm_and_si128(btm, oddMask), 8)
|
||||||
|
|
||||||
|
topShiftedEven = mm_andnot_si128(oddMask, topShifted)
|
||||||
|
topShiftedOdd = mm_srli_epi16(mm_and_si128(topShifted, oddMask), 8)
|
||||||
|
btmShiftedEven = mm_andnot_si128(oddMask, btmShifted)
|
||||||
|
btmShiftedOdd = mm_srli_epi16(mm_and_si128(btmShifted, oddMask), 8)
|
||||||
|
|
||||||
|
topAddedEven = mm_add_epi16(topEven, topShiftedEven)
|
||||||
|
btmAddedEven = mm_add_epi16(btmEven, btmShiftedEven)
|
||||||
|
topAddedOdd = mm_add_epi16(topOdd, topShiftedOdd)
|
||||||
|
bottomAddedOdd = mm_add_epi16(btmOdd, btmShiftedOdd)
|
||||||
|
|
||||||
|
addedEven = mm_add_epi16(topAddedEven, btmAddedEven)
|
||||||
|
addedOdd = mm_add_epi16(topAddedOdd, bottomAddedOdd)
|
||||||
|
|
||||||
|
addedEvenDiv4 = mm_srli_epi16(addedEven, 2)
|
||||||
|
addedOddDiv4 = mm_srli_epi16(addedOdd, 2)
|
||||||
|
|
||||||
|
merged = mm_or_si128(addedEvenDiv4, mm_slli_epi16(addedOddDiv4, 8))
|
||||||
|
|
||||||
|
# merged has the correct values in the even indices
|
||||||
|
|
||||||
|
a = mm_and_si128(merged, first8)
|
||||||
|
b = mm_and_si128(mm_srli_si128(merged, 2), first8)
|
||||||
|
c = mm_and_si128(mm_srli_si128(merged, 4), first8)
|
||||||
|
d = mm_and_si128(mm_srli_si128(merged, 6), first8)
|
||||||
|
e = mm_and_si128(mm_srli_si128(merged, 8), first8)
|
||||||
|
f = mm_and_si128(mm_srli_si128(merged, 10), first8)
|
||||||
|
g = mm_and_si128(mm_srli_si128(merged, 12), first8)
|
||||||
|
h = mm_and_si128(mm_srli_si128(merged, 14), first8)
|
||||||
|
|
||||||
|
ab = mm_or_si128(a, mm_slli_si128(b, 1))
|
||||||
|
cd = mm_or_si128(c, mm_slli_si128(d, 1))
|
||||||
|
ef = mm_or_si128(e, mm_slli_si128(f, 1))
|
||||||
|
gh = mm_or_si128(g, mm_slli_si128(h, 1))
|
||||||
|
|
||||||
|
abcd = mm_or_si128(ab, mm_slli_si128(cd, 2))
|
||||||
|
efgh = mm_or_si128(ef, mm_slli_si128(gh, 2))
|
||||||
|
|
||||||
|
abcdefgh = mm_or_si128(abcd, mm_slli_si128(efgh, 4))
|
||||||
|
|
||||||
|
mm_storeu_si128(result.data[result.dataIndex(x, y)].addr, abcdefgh)
|
||||||
|
x += 8
|
||||||
|
|
||||||
|
for x in x ..< result.width:
|
||||||
let value =
|
let value =
|
||||||
mask.getValueUnsafe(x * 2 + 0, y * 2 + 0).uint32 +
|
src.getValueUnsafe(x * 2 + 0, y * 2 + 0).uint32 +
|
||||||
mask.getValueUnsafe(x * 2 + 1, y * 2 + 0) +
|
src.getValueUnsafe(x * 2 + 1, y * 2 + 0) +
|
||||||
mask.getValueUnsafe(x * 2 + 1, y * 2 + 1) +
|
src.getValueUnsafe(x * 2 + 1, y * 2 + 1) +
|
||||||
mask.getValueUnsafe(x * 2 + 0, y * 2 + 1)
|
src.getValueUnsafe(x * 2 + 0, y * 2 + 1)
|
||||||
result.setValueUnsafe(x, y, (value div 4).uint8)
|
result.setValueUnsafe(x, y, (value div 4).uint8)
|
||||||
|
|
||||||
|
# Set src as this result for if we do another power
|
||||||
|
src = result
|
||||||
|
|
||||||
proc fillUnsafe*(data: var seq[uint8], value: uint8, start, len: int) =
|
proc fillUnsafe*(data: var seq[uint8], value: uint8, start, len: int) =
|
||||||
## Fills the mask data with the parameter value starting at index start and
|
## Fills the mask data with the parameter value starting at index start and
|
||||||
## continuing for len indices.
|
## continuing for len indices.
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 269 B After Width: | Height: | Size: 270 B |
BIN
tests/images/masks/minifiedBlur.png
Normal file
BIN
tests/images/masks/minifiedBlur.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
|
@ -13,27 +13,28 @@ block:
|
||||||
mask.invert()
|
mask.invert()
|
||||||
doAssert mask[0, 0] == 55
|
doAssert mask[0, 0] == 55
|
||||||
|
|
||||||
# block:
|
block:
|
||||||
# let
|
let
|
||||||
# mask = newMask(100, 100)
|
mask = newMask(100, 100)
|
||||||
# r = 10.0
|
r = 10.0
|
||||||
# x = 10.0
|
x = 10.0
|
||||||
# y = 10.0
|
y = 10.0
|
||||||
# h = 80.0
|
h = 80.0
|
||||||
# w = 80.0
|
w = 80.0
|
||||||
# var path: Path
|
var path: Path
|
||||||
# path.moveTo(x + r, y)
|
path.moveTo(x + r, y)
|
||||||
# path.arcTo(x + w, y, x + w, y + h, r)
|
# path.arcTo(x + w, y, x + w, y + h, r)
|
||||||
# path.arcTo(x + w, y + h, x, y + h, r)
|
# path.arcTo(x + w, y + h, x, y + h, r)
|
||||||
# path.arcTo(x, y + h, x, y, r)
|
# path.arcTo(x, y + h, x, y, r)
|
||||||
# path.arcTo(x, y, x + w, y, r)
|
# path.arcTo(x, y, x + w, y, r)
|
||||||
# mask.fillPath(path)
|
path.roundedRect(x, y, w, h, r, r, r, r)
|
||||||
|
mask.fillPath(path)
|
||||||
|
|
||||||
# let minified = mask.minifyBy2()
|
let minified = mask.minifyBy2()
|
||||||
|
|
||||||
# doAssert minified.width == 50 and minified.height == 50
|
doAssert minified.width == 50 and minified.height == 50
|
||||||
|
|
||||||
# writeFile("tests/images/masks/maskMinified.png", minified.encodePng())
|
writeFile("tests/images/masks/maskMinified.png", minified.encodePng())
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let image = newImage(100, 100)
|
let image = newImage(100, 100)
|
||||||
|
@ -155,3 +156,11 @@ block:
|
||||||
mask.fillRect(rect(25, 25, 50, 50))
|
mask.fillRect(rect(25, 25, 50, 50))
|
||||||
mask.blur(20)
|
mask.blur(20)
|
||||||
writeFile("tests/images/maskblur20.png", mask.encodePng())
|
writeFile("tests/images/maskblur20.png", mask.encodePng())
|
||||||
|
|
||||||
|
block:
|
||||||
|
let mask = newMask(200, 200)
|
||||||
|
mask.fillRect(rect(25, 25, 150, 150))
|
||||||
|
mask.blur(25)
|
||||||
|
|
||||||
|
let minified = mask.minifyBy2()
|
||||||
|
writeFile("tests/images/masks/minifiedBlur.png", minified.encodePng())
|
||||||
|
|
Loading…
Reference in a new issue