From ae4d57665bd82a4766a7a7e497776eee2fd47464 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 23 Jan 2024 09:51:00 -0800 Subject: [PATCH] Add nine slice API --- src/playdate/api.nim | 4 +- src/playdate/nineslice.nim | 160 +++++++++++++++++++++++++++++++ tests/source/nineslice_27x3.png | Bin 0 -> 104 bytes tests/source/nineslice_60x60.png | Bin 0 -> 270 bytes tests/source/nineslice_6x6.png | Bin 0 -> 101 bytes tests/source/nineslice_9x9.png | Bin 0 -> 150 bytes tests/src/playdate_tests.nim | 4 +- tests/t_nineslice.nim | 124 ++++++++++++++++++++++++ 8 files changed, 288 insertions(+), 4 deletions(-) create mode 100644 src/playdate/nineslice.nim create mode 100644 tests/source/nineslice_27x3.png create mode 100644 tests/source/nineslice_60x60.png create mode 100644 tests/source/nineslice_6x6.png create mode 100644 tests/source/nineslice_9x9.png create mode 100644 tests/t_nineslice.nim diff --git a/src/playdate/api.nim b/src/playdate/api.nim index 984a644..82cd981 100644 --- a/src/playdate/api.nim +++ b/src/playdate/api.nim @@ -7,8 +7,8 @@ import bindings/utils {.all.} as memory import bindings/api export api -import graphics, system, file, sprite, display, sound, lua, json, utils, types -export graphics, system, file, sprite, display, sound, lua, json, utils, types +import graphics, system, file, sprite, display, sound, lua, json, utils, types, nineslice +export graphics, system, file, sprite, display, sound, lua, json, utils, types, nineslice macro initSDK*() = return quote do: diff --git a/src/playdate/nineslice.nim b/src/playdate/nineslice.nim new file mode 100644 index 0000000..ee1aad0 --- /dev/null +++ b/src/playdate/nineslice.nim @@ -0,0 +1,160 @@ +import graphics +import std/[importutils, bitops, math, strutils] + +privateAccess(BitmapData) +privateAccess(LCDBitmap) + +type + NineSliceRow {.byref.} = object + ## The bytes for a single row within a nine slice + leftBytes: seq[uint8] + middleBytes: seq[uint8] + rightBytes: seq[uint8] + leftRightBitLen: int + + NineSliceData = ref object + ## Stores the rows for a single nine slice bitmap + top: seq[NineSliceRow] + middle: seq[NineSliceRow] + bottom: seq[NineSliceRow] + + NineSlice* = ref object + ## A precalculated nine slice + image: NineSliceData + mask: NineSliceData + +func copyBits( + source: ptr UncheckedArray[uint8]; + target: var seq[uint8]; + sourceStartBit, sourceOffsetBit, sourceLen, targetStartBit, targetLen: int +) = + ## Copies a sequence of bits from the source to the target, where all bit positions are absolute relative to + ## the start of the source or target + let minLength = ceil((targetStartBit + targetLen) / 8).toInt + target.setLen(max(target.len, minLength)) + + for bit in 0..= 3) + assert(source.height >= 3) + return NineSlice( + image: createNineSliceData(source.getData), + mask: if source.getBitmapMask.resource == nil: nil else: createNineSliceData(source.getBitmapMask.getData) + ) + +func overlapBytes(left, right: uint8, offset: int): uint8 = + ## Given two bytes, creates a new byte that is partially made up of the left byte, and partially made up of + ## the right hand byte. The amount taken from each is determined by the `offset` + let leftContribution = left shl (8 - offset) + let rightContribution = right shr offset + result = leftContribution or rightContribution + +func drawRow(target: var BitmapData, source: NineSliceRow, targetY: int) = + ## Draws a single row to a nine slice. + let targetOffsetByte = target.rowbytes * targetY + + # Draw the left column, a byte at a time + for i, byteValue in source.leftBytes: + target.data[i + targetOffsetByte] = byteValue + + # Draw the stretched out middle column + let imageWidthInBytes = target.width div 8 + let middleBytesLen = imageWidthInBytes - (2 * (source.leftRightBitLen div 8)) + for i in 0..42!3HFg0!tPHDaPU;cPEB*=VV?2IZB=`jv*3L zlT#8Bew=q;`19XCfRkBSS=rIlhb1&X@WNFihLtN>SodGotN^NJ@O1TaS?83{1OTbT B8wmga literal 0 HcmV?d00001 diff --git a/tests/source/nineslice_60x60.png b/tests/source/nineslice_60x60.png new file mode 100644 index 0000000000000000000000000000000000000000..700b0b21d8bbb4f73ac329aaa18019083471d25c GIT binary patch literal 270 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8jKx9jP7LeL$-D$|PI$UFhGaCp zon^?^Y#_k$Ug_We)a6`384VQ^=iHsy#T02C*TTDR-KxN-D4Tg(_DwI^P@nKSrpM5H z;@wvX`vb3vPd7O9PT>vTp?5jYx8HHwTRd54dcm9xeVHMfojo=&>3{3+1vBb=wL z8N%$RbbDL){phsQwR#lJ1l9DU-lnUxLigVK6S5snKDXL|eq!)+^>bP0l+XkKid1rO literal 0 HcmV?d00001 diff --git a/tests/source/nineslice_6x6.png b/tests/source/nineslice_6x6.png new file mode 100644 index 0000000000000000000000000000000000000000..c241f5b83bf2bc98d274c7a25a0cb4c2f2268a12 GIT binary patch literal 101 zcmeAS@N?(olHy`uVBq!ia0vp^Y#_`5A|IT2?*XJ3i-X*q7}lMWc?smmd%8G=aLn9$ w(vXpXfrD8g?f*IB#`SwxTDK{1O0@S!SoX1ScloXe1S)0lboFyt=akR{0DtTnNB{r; literal 0 HcmV?d00001 diff --git a/tests/source/nineslice_9x9.png b/tests/source/nineslice_9x9.png new file mode 100644 index 0000000000000000000000000000000000000000..6bfe6855fcc47b29a5989bd0dde0dfb870aa96f8 GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{VjKx9jP7LeL$-D$|0z6$DLnNlQ zPB7#