Ethosa пре 3 година
родитељ
комит
02c71db2ba

+ 2 - 2
.github/workflows/test.yml

@@ -60,7 +60,7 @@ jobs:
           for dir in hello_world calculator novel snake screensaver roguelike builder_features; do
             (
               cd "$dir"
-              nim c main.nim
+              nim c -d:debug main.nim
               timeout 2 xvfb-run --auto-servernum --server-num=1 ./main || [ $? -eq ${{ env.TIMEOUT_EXIT_STATUS }} ]
             )
           done
@@ -70,7 +70,7 @@ jobs:
           cd tests
           for file in $(ls -v test*.nim); do
             echo "test: $file"
-            nim c $file
+            nim c -d:debug $file
             timeout 2 xvfb-run --auto-servernum --server-num=1 ./${file%%.nim} || [ $? -eq ${{ env.TIMEOUT_EXIT_STATUS }} ]
           done
         shell: bash

+ 1 - 0
src/nodesnim/nodes/animation_player.nim

@@ -70,6 +70,7 @@ method addState*(self: AnimationPlayerRef, obj: ptr float, states: seq[tuple[tic
 
 method draw*(self: AnimationPlayerRef, w: GLfloat, h: GLfloat) =
   ## This uses in the `window.nim`.
+  {.warning[LockLevel]: off.}
   if self.is_played:
     if self.tick > self.duration:
       self.tick = 0

+ 23 - 13
src/nodesnim/nodes/node.nim

@@ -1,8 +1,6 @@
 # author: Ethosa
 ## Node is the root type of all other nodes.
 import
-  strutils,
-
   ../thirdparty/gl,
 
   ../core/vector2,
@@ -10,7 +8,9 @@ import
   ../core/anchor,
   ../core/input,
 
-  ../private/templates
+  ../private/templates,
+
+  strutils
 {.used.}
 
 
@@ -124,12 +124,13 @@ method getChildIter*(self: NodeRef): seq[NodeRef] {.base.} =
   ## Returns all children iter.
   result = @[]
   for child in self.children:
+    if child.visibility != VISIBLE:
+      continue
     if child notin result:
       result.add(child)
-    if child.children.len() > 0:
-      for node in child.getChildIter():
-        if node notin result:
-          result.add(node)
+    for node in child.getChildIter():
+      if node notin result:
+        result.add(node)
 
 method getNode*(self: NodeRef, path: string): NodeRef {.base.} =
   ## Returns child by `path`
@@ -138,7 +139,7 @@ method getNode*(self: NodeRef, path: string): NodeRef {.base.} =
     current: NodeRef = self
 
   for name in p:
-    if current == nil:
+    if current.isNil():
       break
 
     case name
@@ -169,22 +170,31 @@ method getPauseMode*(self: NodeRef): PauseMode {.base.} =
   ## Calculates pause mode
   result = self.pausemode
   var current = self
-  while result == INHERIT and current.parent != nil:
+  while result == INHERIT and not current.parent.isNil():
     current = current.parent
     result = current.pausemode
 
 method getRootNode*(self: NodeRef): NodeRef {.base.} =
   ## Gets root node.
   result = self
-  while result.parent != nil:
+  while not result.parent.isNil():
     result = result.parent
 
-method insertChild*(self: NodeRef, index: int, node: NodeRef) {.base.} =
-  self.children.insert(node, index)
+method isChildOf*(self, other: NodeRef): bool {.base, inline.} =
+  ## See also `<#isParentOf.e,NodeRef,NodeRef>`_
+  self in other.children
+
+method isEmpty*(self: NodeRef): bool {.base, inline.} =
+  self.children.len() == 0
 
 method isParentOf*(self, other: NodeRef): bool {.base, inline.} =
+  ## See also `<#isChildOf.e,NodeRef,NodeRef>`_
   other in self.children
 
+method insertChild*(self: NodeRef, index: int, node: NodeRef) {.base.} =
+  ## Inserts child in node at `index` position.
+  self.children.insert(node, index)
+
 method handle*(self: NodeRef, event: InputEvent, mouse_on: var NodeRef) {.base.} =
   ## Handles user input.
   ## This used in the Window object.
@@ -247,7 +257,7 @@ method show*(self: NodeRef) {.base.} =
 
 method delete*(self: NodeRef) {.base.} =
   ## Deletes current node.
-  if self.parent != nil:
+  if not self.parent.isNil():
     self.parent.removeChild(self)
   self.removeChildren()
 

+ 0 - 26
src/nodesnim/nodescontrol/scroll.nim

@@ -27,9 +27,6 @@ type
     viewport_x*, viewport_y*: float
     thumb_color*: ColorRef
     back_color*: ColorRef
-    framebuffer*: Gluint
-    texture*: Gluint
-    renderbuffer*: Gluint
   ScrollRef* = ref ScrollObj
 
 
@@ -54,7 +51,6 @@ proc Scroll*(name: string = "Scroll"): ScrollRef =
   result.thumb_color = current_theme~accent
   result.thumb_y_has_mouse = false
   result.thumb_x_has_mouse = false
-  glGenFramebuffers(1, addr result.framebuffer)
   result.mousemode = MOUSEMODE_IGNORE
   result.kind = SCROLL_NODE
 
@@ -80,34 +76,12 @@ method draw*(self: ScrollRef, w, h: GLfloat) =
   let
     x = -w/2 + self.global_position.x
     y = h/2 - self.global_position.y
-  var
-    texture: Gluint
-    rbo: Gluint
-
-  glBindFramebuffer(GL_FRAMEBUFFER, self.framebuffer)
-  glGenTextures(1, addr texture)
-  glBindTexture(GL_TEXTURE_2D, texture)
-  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB.GLint, self.viewport_w.GLint, self.viewport_h.GLint, 0, GL_RGB, GL_UNSIGNED_BYTE, nil)
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR.GLint)
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR.GLint)
-  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0)
-
-  glGenRenderbuffers(1, addr rbo)
-  glBindRenderbuffer(GL_RENDERBUFFER, rbo)
-  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, self.viewport_w.GLint, self.viewport_h.GLint)
-  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo)
-  glBindRenderbuffer(GL_RENDERBUFFER, 0)
-  glBindTexture(GL_TEXTURE_2D, 0)
-
-  if glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE:
-    echo "Error"
 
   self.background.draw(x, y, self.rect_size.x, self.rect_size.y)
 
   # Press
   if self.pressed:
     self.on_press(self, last_event.x, last_event.y)
