Cross-platform window creation and event handling library.
Can be used as an alternative to GLFW/GLUT/windy
- works with: OpenGL, Vulkan, software rendering
- works on: Linux(X11 and Wayland), Windows
- handles events from: mouse, keyboard
- and also supports: clipboard, offscreen rendering, interactive move/resize, etc.
import siwin, vmath
const color = [32'u8, 32, 32, 255]
run newSoftwareRenderingWindow(), WindowEventsHandler(
onRender: proc(e: RenderEvent) =
let pixelBuffer = e.window.pixelBuffer
for y in 0..<pixelBuffer.size.y:
for x in 0..<pixelBuffer.size.x:
cast[ptr UncheckedArray[array[4, uint8]]](pixelBuffer.pixels)[y * pixelBuffer.size.x + x] = color
convertPixelsInplace(pixelBuffer.data, pixelBuffer.size, PixelBufferFormat.bgrx_32bit, pixelBuffer.format)
,
onKey: proc(e: KeyEvent) =
if (not e.pressed) and e.key == Key.escape:
close e.window
)
import siwin, opengl, vmath
var window = newOpenglWindow(
title="OpenGL example",
preferedPlatform = (when defined(linux): x11 else: defaultPreferedPlatform)
# note: glBegin and other non- OpenGL ES functions don't work on Wayland
# see tests/t_opengl_es.nim for more complex, wayland-compatible opengl example
)
loadExtensions() # init opengl
run window, WindowEventsHandler(
onResize: proc(e: ResizeEvent) =
glViewport 0, 0, e.size.x.GLsizei, e.size.y.GLsizei
glMatrixMode GlProjection
glLoadIdentity()
glOrtho -30, 30, -30, 30, -30, 30
glMatrixMode(GlModelView)
,
onRender: proc(e: RenderEvent) =
glClearColor 0.3, 0.3, 0.3, 0
glClear GlColorBufferBit or GlDepthBufferBit
glShadeModel GlSmooth
glLoadIdentity()
glTranslatef -15, -15, 0
glBegin GlTriangles
glColor3f 1, 0, 0
glVertex2f 0, 0
glColor3f 0, 1, 0
glVertex2f 30, 0
glColor3f 0, 0, 1
glVertex2f 0, 30
glEnd()
)
note: call redraw(window) every time you want window.render to be called. siwin will automatically call window.render only when window resizes.
note: opengl 1.x and 2.x functions (like glBegin
), is not supported on Wayland, due to Wayland only beeng able to initialize with EGL
see t_vulkan.nim
import siwin, nimgl/vulkan, sequtils
doassert vkInit()
let exts = getRequiredVulkanExtensions()
var cexts = exts.mapit(it[0].addr)
var appInfo = newVkApplicationInfo(
pApplicationName = "siwin Vulkan example",
applicationVersion = vkMakeVersion(1, 0, 0),
pEngineName = "No Engine",
engineVersion = vkMakeVersion(1, 0, 0),
apiVersion = vkApiVersion1_1
)
var instanceCreateInfo = newVkInstanceCreateInfo(
pApplicationInfo = appInfo.addr,
enabledExtensionCount = exts.len,
ppEnabledExtensionNames = cast[cstringArray](cexts[0].addr),
enabledLayerCount = 0,
ppEnabledLayerNames = nil,
)
var instance: VkInstance
doassert vkCreateInstance(instanceCreateInfo.addr, nil, result.addr) == VKSuccess
let window = newVulkanWindow(cast[pointer](instance), title="Vulkan example")
let surface = cast[VkSurfaceKHR](window.vulkanSurface)
# do other initialization using instance and surface...
run window, WindowEventsHandler(
onRender: proc(e: RenderEvent) =
## do rendering...
,
onClose: proc(e: CloseEvent) =
## uninitialize before surface destruction
)
# surface already destroyed, continue uninitializing...
note: very slow, but useful if opengl not needed and if window is used to just display one single image
import siwin, pixie
var image: Image
run newSoftwareRenderingWindow(title="pixie example"), WindowEventsHandler(
onResize: proc(e: ResizeEvent) =
if e.size.x * e.size.y <= 0: return
image = newImage(e.size.x, e.size.y)
,
onRender: proc(e: RenderEvent) =
if e.window.size.x * e.window.size.y <= 0: return
image.fill(rgba(255, 255, 255, 255))
let ctx = image.newContext
ctx.fillStyle = rgba(0, 255, 0, 255)
let
wh = vec2(250, 250)
pos = vec2(image.width.float, image.height.float) / 2 - wh / 2
ctx.fillRoundedRect(rect(pos, wh), 25.0)
let pixelBuffer = e.window.pixelBuffer
copyMem(pixelBuffer.data, image.data[0].addr, pixelBuffer.size.x * pixelBuffer.size.y * Color32bit.sizeof)
convertPixelsInplace(pixelBuffer.data, pixelBuffer.size, PixelBufferFormat.rgbx_32bit, pixelBuffer.format)
,
onKey: proc(e: KeyEvent) =
if (not e.pressed) and e.key == Key.escape:
close e.window
)
import siwin
let clipboard = clipboard()
echo clipboard.text
clipboard.text = "some text"
note: on x11 setting cliboard text requires creating window
note: this will create invisible window. ctx
mustn't be discarded as its destructor will close the window.
If you have multiple contexts, use makeCurrent
to select.
import siwin/offscreen, opengl
let ctx {.used.} = newOpenglContext()
loadExtensions()
# do any opengl computing
import siwin
let window = newOenglWindow()
loadExtensions()
let eventsHandler = WindowEventsHandler(
# ...
)
window.firstStep(eventsHandler, makeVisible=true)
while window.opened:
window.step(eventsHandler)
import siwin
let win1 = newOpenglWindow()
let win2 = newOpenglWindow()
loadExtensions()
let win1_eventsHandler = WindowEventsHandler(
onResize: proc(e: ResizeEvent) =
makeCurrent e.window
#...
,
onRender: proc(e: RenderEvent) =
makeCurrent e.window
#...
)
let win2_eventsHandler = WindowEventsHandler(
onResize: proc(e: ResizeEvent) =
makeCurrent e.window
#...
,
onRender: proc(e: RenderEvent) =
makeCurrent e.window
#...
)
runMultiple(
(window: win1, eventsHandler: win1_eventsHandler, makeVisible: true),
(window: win2, eventsHandler: win2_eventsHandler, makeVisible: true),
)
import siwin
let window = newOpenglWindow(transparent=true, frameless=true)
loadExtensions()
run window, WindowEventsHandler(
onMouseMove: proc(e: MouseMoveEvent) =
if MouseButton.left in e.window.mouse.pressed:
window.startInteractiveMove()
# see also: startInteractiveResize
)
see siwin/platforms/any/window
import std/importutils
import siwin/platforms/x11/window
privateAccess WindowX11Obj
# ...
window.handle
If you want to support this project, here is some tasks to do:
- See issues
- Any bugfixes is always accepted, just describe somewhere what you fixed
- Refactoring (my code is bad, i know it)
- if you doing very big refactoring, first create issue to ask is all your changes needed, and if it is, refactor
- Documentation
- Optimization
- MacOS support
- Android/IOS support
- Web support
- copy/paste images
- Make cool site that adverts siwin
Just fork levovix0/siwin to your account, make changes and submit a pull request.
Or if it requires new repository to be created, create it and add an "change dependency" issue.