Add friendly graphics implementation
This commit is contained in:
parent
5c252fdd6e
commit
459787fd36
10 changed files with 269 additions and 23 deletions
|
|
@ -1,12 +1,12 @@
|
||||||
import libnx/wrapper/gfx
|
import libnx/graphics
|
||||||
import libnx/wrapper/hid
|
import libnx/wrapper/hid
|
||||||
import libnx/wrapper/console
|
import libnx/wrapper/console
|
||||||
|
import libnx/ext/integer128
|
||||||
import libnx/account
|
import libnx/account
|
||||||
import libnx/utils
|
import libnx/app
|
||||||
import libnx/wrapper/types
|
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
gfxInitDefault()
|
initDefault()
|
||||||
discard consoleInit(nil)
|
discard consoleInit(nil)
|
||||||
|
|
||||||
echo "\x1b[5;2H" & "Account info:"
|
echo "\x1b[5;2H" & "Account info:"
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import libnx/wrapper/gfx
|
import libnx/graphics
|
||||||
import libnx/wrapper/console
|
import libnx/wrapper/console
|
||||||
import libnx/wrapper/hid
|
import libnx/wrapper/hid
|
||||||
import libnx/utils
|
import libnx/app
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
gfxInitDefault()
|
initDefault()
|
||||||
discard consoleInit(nil)
|
discard consoleInit(nil)
|
||||||
|
|
||||||
echo "\x1b[17;20HHELLO FROM NIM"
|
echo "\x1b[17;20HHELLO FROM NIM"
|
||||||
|
|
|
||||||
14
libnxGen.cfg
14
libnxGen.cfg
|
|
@ -164,7 +164,7 @@ replace.uint64 = "uint64_t* = uint64"
|
||||||
|
|
||||||
search.import = "type\n"
|
search.import = "type\n"
|
||||||
prepend.import = """
|
prepend.import = """
|
||||||
include libnx/ext/integer128
|
import libnx/ext/integer128
|
||||||
template BIT*(n): auto = (1.uint shl n)
|
template BIT*(n): auto = (1.uint shl n)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -299,3 +299,15 @@ import libnx/wrapper/binder
|
||||||
[nxlink.nim]
|
[nxlink.nim]
|
||||||
search.o = "var __nxlink"
|
search.o = "var __nxlink"
|
||||||
replace.o = "var DUnxlink"
|
replace.o = "var DUnxlink"
|
||||||
|
|
||||||
|
[fs.nim]
|
||||||
|
search.o = "import libnx"
|
||||||
|
prepend.o = """
|
||||||
|
import libnx/ext/integer128
|
||||||
|
"""
|
||||||
|
|
||||||
|
[acc.nim]
|
||||||
|
search.o = "import libnx"
|
||||||
|
prepend.o = """
|
||||||
|
import libnx/ext/integer128
|
||||||
|
"""
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@ import strutils
|
||||||
import libnx/wrapper/acc
|
import libnx/wrapper/acc
|
||||||
import libnx/results
|
import libnx/results
|
||||||
import libnx/wrapper/types
|
import libnx/wrapper/types
|
||||||
|
import libnx/ext/integer128
|
||||||
import libnx/service
|
import libnx/service
|
||||||
|
import libnx/utils
|
||||||
|
|
||||||
type
|
type
|
||||||
AccountError* = object of Exception
|
AccountError* = object of Exception
|
||||||
|
|
@ -32,9 +34,6 @@ type
|
||||||
|
|
||||||
var enabled = false
|
var enabled = false
|
||||||
|
|
||||||
template raiseEx(ty: untyped, message: string) =
|
|
||||||
raise newException(ty, message)
|
|
||||||
|
|
||||||
proc getService*(): Service =
|
proc getService*(): Service =
|
||||||
let serv = accountGetService()[]
|
let serv = accountGetService()[]
|
||||||
result = newService(serv)
|
result = newService(serv)
|
||||||
|
|
@ -46,7 +45,10 @@ proc init*() =
|
||||||
|
|
||||||
let code = accountInitialize().newResult
|
let code = accountInitialize().newResult
|
||||||
if code.failed:
|
if code.failed:
|
||||||
raiseEx(AccountInitError, "Error, account api could not be initialized: " & code.description)
|
raiseEx(
|
||||||
|
AccountInitError,
|
||||||
|
"Error, account api could not be initialized: " & code.description
|
||||||
|
)
|
||||||
enabled = true
|
enabled = true
|
||||||
|
|
||||||
proc exit*() =
|
proc exit*() =
|
||||||
|
|
@ -59,7 +61,7 @@ proc exit*() =
|
||||||
proc close*(profile: AccountProfile) =
|
proc close*(profile: AccountProfile) =
|
||||||
accountProfileClose(profile.unsafeAddr)
|
accountProfileClose(profile.unsafeAddr)
|
||||||
|
|
||||||
template withAccountService*(code: typed): typed =
|
template withAccountService*(code: untyped): typed =
|
||||||
init()
|
init()
|
||||||
code
|
code
|
||||||
exit()
|
exit()
|
||||||
|
|
|
||||||
13
src/libnx/app.nim
Normal file
13
src/libnx/app.nim
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import libnx/graphics, libnx/wrapper/hid, libnx/wrapper/applet
|
||||||
|
|
||||||
|
template mainLoop*(code: untyped): untyped =
|
||||||
|
while appletMainLoop():
|
||||||
|
hidScanInput()
|
||||||
|
|
||||||
|
code
|
||||||
|
|
||||||
|
flushBuffers()
|
||||||
|
swapBuffers()
|
||||||
|
waitForVSync()
|
||||||
|
|
||||||
|
graphics.exit()
|
||||||
200
src/libnx/graphics.nim
Normal file
200
src/libnx/graphics.nim
Normal file
|
|
@ -0,0 +1,200 @@
|
||||||
|
import strutils
|
||||||
|
import
|
||||||
|
libnx/wrapper/types,
|
||||||
|
libnx/wrapper/gfx,
|
||||||
|
libnx/utils
|
||||||
|
|
||||||
|
type
|
||||||
|
GraphicsError* = object of Exception
|
||||||
|
InitResolutionError* = object of GraphicsError
|
||||||
|
CropBoundsError* = object of GraphicsError
|
||||||
|
|
||||||
|
RGBA8* = ref object
|
||||||
|
red*: int
|
||||||
|
green*: int
|
||||||
|
blue*: int
|
||||||
|
alpha*: int
|
||||||
|
|
||||||
|
Framebuffer* = ref object
|
||||||
|
width*: uint32
|
||||||
|
height*: uint32
|
||||||
|
data*: Buffer[uint8]
|
||||||
|
|
||||||
|
BufferTransform* {.pure, size: sizeof(cint).} = enum
|
||||||
|
FlipHorizontal = 0x1
|
||||||
|
FlipVertical = 0x2
|
||||||
|
Rotate180 = 0x3
|
||||||
|
Rotate90 = 0x4
|
||||||
|
Rotate270 = 0x7
|
||||||
|
|
||||||
|
## / Converts red, green, blue, and alpha components to packed RGBA8.
|
||||||
|
proc packed*(rgba: RGBA8): int =
|
||||||
|
gfx.RGBA8(rgba.red, rgba.green, rgba.blue, rgba.alpha)
|
||||||
|
|
||||||
|
## / Same as \ref RGBA8 except with alpha=0xff.
|
||||||
|
proc maxAlpha*(r, g, b: int): RGBA8 =
|
||||||
|
RGBA8(red:r, green:g, blue:b, alpha:0xFF)
|
||||||
|
|
||||||
|
## / GfxMode set by \ref gfxSetMode. The default is GfxMode_LinearDouble. Note that the
|
||||||
|
## text-console (see console.h) sets this to GfxMode_TiledDouble.
|
||||||
|
type
|
||||||
|
GfxMode* {.size: sizeof(cint), pure.} = enum
|
||||||
|
TiledSingle, ## /< Single-buffering with raw tiled (block-linear) framebuffer.
|
||||||
|
TiledDouble, ## /< Double-buffering with raw tiled (block-linear) framebuffer.
|
||||||
|
LinearDouble ## /< Double-buffering with linear framebuffer, which is
|
||||||
|
## transferred to the actual framebuffer by \ref gfxFlushBuffers().
|
||||||
|
|
||||||
|
var enabled = false
|
||||||
|
|
||||||
|
## / Framebuffer pixel-format is RGBA8888, there's no known way to change this.
|
||||||
|
## *
|
||||||
|
## @brief Initializes the graphics subsystem.
|
||||||
|
## @warning Do not use \ref viInitialize when using this function.
|
||||||
|
##
|
||||||
|
proc initDefault*() =
|
||||||
|
if not enabled:
|
||||||
|
gfxInitDefault()
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
## *
|
||||||
|
## @brief Uninitializes the graphics subsystem.
|
||||||
|
## @warning Do not use \ref viExit when using this function.
|
||||||
|
##
|
||||||
|
proc exit*() =
|
||||||
|
if enabled:
|
||||||
|
gfxExit()
|
||||||
|
enabled = false
|
||||||
|
|
||||||
|
## / Get the framebuffer width/height without crop.
|
||||||
|
proc getFramebufferResolution*(): tuple[width: uint32, height: uint32] =
|
||||||
|
var
|
||||||
|
width: uint32
|
||||||
|
height: uint32
|
||||||
|
gfxGetFramebufferResolution(width.addr, height.addr)
|
||||||
|
return (width: width, height: height)
|
||||||
|
|
||||||
|
## *
|
||||||
|
## @brief Sets the resolution to be used when initializing the graphics subsystem.
|
||||||
|
## @param[in] width Horizontal resolution, in pixels.
|
||||||
|
## @param[in] height Vertical resolution, in pixels.
|
||||||
|
## @note The default resolution is 720p.
|
||||||
|
## @note This can only be used before calling \ref gfxInitDefault, this will use \ref
|
||||||
|
## fatalSimple otherwise. If the input is 0, the default resolution will be used during
|
||||||
|
## \ref gfxInitDefault. This sets the maximum resolution for the framebuffer, used
|
||||||
|
## during \ref gfxInitDefault. This is also used as the current resolution when crop
|
||||||
|
## isn't set. The width/height are reset to the default when \ref gfxExit is used.
|
||||||
|
## @note Normally you should only use this when you need a maximum resolution larger
|
||||||
|
## than the default, see above.
|
||||||
|
## @note The width and height are aligned to 4.
|
||||||
|
##
|
||||||
|
proc initResolution*(width: uint32; height: uint32) =
|
||||||
|
if not enabled:
|
||||||
|
gfxInitResolution(width, height)
|
||||||
|
else:
|
||||||
|
raiseEx(InitResolutionError, "Cannot init resolution after graphics.initDefault!")
|
||||||
|
|
||||||
|
## / Wrapper for \ref gfxInitResolution with resolution=1080p. Use this if you want to
|
||||||
|
## support 1080p or >720p in docked-mode.
|
||||||
|
proc initResolution1080p*() =
|
||||||
|
if not enabled:
|
||||||
|
gfxInitResolutionDefault()
|
||||||
|
else:
|
||||||
|
raiseEx(InitResolutionError, "Cannot init resolution after graphics.initDefault!")
|
||||||
|
|
||||||
|
proc cropBoundsValid(left, top, right, bottom: uint32, width, height: uint32): bool =
|
||||||
|
|
||||||
|
if left < right and top > bottom:
|
||||||
|
if left <= width and right <= width:
|
||||||
|
if top <= height and bottom <= height:
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
## / Configure framebuffer crop, by default crop is all-zero. Use all-zero input to
|
||||||
|
## reset to default. \ref gfxExit resets this to the default.
|
||||||
|
## / When the input is invalid this returns without changing the crop data, this
|
||||||
|
## includes the input values being larger than the framebuf width/height.
|
||||||
|
## / This will update the display width/height returned by \ref gfxGetFramebuffer, with
|
||||||
|
## that width/height being reset to the default when required.
|
||||||
|
## / \ref gfxGetFramebufferDisplayOffset uses absolute x/y, it will not adjust for
|
||||||
|
## non-zero crop left/top.
|
||||||
|
## / The new crop config will not take affect with double-buffering disabled. When used
|
||||||
|
## during frame-drawing, this should be called before \ref gfxGetFramebuffer.
|
||||||
|
## / The right and bottom params are aligned to 4.
|
||||||
|
proc setCrop*(left, top, right, bottom: uint32) =
|
||||||
|
let (width, height) = getFramebufferResolution()
|
||||||
|
if not cropBoundsValid(left, top, right, bottom, width, height):
|
||||||
|
raiseEx(
|
||||||
|
CropBoundsError,
|
||||||
|
"The crop bounds are outside the frame buffer limits of w: $#, h:$#" %
|
||||||
|
[$width, $height]
|
||||||
|
)
|
||||||
|
gfxConfigureCrop(left.s32, top.s32, right.s32, bottom.s32)
|
||||||
|
|
||||||
|
proc resetCrop*() =
|
||||||
|
setCrop(0, 0, 0, 0)
|
||||||
|
|
||||||
|
## / Wrapper for \ref gfxConfigureCrop. Use this to set the resolution, within the
|
||||||
|
## bounds of the maximum resolution. Use all-zero input to reset to default.
|
||||||
|
proc setCropResolution*(width, height: uint32) =
|
||||||
|
gfxConfigureResolution(width.s32, height.s32)
|
||||||
|
|
||||||
|
## / If enabled, \ref gfxConfigureResolution will be used with the input resolution for
|
||||||
|
## the current OperationMode. Then \ref gfxConfigureResolution will automatically be
|
||||||
|
## used with the specified resolution each time OperationMode changes.
|
||||||
|
proc setAutoResolution*(enable: bool, handheldWidth,
|
||||||
|
handheldHeight, dockedWidth,
|
||||||
|
dockedHeight: uint32) =
|
||||||
|
gfxConfigureAutoResolution(
|
||||||
|
enable, handheldWidth.s32, handheldHeight.s32, dockedWidth.s32, dockedHeight.s32
|
||||||
|
)
|
||||||
|
|
||||||
|
## / Wrapper for \ref gfxConfigureAutoResolution. handheld_resolution=720p,
|
||||||
|
## docked_resolution={all-zero for using current maximum resolution}.
|
||||||
|
proc setAutoResolutionDefault*(enable: bool) =
|
||||||
|
gfxConfigureAutoResolutionDefault(enable)
|
||||||
|
|
||||||
|
## / Waits for vertical sync.
|
||||||
|
proc waitForVsync*() = gfxWaitForVSync()
|
||||||
|
|
||||||
|
## / Swaps the framebuffers (for double-buffering).
|
||||||
|
proc swapBuffers*() = gfxSwapBuffers()
|
||||||
|
|
||||||
|
## / Use this to get the actual byte-size of the framebuffer for use with memset/etc.
|
||||||
|
proc getFramebufferSize*(): int = gfxGetFramebufferSize().int
|
||||||
|
|
||||||
|
## / Get the current framebuffer address, with optional output ptrs for the display
|
||||||
|
## framebuffer width/height. The display width/height is adjusted by \ref
|
||||||
|
## gfxConfigureCrop and \ref gfxConfigureResolution.
|
||||||
|
proc getFramebuffer*(): Framebuffer =
|
||||||
|
result = new(Framebuffer)
|
||||||
|
let size = getFramebufferSize()
|
||||||
|
let frameBuf = gfxGetFrameBuffer(
|
||||||
|
result.width.addr,
|
||||||
|
result.height.addr
|
||||||
|
)
|
||||||
|
let arr = cast[ptr UncheckedArray[uint8]](frameBuf)
|
||||||
|
result.data = Buffer[uint8](len: size, data: arr)
|
||||||
|
|
||||||
|
## / Sets the \ref GfxMode.
|
||||||
|
proc setMode*(mode: GfxMode) = gfxSetMode(gfx.GfxMode(mode))
|
||||||
|
|
||||||
|
## / Controls whether a vertical-flip is done when determining the pixel-offset within
|
||||||
|
## the actual framebuffer. By default this is enabled.
|
||||||
|
proc setDrawFlip*(enabled: bool) = gfxSetDrawFlip(enabled)
|
||||||
|
|
||||||
|
## / Configures transform. See the NATIVE_WINDOW_TRANSFORM_* enums in buffer_producer.h.
|
||||||
|
## The default is NATIVE_WINDOW_TRANSFORM_FLIP_V.
|
||||||
|
proc configureTransform*(transform: BufferTransform) =
|
||||||
|
gfxConfigureTransform(transform.uint32)
|
||||||
|
|
||||||
|
## / Flushes the framebuffer in the data cache. When \ref GfxMode is
|
||||||
|
## GfxMode_LinearDouble, this also transfers the linear-framebuffer to the actual
|
||||||
|
## framebuffer.
|
||||||
|
proc flushBuffers*() = gfxFlushBuffers()
|
||||||
|
|
||||||
|
## / Use this to get the pixel-offset in the framebuffer. Returned value is in pixels,
|
||||||
|
## not bytes.
|
||||||
|
## / This implements tegra blocklinear, with hard-coded constants etc.
|
||||||
|
## / Do not use this when \ref GfxMode is GfxMode_LinearDouble.
|
||||||
|
proc getFramebufferDisplayOffset*(x: uint32; y: uint32): uint32 =
|
||||||
|
gfxGetFrameBufferDisplayOffset(x, y)
|
||||||
|
|
@ -1,13 +1,30 @@
|
||||||
import libnx/wrapper/gfx, libnx/wrapper/hid, libnx/wrapper/applet
|
|
||||||
|
|
||||||
template mainLoop*(code: untyped): untyped =
|
|
||||||
while appletMainLoop():
|
|
||||||
hidScanInput()
|
|
||||||
|
|
||||||
code
|
type
|
||||||
|
BufferError* = object of Exception
|
||||||
|
BufferIndexError* = object of BufferError
|
||||||
|
|
||||||
gfxFlushBuffers()
|
Buffer*[T] = ref object
|
||||||
gfxSwapBuffers()
|
len*: int
|
||||||
gfxWaitForVSync()
|
data*: ptr UncheckedArray[T]
|
||||||
|
|
||||||
gfxExit()
|
template raiseEx*(ty: untyped, message: string): untyped =
|
||||||
|
raise newException(ty, message)
|
||||||
|
|
||||||
|
proc `[]`[T](buff: Buffer[T], index: int): T =
|
||||||
|
if index > (buff.len - 1):
|
||||||
|
raiseEx(
|
||||||
|
BufferIndexError,
|
||||||
|
"Index: $# is greater than buffer length: $#!" % [$index, $buff.len]
|
||||||
|
)
|
||||||
|
|
||||||
|
result = buff.data[][index]
|
||||||
|
|
||||||
|
proc `[]=`[T](buff: Buffer[T], index: int, value: T) =
|
||||||
|
if index > (buff.len - 1):
|
||||||
|
raiseEx(
|
||||||
|
BufferIndexError,
|
||||||
|
"Index: $# is greater than buffer length: $#!" % [$index, $buff.len]
|
||||||
|
)
|
||||||
|
|
||||||
|
buff.data[][index] = value
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import strutils
|
import strutils
|
||||||
import ospaths
|
import ospaths
|
||||||
const headeracc = currentSourcePath().splitPath().head & "/nx/include/switch/services/acc.h"
|
const headeracc = currentSourcePath().splitPath().head & "/nx/include/switch/services/acc.h"
|
||||||
|
import libnx/ext/integer128
|
||||||
import libnx/wrapper/types
|
import libnx/wrapper/types
|
||||||
import libnx/wrapper/sm
|
import libnx/wrapper/sm
|
||||||
type
|
type
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import strutils
|
import strutils
|
||||||
import ospaths
|
import ospaths
|
||||||
const headerfs = currentSourcePath().splitPath().head & "/nx/include/switch/services/fs.h"
|
const headerfs = currentSourcePath().splitPath().head & "/nx/include/switch/services/fs.h"
|
||||||
|
import libnx/ext/integer128
|
||||||
import libnx/wrapper/types
|
import libnx/wrapper/types
|
||||||
import libnx/wrapper/sm
|
import libnx/wrapper/sm
|
||||||
const
|
const
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import strutils
|
import strutils
|
||||||
import ospaths
|
import ospaths
|
||||||
const headertypes = currentSourcePath().splitPath().head & "/nx/include/switch/types.h"
|
const headertypes = currentSourcePath().splitPath().head & "/nx/include/switch/types.h"
|
||||||
include libnx/ext/integer128
|
import libnx/ext/integer128
|
||||||
template BIT*(n): auto = (1.uint shl n)
|
template BIT*(n): auto = (1.uint shl n)
|
||||||
type
|
type
|
||||||
u8* = uint8
|
u8* = uint8
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue