Skip to content

Instantly share code, notes, and snippets.

@fowlmouth
Last active December 14, 2015 03:18
Show Gist options
  • Save fowlmouth/5019522 to your computer and use it in GitHub Desktop.
Save fowlmouth/5019522 to your computer and use it in GitHub Desktop.
import opengl, os, math
discard """
Saffron is a Nimrod adapatation of the Simple and Fast Multimedia Library by
Laurent Gomila.
SFML - Copyright (c) 2007-2008 Laurent Gomila
This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but
is not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any
source distribution.
"""
## move to vector math module
type
TVector2*[A] = tuple[x, y: A]
TVector3*[A] = tuple[x, y, z: A]
TVector4*[A] = tuple[x, y, z, w: A]
TVector2i* = TVector2[GLint]
TVector2f* = TVector2[GLfloat]
TColor4f* = TVector4[GLclampf]
proc vec4*[A](x, y, z, w: A): TVector4[A] =
result.x = x
result.y = y
result.z = z
result.w = w
proc colorf*(r, g, b: range[0.0 .. 1.0]; a: range[0.0..1.0] = 1.0): TColor4f {.
inline.}= vec4[GLclampf](r, g, b, a)
proc colorf*(r, g, b: range[0..255]; a: range[0..255] = 255): TColor4f {.
inline.} = vec4[GLclampf](r / 255, g / 255, b / 255, a / 255)
proc glClearColor*(col: TColor4f){.inline.} = glClearColor(col.x, col.y, col.z, col.w)
type
TWindowStyle* = enum
noStyle, fullscreen, resizable
TDisplayMode* = tuple[
width, height: int, bpp: int ]
TEventType* = enum
EvtUnknown, KeyPressed, KeyReleased, MouseMove, MouseDelta,
ButtonPressed, ButtonReleased, GainedFocus, LostFocus, WindowResized
TEvent* = object
case kind*: TEventType
of KeyPressed, KeyReleased:
key*: TKey ##maybe add here control*, shift*, meta*, alt*: bool ? \
## if so, just make a TKeyEvent and pass it to TEventHandler.keyHandlers
of MouseMove, MouseDelta:
pos*: TVector2i
of WindowResized:
size*: TVector2i
of ButtonPressed, ButtonReleased:
button*: TMouseButton
at*: TVector2i
else: nil
TKey* = enum
KeyNone, KeyLeft, KeyRight, KeyUp, KeyDown,
KeyNumpad0, KeyNumpad1, KeyNumpad2, KeyNumpad3,
KeyNumpad4, KeyNumpad5, KeyNumpad6, KeyNumpad7,
KeyNumpad8, KeyNumpad9, KeyEscape, KeyA, KeyB, KeyC, KeyD,
KeyE, KeyF, KeyG, KeyH, KeyI, KeyJ, KeyK, KeyL, KeyM, KeyN,
KeyO, KeyP, KeyQ, KeyR, KeyS, KeyT, KeyU, KeyV,
KeyW, KeyX, KeyY, KeyZ, Key0, Key1, key2, key3, key4, key5,
key6, key7, key8, key9, keySpace, keyComma, keyPeriod, keyColon,
KeyLControl, KeyLShift, KeyLAlt, KeyCapslock, KeyMeta, KeyTab,
KeyRControl, KeyRShift, KeyRAlt, KeyEnter, KeyMenu, KeyBackspace
TMouseButton* = enum
MouseUnknown = 0, MouseLeft, MouseMiddle, MouseRight,
MouseWheelUp, MouseWheelDown,
MouseButton1, MouseButton2, MouseButton3, MouseButton4
when defined(Linux):
include window_linux
else:
{.error "Your platform is not supported!".}
type
PWindow* = ref saffron.TWindow
TWindow* = object
impl: TWindowImpl
eventHandler: PEventHandler
PEventHandler* = ref TEventHandler
TEventHandler* = object
eventHandlers: array[TEventType, seq[proc(e: var TEvent){.closure.}]]
keyHandlers: array[bool, array[TKey, proc(){.closure.}]] # true = keydown false = keyup
parent*: PEventHandler
proc newEventHandler*(parent: PEventHandler = nil): PEventHandler
## windows
proc newWindow*(mode: TDisplayMode; style: set[TWindowStyle]): PWindow =
new result
result.impl = newWindowImpl(mode, style)
result.eventHandler = newEventHandler()
#result.eventHandler = newEventHandler()
proc close*(w: PWindow) {.inline.} =
w.impl.destroy()
proc display*(W: PWindow) {.inline.} =
display(W.impl)
proc clear*(W: PWindow, color: TColor4f) =
glClearColor(color) #color.x, color.y, color.z, color.w)
glClear(GL_COLOR_BUFFER_BIT)
## event handling
proc newEventHandler*(parent: PEventHandler = nil): PEventHandler =
new result
result.parent = parent
for i in TEventType:
{.unroll.}
result.eventHandlers[i] = @[]
proc dispatch*(H: PEventHandler; E: var TEvent) =
for f in items(H.eventHandlers[E.kind]): f(E)
if not isNil(H.parent): H.parent.dispatch(E)
iterator pollEvents*(w: PWindow): TEvent =
var events = w.impl.processEvents()
if not events.isNil:
for e in items(events): yield e
iterator pollEvents*(w: PWindow, only: set[TEventType]): TEvent =
var events = w.impl.processEvents()
if not events.isNil:
for e in items(events):
if e.kind in only: yield e
proc dispatchEvents*(w: PWindow) =
var events = w.impl.processEvents()
events.map(proc(some: var TEvent) = w.eventHandler.dispatch(some))
#for i in 0.. < events.len:
# w.eventHandler.dispatch(events[i])
import saffron, os
var w = newWindow((800, 600, 32), {resizable})
var blk = colorf(0, 0, 0)
for i in 0..10:
w.clear(blk)
w.display()
os.sleep 500
blk.x = i/10
w.close()
echo "WHOOO"
import xlib, x, xutil, keysym
type
TWindowImpl = object
screen: cint
context: GLXcontext
window: x.TWindow
display: xlib.PDisplay
#var
# activeContext: GLXcontext
discard """glXQueryExtension*(dpy: PDisplay, errorBase: PGLint, eventBase: PGLint): GLboolean{.
stdcall, importc, oglx.}
"""
proc switchToFullscreen(mode: TDisplayMode) = nil
proc newWindowImpl(mode: TDisplayMode; style: set[TWindowStyle]): TWindowImpl =
result.display = XOpenDisplay(nil)
if result.display.isNil:
echo "Cannot connect to X server!"
return
opengl.loadExtensions()
var err1, err2: cint
echo glxQueryExtension(result.display, addr err1, addr err2)
when false:
echo "X server has no OpenGL GLX!"
return
result.screen = XDefaultScreen(result.display)
var
attributes = [GLint(GLX_RGBA), GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4, None] ##GLX_RGBA), GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, GLX_NONE]
root = xDefaultRootWindow(result.display)
cmap: TColorMap
vinfo: PXVisualInfo
swa: TXSetWindowAttributes
vinfo = glxChooseVisual(result.display, result.screen, addr attributes[0])
cmap = xCreateColormap(result.display, root, vinfo.visual, allocNone)
swa.colormap = cmap
swa.event_mask = KeyPressMask or VisibilityChangeMask or
KeyReleaseMask or ButtonPressMask or ButtonReleaseMask or PointerMotionMask or
StructureNotifyMask or FocusChangeMask ##or ExposureMask
result.window = xCreateWindow(result.display, root, 0, 0, mode.width.cuint, mode.height.cuint,
0, vinfo.depth, x.CopyFromParent, vinfo.visual, CWColorMap or CWEventMask,
addr swa)
echo XMapWindow(result.display, result.window)
##echo XStoreName(dpy, result.window, title)
result.context = glxCreateContext(result.display, vinfo, nil, true)
echo glxMakeCurrent(result.display, result.window, result.context)
glEnable GL_DEPTH_TEST
proc setWindowTitle(w: var TWindowImpl; title: string) =
echo XStoreName(w.display, w.window, cstring(title))
proc setPosition(w: var TWindowImpl; pos: TVector2i) =
echo XMoveWindow(w.display, w.window, pos.x, pos.y)
echo xflush(w.display)
proc getSize(w: var TWindowImpl): TVector2i =
var attributes: TXWindowAttributes
echo XGetWindowAttributes(w.display, w.window, addr attributes)
result.x = attributes.width
result.y = attributes.height
from strutils import toHex
proc getKey(some: TKeysym): TKey =
case some.int32
of XK_Up: return KeyUp
of XK_Down: return KeyDown
of XK_Right: return KeyRight
of XK_Left: return KeyLEft
of XK_KP_0: return KeyNumpad0
of XK_KP_1: return KeyNumpad1
of XK_KP_2: return KeyNumpad2
of XK_KP_3: return KeyNumpad3
of XK_KP_4: return KeyNumpad4
of XK_KP_5: return KeyNumpad5
of XK_KP_6: return KeyNumpad6
of XK_KP_7: return KeyNumpad7
of XK_KP_8: return KeyNumpad8
of XK_KP_9: return KeyNumpad9
of XK_Escape: return KeyEscape
of XK_A, XKC_A: return keyA
of XK_B, XKC_B: return keyB
of XK_C, XKC_C: return keyC
of xk_d, xkc_d: return keyd
of xk_e, xkc_e: return keye
of xk_f, xkc_f: return keyf
of xk_g, xkc_g: return keyg
of xk_h, xkc_h: return keyh
of xk_i, xkc_i: return keyi
of xk_j, xkc_j: return keyj
of xk_k, xkc_K: return keyk
of xk_L, xkc_L: return keyL
of xk_m, xkc_m: return keyM
of xk_n, xkc_n: return keyN
of xk_o, xkc_o: return keyO
of xk_p, xkc_p: return keyP
of xk_q, xkc_q: return keyQ
of xk_r, xkc_r: return keyR
of xk_s, xkc_s: return keyS
of xk_t, xkc_t: return keyT
of xk_u, xkc_u: return KeyU
of xk_v, xkc_v: return keyV
of xk_w, xkc_w: return keyW
of xk_x, xkc_x: return keyX
of xk_y, xkc_y: return keyY
of xk_z, xkc_z: return keyZ
of xk_0, xk_parenright: return Key0
of xk_1, xk_parenleft: return key1
of xk_2: return key2
of xk_3: return key3
of xk_4: return key4
of xk_5: return key5
of xk_6: return key6
of xk_7: return key7
of xk_8: return key8
of xk_9: return key9
of xk_space: return keySpace
of xk_comma, xk_less: return keyComma
of xk_period, xk_greater: return KeyPeriod
of xk_colon: return keyColon
else:
echo "unknown key: ", some, " 0x", toHex(some.biggestINT, 2)
proc getMouseButton(some: cuint): TMouseButton =
case some.int32
of Button1: return MouseLeft
of Button2: return MouseMiddle
of Button3: return MouseRight
of Button4: return MouseWheelUp
of Button5: return MouseWheelDown
of Button5+1: return MouseButton1
of Button5+2: return MouseButton2
of Button5+3: return MouseButton3
of Button5+4: return MouseButton4
else: nil #add more buttons?
proc interpEvent(w: var TWindowImpl; xevent: var TXEvent): TEvent =
case xevent.theType
of KeyPress, KeyRelease:
let k = cast[PXkeyEvent](addr xevent)
result.kind = if xevent.thetype == KeyPress: KeyPressed else: KeyReleased
#result.key = getKey(XKeycodeToKeysym(w.display, k.keycode, 0))
result.key = getKey(XLookupKeysym(k, 0))
echo(repr(result), " ", XLookupKeysym(k, 0))
#echo(repr(k))
of ButtonPress, ButtonRelease:
let b = cast[PXbuttonEvent](addr xevent)
result.kind = if xevent.thetype == ButtonPress: ButtonPressed else: ButtonReleased
result.button = getMouseButton(b.button)
result.at.x = b.x
result.at.y = b.y
echo("Button: ", result.button, "\n\n", repr(result))
of MotionNotify:
let m = cast[PXmotionEvent](addr xevent)
result.kind = MouseMove
result.pos.x = m.x
result.pos.y = m.y
of FocusIn, FocusOut:
#let f = cast[PXfocusChangeEvent](addr xevent)
result.kind = if xevent.thetype == FocusIn: GainedFocus else: LostFocus
of ConfigureNotify:
let c = cast[PXconfigureEvent](addr xevent)
#echo("resize event: ", repr(c))
result.kind = WindowResized
result.size.x = c.x
result.size.y = c.y
else:
#echo "unk event: ", repr(xevent)
##funcifevent* = proc (display: PDisplay, event: PXEvent, p: TXPointer): TBool
proc checkEvent(display: PDisplay; event: PXevent;
p: TXPointer): xlib.TBool {.cdecl.} =
result = xlib.TBool(cast[PXanyEvent](event).window.clong == cast[ptr x.TWindow](p)[].clong)
proc processEvents(w: var TWindowImpl): seq[TEvent] =
var xevent: TXEvent
let p = cast[TXpointer](addr w.window)
while xCheckIfEvent(w.display, addr xevent, checkEvent, p) == 1:
if result.isNil: result = @[]
result.add(interpEvent(w, xevent))
discard """CheckIfEvent*(para1: PDisplay, para2: PXEvent, para3: funcifevent,
para4: TXPointer): TBool{.cdecl, dynlib: libX11, importc.} """
proc display(w: var TWindowImpl) =
if w.window.int != 0:
glxSwapBuffers(w.display, w.window)
proc activate(w: var TWindowImpl) =
if w.context != glxGetCurrentContext(): discard glxMakeCurrent(w.display, w.window, w.context)
# activeContext = w.context
proc destroy(w: var TWindowImpl) =
if not w.context.isNil:
if glxGetCurrentContext() == w.context:
discard glxMakeCurrent(w.display, None, nil)
glxDestroyContext(w.display, w.context)
if w.window.clong != 0.clong:
discard XDestroyWindow(w.display, w.window)
discard XFlush(w.display)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment