Add friendly graphics implementation

This commit is contained in:
Joey Yakimowich-Payne 2018-06-25 20:14:11 +09:00
commit 459787fd36
10 changed files with 269 additions and 23 deletions

View file

@ -1,12 +1,12 @@
import libnx/wrapper/gfx
import libnx/graphics
import libnx/wrapper/hid
import libnx/wrapper/console
import libnx/ext/integer128
import libnx/account
import libnx/utils
import libnx/wrapper/types
import libnx/app
proc main() =
gfxInitDefault()
initDefault()
discard consoleInit(nil)
echo "\x1b[5;2H" & "Account info:"

View file

@ -1,10 +1,10 @@
import libnx/wrapper/gfx
import libnx/graphics
import libnx/wrapper/console
import libnx/wrapper/hid
import libnx/utils
import libnx/app
proc main() =
gfxInitDefault()
initDefault()
discard consoleInit(nil)
echo "\x1b[17;20HHELLO FROM NIM"

View file

@ -164,7 +164,7 @@ replace.uint64 = "uint64_t* = uint64"
search.import = "type\n"
prepend.import = """
include libnx/ext/integer128
import libnx/ext/integer128
template BIT*(n): auto = (1.uint shl n)
"""
@ -299,3 +299,15 @@ import libnx/wrapper/binder
[nxlink.nim]
search.o = "var __nxlink"
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
"""

View file

@ -2,7 +2,9 @@ import strutils
import libnx/wrapper/acc
import libnx/results
import libnx/wrapper/types
import libnx/ext/integer128
import libnx/service
import libnx/utils
type
AccountError* = object of Exception
@ -32,9 +34,6 @@ type
var enabled = false
template raiseEx(ty: untyped, message: string) =
raise newException(ty, message)
proc getService*(): Service =
let serv = accountGetService()[]
result = newService(serv)
@ -46,7 +45,10 @@ proc init*() =
let code = accountInitialize().newResult
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
proc exit*() =
@ -59,7 +61,7 @@ proc exit*() =
proc close*(profile: AccountProfile) =
accountProfileClose(profile.unsafeAddr)
template withAccountService*(code: typed): typed =
template withAccountService*(code: untyped): typed =
init()
code
exit()

13
src/libnx/app.nim Normal file
View 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
View 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)

View file

@ -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()
gfxSwapBuffers()
gfxWaitForVSync()
Buffer*[T] = ref object
len*: int
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

View file

@ -1,6 +1,7 @@
import strutils
import ospaths
const headeracc = currentSourcePath().splitPath().head & "/nx/include/switch/services/acc.h"
import libnx/ext/integer128
import libnx/wrapper/types
import libnx/wrapper/sm
type

View file

@ -1,6 +1,7 @@
import strutils
import ospaths
const headerfs = currentSourcePath().splitPath().head & "/nx/include/switch/services/fs.h"
import libnx/ext/integer128
import libnx/wrapper/types
import libnx/wrapper/sm
const

View file

@ -1,7 +1,7 @@
import strutils
import ospaths
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)
type
u8* = uint8