123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- # author: Ethosa
- import
- thirdparty/opengl,
- thirdparty/opengl/glu,
- thirdparty/sdl2,
- thirdparty/sdl2/image,
- core/color,
- core/input,
- core/exceptions,
- nodes/node,
- nodes/scene,
- environment,
- strutils,
- unicode,
- os
- when defined(debug):
- import logging
- discard sdl2.init(INIT_EVERYTHING)
- discard glSetAttribute(SDL_GL_DOUBLEBUFFER, 1)
- discard glSetAttribute(SDL_GL_RED_SIZE, 5)
- discard glSetAttribute(SDL_GL_GREEN_SIZE, 6)
- discard glSetAttribute(SDL_GL_BLUE_SIZE, 5)
- var
- env*: EnvironmentRef = newEnvironment()
- width, height: cint
- main_scene*: SceneRef = nil
- current_scene*: SceneRef = nil
- windowptr: WindowPtr
- glcontext: GlContextPtr
- scenes*: seq[SceneRef] = @[]
- paused*: bool = false
- running*: bool = true
- event = sdl2.defaultEvent
- # --- Callbacks --- #
- var
- mouse_on: NodeRef = nil
- window_created: bool = false
- proc display {.cdecl.} =
- ## Displays window.
- glClearColor(env.color.r, env.color.g, env.color.b, env.color.a)
- glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
- glEnable(GL_BLEND)
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
- # Draw current scene.
- current_scene.drawScene(width.GLfloat, height.GLfloat, paused)
- press_state = -1
- mouse_on = nil
- # Update window.
- glFlush()
- windowptr.glSwapWindow()
- os.sleep(env.delay)
- proc reshape(w, h: cint) {.cdecl.} =
- ## This called when window resized.
- if w > 0 and h > 0:
- glViewport(0, 0, w, h)
- glLoadIdentity()
- glMatrixMode(GL_PROJECTION)
- glMatrixMode(GL_MODELVIEW)
- glOrtho(-w.GLdouble/2, w.GLdouble/2, -h.GLdouble/2, h.GLdouble/2, -w.GLdouble, w.GLdouble)
- gluPerspective(45.0, w/h, 1.0, 200.0)
- width = w
- height = h
- if current_scene != nil:
- current_scene.reAnchorScene(w.GLfloat, h.GLfloat, paused)
- template check(event, condition, conditionelif: untyped): untyped =
- if last_event is `event` and `condition`:
- press_state = 2
- elif `conditionelif`:
- press_state = 1
- else:
- press_state = 0
- proc mouse(button, x, y: cint, pressed: bool) {.cdecl.} =
- ## Handle mouse input.
- check(InputEventMouseButton, last_event.pressed and pressed, pressed)
- last_event.button_index = button
- last_event.x = x.float
- last_event.y = y.float
- last_event.kind = MOUSE
- mouse_pressed = pressed
- last_event.pressed = pressed
- current_scene.handleScene(last_event, mouse_on, paused)
- proc wheel(x, y: cint) {.cdecl.} =
- ## Handle mouse wheel input.
- check(InputEventMouseWheel, false, false)
- last_event.kind = WHEEL
- last_event.xrel = x.float
- last_event.yrel = y.float
- current_scene.handleScene(last_event, mouse_on, paused)
- proc keyboardpress(c: cint) {.cdecl.} =
- ## Called when press any key on keyboard.
- if c < 0:
- return
- let key = $c
- check(InputEventKeyboard, last_event.pressed, true)
- last_event.key = key
- last_event.key_int = c
- if key notin pressed_keys:
- pressed_keys.add(key)
- pressed_keys_ints.add(c)
- last_event.kind = KEYBOARD
- last_key_state = key_state
- key_state = true
- current_scene.handleScene(last_event, mouse_on, paused)
- proc textinput(c: TextInputEventPtr) {.cdecl.} =
- ## Called when start text input
- last_event.key = toRunes(join(c.text[0..<32]))[0].toUtf8()
- last_event.kind = TEXT
- last_key_state = key_state
- key_state = true
- current_scene.handleScene(last_event, mouse_on, paused)
- proc keyboardup(c: cint) {.cdecl.} =
- ## Called when any key no more pressed.
- if c < 0:
- return
- let key = $c
- check(InputEventKeyboard, false, false)
- last_event.key = key
- last_event.key_int = c
- last_event.kind = KEYBOARD
- last_key_state = key_state
- key_state = false
- var i = 0
- for k in pressed_keys:
- if k == key:
- pressed_keys.delete(i)
- pressed_keys_ints.delete(i)
- break
- inc i
- current_scene.handleScene(last_event, mouse_on, paused)
- proc motion(x, y: cint) {.cdecl.} =
- ## Called on any mouse motion.
- last_event.kind = MOTION
- last_event.xrel = last_event.x - x.float
- last_event.yrel = last_event.y - y.float
- last_event.x = x.float
- last_event.y = y.float
- current_scene.handleScene(last_event, mouse_on, paused)
- # -------------------- Public -------------------- #
- proc addScene*(scene: SceneRef) =
- ## Adds a new scenes in app.
- ##
- ## Arguments:
- ## - `scene` - pointer to the Scene object.
- if scene notin scenes:
- scenes.add(scene)
- scene.rect_size.x = width.float
- scene.rect_size.y = height.float
- proc addMainScene*(scene: SceneRef) =
- ## Adds a new scene in the app and set it mark it as main scene.
- ##
- ## Arguents:
- ## - `scene` - pointer to the Scene object.
- if scene notin scenes:
- scenes.add(scene)
- main_scene = scene
- proc centeredWindow* =
- var dm: DisplayMode
- discard getCurrentDisplayMode(0, dm)
- windowptr.setPosition((dm.w/2 - width/2).cint, (dm.h/2 - height/2).cint)
- proc changeScene*(name: string, extra: seq[tuple[k: string, v: string]] = @[]): bool {.discardable.} =
- ## Changes current scene.
- ##
- ## Arguments:
- ## - `name` - name of the added scene.
- result = false
- for scene in scenes:
- if scene.name == name:
- if current_scene != nil:
- current_scene.exit()
- current_scene.data = @[]
- current_scene = nil
- current_scene = scene
- current_scene.data = extra
- current_scene.enter()
- current_scene.reAnchorScene(width.GLfloat, height.GLfloat, paused)
- result = true
- break
- when defined(debug):
- debug("result of `changeScene` is ", result)
- proc resizeWindow*(x, y: cint) =
- windowptr.setSize(x, y)
- proc setMainScene*(name: string) =
- ## Set up main scene.
- ##
- ## Arguments:
- ## - `name` - name of the added scene.
- for scene in scenes:
- if scene.name == name:
- main_scene = scene
- break
- proc setTitle*(title: cstring) =
- ## Changes window title.
- if window_created:
- windowptr.setTitle(title)
- else:
- raise newException(WindowError, "Window not launched!")
- proc setIcon*(icon_path: cstring) =
- ## Changes window title.
- if window_created:
- windowptr.setIcon(image.load(icon_path))
- else:
- raise newException(WindowError, "Window not launched!")
- proc Window*(title: cstring, w: cint = 640, h: cint = 360) {.cdecl.} =
- ## Creates a new window pointer
- ##
- ## Arguments:
- ## - `title` - window title.
- # Set up window.
- once:
- when not defined(android) and not defined(ios):
- loadExtensions() # Load OpenGL extensions.
- discard captureMouse(True32)
- windowptr = createWindow(
- title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h,
- SDL_WINDOW_SHOWN or SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE or
- SDL_WINDOW_ALLOW_HIGHDPI or SDL_WINDOW_FOREIGN or SDL_WINDOW_INPUT_FOCUS or SDL_WINDOW_MOUSE_FOCUS)
- glcontext = windowptr.glCreateContext()
- # Set up OpenGL
- glShadeModel(GL_SMOOTH)
- glClear(GL_COLOR_BUFFER_BIT)
- glEnable(GL_COLOR_MATERIAL)
- glMaterialf(GL_FRONT, GL_SHININESS, 15)
- reshape(w, h)
- window_created = true
- proc onReshape(userdata: pointer; event: ptr Event): Bool32 {.cdecl.} =
- if event.kind == WindowEvent:
- case evWindow(event[]).event
- of WindowEvent_Resized, WindowEvent_SizeChanged, WindowEvent_Minimized, WindowEvent_Maximized, WindowEvent_Restored:
- windowptr.getSize(width, height)
- if env.screen_mode == SCREEN_MODE_NONE:
- reshape(width, height)
- display()
- else:
- discard
- False32
- proc windowLaunch* =
- if main_scene.isNil():
- raise newException(SceneError, "Main scene is not indicated!")
- changeScene(main_scene.name)
- when defined(debug):
- info("window launched")
- addEventWatch(onReshape, windowptr)
- while running:
- while sdl2.pollEvent(event):
- case event.kind
- of QuitEvent:
- running = false
- of KeyDown:
- let e = evKeyboard(event)
- keyboardpress(e.keysym.sym)
- of KeyUp:
- let e = evKeyboard(event)
- keyboardup(e.keysym.sym)
- of TextInput:
- let e = text(event)
- textinput(e)
- of MouseMotion:
- let e = evMouseMotion(event)
- motion(e.x, e.y)
- of MouseButtonDown:
- let e = evMouseButton(event)
- mouse(e.button.cint, e.x, e.y, true)
- of MouseButtonUp:
- let e = evMouseButton(event)
- mouse(e.button.cint, e.x, e.y, false)
- of MouseWheel:
- let e = evMouseWheel(event)
- wheel(e.x, e.y)
- else:
- discard
- display()
- current_scene.exit()
- sdl2.glDeleteContext(glcontext)
- sdl2.destroy(windowptr)
- sdl2.quit()
|