Last active
December 14, 2015 03:18
-
-
Save fowlmouth/5019522 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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