window.nim 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. # author: Ethosa
  2. import
  3. thirdparty/opengl,
  4. thirdparty/opengl/glut,
  5. core/color,
  6. core/exceptions,
  7. core/input,
  8. nodes/node,
  9. nodes/scene,
  10. environment
  11. var
  12. cmdLine {.importc: "cmdLine".}: array[0..255, cstring]
  13. cmdCount {.importc: "cmdCount".}: cint
  14. loadExtensions() # Load OpenGL extensions.
  15. glutInit(addr cmdCount, addr cmdLine) # Initializ glut lib.
  16. glutInitDisplayMode(GLUT_DOUBLE)
  17. var
  18. env*: EnvironmentRef = newEnvironment()
  19. width, height: cint
  20. main_scene*: ScenePtr = nil
  21. current_scene*: ScenePtr = nil
  22. scenes*: seq[ScenePtr] = @[]
  23. paused*: bool = false
  24. # --- Callbacks --- #
  25. var mouse_on: NodePtr = nil
  26. proc display {.cdecl.} =
  27. ## Displays window.
  28. let (r, g, b, a) = env.color.toFloatTuple()
  29. glClearColor(r*env.brightness, g*env.brightness, b*env.brightness, a*env.brightness)
  30. glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
  31. glEnable(GL_BLEND)
  32. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
  33. # Draw current scene.
  34. current_scene.drawScene(width.GLfloat, height.GLfloat, paused)
  35. press_state = -1
  36. mouse_on = nil
  37. # Update window.
  38. glFlush()
  39. glutSwapBuffers()
  40. proc reshape(w, h: cint) {.cdecl.} =
  41. ## This called when window resized.
  42. if w > 0 and h > 0:
  43. glViewport(0, 0, w, h)
  44. glMatrixMode(GL_PROJECTION)
  45. glLoadIdentity()
  46. glOrtho(-w.GLdouble/2, w.GLdouble/2, -h.GLdouble/2, h.GLdouble/2, -1, 1)
  47. glMatrixMode(GL_MODELVIEW)
  48. glLoadIdentity()
  49. width = w
  50. height = h
  51. if current_scene != nil:
  52. current_scene.reAnchorScene(w.GLfloat, h.GLfloat, paused)
  53. template check(event, condition, conditionelif: untyped): untyped =
  54. if last_event is `event` and `condition`:
  55. press_state = 2
  56. elif `conditionelif`:
  57. press_state = 1
  58. else:
  59. press_state = 0
  60. proc mouse(button, state, x, y: cint) {.cdecl.} =
  61. ## Handle mouse input.
  62. check(InputEventMouseButton, last_event.pressed and state == GLUT_DOWN, state == GLUT_DOWN)
  63. last_event.button_index = button
  64. last_event.x = x.float
  65. last_event.y = y.float
  66. last_event.kind = MOUSE
  67. mouse_pressed = state == GLUT_DOWN
  68. last_event.pressed = state == GLUT_DOWN
  69. current_scene.handleScene(last_event, mouse_on, paused)
  70. proc keyboardpress(c: int8, x, y: cint) {.cdecl.} =
  71. ## Called when press any key on keyboard.
  72. let key = $c.char
  73. check(InputEventKeyboard, last_event.pressed, true)
  74. last_event.key = key
  75. last_event.key_int = c
  76. last_event.x = x.float
  77. last_event.y = y.float
  78. if key notin pressed_keys:
  79. pressed_keys.add(key)
  80. pressed_keys_ints.add(c)
  81. last_event.kind = KEYBOARD
  82. last_key_state = key_state
  83. key_state = true
  84. current_scene.handleScene(last_event, mouse_on, paused)
  85. proc keyboardup(c: int8, x, y: cint) {.cdecl.} =
  86. ## Called when any key no more pressed.
  87. let key = $c.char
  88. check(InputEventKeyboard, false, false)
  89. last_event.key = key
  90. last_event.key_int = c
  91. last_event.x = x.float
  92. last_event.y = y.float
  93. last_event.kind = KEYBOARD
  94. last_key_state = key_state
  95. key_state = false
  96. var i = 0
  97. for k in pressed_keys:
  98. if k == key:
  99. pressed_keys.delete(i)
  100. pressed_keys_ints.delete(i)
  101. break
  102. inc i
  103. current_scene.handleScene(last_event, mouse_on, paused)
  104. proc motion(x, y: cint) {.cdecl.} =
  105. ## Called on any mouse motion.
  106. last_event.kind = MOTION
  107. last_event.xrel = last_event.x - x.float
  108. last_event.yrel = last_event.y - y.float
  109. last_event.x = x.float
  110. last_event.y = y.float
  111. current_scene.handleScene(last_event, mouse_on, paused)
  112. # ---- Public ---- #
  113. proc addScene*(scene: ScenePtr) =
  114. ## Adds a new scenes in app.
  115. ##
  116. ## Arguments:
  117. ## - `scene` - pointer to the Scene object.
  118. if scene notin scenes:
  119. scenes.add(scene)
  120. proc changeScene*(name: string): bool {.discardable.} =
  121. ## Changes current scene.
  122. ##
  123. ## Arguments:
  124. ## - `name` - name of the added scene.
  125. result = false
  126. for scene in scenes:
  127. if scene.name == name:
  128. if current_scene != nil:
  129. current_scene.exit()
  130. current_scene = nil
  131. current_scene = scene
  132. current_scene.enter()
  133. current_scene.reAnchorScene(width.GLfloat, height.GLfloat, paused)
  134. result = true
  135. break
  136. proc setMainScene*(name: string) =
  137. ## Set up main scene.
  138. ##
  139. ## Arguments:
  140. ## - `name` - name of the added scene.
  141. for scene in scenes:
  142. if scene.name == name:
  143. main_scene = scene
  144. break
  145. proc Window*(title: cstring, w: cint = 640, h: cint = 360) {.cdecl.} =
  146. ## Creates a new window pointer
  147. ##
  148. ## Arguments:
  149. ## - `title` - window title.
  150. # Set up window.
  151. glutInitWindowSize(w, h)
  152. glutInitWindowPosition(100, 100)
  153. let success = glutCreateWindow(title)
  154. # Set up OpenGL
  155. let (r, g, b, a) = env.color.toFloatTuple()
  156. glClearColor(r, g, b, a)
  157. glShadeModel(GL_FLAT)
  158. glClear(GL_COLOR_BUFFER_BIT)
  159. reshape(w, h)
  160. proc windowLaunch* =
  161. ## Start main window loop.
  162. glutDisplayFunc(display)
  163. glutIdleFunc(display)
  164. glutReshapeFunc(reshape)
  165. glutMouseFunc(mouse)
  166. glutKeyboardFunc(keyboardpress)
  167. glutKeyboardUpFunc(keyboardup)
  168. glutMotionFunc(motion)
  169. glutPassiveMotionFunc(motion)
  170. if main_scene == nil:
  171. raise newException(MainSceneNotLoadedError, "Main scene is not indicated!")
  172. changeScene(main_scene.name)
  173. glutMainLoop()
  174. current_scene.exit()