-  glBindFramebuffer(GL_FRAMEBUFFER, 0)
 
 
 method scrollBy*(self: ScrollRef, x, y: float) {.base.} =

+ 11 - 0
src/nodesnim/private/templates.nim

@@ -424,3 +424,14 @@ template canvasDrawGL*(canvas: untyped): untyped =
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE.GLint)
   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA.GLint, `canvas`.surface.w,  `canvas`.surface.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, `canvas`.surface.pixels)
   glBindTexture(GL_TEXTURE_2D, 0)
+
+
+
+# ----- Window ----- #
+template checkWindowCallback*(event, condition, conditionelif: untyped): untyped =
+  if last_event is `event` and `condition`:
+    press_state = 2
+  elif `conditionelif`:
+    press_state = 1
+  else:
+    press_state = 0

+ 119 - 0
src/nodesnim/private/window_events.nim

@@ -0,0 +1,119 @@
+# author: Ethosa
+import ../thirdparty/sdl2 except Color, glBindTexture
+import
+  ../thirdparty/gl,
+  ../thirdparty/opengl/glu,
+  ../core/input,
+  ../nodes/node,
+  ../nodes/scene,
+  ../environment,
+  templates,
+  strutils,
+  unicode,
+  os
+
+var mouse_on: NodeRef = nil
+
+
+{.push optimization: speed.}
+proc display*(env: EnvironmentRef, current_scene: SceneRef, width, height: cint, paused: bool, windowptr: WindowPtr) =
+  ## Displays window.
+  glClearColor(env.background_color.r, env.background_color.g, env.background_color.b, env.background_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*(current_scene: SceneRef, w, h: var cint, paused: bool) =
+  ## 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)
+
+    if current_scene != nil:
+      current_scene.reAnchorScene(w.GLfloat, h.GLfloat, paused)
+
+proc mouse*(current_scene: SceneRef, button, x, y: cint, pressed, paused: bool) =
+  ## Handle mouse input.
+  checkWindowCallback(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*(current_scene: SceneRef, x, y: cint, paused: bool) =
+  ## Handle mouse wheel input.
+  checkWindowCallback(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*(current_scene: SceneRef, c: cint, paused: bool) =
+  ## Called when press any key on keyboard.
+  if c < 0:
+    return
+  checkWindowCallback(InputEventKeyboard, last_event.pressed, true)
+  last_event.key_int = c
+  if c notin pressed_keys_cint:
+    pressed_keys_cint.add(c)
+  last_event.kind = KEYBOARD
+  last_key_state = key_state
+  key_state = true
+
+  current_scene.handleScene(last_event, mouse_on, paused)
+
+proc textinput*(current_scene: SceneRef, c: TextInputEventPtr, paused: bool) =
+  ## 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*(current_scene: SceneRef, c: cint, paused: bool) =
+  ## Called when any key no more pressed.
+  if c < 0:
+    return
+  checkWindowCallback(InputEventKeyboard, false, false)
+  last_event.key_int = c
+  last_event.kind = KEYBOARD
+  last_key_state = key_state
+  key_state = false
+  for i in pressed_keys_cint.low..pressed_keys_cint.high:
+    if pressed_keys_cint[i] == c:
+      pressed_keys_cint.delete(i)
+      break
+
+  current_scene.handleScene(last_event, mouse_on, paused)
+
+proc motion*(current_scene: SceneRef, x, y, xrel, yrel: cint, paused: bool) =
+  ## Called on any mouse motion.
+  last_event.kind = MOTION
+  last_event.xrel = xrel.float
+  last_event.yrel = yrel.float
+  last_event.x = x.float
+  last_event.y = y.float
+
+  current_scene.handleScene(last_event, mouse_on, paused)
+{.pop.}

+ 17 - 141
src/nodesnim/window.nim

@@ -2,22 +2,14 @@
 import thirdparty/sdl2 except Color, glBindTexture
 import
   thirdparty/gl,
-  thirdparty/opengl/glu,
   thirdparty/sdl2/image,
-
-  core/color,
-  core/input,
   core/exceptions,
   core/vector2,
   core/enums,
-
   nodes/node,
   nodes/scene,
-
-  environment,
-  strutils,
-  unicode,
-  os
+  private/window_events,
+  environment
 when defined(debug):
   import logging
 
@@ -44,123 +36,6 @@ var
   event = sdl2.defaultEvent
 
 
-# --- Callbacks --- #
-var
-  mouse_on: NodeRef = nil
-  window_created: bool = false
-
-proc display {.cdecl.} =
-  ## Displays window.
-  glClearColor(env.background_color.r, env.background_color.g, env.background_color.b, env.background_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
-  check(InputEventKeyboard, last_event.pressed, true)
-  last_event.key_int = c
-  if c notin pressed_keys_cint:
-    pressed_keys_cint.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
-  check(InputEventKeyboard, false, false)
-  last_event.key_int = c
-  last_event.kind = KEYBOARD
-  last_key_state = key_state
-  key_state = false
-  for i in pressed_keys_cint.low..pressed_keys_cint.high:
-    if pressed_keys_cint[i] == c:
-      pressed_keys_cint.delete(i)
-      break
-
-  current_scene.handleScene(last_event, mouse_on, paused)
-
-proc motion(x, y, xrel, yrel: cint) {.cdecl.} =
-  ## Called on any mouse motion.
-  last_event.kind = MOTION
-  last_event.xrel = xrel.float
-  last_event.yrel = yrel.float
-  last_event.x = x.float
-  last_event.y = y.float
-
-  current_scene.handleScene(last_event, mouse_on, paused)
-
-
 
 # -------------------- Public -------------------- #
 
@@ -236,14 +111,14 @@ proc setMainScene*(name: string) =
 
 proc setTitle*(title: cstring) =
   ## Changes window title.
-  if window_created:
+  if not windowptr.isNil():
     windowptr.setTitle(title)
   else:
     throwError(WindowError, "Window not launched!")
 
 proc setIcon*(icon_path: cstring) =
   ## Changes window title.
-  if window_created:
+  if not windowptr.isNil():
     windowptr.setIcon(image.load(icon_path))
   else:
     throwError(WindowError, "Window not launched!")
@@ -273,8 +148,9 @@ proc Window*(title: cstring, w: cint = 640, h: cint = 360) {.cdecl.} =
   glEnable(GL_COLOR_MATERIAL)
   glMaterialf(GL_FRONT, GL_SHININESS, 15)
 
-  reshape(w, h)
-  window_created = true
+  width = w
+  height = h
+  reshape(current_scene, width, height, paused)
 
 
 proc onReshape(userdata: pointer; event: ptr Event): Bool32 {.cdecl.} =
@@ -283,8 +159,8 @@ proc onReshape(userdata: pointer; event: ptr Event): Bool32 {.cdecl.} =
     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()
+        reshape(current_scene, width, height, paused)
+        display(env, current_scene, width, height, paused, windowptr)
     else:
       discard
   False32
@@ -305,28 +181,28 @@ proc windowLaunch* =
         running = false
       of KeyDown:
         let e = evKeyboard(event)
-        keyboardpress(e.keysym.sym)
+        keyboardpress(current_scene, e.keysym.sym, paused)
       of KeyUp:
         let e = evKeyboard(event)
-        keyboardup(e.keysym.sym)
+        keyboardup(current_scene, e.keysym.sym, paused)
       of TextInput:
         let e = text(event)
-        textinput(e)
+        textinput(current_scene, e, paused)
       of MouseMotion:
         let e = evMouseMotion(event)
-        motion(e.x, e.y, e.xrel, e.yrel)
+        motion(current_scene, e.x, e.y, e.xrel, e.yrel, paused)
       of MouseButtonDown:
         let e = evMouseButton(event)
-        mouse(e.button.cint, e.x, e.y, true)
+        mouse(current_scene, e.button.cint, e.x, e.y, true, paused)
       of MouseButtonUp:
         let e = evMouseButton(event)
-        mouse(e.button.cint, e.x, e.y, false)
+        mouse(current_scene, e.button.cint, e.x, e.y, false, paused)
       of MouseWheel:
         let e = evMouseWheel(event)
-        wheel(e.x, e.y)
+        wheel(current_scene, e.x, e.y, paused)
       else:
         discard
-    display()
+    display(env, current_scene, width, height, paused, windowptr)
 
   current_scene.exit()
   sdl2.glDeleteContext(glcontext)

+ 1 - 1
tests/test3.nim

@@ -223,8 +223,8 @@ suite "Work with Control nodes.":
         - GridBox grid:
           call:
             setPadding(2, 4, 8, 16)
-            setRow(3)
             setBackgroundColor(Color(1f, 1f, 1f))
+            setRow(3)
           - ColorRect first(color: Color(0xff6699ff'u32), rect_size: Vector2(100, 200))
           - ColorRect second(color: Color(0xff64ffff'u32))
           - ColorRect third(color: Color(0xffaa00ff'u32))