nvg.lisp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. (cl:defpackage :ocm.nvg
  2. (:use :cl :cffi-c-ref :alexandria)
  3. (:export run))
  4. (cl:in-package :ocm.nvg)
  5. (defun aget (alist key)
  6. (cdr (assoc key alist :test #'equal)))
  7. (defun agets (alist &rest keys)
  8. (reduce #'aget keys :initial-value alist))
  9. (defun agetter (&rest keys)
  10. (lambda (alist)
  11. (apply 'agets alist keys)))
  12. (defun tags (obj)
  13. (let ((tags (ocm.osm::obj-tags obj)))
  14. (when (functionp tags)
  15. (setf tags (funcall tags)
  16. (ocm.osm::obj-tags obj) tags))
  17. tags))
  18. (defun merge-tags (obj parent)
  19. (append obj parent))
  20. (defvar *context* nil "NanoVG Context")
  21. (defvar *window-width* 640.0)
  22. (defvar *window-height* 480.0)
  23. (defvar *frame-width* 640.0)
  24. (defvar *frame-height* 480.0)
  25. (defvar *pixel-ratio* 1.0)
  26. (defvar *scale* 3f0)
  27. (defvar *pos-x* 0f0)
  28. (defvar *pos-y* 0f0)
  29. (defparameter +granularity+ (expt 10 8))
  30. (defun node-x (node)
  31. (float (/ (ocm.osm::node-lat node) +granularity+)))
  32. (defun node-y (node)
  33. (float (/ (ocm.osm::node-lon node) +granularity+)))
  34. (defun render-path (nodes)
  35. (%nvg:begin-path *context*)
  36. (let ((start (car nodes)))
  37. (%nvg:move-to *context* (node-x start) (node-y start))
  38. (loop for node in (cdr nodes)
  39. do (%nvg:line-to *context* (node-x node) (node-y node)))))
  40. (defparameter +highway-color+ '(250 0 0 255))
  41. (defparameter +strokes+
  42. `(
  43. (((:way "highway")) :color ,+highway-color+ :width 10)))
  44. (defun apply-stroke (tags)
  45. (when-let (options (find-match +strokes+ tags :way))
  46. (destructuring-bind (&key color width) options
  47. (when color
  48. (c-with ((n-color %nvg:color))
  49. (%nvg:stroke-color *context* (apply '%nvg:rgba (n-color &) color))))
  50. (when width (%nvg:stroke-width *context* width)))))
  51. (defun render-line (nodes tags)
  52. (render-path nodes)
  53. (apply-stroke tags)
  54. (%nvg:stroke *context*))
  55. (defparameter +water-color+ '(0 0 250 255))
  56. (defparameter +wood-color+ '(0 250 0 255))
  57. (defparameter +fills+
  58. `(
  59. (((nil "natural" "water")) :color ,+water-color+)
  60. (((nil "natural" "scrub")
  61. (nil "natural" "wood")) :color ,+wood-color+)
  62. ))
  63. (defun find-match (query-value tags type)
  64. (loop for (query . value) in query-value
  65. when (ocm.osm::query-match2 query type tags)
  66. do (return value)))
  67. (defun apply-fill (tags)
  68. (when-let (fill (find-match +fills+ tags :way))
  69. (destructuring-bind (&key color paint) fill
  70. (when color
  71. (c-with ((n-color %nvg:color))
  72. (%nvg:fill-color *context* (apply '%nvg:rgba (n-color &) color))))
  73. (when paint))))
  74. (defun render-poly (nodes tags &optional hole)
  75. (render-path nodes)
  76. (%nvg:close-path *context*)
  77. (when hole
  78. (%nvg:path-winding *context* (cffi:foreign-bitfield-value '%nvg:solidity :hole)))
  79. (apply-fill tags)
  80. (%nvg:fill *context*))
  81. (defparameter +closed-lines+
  82. '((:way "highway")))
  83. (defun is-area (nodes tags)
  84. (let ((first (first nodes))
  85. (last (car (last nodes))))
  86. (and first last
  87. (= (if (ocm.osm::obj-p first) (ocm.osm::obj-id first) first)
  88. (if (ocm.osm::obj-p last) (ocm.osm::obj-id last) last))
  89. (not (ocm.osm::query-match2 +closed-lines+ :way tags)))))
  90. (defun render-way (nodes tags)
  91. (if (is-area nodes tags)
  92. (render-poly nodes tags)
  93. (render-path nodes)))
  94. (defun render-multipoly (rel)
  95. (loop for mem in (ocm.osm::rel-memids rel)
  96. for mem-role in (ocm.osm::rel-roles rel)
  97. for mem-type in (ocm.osm::rel-types rel)
  98. when (ocm.osm::way-p mem) ;; skip non-ways
  99. do (render-poly (ocm.osm::way-refs mem)
  100. (merge-tags (tags mem) (tags rel))
  101. (equal "inner" mem-role))))
  102. (defun render-objects (objects)
  103. (loop for obj in objects
  104. do (typecase obj
  105. (ocm.osm::way
  106. (render-way (ocm.osm::way-refs obj) (tags obj)))
  107. (ocm.osm::rel
  108. (when (equal (aget (tags obj) "type")
  109. "multipolygon")
  110. (render-multipoly obj))))))
  111. (defun render ()
  112. (%nvg:begin-frame *context* *window-width* *window-height* *pixel-ratio*)
  113. (%nvg:transform *context* *scale* 0f0 0f0 *scale* *pos-x* *pos-y*)
  114. (render-objects ocm.osm::+water+)
  115. (%nvg:begin-path *context*)
  116. (%nvg:rect *context* 0f0 0f0 120f0 30f0)
  117. (c-with ((color %nvg:color))
  118. (%nvg:fill-color *context* (%nvg:rgba (color &)
  119. (round (* 127.5 (+ 1 (sin (* 2 (%glfw:get-time))))))
  120. 192 192 255)))
  121. (%nvg:fill *context*)
  122. (%nvg:end-frame *context*)
  123. )
  124. (defparameter +translate-step+ 10f0)
  125. (defparameter +scale-step+ 0.1)
  126. (glfw:define-key-callback on-keys (window key scancode action mod-keys)
  127. (declare (ignorable window key scancode action mod-keys))
  128. (format t "KEY: ~{~A ~}~%" (list key scancode action mod-keys))
  129. (when (eql action %glfw:+press+)
  130. (cond
  131. ((or
  132. (eql key %glfw:+key-escape+)
  133. (eql key %glfw:+key-q+))
  134. (%glfw:set-window-should-close window %glfw:+true+))
  135. ((eql key %glfw:+key-left+) (decf *pos-x* +translate-step+))
  136. ((eql key %glfw:+key-right+) (incf *pos-x* +translate-step+))
  137. ((eql key %glfw:+key-up+) (decf *pos-y* +translate-step+))
  138. ((eql key %glfw:+key-down+) (incf *pos-y* +translate-step+))
  139. ((eql key %glfw:+key-minus+) (decf *scale* +scale-step+))
  140. ((eql key %glfw:+key-equal+) (incf *scale* +scale-step+))))
  141. (print (list *scale* *pos-x* *pos-y*)))
  142. (glfw:define-framebuffer-size-callback on-fb-size (window width height)
  143. (declare (ignorable window))
  144. (setf *frame-width* (float width)
  145. *frame-height* (float height)
  146. *pixel-ratio* (/ *frame-width* *window-width*)))
  147. (glfw:define-window-size-callback on-win-size (window width height)
  148. (declare (ignorable window))
  149. (setf *window-width* (float width)
  150. *window-height* (float height)
  151. *pixel-ratio* (/ *frame-width* *window-width*)))
  152. (Defun create-window ()
  153. (if (uiop:featurep :bodge-gl2)
  154. (glfw:with-window-hints ((%glfw:+context-version-major+ 2)
  155. (%glfw:+context-version-minor+ 1)
  156. (%glfw:+depth-bits+ 24)
  157. (%glfw:+stencil-bits+ 8))
  158. (%glfw:create-window 640 480 "Hello NanoVG 2" nil nil))
  159. (glfw:with-window-hints ((%glfw:+context-version-major+ 3)
  160. (%glfw:+context-version-minor+ 3)
  161. (%glfw:+opengl-profile+ %glfw:+opengl-core-profile+)
  162. (%glfw:+opengl-forward-compat+ %glfw:+true+)
  163. (%glfw:+depth-bits+ 24)
  164. (%glfw:+stencil-bits+ 8))
  165. (%glfw:create-window 640 480 "Hello NanoVG 3" nil nil))))
  166. (defun main ()
  167. ;; Initializing window and OpenGL context
  168. (glfw:with-init ()
  169. (c-let ((window %glfw:window :from (create-window))
  170. (width :int :alloc t)
  171. (height :int :alloc t))
  172. (when (cffi:null-pointer-p (window &))
  173. (%glfw:terminate)
  174. (error "Failed to create GLFW window"))
  175. (%glfw:make-context-current (window &))
  176. ;; Mangling GL function pointers
  177. (glad:init)
  178. ;; Set event callbacks
  179. (%glfw:set-key-callback (window &) (cffi:callback on-keys))
  180. (%glfw:set-framebuffer-size-callback (window &) (cffi:callback on-fb-size))
  181. (%glfw:set-window-size-callback (window &) (cffi:callback on-win-size))
  182. ;; Get initial values
  183. (%glfw:get-framebuffer-size (window &) (width &) (height &))
  184. (setf *frame-width* (float width)
  185. *frame-height* (float height))
  186. (%glfw:get-window-size (window &) (width &) (height &))
  187. (setf *window-width* (float width)
  188. *window-height* (float height)
  189. *pixel-ratio* (/ *frame-width* *window-width*))
  190. ;; reset
  191. (setf *scale* 1f0
  192. *pos-x* 0f0
  193. *pos-y* 0f0)
  194. ;; Creating NanoVG context
  195. (let ((*context* (nvg:make-context)))
  196. (unwind-protect
  197. (loop while (= (%glfw:window-should-close (window &)) 0) do
  198. (gl:clear-color 1f0 1f0 1f0 1f0)
  199. (gl:clear :color-buffer-bit :depth-buffer-bit :stencil-buffer-bit)
  200. ;; Actually drawing into nanovg context and onto display
  201. (render)
  202. (%glfw:swap-buffers (window &))
  203. (%glfw:poll-events))
  204. ;; Cleaning up NanoVG context
  205. (nvg:destroy-context *context*))))))
  206. (defun run ()
  207. (main)
  208. ;; (trivial-main-thread:with-body-in-main-thread (:blocking t)
  209. ;; (float-features:with-float-traps-masked t
  210. ;; (main)))
  211. )