This is as stable as we're going to get for a while. Still some freeze event, possibly a deadlock, but it's working.

(proclaim '(optimize (speed 0) (safety 3) (debug 3)))

(declaim #+sbcl(sb-ext:muffle-conditions style-warning))
(declaim #+sbcl(sb-ext:muffle-conditions warning))

(ql:quickload '(alexandria iterate anaphora cl-cairo2 cl-cairo2-xlib cl-pango) :silent t)

(defpackage arboreta
  (:use cl iterate anaphora cl-cairo2))

(in-package cl-cairo2)

(defcstruct xbuttonevent
  (type :int)
  (serial :unsigned-long)
  (send-event bool)
  (display display)
  (window window)
  (root window)
  (subwindow window)
  (time :long)
  (x :int)
  (y :int)
  (x-root :int)
  (y-root :int)
  (state :int)
  (button :int))

(defcstruct xkeyevent
  (type :int)
  (serial :unsigned-long)
  (send-event bool)
  (display display)
  (window window)
  (root window)
  (subwindow window)
  (time :long)
  (x :int)
  (y :int)
  (x-root :int)
  (y-root :int)
  (state :int)
  (keycode :int))

(defcfun ("XKeycodeToKeysym" xkeycode->keysym) :int
  (display display)
  (keycode :int)
  (index :int))

(defcfun ("XKeysymToString" xkeysym->string) :string
  (keysym :int))

(defcfun ("XPending" xpending) :int
  (display display))

(defun refresh (xlib-image-context)
   (with-slots (context (display-pointer display) dest-surface) xlib-image-context
      (cairo_paint (xlib-context xlib-image-context))
      (cairo_surface_flush dest-surface)
      ))

(defparameter initialization-done? nil)

(defun handle-event (xlib-image-context)
   (with-foreign-object (xev :long 24)
     ;; get next event
     (with-slots (display) xlib-image-context
        (if (> (xpending display) 0)
            (xnextevent display xev)
            (return-from handle-event nil)))
     ;; decipher structure, at least partially
     (with-foreign-slots ((type window serial) xev xanyevent)
       ;; action based on event type
       (cond
         ;; expose events
         ((and (= type 12))
          ;; (refresh xlib-image-context)
          nil)
         ;; clientnotify event
         ((= type 33)
          nil)
         ;; key press and release events
         ;; remember to update cursor position from here as well
         ((or (= type 2)) ;; type 3 for release
          (with-foreign-slots ((state keycode x y) xev xkeyevent)
            (let ((code
               (with-slots (display) xlib-image-context
                  (xkeycode->keysym display keycode state))))
              (alexandria::appendf arboreta::*key-events*
                 (list (if (zerop code)
                           (arboreta::make-keypress :mods state
                                                    :code (with-slots (display) xlib-image-context
                                                             (xkeycode->keysym display keycode 0))
                                                    :str nil)
                           (arboreta::make-keypress :mods state
                                                    :code code
                                                    :str (xkeysym->string code)))))))))
      t)))

(defun default-event-handling (xlib-image-context)
   (loop (handle-event xlib-image-context)))

(defparameter event-handling-function #'default-event-handling)

(defun start-event-loop (xlib-image-context width height window-name)
   (finish-output)
   (call-xinitthreads)
   (bind (((:slots display signal-window (this-window window)
                   wm-delete-window pointer graphics-context
                   xlib-context dest-surface)
           xlib-image-context)
          (screen (xdefaultscreen display))
          (root (xdefaultrootwindow display))
          (visual (xdefaultvisual display screen))
          (whitepixel (xwhitepixel display screen))
          (wm-protocols (xinternatom display "WM_PROTOCOLS" 1)))
         ;; we sync everything for initialization
         (xsynchronize display 1)
         ;; create signal window and window
         (setf this-window
               (create-window display root width height 'inputoutput
                              visual whitepixel
                              (logior exposuremask
                                      keypressmask
                                      keyreleasemask
                                      structurenotifymask)
                              t))
         (setf signal-window
               (create-window display root 1 1 'inputonly visual
                              whitepixel 0 nil))
         ;; create graphics-context
         (setf graphics-context
               (xcreategc display this-window 0 (null-pointer)))
         ;; set size hints on window (hoping that window managers will
         ;; respect this)
         (set-window-size-hints display this-window width width height height)
         ;; intern atom for window closing, set protocol on window
         (setf wm-delete-window (xinternatom display "WM_DELETE_WINDOW" 1))
         (with-foreign-object (prot 'xatom)
           (setf (mem-aref prot 'xatom) wm-delete-window)
           (xsetwmprotocols display this-window prot 1))
         ;; store name
         (xstorename display this-window window-name)
         ;; first we create an X11 surface and context on the window
         (let ((xlib-surface (cairo_xlib_surface_create display this-window visual width height)))
           (setf xlib-context (cairo_create xlib-surface))
           (setf dest-surface xlib-surface))
         ;; create cairo surface, then context, then set the
         ;; surface as the source of the xlib-context
         (let ((surface (cairo_image_surface_create :CAIRO_FORMAT_RGB24 width height)))
           (setf pointer (cairo_create surface))
           (cairo_set_source_surface xlib-context surface 0 0))
         ;; map window
         (xmapwindow display this-window)
         ;; end of synchronizing
         (xsynchronize display 0)
         ;; end of initialization
         (setf initialization-done? t)
         ;; EVENT LOOP
         (funcall event-handling-function xlib-image-context)
         )
   ;; close down everything
   (with-slots (display pixmap window signal-window pointer xlib-context dest-surface) xlib-image-context
     (xsynchronize display 1)
     (let ((saved-pointer pointer))
           (setf pointer nil) ; invalidate first so it can't be used
           (cairo_destroy saved-pointer))
     (cairo_surface_destroy dest-surface)
     (cairo_destroy xlib-context)
     ;; !! free xlib-context, surface
     (xdestroywindow display window)
     (xdestroywindow display signal-window)
     (xclosedisplay display)))

(defun create-arboreta-window (width height &key (background-color +white+))
  (let ((display (xopendisplay (null-pointer)))
        (window-name (next-xlib-image-context-name)))
        (when (null-pointer-p display)
              (error "couldn't open display"))
        (let ((xlib-image-context
                (make-instance 'xlib-image-context
                   :display display
                   :width width
                   :height height
                   :pixel-based-p t
                   :background-color background-color)))
      ;; start event loop thread
      (setf (slot-value xlib-image-context 'thread)
         (sb-thread:make-thread #'start-event-loop
                 :name (format nil "thread for display")
                 :arguments (list xlib-image-context width height window-name)))
      ;; wait for initialization to finish
      (loop until initialization-done?)
      ;; paint it if we are given a background color
      (when background-color
            (set-source-color background-color xlib-image-context)
            (paint xlib-image-context)
            (sync xlib-image-context))
      ;; return context
      xlib-image-context)))

(in-package arboreta)

;; TODO & NOTES
;; find a way to fix the screen tearing issue
;; can we blit windows, or do they just have to be redrawn?
;; does normal pango layouts allow for smooth scolling?
;; text selection is going to be really weird, if implemented
;;   can we pull the font height from pango or fc for highlighting?
;;   how do we change the cursor to the text selection one?
;;     do we even have a cursor in wm mode?
;;   "worse is better" solution
;;     use internal clipboard, disregard people trying to use the applications by themselves
;;   alternative ("the right thing") solutions
;;     try to interface with x font rendering
;;       that means the main clipboard would need to be used
;;       using cl-x, probably
;;     switch platforms -- low preference

(defstruct keypress mods code str)
(defparameter *key-events* nil)

(defparameter context nil)
(defparameter surface nil)
(defparameter layout nil)
(defparameter font nil)

(defparameter w 600)
(defparameter h 400)

(defstruct window
   (attributes (make-hash-table :test #'eq))
   (draw nil))

(defun draw (window)
   (funcall (window-draw window) window))

(defun draw-subwindows (window)
   (awhen (gethash 'subwindows (window-attributes window))
          (iter (for x in it)
                (draw x))))

(defparameter root-window
   (make-window :draw
      (lambda (window)
         (new-path)
         (set-source-rgb 37/255 46/255 50/255)
         (rectangle 0 0 w h)
         (fill-path)
         (draw-subwindows window))))

(defun add-as-subwindow (source-window target-window)
   (push source-window (gethash 'subwindows (window-attributes target-window))))

(defun pango-update ()
   (pango:pango_cairo_update_layout (slot-value *context* 'cairo::pointer) layout)
   (pango:pango_cairo_show_layout (slot-value *context* 'cairo::pointer) layout))

(defun flush-surface ()
   (cairo::refresh context))

(defun window-update-loop ()
   (iter (for x = (+ (get-internal-real-time) 16))
         (draw root-window)
         (cairo::refresh context)
         (sleep (let ((delay (/ (- x (get-internal-real-time)) 1000)))
                      ;; (print (* 1000.0 delay))
                      (if (> delay 0) delay 0)))))

(defun repl-update-loop ()
   (iter (for x = (+ (get-internal-real-time) 16))
         (draw root-window)
         (when *buffer-needs-update*
            (cairo::refresh context)
            (setf *buffer-needs-update* nil))
         (sleep (let ((delay (/ (- x (get-internal-real-time)) 1000)))
                      ;; (print (* 1000.0 delay))
                      (if (> delay 0) delay 0)))))

(defun unicode-test ()
   (setf layout (pango:pango_cairo_create_layout (slot-value cairo:*context* 'cairo::pointer)))
   (setf font (pango:pango_font_description_from_string "Fantasque sans mono 10"))
   (pango:pango_layout_set_font_description layout font)

   (set-source-rgb 37/255 46/255 50/255)
   (rectangle 0 0 w h)
   (fill-path)
   (new-path)
   (move-to 0 0)
   (set-source-rgb 148/255 163/255 165/255)

   (pango:pango_layout_set_text layout
     (format nil "~{~a~%~}"
       '("Hello, glorious pango text rendering!"
         "いあだ〜〜ずかしいです〜〜"
         "Τη γλώσσα μου έδωσαν ελληνική"
         "ᚠᛇᚻ᛫ᛒᛦᚦ᛫ᚠᚱᚩᚠᚢᚱ᛫ᚠᛁᚱᚪ᛫ᚷᛖᚻᚹᛦᛚᚳᚢᛗ"
         "ಬಾ ಇಲ್ಲಿ ಸಂಭವಿಸು ಇಂದೆನ್ನ ಹೃದಯದಲಿ "
         "मैं काँच खा सकता हूँ और मुझे उससे कोई चोट नहीं पहुंचती "))
     -1)

   (pango-update)
   (flush-surface))

(defparameter raven "Once upon a midnight dreary, while I pondered, weak and weary...")

;; you might not have this font, change it to a good non-bitmap monospaced font you do have.
(defun update-test ()
   (setf layout (pango:pango_cairo_create_layout (slot-value cairo:*context* 'cairo::pointer)))
   (setf font (pango:pango_font_description_from_string "Fantasque sans mono 10"))
   (pango:pango_layout_set_font_description layout font)

   (iter (for x from 0 to (length raven))
         (set-source-rgb 37/255 46/255 50/255)
         (rectangle 0 0 w h)
         (fill-path)
         (new-path)
         (move-to 0 0)
         (set-source-rgb 148/255 163/255 165/255)
         (pango:pango_layout_set_text layout (subseq raven 0 x) -1)
         (pango-update)
         (flush-surface)
         (sleep 0.1)))

(defparameter index 0)
(defparameter timer 0)

(defun windowing-test ()
   (setf layout (pango:pango_cairo_create_layout (slot-value cairo:*context* 'cairo::pointer)))
   (setf font (pango:pango_font_description_from_string "Blueberry 10"))
   (pango:pango_layout_set_font_description layout font)

   (sb-thread:make-thread 'handle-key-events-test :name "keyevents-thread")

   (add-as-subwindow
      (make-window :draw
         (lambda (window)
            (incf timer)
            (new-path)
            (set-source-rgb 47/255 56/255 60/255)
            (rectangle 20 (+ 20 (* 0.7 h (sin (/ timer 10)))) (- w 40) (- h 40))
            (fill-path)

            (new-path)
            (move-to 20 (+ 20 (* 0.7 h (sin (/ timer 10)))))
            (set-source-rgb 148/255 163/255 165/255)
            (if (< index (length raven)) (incf index))
            (pango:pango_layout_set_text layout (subseq raven 0 index) -1)
            (pango-update)

            (draw-subwindows window)))
      root-window)
   (window-update-loop))

(defparameter *typing-buffer* "")

(defun buffer-append (str)
   (setf *typing-buffer* (concatenate 'string *typing-buffer* str)))

(defun handle-key-events-test ()
   (iter
      (if *key-events*
         (let ((kev (pop *key-events*)))
               (print kev)
               (when (and (eql (keypress-code kev) 113) (eql (keypress-mods kev) 4))
                     (cairo:destroy context)
                     (sb-ext:exit))
               (alexandria::switch ((keypress-str kev) :test #'equalp)
                  ("Return" (buffer-append (format nil "~%")))
                  ("Shift_L" nil)
                  ("Control_L" nil)
                  ("Control_R" nil)
                  ("Shift_R" nil)
                  ("BackSpace" (when (> (length *typing-buffer*) 0)
                                     (setf *typing-buffer* (subseq *typing-buffer* 0 (- (length *typing-buffer*) 1)))))
                  (otherwise (buffer-append (if (> (length (keypress-str kev)) 1)
                                                (string (code-char (keypress-code kev)))
                                                (keypress-str kev)))))))))

(defun typing-test ()
   (setf layout (pango:pango_cairo_create_layout (slot-value cairo:*context* 'cairo::pointer)))
   (setf font (pango:pango_font_description_from_string "Fantasque Sans Mono 10"))
   (pango:pango_layout_set_font_description layout font)

   (sb-thread:make-thread 'handle-key-events-test :name "keyevents-thread")

   (add-as-subwindow
      (make-window :draw
         (lambda (window)
            (new-path)
            (set-source-rgb 47/255 56/255 60/255)
            (rectangle 20 20 (- w 40) (- h 40))
            (fill-path)

            (new-path)
            (move-to 20 20)
            (set-source-rgb 148/255 163/255 165/255)
            (pango:pango_layout_set_text layout *typing-buffer* -1)
            (pango-update)

            (draw-subwindows window)))
      root-window)
   (window-update-loop))

(defparameter *repl-buffer* "> ")
(defparameter *current-input* "")

(defparameter *buffer-needs-update* t)

(defun repl-append (str)
   (setf *repl-buffer* (concatenate 'string *repl-buffer* str))
   (setf *current-input* (concatenate 'string *current-input* str)))

(defun handle-repl-key-events ()
   (iter
      (if *key-events*
         (let ((kev (pop *key-events*)))
               ;; (print kev)
               (setf *buffer-needs-update* t)
               (when (and (eql (keypress-code kev) 113) (eql (keypress-mods kev) 4))
                     (cairo:destroy context)
                     (sb-ext:exit))
               (alexandria::switch ((keypress-str kev) :test #'equalp)
                  ("Return" (repl-append (format nil "~%~a~%> " (ignore-errors (eval (read-from-string *current-input*)))))
                            (finish-output)
                            (setf *current-input* ""))
                  ("Shift_L" nil)
                  ("Control_L" nil)
                  ("Control_R" nil)
                  ("Shift_R" nil)
                  ("BackSpace" (when (> (length *current-input*) 0)
                                     (setf *current-input* (subseq *current-input* 0 (- (length *current-input*) 1)))
                                     (setf *repl-buffer* (subseq *repl-buffer* 0 (- (length *repl-buffer*) 1)))))
                  (otherwise (repl-append (if (> (length (keypress-str kev)) 1)
                                                (string (code-char (keypress-code kev)))
                                                (keypress-str kev)))))))))

(defun repl-test ()
   (setf layout (pango:pango_cairo_create_layout (slot-value cairo:*context* 'cairo::pointer)))
   (setf font (pango:pango_font_description_from_string "Fantasque Sans Mono 10"))
   (pango:pango_layout_set_font_description layout font)

   (sb-thread:make-thread 'handle-repl-key-events :name "keyevents-thread")

   (add-as-subwindow
      (make-window :draw
         (lambda (window)
            (when *buffer-needs-update*
               (new-path)
               (set-source-rgb 47/255 56/255 60/255)
               (rectangle 20 20 (- w 40) (- h 40))
               (fill-path)

               (new-path)
               (move-to 20 20)
               (set-source-rgb 148/255 163/255 165/255)
               (pango:pango_layout_set_text layout *repl-buffer* -1)
               (pango-update)
               )

            (setf *last-length* (length *repl-buffer*))
            (draw-subwindows window)))
      root-window)
   (repl-update-loop))

(proclaim '(optimize (speed 0) (safety 3) (debug 3)))

(declaim #+sbcl(sb-ext:muffle-conditions style-warning))
(declaim #+sbcl(sb-ext:muffle-conditions warning))

(ql:quickload '(alexandria iterate anaphora cl-cairo2 cl-cairo2-xlib cl-pango) :silent t)

(defpackage arboreta
  (:use cl iterate anaphora cl-cairo2))

(in-package cl-cairo2)

(defcstruct xbuttonevent
  (type :int)
  (serial :unsigned-long)
  (send-event bool)
  (display display)
  (window window)
  (root window)
  (subwindow window)
  (time :long)
  (x :int)
  (y :int)
  (x-root :int)
  (y-root :int)
  (state :int)
  (button :int))

(defcstruct xkeyevent
  (type :int)
  (serial :unsigned-long)
  (send-event bool)
  (display display)
  (window window)
  (root window)
  (subwindow window)
  (time :long)
  (x :int)
  (y :int)
  (x-root :int)
  (y-root :int)
  (state :int)
  (keycode :int))

(defcfun ("XKeycodeToKeysym" xkeycode->keysym) :int
  (display display)
  (keycode :int)
  (index :int))

(defcfun ("XKeysymToString" xkeysym->string) :string
  (keysym :int))

(defcfun ("XPending" xpending) :int
  (display display))

(defun refresh (xlib-image-context)
   (with-slots (context (display-pointer display) dest-surface) xlib-image-context
      (cairo_paint (xlib-context xlib-image-context))
      (cairo_surface_flush dest-surface)
      ))

(defparameter initialization-done? nil)

(defun handle-event (xlib-image-context)
   (with-foreign-object (xev :long 24)
     ;; get next event
     (with-slots (display) xlib-image-context
        (if (> (xpending display) 0)
            (xnextevent display xev)
            (return-from handle-event nil)))
     ;; decipher structure, at least partially
     (with-foreign-slots ((type window serial) xev xanyevent)
       ;; action based on event type
       (cond
         ;; expose events
         ((and (= type 12))
          ;; (refresh xlib-image-context)
          nil)
         ;; clientnotify event
         ((= type 33)
          nil)
         ;; key press and release events
         ;; remember to update cursor position from here as well
         ((or (= type 2)) ;; type 3 for release
          (with-foreign-slots ((state keycode x y) xev xkeyevent)
            (let ((code
               (with-slots (display) xlib-image-context
                  (xkeycode->keysym display keycode state))))
              (alexandria::appendf arboreta::*key-events*
                 (list (if (zerop code)
                           (arboreta::make-keypress :mods state
                                                    :code (with-slots (display) xlib-image-context
                                                             (xkeycode->keysym display keycode 0))
                                                    :str nil)
                           (arboreta::make-keypress :mods state
                                                    :code code
                                                    :str (xkeysym->string code)))))))))
      t)))

(defun default-event-handling (xlib-image-context)
   (loop (handle-event xlib-image-context)))

(defparameter event-handling-function #'default-event-handling)

(defun start-event-loop (xlib-image-context width height window-name)
   (finish-output)
   (call-xinitthreads)
   (bind (((:slots display signal-window (this-window window)
                   wm-delete-window pointer graphics-context
                   xlib-context dest-surface)
           xlib-image-context)
          (screen (xdefaultscreen display))
          (root (xdefaultrootwindow display))
          (visual (xdefaultvisual display screen))
          (whitepixel (xwhitepixel display screen))
          (wm-protocols (xinternatom display "WM_PROTOCOLS" 1)))
         ;; we sync everything for initialization
         (xsynchronize display 1)
         ;; create signal window and window
         (setf this-window
               (create-window display root width height 'inputoutput
                              visual whitepixel
                              (logior exposuremask
                                      keypressmask
                                      keyreleasemask
                                      structurenotifymask)
                              t))
         (setf signal-window
               (create-window display root 1 1 'inputonly visual
                              whitepixel 0 nil))
         ;; create graphics-context
         (setf graphics-context
               (xcreategc display this-window 0 (null-pointer)))
         ;; set size hints on window (hoping that window managers will
         ;; respect this)
         (set-window-size-hints display this-window width width height height)
         ;; intern atom for window closing, set protocol on window
         (setf wm-delete-window (xinternatom display "WM_DELETE_WINDOW" 1))
         (with-foreign-object (prot 'xatom)
           (setf (mem-aref prot 'xatom) wm-delete-window)
           (xsetwmprotocols display this-window prot 1))
         ;; store name
         (xstorename display this-window window-name)
         ;; first we create an X11 surface and context on the window
         (let ((xlib-surface (cairo_xlib_surface_create display this-window visual width height)))
           (setf xlib-context (cairo_create xlib-surface))
           (setf dest-surface xlib-surface))
         ;; create cairo surface, then context, then set the
         ;; surface as the source of the xlib-context
         (let ((surface (cairo_image_surface_create :CAIRO_FORMAT_RGB24 width height)))
           (setf pointer (cairo_create surface))
           (cairo_set_source_surface xlib-context surface 0 0))
         ;; map window
         (xmapwindow display this-window)
         ;; end of synchronizing
         (xsynchronize display 0)
         ;; end of initialization
         (setf initialization-done? t)
         ;; EVENT LOOP
         (funcall event-handling-function xlib-image-context))
   ;; close down everything
   (with-slots (display pixmap window signal-window pointer xlib-context dest-surface) xlib-image-context
     (xsynchronize display 1)
     (let ((saved-pointer pointer))
           (setf pointer nil) ; invalidate first so it can't be used
           (cairo_destroy saved-pointer))
     (cairo_surface_destroy dest-surface)
     (cairo_destroy xlib-context)
     ;; !! free xlib-context, surface
     (xdestroywindow display window)
     (xdestroywindow display signal-window)
     (xclosedisplay display)))

(defun create-arboreta-window (width height &key (background-color +white+))
  (let ((display (xopendisplay (null-pointer)))
        (window-name (next-xlib-image-context-name)))
        (when (null-pointer-p display)
              (error "couldn't open display"))
        (let ((xlib-image-context
                (make-instance 'xlib-image-context
                   :display display
                   :width width
                   :height height
                   :pixel-based-p t
                   :background-color background-color)))
      ;; start event loop thread
      (setf (slot-value xlib-image-context 'thread)
         (sb-thread:make-thread #'start-event-loop
                 :name (format nil "thread for display")
                 :arguments (list xlib-image-context width height window-name)))
      ;; wait for initialization to finish
      (loop until initialization-done?)
      ;; paint it if we are given a background color
      (when background-color
            (set-source-color background-color xlib-image-context)
            (paint xlib-image-context)
            (sync xlib-image-context))
      ;; return context
      xlib-image-context)))

(in-package arboreta)

;; TODO & NOTES
;; find a way to fix the screen tearing issue
;; can we blit windows, or do they just have to be redrawn?
;; does normal pango layouts allow for smooth scolling?
;; text selection is going to be really weird, if implemented
;;   can we pull the font height from pango or fc for highlighting?
;;   how do we change the cursor to the text selection one?
;;     do we even have a cursor in wm mode?
;;   "worse is better" solution
;;     use internal clipboard, disregard people trying to use the applications by themselves
;;   alternative ("the right thing") solutions
;;     try to interface with x font rendering
;;       that means the main clipboard would need to be used
;;       using cl-x, probably
;;     switch platforms -- low preference

(defstruct keypress mods code str)
(defparameter *key-events* nil)

(defparameter context nil)
(defparameter surface nil)
(defparameter layout nil)
(defparameter font nil)

(defparameter w 600)
(defparameter h 400)

(defstruct window
   (attributes (make-hash-table :test #'eq))
   (draw nil))

(defun draw (window)
   (funcall (window-draw window) window))

(defun draw-subwindows (window)
   (awhen (gethash 'subwindows (window-attributes window))
          (iter (for x in it)
                (draw x))))

(defparameter root-window
   (make-window :draw
      (lambda (window)
         (new-path)
         (set-source-rgb 37/255 46/255 50/255)
         (rectangle 0 0 w h)
         (fill-path)
         (draw-subwindows window))))

(defun add-as-subwindow (source-window target-window)
   (push source-window (gethash 'subwindows (window-attributes target-window))))

(defun pango-update ()
   (pango:pango_cairo_update_layout (slot-value *context* 'cairo::pointer) layout)
   (pango:pango_cairo_show_layout (slot-value *context* 'cairo::pointer) layout))

(defun flush-surface ()
   (cairo::refresh context))

(defun window-update-loop ()
   (iter (for x = (+ (get-internal-real-time) 16)) ;; 33 -> 30 FPS, 16 -> 60 FPS

         (draw root-window)

         (cairo::refresh context)

         ;; (iter (while (cairo::handle-event context)))

         (sleep (let ((delay (/ (- x (get-internal-real-time)) 1000)))
                      ;; (print (* 1000.0 delay))
                      (if (> delay 0) delay 0)))))

(defun unicode-test ()
   (setf layout (pango:pango_cairo_create_layout (slot-value cairo:*context* 'cairo::pointer)))
   (setf font (pango:pango_font_description_from_string "Fantasque sans mono 10"))
   (pango:pango_layout_set_font_description layout font)

   (set-source-rgb 37/255 46/255 50/255)
   (rectangle 0 0 w h)
   (fill-path)
   (new-path)
   (move-to 0 0)
   (set-source-rgb 148/255 163/255 165/255)

   (pango:pango_layout_set_text layout
     (format nil "~{~a~%~}"
       '("Hello, glorious pango text rendering!"
         "いあだ〜〜ずかしいです〜〜"
         "Τη γλώσσα μου έδωσαν ελληνική"
         "ᚠᛇᚻ᛫ᛒᛦᚦ᛫ᚠᚱᚩᚠᚢᚱ᛫ᚠᛁᚱᚪ᛫ᚷᛖᚻᚹᛦᛚᚳᚢᛗ"
         "ಬಾ ಇಲ್ಲಿ ಸಂಭವಿಸು ಇಂದೆನ್ನ ಹೃದಯದಲಿ "
         "मैं काँच खा सकता हूँ और मुझे उससे कोई चोट नहीं पहुंचती "))
     -1)

   (pango-update)
   (flush-surface))

(defparameter raven "Once upon a midnight dreary, while I pondered, weak and weary...")

;; you might not have this font, change it to a good non-bitmap monospaced font you do have.
(defun update-test ()
   (setf layout (pango:pango_cairo_create_layout (slot-value cairo:*context* 'cairo::pointer)))
   (setf font (pango:pango_font_description_from_string "Fantasque sans mono 10"))
   (pango:pango_layout_set_font_description layout font)

   (iter (for x from 0 to (length raven))
         (set-source-rgb 37/255 46/255 50/255)
         (rectangle 0 0 w h)
         (fill-path)
         (new-path)
         (move-to 0 0)
         (set-source-rgb 148/255 163/255 165/255)
         (pango:pango_layout_set_text layout (subseq raven 0 x) -1)
         (pango-update)
         (flush-surface)
         (sleep 0.1)))

(defparameter index 0)
(defparameter timer 0)

(defun windowing-test ()
   (setf layout (pango:pango_cairo_create_layout (slot-value cairo:*context* 'cairo::pointer)))
   (setf font (pango:pango_font_description_from_string "Blueberry 10"))
   (pango:pango_layout_set_font_description layout font)

   (add-as-subwindow
      (make-window :draw
         (lambda (window)
            (incf timer)
            (new-path)
            (set-source-rgb 47/255 56/255 60/255)
            (rectangle 20 (+ 20 (* 0.7 h (sin (/ timer 10)))) (- w 40) (- h 40))
            (fill-path)

            (new-path)
            (move-to 20 (+ 20 (* 0.7 h (sin (/ timer 10)))))
            (set-source-rgb 148/255 163/255 165/255)
            (if (< index (length raven)) (incf index))
            (pango:pango_layout_set_text layout (subseq raven 0 index) -1)
            (pango-update)

            (draw-subwindows window)))
      root-window)
   (window-update-loop))

(defparameter *typing-buffer* "")

(defun buffer-append (str)
   (setf *typing-buffer* (concatenate 'string *typing-buffer* str)))

(defun handle-key-events-test ()
   (iter
      (if *key-events*
         (let ((kev (pop *key-events*)))
               (print kev)
               (when (and (eql (keypress-code kev) 113) (eql (keypress-mods kev) 4))
                     (cairo:destroy context)
                     (sb-ext:exit))
               (alexandria::switch ((keypress-str kev) :test #'equalp)
                  ("Return" (buffer-append (format nil "~%")))
                  ("Shift_L" nil)
                  ("Control_L" nil)
                  ("Control_R" nil)
                  ("Shift_R" nil)
                  ("BackSpace" (when (> (length *typing-buffer*) 0)
                                     (setf *typing-buffer* (subseq *typing-buffer* 0 (- (length *typing-buffer*) 1)))))
                  (otherwise (buffer-append (if (> (length (keypress-str kev)) 1)
                                                (string (code-char (keypress-code kev)))
                                                (keypress-str kev)))))))))

(defun typing-test ()
   (setf layout (pango:pango_cairo_create_layout (slot-value cairo:*context* 'cairo::pointer)))
   (setf font (pango:pango_font_description_from_string "Fantasque Sans Mono 10"))
   (pango:pango_layout_set_font_description layout font)

   (sb-thread:make-thread 'handle-key-events-test :name "keyevents-thread")

   (add-as-subwindow
      (make-window :draw
         (lambda (window)
            (new-path)
            (set-source-rgb 47/255 56/255 60/255)
            (rectangle 20 20 (- w 40) (- h 40))
            (fill-path)

            (new-path)
            (move-to 20 20)
            (set-source-rgb 148/255 163/255 165/255)
            (pango:pango_layout_set_text layout *typing-buffer* -1)
            (pango-update)

            (draw-subwindows window)))
      root-window)
   (window-update-loop))

(defparameter *repl-buffer* "> ")
(defparameter *current-input* "")

(defun repl-append (str)
   (setf *repl-buffer* (concatenate 'string *repl-buffer* str))
   (setf *current-input* (concatenate 'string *current-input* str)))

(defun handle-repl-key-events ()
   (iter
      (if *key-events*
         (let ((kev (pop *key-events*)))
               (when (and (eql (keypress-code kev) 113) (eql (keypress-mods kev) 4))
                     (cairo:destroy context)
                     (sb-ext:exit))
               (alexandria::switch ((keypress-str kev) :test #'equalp)
                  ("Return" (repl-append (format nil "~%~a~%> " (ignore-errors (eval (read-from-string *current-input*)))))
                            (finish-output)
                            (setf *current-input* ""))
                  ("Shift_L" nil)
                  ("Control_L" nil)
                  ("Control_R" nil)
                  ("Shift_R" nil)
                  ("BackSpace" (when (> (length *current-input*) 0)
                                     (setf *current-input* (subseq *current-input* 0 (- (length *current-input*) 1)))
                                     (setf *repl-buffer* (subseq *repl-buffer* 0 (- (length *repl-buffer*) 1)))))
                  (otherwise (repl-append (if (> (length (keypress-str kev)) 1)
                                                (string (code-char (keypress-code kev)))
                                                (keypress-str kev)))))))))

(defun repl-test ()
   (setf layout (pango:pango_cairo_create_layout (slot-value cairo:*context* 'cairo::pointer)))
   (setf font (pango:pango_font_description_from_string "Fantasque Sans Mono 10"))
   (pango:pango_layout_set_font_description layout font)

   (sb-thread:make-thread 'handle-repl-key-events :name "keyevents-thread")

   (add-as-subwindow
      (make-window :draw
         (lambda (window)
            (new-path)
            (set-source-rgb 47/255 56/255 60/255)
            (rectangle 20 20 (- w 40) (- h 40))
            (fill-path)

            (new-path)
            (move-to 20 20)
            (set-source-rgb 148/255 163/255 165/255)
            (pango:pango_layout_set_text layout *repl-buffer* -1)
            (pango-update)

            (draw-subwindows window)))
      root-window)
   (window-update-loop))


Fix for SW on the GPU. Now also uses a scoring matrix.

__kernel
void interleaveSeq(__global char const * _src, __global char * dest) {

	__global char const * src = _src + ((global_index) * ref_length);
	dest = dest + ((global_index / interleave_number) * interleave_number * ref_length) + global_index % interleave_number;

	int i = 0;
	for (i = 0; i < ref_length / 4 * 4; i += 4) {
		char4 temp = vload4(0, src);
		dest[(i) * interleave_number] = temp.s0;
		dest[(i + 1) * interleave_number] = temp.s1;
		dest[(i + 2) * interleave_number] = temp.s2;
		dest[(i + 3) * interleave_number] = temp.s3;
		src += 4;
	}

	for (; i < ref_length; i += 1) {
		dest[(i) * interleave_number] = *src++;
	}
}

#ifdef __GPU__

#ifndef __BS__
__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix) {
#else
	__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix, __global char const * direction) {
#endif

		matrix = matrix + ((global_index / threads_per_block) * threads_per_block * ((corridor_length + 1) * (read_length + 1))) + global_index % threads_per_block;
		read = read + (global_index * read_length);
		scaff = scaff + ((global_index / interleave_number) * interleave_number * ref_length) + global_index % interleave_number;
		result = result + result_number * global_index;

		__local
		short l_matrix_lines[MATRIX_LENGTH];
		__local
		//	short * local_matrix_line = l_matrix_lines + local_index * corridor_length;
		short * local_matrix_line = l_matrix_lines + local_index;

		//Init matrix lines
		for (short i = 0; i < corridor_length; ++i) {
			local_matrix_line[i * threads_per_block] = 0;
			matrix[i * threads_per_block] = CIGAR_STOP;
		}
		matrix[corridor_length * threads_per_block] = CIGAR_STOP;

		short curr_max = -1;
		short read_index = 0;

		//	if (read[0] != '\0') {
		//		//printf("GPU Ref : %s\n", scaff);
		//		//printf("GPU Read: %s\n", read);
		//		printf("S:\t");
		//		char c;
		//		int i = 0;
		//		while ((c = scaff[i * interleave_number]) != '\0') {
		//			printf("\t%c", c);
		//			i += 1;
		//		}
		//		printf("\n");
		//	}

		//for (char read_char_cache; (read_char_cache = *read) != line_end; read
		//		= read + threads_per_block) {
		for (char read_char_cache; (read_char_cache = *read) != line_end; ++read) {
			//						printf("%c:\t", read_char_cache);
			//						for (short i = 0; i < read_index; ++i) {
			//							printf("\t");
			//						}
			matrix += (corridor_length + 1) * threads_per_block;
			//char read_char_cache;
			//while ((read_char_cache = read[read_index]) != line_end) {
			short left_cell = 0;
			matrix[0] = CIGAR_STOP;
			for (short ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

				//init values
				left_cell += gap_ref;
				short diag_cell = local_matrix_line[ref_index * threads_per_block];
				//			printf("%c == %c\n", read_char_cache, scaff[ref_index * interleave_number]);
				int pointer = CIGAR_X;

#ifndef __BS__
				//if (read_char_cache == scaff[ref_index * interleave_number]) {
				//	diag_cell += match;//typedef struct {
				//	pointer = CIGAR_EQ;
				//} else if (read_char_cache != 'N' && read_char_cache != line_end) {
				//	diag_cell += mismatch;
				//}
				diag_cell += scores[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
				pointer = select(CIGAR_X, CIGAR_EQ, (read_char_cache == scaff[ref_index * interleave_number]));
#else
				short score = 0;
				if(direction[global_index] == 0) {
					score = scoresTC[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
				} else {
					score = scoresAG[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
				}
				diag_cell += score;
				//pointer = select(CIGAR_X, CIGAR_EQ, (score == match));
				pointer = select(CIGAR_X, CIGAR_EQ, (read_char_cache == scaff[ref_index * interleave_number]));
#endif

				//			int eq = (read_char_cache == scaff[ref_index * interleave_number]);
				//			diag_cell += select(mismatch, match, eq);
				//			if (!eq && (read_char_cache == 'N' || read_char_cache == line_end)) {
				//				diag_cell -= mismatch;
				//			}

				short up_cell = local_matrix_line[(ref_index + 1) * threads_per_block] + gap_read;

				//find max
				short max_cell = 0;
				max_cell = max(left_cell, max_cell);
				max_cell = max(diag_cell, max_cell);
				max_cell = max(up_cell, max_cell);

				//store "pointer"
				//int pointer = 0;//typedef struct {
				//	short best_ref_index;
				//	short best_read_index;
				//} Index;
				//if (max_cell > 0) {

				//						if (max_cell == up_cell) {
				//							//pointer = 2;
				//							pointer = CIGAR_I;
				//						} else if (max_cell == left_cell) {
				//							//pointer = 1;
				//							pointer = CIGAR_D;
				//						} else if (max_cell > 0) {
				//							//pointer = 4;
				//						} else {
				//							pointer = CIGAR_STOP;
				//						}

				if (max_cell == up_cell && max_cell != (local_matrix_line[ref_index * threads_per_block] + mismatch)) {
					//pointer = 2;
					pointer = CIGAR_I;
				} else if (max_cell == left_cell && max_cell != (local_matrix_line[ref_index * threads_per_block] + mismatch)) {
					//pointer = 1;
					pointer = CIGAR_D;
				} else if (max_cell > 0 && (max_cell == diag_cell || max_cell == (local_matrix_line[ref_index * threads_per_block] + mismatch) || max_cell == (local_matrix_line[ref_index] + match))) {
					//pointer = 4;
				} else {
					pointer = CIGAR_STOP;
				}

				//}
				//printf("\t%d", max_cell);
				matrix[(ref_index + 1) * threads_per_block] = pointer;

				if (max_cell > curr_max) {
					curr_max = max_cell;
					result[param_best_read_index] = read_index;
					result[param_best_ref_index] = ref_index;
				}

				left_cell = max_cell;
				local_matrix_line[ref_index * threads_per_block] = max_cell;
			}
			matrix[corridor_length * threads_per_block] = CIGAR_STOP;
			scaff += interleave_number;
			read_index += 1;

			//for (short i = 0; i < corridor_length + 1; ++i) {
			//	printf("%d ", matrix[i]);
			//}
			//printf("\n");
		}
		result[qend] = read_index - result[param_best_read_index] - 1;
		if (read_index == 0) {
			result[param_best_read_index] = result[param_best_read_index] = 0;
		}
	}

#ifndef __BS__
	__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results) {
#else
		__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results, __global char const * direction) {
#endif

			read = read + (global_index * read_length);
			scaff = scaff + ((global_index / interleave_number) * interleave_number * ref_length) + (global_index % interleave_number);

			__local
			short l_matrix_lines[MATRIX_LENGTH];
			__local
			short * matrix_lines = l_matrix_lines + local_index;
			//Init matrix lines
			for (short i = 0; i < corridor_length; ++i) {
				matrix_lines[i * threads_per_block] = 0;
			}

			short curr_max = -1;

			//for (char read_char_cache; (read_char_cache = *read) != line_end; read += interleave_number) {
			for (int read_pos = 0; read_pos < read_length; ++read_pos) {
				//char read_char_cache = *read;
				//read += interleave_number;
				char read_char_cache = *read++;
				short left_cell = 0;
				//		for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {
				for (int ref_index = 0; ref_index < (corridor_length - 1); ++ref_index) {

					short diag_cell = matrix_lines[ref_index * threads_per_block];

#ifndef __BS__
					//int eq = (read_char_cache == scaff[ref_index * interleave_number]) && read_char_cache != line_end;
					//diag_cell += select(mismatch, match, eq);
					//if (!eq && (read_char_cache == 'N' || read_char_cache == line_end)) {
					//	diag_cell -= mismatch;
					//}
					diag_cell += scores[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
#else
					if(direction[global_index] == 0) {
						diag_cell += scoresTC[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
					} else {
						diag_cell += scoresAG[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
					}
#endif

					//diag_cell += select(0, match, eq);
					//diag_cell += select(0, mismatch, (!eq && read_char_cache != N && read_char_cache != line_end));

					//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
					left_cell = max(null, (short) (left_cell + gap_ref));
					left_cell = max((short) (matrix_lines[ref_index * threads_per_block + threads_per_block] + gap_read), left_cell);
					left_cell = max(diag_cell, left_cell);

					curr_max = max(curr_max, left_cell);
					matrix_lines[ref_index * threads_per_block] = left_cell;
				}
				scaff += interleave_number;
				//scaff += 1;
			}
			results[global_index] = curr_max;
		}

#endif

#ifdef __CPU__

//__kernel void interleaveSeq(__global char const * src, __global char * dest) {
//	src = src + (global_index * ref_length * 4);
//
//	dest = dest + ((global_index / interleave_number) * interleave_number * ref_length * 4)
//	+ (global_index % interleave_number) * 4;
//	for (int i = 0; i < ref_length; ++i) {
//		dest[i * interleave_number * 4] = src[0];
//		dest[i * interleave_number * 4 + 1] = src[ref_length * 1];
//		dest[i * interleave_number * 4 + 2] = src[ref_length * 2];
//		dest[i * interleave_number * 4 + 3] = src[ref_length * 3];
//		src += 1;
//	}
//}

#ifndef __BS__
		__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix) {
#else
			__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix, __global char const * direction) {

			int4 direction4 =  convert_int4(vload4(global_index, direction));
#endif

				matrix = matrix + (global_index * ((corridor_length + 1) * (read_length + 1)) * 4);
				read = read + (global_index * read_length * 4);
				scaff = scaff + (global_index * ref_length * 4);
				result = result + result_number * global_index * 4;

//	int corridor_lengt4 = corridor_length * 4;

				float4 best_read_index4 = null4;
				float4 best_ref_index4 = null4;
				float4 qend4 = null4;

//	for(int k = 0; k < 4; ++k) {
//		printf("Ref  (GPU) %d:", k);
//		for(int i = 0; i < read_length + corridor_length - 1; ++i) {
//			printf("%c", scaff[i + k * ref_length]);
//		}
//		printf("\n");
//		printf("Read (GPU) %d:", k);
//		for(int i = 0; i < read_length; ++i) {
//			if(read[i + k * read_length] == '\0') {
//				printf("X");
//			} else {
//				printf("%c", read[i + k * read_length]);
//			}
//		}
//		printf("\n");
//	}

				if (read[0] != line_end) {
					float4 l_matrix_lines[MATRIX_LENGTH];
					float4 * local_matrix_line = l_matrix_lines + local_index * corridor_length;

					//Init matrix lines
					for (short i = 0; i < corridor_length; ++i) {
						local_matrix_line[i] = null4;
						vstore4(CIGAR_STOP, i, matrix);
					}
					vstore4(CIGAR_STOP, corridor_length, matrix);

					float4 curr_max = -1;
					float4 read_index = null4;

					for (short read_pos = 0; read_pos < read_length; ++read_pos) {
						//		while (true) {
						//			int read_pos = 0;
						int4 read_char_cache = (int4)(trans[read[read_pos + 0 * read_length]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);
						//			read += 1;
						//			int4 test = read_char_cache == (int4) 5;
						//			printf("%d %d %d %d\n", test.s0, test.s1, test.s2, test.s3);
						//			if (test.s0 == -1 && test.s1 == -1 && test.s2 == -1 && test.s3 == -1) {
						//				break;
						//			}

						matrix += (corridor_length + 1) * 4;

						float4 left_cell = null4;

						vstore4(CIGAR_STOP, 0, matrix);

						for (short ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

							//
							//init values
							left_cell += gap_ref4;
#ifndef __BS__
							float4 score = (float4)(scores[read_char_cache.s0][trans[scaff[ref_index]]], scores[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]);
							float4 diag_cell = local_matrix_line[ref_index] + score;
							float4 pointer = select(CIGAR_X4, CIGAR_EQ4, (score == match));
#else
							float4 score = select((float4)(scoresAG[read_char_cache.s0][trans[scaff[ref_index]]], scoresAG[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresAG[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresAG[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), (float4)(scoresTC[read_char_cache.s0][trans[scaff[ref_index]]], scoresTC[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresTC[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresTC[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), direction4 == 0);

							float4 diag_cell = local_matrix_line[ref_index] + score;
							float4 pointer = select(CIGAR_X4, CIGAR_EQ4, (read_char_cache == (int4)(trans[scaff[ref_index]], trans[scaff[ref_index + 1 * ref_length]], trans[scaff[ref_index + 2 * ref_length]], trans[scaff[ref_index + 3 * ref_length]])));
#endif

							//int4 pointer = select(CIGAR_X, CIGAR_EQ, (score == match));
							//
							float4 up_cell = local_matrix_line[(ref_index + 1)] + gap_read4;

							//find max
							float4 max_cell = null4;
							max_cell = max(left_cell, max_cell);
							max_cell = max(diag_cell, max_cell);
							max_cell = max(up_cell, max_cell);

							//pointer = select(pointer, CIGAR_STOP, (max_cell == 0));

							pointer = select(CIGAR_STOP, pointer, (max_cell > 0 && (max_cell == diag_cell || max_cell == (local_matrix_line[ref_index] + mismatch) || max_cell == (local_matrix_line[ref_index] + match))));
							pointer = select(pointer, CIGAR_D, (max_cell == left_cell && max_cell != (local_matrix_line[ref_index] + mismatch)));
							pointer = select(pointer, CIGAR_I, (max_cell == up_cell && max_cell != (local_matrix_line[ref_index] + mismatch)));

							//max_cell > 0 && (max_cell == diag_cell || max_cell == (local_matrix_line[ref_index * threads_per_block] + mismatch) || max_cell == (local_matrix_line[ref_index] + match))

							vstore4(convert_char4(pointer), (ref_index + 1), matrix);

							best_read_index4 = select(best_read_index4, read_index, (max_cell > curr_max));
							best_ref_index4 = select(best_ref_index4, ref_index, (max_cell > curr_max));

							curr_max = max(curr_max, max_cell);

							left_cell = max_cell;

							local_matrix_line[ref_index] = max_cell;

						}
						vstore4(CIGAR_STOP, corridor_length, matrix);
						scaff += 1;
						//			read_index += 1;
						//			read_index = select(read_index + 1, read_index, test);
						read_index = select(read_index + 1, read_index, read_char_cache == (int4) 6);
						//			read_index -= convert_float4(test);
						//			read_index -= read_char_cache == 5.0;
					}
					qend4 = read_index - best_read_index4 - 1;
				}

				vstore4(convert_short4(best_read_index4), param_best_read_index, result);
				vstore4(convert_short4(best_ref_index4), param_best_ref_index, result);
				vstore4(convert_short4(qend4), qend, result);
			}

#ifndef __BS__
			__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results) {
#else
				__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results, __global char const * direction) {

				int4 direction4 =  convert_int4(vload4(global_index, direction));
#endif

					scaff = scaff + (global_index * ref_length * 4);
					read = read + (global_index * read_length * 4);

					float4 l_matrix_lines[MATRIX_LENGTH];
					float4 * matrix_lines = l_matrix_lines + local_index * corridor_length;

					float4 curr_max = (float4)(-1.0f);
					if (read[0] != line_end) {
						//printf("Ref: %s\n", scaff);
						//Init matrix lines
						for (short i = 0; i < corridor_length; ++i) {
							matrix_lines[i] = null4;
						}
						for (int read_pos = 0; read_pos < read_length; ++read_pos) {

							int4 read_char_cache = (int4)(trans[read[read_pos]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);

							float4 left_cell = 0;
							for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

								//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
								left_cell = max(null4, left_cell + gap_ref);
								left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);

#ifndef __BS__
								float4 scores4 = (float4)(scores[read_char_cache.s0][trans[scaff[ref_index]]], scores[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]);
#else
								float4 scores4 = select((float4)(scoresAG[read_char_cache.s0][trans[scaff[ref_index]]], scoresAG[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresAG[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresAG[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), (float4)(scoresTC[read_char_cache.s0][trans[scaff[ref_index]]], scoresTC[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresTC[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresTC[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), direction4 == 0);
#endif

								left_cell = max(matrix_lines[ref_index] + scores4, left_cell);

								curr_max = max(curr_max, left_cell);

								matrix_lines[ref_index] = left_cell;
							}
							scaff += 1;
						}
					}
					vstore4(curr_max, global_index, results);

				}

				__kernel void oclSW_wSSE(__global char const * scaff, __global char const * read, __global float * results) {

					scaff = scaff + (global_index * ref_length);
					read = read + (global_index * read_length);

					float l_matrix_lines[MATRIX_LENGTH];
					float * matrix_lines = l_matrix_lines + local_index * corridor_length;

					float curr_max = -1.0f;
					if (read[0] != line_end) {
						//printf("Refxxx: %s\n", scaff);
						//Init matrix lines
						for (short i = 0; i < corridor_length; ++i) {
							matrix_lines[i] = 0.0f;
						}
						for (int read_pos = 0; read_pos < read_length; ++read_pos) {

							int read_char_cache = trans[read[read_pos]];

							float left_cell = 0.0f;
							for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

								//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
								left_cell = max(0.0f, left_cell + gap_ref);
								left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);

								//printf("%c", 'X');
								//printf("%c == %c\n", read_char_cache, scaff[ref_index]);
								float score = scores[read_char_cache][trans[scaff[ref_index]]];

								left_cell = max(matrix_lines[ref_index] + score, left_cell);

								curr_max = max(curr_max, left_cell);

								matrix_lines[ref_index] = left_cell;
							}
							scaff += 1;
						}
					}
					results[global_index] = curr_max;

					//results[global_index] = -101.0f;
				}

//__kernel void oclSW(__global char const * _scaff, __global char const * _read, __global float * results) {
//	for (int x = 0; x < 4; ++x) {
//		__global
//		char const *scaff = _scaff + (global_index * ref_length * 4 * 4) + 4 * x * ref_length;
//		__global
//		char const *read = _read + (global_index * read_length * 4 * 4) + 4 * x * read_length;
//
//		float4 l_matrix_lines[MATRIX_LENGTH];
//		float4 * matrix_lines = l_matrix_lines + local_index * corridor_length;
//
//		float4 curr_max = (float4)(-1.0f, -1.0f, -1.0f, -1.0f);
//		if (read[0] != line_end) {
//			//printf("Ref: %s\n", scaff);
//			//Init matrix lines
//			for (short i = 0; i < corridor_length; ++i) {
//				matrix_lines[i] = null4;
//			}
//			for (int read_pos = 0; read_pos < read_length; ++read_pos) {
//
//				int4 read_char_cache = (int4)(trans[read[read_pos]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);
//
//				float4 left_cell = 0;
//				for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {
//
//					//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
//					left_cell = max(null4, left_cell + gap_ref);
//					left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);
//
//					float4 scores4 = (float4)(scores[read_char_cache.x][trans[scaff[ref_index]]], scores[read_char_cache.y][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.z][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.w][trans[scaff[ref_index + 3 * ref_length]]]);
//
//					left_cell = max(matrix_lines[ref_index] + scores4, left_cell);
//
//					curr_max = max(curr_max, left_cell);
//
//					matrix_lines[ref_index] = left_cell;
//				}
//				scaff += 1;
//			}
//		}
//		vstore4(curr_max, global_index * 4, results + 4 * x);
//	}
//	//	scaff = _scaff + global_index * (ref_length * 8) + 4 * ref_length;
//	//	read = _read + global_index * (read_length * 8) + 4 * read_length;
//	//
//	//	curr_max = (float4)(-1.0f, -1.0f, -1.0f, -1.0f);
//	//	if (read[0] != line_end) {
//	//		//printf("Ref: %s\n", scaff);
//	//
//	//		float4 l_matrix_lines[MATRIX_LENGTH];
//	//		float4 * matrix_lines = l_matrix_lines + local_index * corridor_length;
//	//		//Init matrix lines
//	//		for (short i = 0; i < corridor_length; ++i) {
//	//			matrix_lines[i] = null4;
//	//		}
//	//
//	//		for (int read_pos = 0; read_pos < read_length; ++read_pos) {
//	//
//	//			int4 read_char_cache = (int4)(trans[read[read_pos]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);
//	//
//	//			float4 left_cell = 0;
//	//			for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {
//	//
//	//				//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
//	//				left_cell = max(null4, left_cell + gap_ref);
//	//				left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);
//	//
//	//				float4 scores4 = (float4)(scores[read_char_cache.x][trans[scaff[ref_index]]], scores[read_char_cache.y][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.z][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.w][trans[scaff[ref_index + 3 * ref_length]]]);
//	//
//	//				left_cell = max(matrix_lines[ref_index] + scores4, left_cell);
//	//
//	//				curr_max = max(curr_max, left_cell);
//	//
//	//				matrix_lines[ref_index] = left_cell;
//	//			}
//	//			scaff += 1;
//	//		}
//	//	}
//	//	vstore4(curr_max, global_index * 2, results + 4);
//}
#endif

__kernel
void interleaveSeq(__global char const * _src, __global char * dest) {

	__global char const * src = _src + ((global_index) * ref_length);
	dest = dest + ((global_index / interleave_number) * interleave_number * ref_length) + global_index % interleave_number;

	int i = 0;
	for (i = 0; i < ref_length / 4 * 4; i += 4) {
		char4 temp = vload4(0, src);
		dest[(i) * interleave_number] = temp.s0;
		dest[(i + 1) * interleave_number] = temp.s1;
		dest[(i + 2) * interleave_number] = temp.s2;
		dest[(i + 3) * interleave_number] = temp.s3;
		src += 4;
	}

	for (; i < ref_length; i += 1) {
		dest[(i) * interleave_number] = *src++;
	}
}

#ifdef __GPU__

#ifndef __BS__
__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix) {
#else
	__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix, __global char const * direction) {
#endif

		matrix = matrix + ((global_index / threads_per_block) * threads_per_block * ((corridor_length + 1) * (read_length + 1))) + global_index % threads_per_block;
		read = read + (global_index * read_length);
		scaff = scaff + ((global_index / interleave_number) * interleave_number * ref_length) + global_index % interleave_number;
		result = result + result_number * global_index;

		__local
		short l_matrix_lines[MATRIX_LENGTH];
		__local
		//	short * local_matrix_line = l_matrix_lines + local_index * corridor_length;
		short * local_matrix_line = l_matrix_lines + local_index;

		//Init matrix lines
		for (short i = 0; i < corridor_length; ++i) {
			local_matrix_line[i * threads_per_block] = 0;
			matrix[i * threads_per_block] = CIGAR_STOP;
		}
		matrix[corridor_length * threads_per_block] = CIGAR_STOP;

		short curr_max = -1;
		short read_index = 0;

		//	if (read[0] != '\0') {
		//		//printf("GPU Ref : %s\n", scaff);
		//		//printf("GPU Read: %s\n", read);
		//		printf("S:\t");
		//		char c;
		//		int i = 0;
		//		while ((c = scaff[i * interleave_number]) != '\0') {
		//			printf("\t%c", c);
		//			i += 1;
		//		}
		//		printf("\n");
		//	}

		//for (char read_char_cache; (read_char_cache = *read) != line_end; read
		//		= read + threads_per_block) {
		for (char read_char_cache; (read_char_cache = *read) != line_end; ++read) {
			//						printf("%c:\t", read_char_cache);
			//						for (short i = 0; i < read_index; ++i) {
			//							printf("\t");
			//						}
			matrix += (corridor_length + 1) * threads_per_block;
			//char read_char_cache;
			//while ((read_char_cache = read[read_index]) != line_end) {
			short left_cell = 0;
			matrix[0] = CIGAR_STOP;
			for (short ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

				//init values
				left_cell += gap_ref;
				short diag_cell = local_matrix_line[ref_index * threads_per_block];
				//			printf("%c == %c\n", read_char_cache, scaff[ref_index * interleave_number]);
				int pointer = CIGAR_X;

#ifndef __BS__
				if (read_char_cache == scaff[ref_index * interleave_number]) {
					diag_cell += match;//typedef struct {
					pointer = CIGAR_EQ;
				} else if (read_char_cache != 'N' && read_char_cache != line_end) {
					diag_cell += mismatch;
				}
#else
				short score = 0;
				if(direction[global_index] == 0) {
					score = scoresTC[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
				} else {
					score = scoresAG[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
				}
				diag_cell += score;
				//pointer = select(CIGAR_X, CIGAR_EQ, (score == match));
				pointer = select(CIGAR_X, CIGAR_EQ, (read_char_cache == scaff[ref_index * interleave_number]));
#endif

				//			int eq = (read_char_cache == scaff[ref_index * interleave_number]);
				//			diag_cell += select(mismatch, match, eq);
				//			if (!eq && (read_char_cache == 'N' || read_char_cache == line_end)) {
				//				diag_cell -= mismatch;
				//			}

				short up_cell = local_matrix_line[(ref_index + 1) * threads_per_block] + gap_read;

				//find max
				short max_cell = 0;
				max_cell = max(left_cell, max_cell);
				max_cell = max(diag_cell, max_cell);
				max_cell = max(up_cell, max_cell);

				//store "pointer"
				//int pointer = 0;//typedef struct {
				//	short best_ref_index;
				//	short best_read_index;
				//} Index;
				//if (max_cell > 0) {

				//						if (max_cell == up_cell) {
				//							//pointer = 2;
				//							pointer = CIGAR_I;
				//						} else if (max_cell == left_cell) {
				//							//pointer = 1;
				//							pointer = CIGAR_D;
				//						} else if (max_cell > 0) {
				//							//pointer = 4;
				//						} else {
				//							pointer = CIGAR_STOP;
				//						}

				if (max_cell == up_cell && max_cell != (local_matrix_line[ref_index * threads_per_block] + mismatch)) {
					//pointer = 2;
					pointer = CIGAR_I;
				} else if (max_cell == left_cell && max_cell != (local_matrix_line[ref_index * threads_per_block] + mismatch)) {
					//pointer = 1;
					pointer = CIGAR_D;
				} else if (max_cell > 0 && (max_cell == diag_cell || max_cell == (local_matrix_line[ref_index * threads_per_block] + mismatch) || max_cell == (local_matrix_line[ref_index] + match))) {
					//pointer = 4;
				} else {
					pointer = CIGAR_STOP;
				}

				//}
				//printf("\t%d", max_cell);
				matrix[(ref_index + 1) * threads_per_block] = pointer;

				if (max_cell > curr_max) {
					curr_max = max_cell;
					result[param_best_read_index] = read_index;
					result[param_best_ref_index] = ref_index;
				}

				left_cell = max_cell;
				local_matrix_line[ref_index * threads_per_block] = max_cell;
			}
			matrix[corridor_length * threads_per_block] = CIGAR_STOP;
			scaff += interleave_number;
			read_index += 1;

			//for (short i = 0; i < corridor_length + 1; ++i) {
			//	printf("%d ", matrix[i]);
			//}
			//printf("\n");
		}
		result[qend] = read_index - result[param_best_read_index] - 1;
		if (read_index == 0) {
			result[param_best_read_index] = result[param_best_read_index] = 0;
		}
	}

#ifndef __BS__
	__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results) {
#else
		__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results, __global char const * direction) {
#endif

			read = read + (global_index * read_length);
			scaff = scaff + ((global_index / interleave_number) * interleave_number * ref_length) + (global_index % interleave_number);

			__local
			short l_matrix_lines[MATRIX_LENGTH];
			__local
			short * matrix_lines = l_matrix_lines + local_index;
			//Init matrix lines
			for (short i = 0; i < corridor_length; ++i) {
				matrix_lines[i * threads_per_block] = 0;
			}

			short curr_max = -1;

			//for (char read_char_cache; (read_char_cache = *read) != line_end; read += interleave_number) {
			for (int read_pos = 0; read_pos < read_length; ++read_pos) {
				//char read_char_cache = *read;
				//read += interleave_number;
				char read_char_cache = *read++;
				short left_cell = 0;
				//		for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {
				for (int ref_index = 0; ref_index < (corridor_length - 1); ++ref_index) {

					short diag_cell = matrix_lines[ref_index * threads_per_block];

#ifndef __BS__
					int eq = (read_char_cache == scaff[ref_index * interleave_number]) && read_char_cache != line_end;
					diag_cell += select(mismatch, match, eq);
					if (!eq && (read_char_cache == 'N' || read_char_cache == line_end)) {
						diag_cell -= mismatch;
					}
#else
					if(direction[global_index] == 0) {
						diag_cell += scoresTC[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
					} else {
						diag_cell += scoresAG[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
					}
#endif

					//diag_cell += select(0, match, eq);
					//diag_cell += select(0, mismatch, (!eq && read_char_cache != N && read_char_cache != line_end));

					//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
					left_cell = max(null, (short) (left_cell + gap_ref));
					left_cell = max((short) (matrix_lines[ref_index * threads_per_block + threads_per_block] + gap_read), left_cell);
					left_cell = max(diag_cell, left_cell);

					curr_max = max(curr_max, left_cell);
					matrix_lines[ref_index * threads_per_block] = left_cell;
				}
				scaff += interleave_number;
				//scaff += 1;
			}
			results[global_index] = curr_max;
		}

#endif

#ifdef __CPU__

//__kernel void interleaveSeq(__global char const * src, __global char * dest) {
//	src = src + (global_index * ref_length * 4);
//
//	dest = dest + ((global_index / interleave_number) * interleave_number * ref_length * 4)
//	+ (global_index % interleave_number) * 4;
//	for (int i = 0; i < ref_length; ++i) {
//		dest[i * interleave_number * 4] = src[0];
//		dest[i * interleave_number * 4 + 1] = src[ref_length * 1];
//		dest[i * interleave_number * 4 + 2] = src[ref_length * 2];
//		dest[i * interleave_number * 4 + 3] = src[ref_length * 3];
//		src += 1;
//	}
//}

#ifndef __BS__
		__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix) {
#else
			__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix, __global char const * direction) {

			int4 direction4 =  convert_int4(vload4(global_index, direction));
#endif

				matrix = matrix + (global_index * ((corridor_length + 1) * (read_length + 1)) * 4);
				read = read + (global_index * read_length * 4);
				scaff = scaff + (global_index * ref_length * 4);
				result = result + result_number * global_index * 4;

//	int corridor_lengt4 = corridor_length * 4;

				float4 best_read_index4 = null4;
				float4 best_ref_index4 = null4;
				float4 qend4 = null4;

//	for(int k = 0; k < 4; ++k) {
//		printf("Ref  (GPU) %d:", k);
//		for(int i = 0; i < read_length + corridor_length - 1; ++i) {
//			printf("%c", scaff[i + k * ref_length]);
//		}
//		printf("\n");
//		printf("Read (GPU) %d:", k);
//		for(int i = 0; i < read_length; ++i) {
//			if(read[i + k * read_length] == '\0') {
//				printf("X");
//			} else {
//				printf("%c", read[i + k * read_length]);
//			}
//		}
//		printf("\n");
//	}

				if (read[0] != line_end) {
					float4 l_matrix_lines[MATRIX_LENGTH];
					float4 * local_matrix_line = l_matrix_lines + local_index * corridor_length;

					//Init matrix lines
					for (short i = 0; i < corridor_length; ++i) {
						local_matrix_line[i] = null4;
						vstore4(CIGAR_STOP, i, matrix);
					}
					vstore4(CIGAR_STOP, corridor_length, matrix);

					float4 curr_max = -1;
					float4 read_index = null4;

					for (short read_pos = 0; read_pos < read_length; ++read_pos) {
						//		while (true) {
						//			int read_pos = 0;
						int4 read_char_cache = (int4)(trans[read[read_pos + 0 * read_length]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);
						//			read += 1;
						//			int4 test = read_char_cache == (int4) 5;
						//			printf("%d %d %d %d\n", test.s0, test.s1, test.s2, test.s3);
						//			if (test.s0 == -1 && test.s1 == -1 && test.s2 == -1 && test.s3 == -1) {
						//				break;
						//			}

						matrix += (corridor_length + 1) * 4;

						float4 left_cell = null4;

						vstore4(CIGAR_STOP, 0, matrix);

						for (short ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

							//
							//init values
							left_cell += gap_ref4;
#ifndef __BS__
							float4 score = (float4)(scores[read_char_cache.s0][trans[scaff[ref_index]]], scores[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]);
							float4 diag_cell = local_matrix_line[ref_index] + score;
							float4 pointer = select(CIGAR_X4, CIGAR_EQ4, (score == match));
#else
							float4 score = select((float4)(scoresAG[read_char_cache.s0][trans[scaff[ref_index]]], scoresAG[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresAG[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresAG[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), (float4)(scoresTC[read_char_cache.s0][trans[scaff[ref_index]]], scoresTC[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresTC[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresTC[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), direction4 == 0);

							float4 diag_cell = local_matrix_line[ref_index] + score;
							float4 pointer = select(CIGAR_X4, CIGAR_EQ4, (read_char_cache == (int4)(trans[scaff[ref_index]], trans[scaff[ref_index + 1 * ref_length]], trans[scaff[ref_index + 2 * ref_length]], trans[scaff[ref_index + 3 * ref_length]])));
#endif

							//int4 pointer = select(CIGAR_X, CIGAR_EQ, (score == match));
							//
							float4 up_cell = local_matrix_line[(ref_index + 1)] + gap_read4;

							//find max
							float4 max_cell = null4;
							max_cell = max(left_cell, max_cell);
							max_cell = max(diag_cell, max_cell);
							max_cell = max(up_cell, max_cell);

							//pointer = select(pointer, CIGAR_STOP, (max_cell == 0));

							pointer = select(CIGAR_STOP, pointer, (max_cell > 0 && (max_cell == diag_cell || max_cell == (local_matrix_line[ref_index] + mismatch) || max_cell == (local_matrix_line[ref_index] + match))));
							pointer = select(pointer, CIGAR_D, (max_cell == left_cell && max_cell != (local_matrix_line[ref_index] + mismatch)));
							pointer = select(pointer, CIGAR_I, (max_cell == up_cell && max_cell != (local_matrix_line[ref_index] + mismatch)));

							//max_cell > 0 && (max_cell == diag_cell || max_cell == (local_matrix_line[ref_index * threads_per_block] + mismatch) || max_cell == (local_matrix_line[ref_index] + match))

							vstore4(convert_char4(pointer), (ref_index + 1), matrix);

							best_read_index4 = select(best_read_index4, read_index, (max_cell > curr_max));
							best_ref_index4 = select(best_ref_index4, ref_index, (max_cell > curr_max));

							curr_max = max(curr_max, max_cell);

							left_cell = max_cell;

							local_matrix_line[ref_index] = max_cell;

						}
						vstore4(CIGAR_STOP, corridor_length, matrix);
						scaff += 1;
						//			read_index += 1;
						//			read_index = select(read_index + 1, read_index, test);
						read_index = select(read_index + 1, read_index, read_char_cache == (int4) 6);
						//			read_index -= convert_float4(test);
						//			read_index -= read_char_cache == 5.0;
					}
					qend4 = read_index - best_read_index4 - 1;
				}

				vstore4(convert_short4(best_read_index4), param_best_read_index, result);
				vstore4(convert_short4(best_ref_index4), param_best_ref_index, result);
				vstore4(convert_short4(qend4), qend, result);
			}

#ifndef __BS__
			__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results) {
#else
				__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results, __global char const * direction) {

				int4 direction4 =  convert_int4(vload4(global_index, direction));
#endif

					scaff = scaff + (global_index * ref_length * 4);
					read = read + (global_index * read_length * 4);

					float4 l_matrix_lines[MATRIX_LENGTH];
					float4 * matrix_lines = l_matrix_lines + local_index * corridor_length;

					float4 curr_max = (float4)(-1.0f);
					if (read[0] != line_end) {
						//printf("Ref: %s\n", scaff);
						//Init matrix lines
						for (short i = 0; i < corridor_length; ++i) {
							matrix_lines[i] = null4;
						}
						for (int read_pos = 0; read_pos < read_length; ++read_pos) {

							int4 read_char_cache = (int4)(trans[read[read_pos]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);

							float4 left_cell = 0;
							for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

								//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
								left_cell = max(null4, left_cell + gap_ref);
								left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);

#ifndef __BS__
								float4 scores4 = (float4)(scores[read_char_cache.s0][trans[scaff[ref_index]]], scores[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]);
#else
								float4 scores4 = select((float4)(scoresAG[read_char_cache.s0][trans[scaff[ref_index]]], scoresAG[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresAG[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresAG[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), (float4)(scoresTC[read_char_cache.s0][trans[scaff[ref_index]]], scoresTC[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresTC[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresTC[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), direction4 == 0);
#endif

								left_cell = max(matrix_lines[ref_index] + scores4, left_cell);

								curr_max = max(curr_max, left_cell);

								matrix_lines[ref_index] = left_cell;
							}
							scaff += 1;
						}
					}
					vstore4(curr_max, global_index, results);

				}

				__kernel void oclSW_wSSE(__global char const * scaff, __global char const * read, __global float * results) {

					scaff = scaff + (global_index * ref_length);
					read = read + (global_index * read_length);

					float l_matrix_lines[MATRIX_LENGTH];
					float * matrix_lines = l_matrix_lines + local_index * corridor_length;

					float curr_max = -1.0f;
					if (read[0] != line_end) {
						//printf("Refxxx: %s\n", scaff);
						//Init matrix lines
						for (short i = 0; i < corridor_length; ++i) {
							matrix_lines[i] = 0.0f;
						}
						for (int read_pos = 0; read_pos < read_length; ++read_pos) {

							int read_char_cache = trans[read[read_pos]];

							float left_cell = 0.0f;
							for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

								//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
								left_cell = max(0.0f, left_cell + gap_ref);
								left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);

								//printf("%c", 'X');
								//printf("%c == %c\n", read_char_cache, scaff[ref_index]);
								float score = scores[read_char_cache][trans[scaff[ref_index]]];

								left_cell = max(matrix_lines[ref_index] + score, left_cell);

								curr_max = max(curr_max, left_cell);

								matrix_lines[ref_index] = left_cell;
							}
							scaff += 1;
						}
					}
					results[global_index] = curr_max;

					//results[global_index] = -101.0f;
				}

//__kernel void oclSW(__global char const * _scaff, __global char const * _read, __global float * results) {
//	for (int x = 0; x < 4; ++x) {
//		__global
//		char const *scaff = _scaff + (global_index * ref_length * 4 * 4) + 4 * x * ref_length;
//		__global
//		char const *read = _read + (global_index * read_length * 4 * 4) + 4 * x * read_length;
//
//		float4 l_matrix_lines[MATRIX_LENGTH];
//		float4 * matrix_lines = l_matrix_lines + local_index * corridor_length;
//
//		float4 curr_max = (float4)(-1.0f, -1.0f, -1.0f, -1.0f);
//		if (read[0] != line_end) {
//			//printf("Ref: %s\n", scaff);
//			//Init matrix lines
//			for (short i = 0; i < corridor_length; ++i) {
//				matrix_lines[i] = null4;
//			}
//			for (int read_pos = 0; read_pos < read_length; ++read_pos) {
//
//				int4 read_char_cache = (int4)(trans[read[read_pos]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);
//
//				float4 left_cell = 0;
//				for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {
//
//					//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
//					left_cell = max(null4, left_cell + gap_ref);
//					left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);
//
//					float4 scores4 = (float4)(scores[read_char_cache.x][trans[scaff[ref_index]]], scores[read_char_cache.y][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.z][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.w][trans[scaff[ref_index + 3 * ref_length]]]);
//
//					left_cell = max(matrix_lines[ref_index] + scores4, left_cell);
//
//					curr_max = max(curr_max, left_cell);
//
//					matrix_lines[ref_index] = left_cell;
//				}
//				scaff += 1;
//			}
//		}
//		vstore4(curr_max, global_index * 4, results + 4 * x);
//	}
//	//	scaff = _scaff + global_index * (ref_length * 8) + 4 * ref_length;
//	//	read = _read + global_index * (read_length * 8) + 4 * read_length;
//	//
//	//	curr_max = (float4)(-1.0f, -1.0f, -1.0f, -1.0f);
//	//	if (read[0] != line_end) {
//	//		//printf("Ref: %s\n", scaff);
//	//
//	//		float4 l_matrix_lines[MATRIX_LENGTH];
//	//		float4 * matrix_lines = l_matrix_lines + local_index * corridor_length;
//	//		//Init matrix lines
//	//		for (short i = 0; i < corridor_length; ++i) {
//	//			matrix_lines[i] = null4;
//	//		}
//	//
//	//		for (int read_pos = 0; read_pos < read_length; ++read_pos) {
//	//
//	//			int4 read_char_cache = (int4)(trans[read[read_pos]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);
//	//
//	//			float4 left_cell = 0;
//	//			for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {
//	//
//	//				//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
//	//				left_cell = max(null4, left_cell + gap_ref);
//	//				left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);
//	//
//	//				float4 scores4 = (float4)(scores[read_char_cache.x][trans[scaff[ref_index]]], scores[read_char_cache.y][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.z][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.w][trans[scaff[ref_index + 3 * ref_length]]]);
//	//
//	//				left_cell = max(matrix_lines[ref_index] + scores4, left_cell);
//	//
//	//				curr_max = max(curr_max, left_cell);
//	//
//	//				matrix_lines[ref_index] = left_cell;
//	//			}
//	//			scaff += 1;
//	//		}
//	//	}
//	//	vstore4(curr_max, global_index * 2, results + 4);
//}
#endif


ORB.cl : fixed redefinition of val

ORB.cl : fixed redefinition of val

// OpenCL port of the ORB feature detector and descriptor extractor
// Copyright (C) 2014, Itseez Inc. See the license at http://opencv.org
//
// The original code has been contributed by Peter Andreas Entschev, peter@entschev.com

#define LAYERINFO_SIZE 1
#define LAYERINFO_OFS 0
#define KEYPOINT_SIZE 3
#define ORIENTED_KEYPOINT_SIZE 4
#define KEYPOINT_X 0
#define KEYPOINT_Y 1
#define KEYPOINT_Z 2
#define KEYPOINT_ANGLE 3

/////////////////////////////////////////////////////////////

#ifdef ORB_RESPONSES

__kernel void
ORB_HarrisResponses(__global const uchar* imgbuf, int imgstep, int imgoffset0,
                    __global const int* layerinfo, __global const int* keypoints,
                    __global float* responses, int nkeypoints )
{
    int idx = get_global_id(0);
    if( idx < nkeypoints )
    {
        __global const int* kpt = keypoints + idx*KEYPOINT_SIZE;
        __global const int* layer = layerinfo + kpt[KEYPOINT_Z]*LAYERINFO_SIZE;
        __global const uchar* img = imgbuf + imgoffset0 + layer[LAYERINFO_OFS] +
            (kpt[KEYPOINT_Y] - blockSize/2)*imgstep + (kpt[KEYPOINT_X] - blockSize/2);

        int i, j;
        int a = 0, b = 0, c = 0;
        for( i = 0; i < blockSize; i++, img += imgstep-blockSize )
        {
            for( j = 0; j < blockSize; j++, img++ )
            {
                int Ix = (img[1] - img[-1])*2 + img[-imgstep+1] - img[-imgstep-1] + img[imgstep+1] - img[imgstep-1];
                int Iy = (img[imgstep] - img[-imgstep])*2 + img[imgstep-1] - img[-imgstep-1] + img[imgstep+1] - img[-imgstep+1];
                a += Ix*Ix;
                b += Iy*Iy;
                c += Ix*Iy;
            }
        }
        responses[idx] = ((float)a * b - (float)c * c - HARRIS_K * (float)(a + b) * (a + b))*scale_sq_sq;
    }
}

#endif

/////////////////////////////////////////////////////////////

#ifdef ORB_ANGLES

#define _DBL_EPSILON 2.2204460492503131e-16f
#define atan2_p1 (0.9997878412794807f*57.29577951308232f)
#define atan2_p3 (-0.3258083974640975f*57.29577951308232f)
#define atan2_p5 (0.1555786518463281f*57.29577951308232f)
#define atan2_p7 (-0.04432655554792128f*57.29577951308232f)

inline float fastAtan2( float y, float x )
{
    float ax = fabs(x), ay = fabs(y);
    float a, c, c2;
    if( ax >= ay )
    {
        c = ay/(ax + _DBL_EPSILON);
        c2 = c*c;
        a = (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c;
    }
    else
    {
        c = ax/(ay + _DBL_EPSILON);
        c2 = c*c;
        a = 90.f - (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c;
    }
    if( x < 0 )
        a = 180.f - a;
    if( y < 0 )
        a = 360.f - a;
    return a;
}

__kernel void
ORB_ICAngle(__global const uchar* imgbuf, int imgstep, int imgoffset0,
            __global const int* layerinfo, __global const int* keypoints,
            __global float* responses, const __global int* u_max,
            int nkeypoints, int half_k )
{
    int idx = get_global_id(0);
    if( idx < nkeypoints )
    {
        __global const int* kpt = keypoints + idx*KEYPOINT_SIZE;

        __global const int* layer = layerinfo + kpt[KEYPOINT_Z]*LAYERINFO_SIZE;
        __global const uchar* center = imgbuf + imgoffset0 + layer[LAYERINFO_OFS] +
            kpt[KEYPOINT_Y]*imgstep + kpt[KEYPOINT_X];

        int u, v, m_01 = 0, m_10 = 0;

        // Treat the center line differently, v=0
        for( u = -half_k; u <= half_k; u++ )
            m_10 += u * center[u];

        // Go line by line in the circular patch
        for( v = 1; v <= half_k; v++ )
        {
            // Proceed over the two lines
            int v_sum = 0;
            int d = u_max[v];
            for( u = -d; u <= d; u++ )
            {
                int val_plus = center[u + v*imgstep], val_minus = center[u - v*imgstep];
                v_sum += (val_plus - val_minus);
                m_10 += u * (val_plus + val_minus);
            }
            m_01 += v * v_sum;
        }

        // we do not use OpenCL's atan2 intrinsic,
        // because we want to get _exactly_ the same results as the CPU version
        responses[idx] = fastAtan2((float)m_01, (float)m_10);
    }
}

#endif

/////////////////////////////////////////////////////////////

#ifdef ORB_DESCRIPTORS

__kernel void
ORB_computeDescriptor(__global const uchar* imgbuf, int imgstep, int imgoffset0,
                      __global const int* layerinfo, __global const int* keypoints,
                      __global uchar* _desc, const __global int* pattern,
                      int nkeypoints, int dsize )
{
    int idx = get_global_id(0);
    if( idx < nkeypoints )
    {
        int i;
        __global const int* kpt = keypoints + idx*ORIENTED_KEYPOINT_SIZE;

        __global const int* layer = layerinfo + kpt[KEYPOINT_Z]*LAYERINFO_SIZE;
        __global const uchar* center = imgbuf + imgoffset0 + layer[LAYERINFO_OFS] +
                                kpt[KEYPOINT_Y]*imgstep + kpt[KEYPOINT_X];
        float angle = as_float(kpt[KEYPOINT_ANGLE]);
        angle *= 0.01745329251994329547f;

        float sina = sin(angle);
        float cosa = cos(angle);

        __global uchar* desc = _desc + idx*dsize;

        #define GET_VALUE(idx) \
            center[mad24(convert_int_rte(pattern[(idx)*2] * sina + pattern[(idx)*2+1] * cosa), imgstep, \
                        convert_int_rte(pattern[(idx)*2] * cosa - pattern[(idx)*2+1] * sina))]

        for( i = 0; i < dsize; i++ )
        {
            int val;
        #if WTA_K == 2
            int t0, t1;

            t0 = GET_VALUE(0); t1 = GET_VALUE(1);
            val = t0 < t1;

            t0 = GET_VALUE(2); t1 = GET_VALUE(3);
            val |= (t0 < t1) << 1;

            t0 = GET_VALUE(4); t1 = GET_VALUE(5);
            val |= (t0 < t1) << 2;

            t0 = GET_VALUE(6); t1 = GET_VALUE(7);
            val |= (t0 < t1) << 3;

            t0 = GET_VALUE(8); t1 = GET_VALUE(9);
            val |= (t0 < t1) << 4;

            t0 = GET_VALUE(10); t1 = GET_VALUE(11);
            val |= (t0 < t1) << 5;

            t0 = GET_VALUE(12); t1 = GET_VALUE(13);
            val |= (t0 < t1) << 6;

            t0 = GET_VALUE(14); t1 = GET_VALUE(15);
            val |= (t0 < t1) << 7;

            pattern += 16*2;

        #elif WTA_K == 3
            int t0, t1, t2;

            t0 = GET_VALUE(0); t1 = GET_VALUE(1); t2 = GET_VALUE(2);
            val = t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0);

            t0 = GET_VALUE(3); t1 = GET_VALUE(4); t2 = GET_VALUE(5);
            val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 2;

            t0 = GET_VALUE(6); t1 = GET_VALUE(7); t2 = GET_VALUE(8);
            val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 4;

            t0 = GET_VALUE(9); t1 = GET_VALUE(10); t2 = GET_VALUE(11);
            val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 6;

            pattern += 12*2;

        #elif WTA_K == 4
            int t0, t1, t2, t3, k;
            int a, b;

            t0 = GET_VALUE(0); t1 = GET_VALUE(1);
            t2 = GET_VALUE(2); t3 = GET_VALUE(3);
            a = 0, b = 2;
            if( t1 > t0 ) t0 = t1, a = 1;
            if( t3 > t2 ) t2 = t3, b = 3;
            k = t0 > t2 ? a : b;
            val = k;

            t0 = GET_VALUE(4); t1 = GET_VALUE(5);
            t2 = GET_VALUE(6); t3 = GET_VALUE(7);
            a = 0, b = 2;
            if( t1 > t0 ) t0 = t1, a = 1;
            if( t3 > t2 ) t2 = t3, b = 3;
            k = t0 > t2 ? a : b;
            val |= k << 2;

            t0 = GET_VALUE(8); t1 = GET_VALUE(9);
            t2 = GET_VALUE(10); t3 = GET_VALUE(11);
            a = 0, b = 2;
            if( t1 > t0 ) t0 = t1, a = 1;
            if( t3 > t2 ) t2 = t3, b = 3;
            k = t0 > t2 ? a : b;
            val |= k << 4;

            t0 = GET_VALUE(12); t1 = GET_VALUE(13);
            t2 = GET_VALUE(14); t3 = GET_VALUE(15);
            a = 0, b = 2;
            if( t1 > t0 ) t0 = t1, a = 1;
            if( t3 > t2 ) t2 = t3, b = 3;
            k = t0 > t2 ? a : b;
            val |= k << 6;

            pattern += 16*2;
        #else
            #error "unknown/undefined WTA_K value; should be 2, 3 or 4"
        #endif
            desc[i] = (uchar)val;
        }
    }
}

#endif

// OpenCL port of the ORB feature detector and descriptor extractor
// Copyright (C) 2014, Itseez Inc. See the license at http://opencv.org
//
// The original code has been contributed by Peter Andreas Entschev, peter@entschev.com

#define LAYERINFO_SIZE 1
#define LAYERINFO_OFS 0
#define KEYPOINT_SIZE 3
#define ORIENTED_KEYPOINT_SIZE 4
#define KEYPOINT_X 0
#define KEYPOINT_Y 1
#define KEYPOINT_Z 2
#define KEYPOINT_ANGLE 3

/////////////////////////////////////////////////////////////

#ifdef ORB_RESPONSES

__kernel void
ORB_HarrisResponses(__global const uchar* imgbuf, int imgstep, int imgoffset0,
                    __global const int* layerinfo, __global const int* keypoints,
                    __global float* responses, int nkeypoints )
{
    int idx = get_global_id(0);
    if( idx < nkeypoints )
    {
        __global const int* kpt = keypoints + idx*KEYPOINT_SIZE;
        __global const int* layer = layerinfo + kpt[KEYPOINT_Z]*LAYERINFO_SIZE;
        __global const uchar* img = imgbuf + imgoffset0 + layer[LAYERINFO_OFS] +
            (kpt[KEYPOINT_Y] - blockSize/2)*imgstep + (kpt[KEYPOINT_X] - blockSize/2);

        int i, j;
        int a = 0, b = 0, c = 0;
        for( i = 0; i < blockSize; i++, img += imgstep-blockSize )
        {
            for( j = 0; j < blockSize; j++, img++ )
            {
                int Ix = (img[1] - img[-1])*2 + img[-imgstep+1] - img[-imgstep-1] + img[imgstep+1] - img[imgstep-1];
                int Iy = (img[imgstep] - img[-imgstep])*2 + img[imgstep-1] - img[-imgstep-1] + img[imgstep+1] - img[-imgstep+1];
                a += Ix*Ix;
                b += Iy*Iy;
                c += Ix*Iy;
            }
        }
        responses[idx] = ((float)a * b - (float)c * c - HARRIS_K * (float)(a + b) * (a + b))*scale_sq_sq;
    }
}

#endif

/////////////////////////////////////////////////////////////

#ifdef ORB_ANGLES

#define _DBL_EPSILON 2.2204460492503131e-16f
#define atan2_p1 (0.9997878412794807f*57.29577951308232f)
#define atan2_p3 (-0.3258083974640975f*57.29577951308232f)
#define atan2_p5 (0.1555786518463281f*57.29577951308232f)
#define atan2_p7 (-0.04432655554792128f*57.29577951308232f)

inline float fastAtan2( float y, float x )
{
    float ax = fabs(x), ay = fabs(y);
    float a, c, c2;
    if( ax >= ay )
    {
        c = ay/(ax + _DBL_EPSILON);
        c2 = c*c;
        a = (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c;
    }
    else
    {
        c = ax/(ay + _DBL_EPSILON);
        c2 = c*c;
        a = 90.f - (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c;
    }
    if( x < 0 )
        a = 180.f - a;
    if( y < 0 )
        a = 360.f - a;
    return a;
}

__kernel void
ORB_ICAngle(__global const uchar* imgbuf, int imgstep, int imgoffset0,
            __global const int* layerinfo, __global const int* keypoints,
            __global float* responses, const __global int* u_max,
            int nkeypoints, int half_k )
{
    int idx = get_global_id(0);
    if( idx < nkeypoints )
    {
        __global const int* kpt = keypoints + idx*KEYPOINT_SIZE;

        __global const int* layer = layerinfo + kpt[KEYPOINT_Z]*LAYERINFO_SIZE;
        __global const uchar* center = imgbuf + imgoffset0 + layer[LAYERINFO_OFS] +
            kpt[KEYPOINT_Y]*imgstep + kpt[KEYPOINT_X];

        int u, v, m_01 = 0, m_10 = 0;

        // Treat the center line differently, v=0
        for( u = -half_k; u <= half_k; u++ )
            m_10 += u * center[u];

        // Go line by line in the circular patch
        for( v = 1; v <= half_k; v++ )
        {
            // Proceed over the two lines
            int v_sum = 0;
            int d = u_max[v];
            for( u = -d; u <= d; u++ )
            {
                int val_plus = center[u + v*imgstep], val_minus = center[u - v*imgstep];
                v_sum += (val_plus - val_minus);
                m_10 += u * (val_plus + val_minus);
            }
            m_01 += v * v_sum;
        }

        // we do not use OpenCL's atan2 intrinsic,
        // because we want to get _exactly_ the same results as the CPU version
        responses[idx] = fastAtan2((float)m_01, (float)m_10);
    }
}

#endif

/////////////////////////////////////////////////////////////

#ifdef ORB_DESCRIPTORS

__kernel void
ORB_computeDescriptor(__global const uchar* imgbuf, int imgstep, int imgoffset0,
                      __global const int* layerinfo, __global const int* keypoints,
                      __global uchar* _desc, const __global int* pattern,
                      int nkeypoints, int dsize )
{
    int idx = get_global_id(0);
    if( idx < nkeypoints )
    {
        int i;
        __global const int* kpt = keypoints + idx*ORIENTED_KEYPOINT_SIZE;

        __global const int* layer = layerinfo + kpt[KEYPOINT_Z]*LAYERINFO_SIZE;
        __global const uchar* center = imgbuf + imgoffset0 + layer[LAYERINFO_OFS] +
                                kpt[KEYPOINT_Y]*imgstep + kpt[KEYPOINT_X];
        float angle = as_float(kpt[KEYPOINT_ANGLE]);
        angle *= 0.01745329251994329547f;

        float sina = sin(angle);
        float cosa = cos(angle);

        __global uchar* desc = _desc + idx*dsize;

        #define GET_VALUE(idx) \
            center[mad24(convert_int_rte(pattern[(idx)*2] * sina + pattern[(idx)*2+1] * cosa), imgstep, \
                        convert_int_rte(pattern[(idx)*2] * cosa - pattern[(idx)*2+1] * sina))]

        for( i = 0; i < dsize; i++ )
        {
            int val;
        #if WTA_K == 2
            int t0, t1;

            t0 = GET_VALUE(0); t1 = GET_VALUE(1);
            val = t0 < t1;

            t0 = GET_VALUE(2); t1 = GET_VALUE(3);
            val |= (t0 < t1) << 1;

            t0 = GET_VALUE(4); t1 = GET_VALUE(5);
            val |= (t0 < t1) << 2;

            t0 = GET_VALUE(6); t1 = GET_VALUE(7);
            val |= (t0 < t1) << 3;

            t0 = GET_VALUE(8); t1 = GET_VALUE(9);
            val |= (t0 < t1) << 4;

            t0 = GET_VALUE(10); t1 = GET_VALUE(11);
            val |= (t0 < t1) << 5;

            t0 = GET_VALUE(12); t1 = GET_VALUE(13);
            val |= (t0 < t1) << 6;

            t0 = GET_VALUE(14); t1 = GET_VALUE(15);
            val |= (t0 < t1) << 7;

            pattern += 16*2;

        #elif WTA_K == 3
            int t0, t1, t2;

            t0 = GET_VALUE(0); t1 = GET_VALUE(1); t2 = GET_VALUE(2);
            val = t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0);

            t0 = GET_VALUE(3); t1 = GET_VALUE(4); t2 = GET_VALUE(5);
            val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 2;

            t0 = GET_VALUE(6); t1 = GET_VALUE(7); t2 = GET_VALUE(8);
            val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 4;

            t0 = GET_VALUE(9); t1 = GET_VALUE(10); t2 = GET_VALUE(11);
            val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 6;

            pattern += 12*2;

        #elif WTA_K == 4
            int t0, t1, t2, t3, k, val;
            int a, b;

            t0 = GET_VALUE(0); t1 = GET_VALUE(1);
            t2 = GET_VALUE(2); t3 = GET_VALUE(3);
            a = 0, b = 2;
            if( t1 > t0 ) t0 = t1, a = 1;
            if( t3 > t2 ) t2 = t3, b = 3;
            k = t0 > t2 ? a : b;
            val = k;

            t0 = GET_VALUE(4); t1 = GET_VALUE(5);
            t2 = GET_VALUE(6); t3 = GET_VALUE(7);
            a = 0, b = 2;
            if( t1 > t0 ) t0 = t1, a = 1;
            if( t3 > t2 ) t2 = t3, b = 3;
            k = t0 > t2 ? a : b;
            val |= k << 2;

            t0 = GET_VALUE(8); t1 = GET_VALUE(9);
            t2 = GET_VALUE(10); t3 = GET_VALUE(11);
            a = 0, b = 2;
            if( t1 > t0 ) t0 = t1, a = 1;
            if( t3 > t2 ) t2 = t3, b = 3;
            k = t0 > t2 ? a : b;
            val |= k << 4;

            t0 = GET_VALUE(12); t1 = GET_VALUE(13);
            t2 = GET_VALUE(14); t3 = GET_VALUE(15);
            a = 0, b = 2;
            if( t1 > t0 ) t0 = t1, a = 1;
            if( t3 > t2 ) t2 = t3, b = 3;
            k = t0 > t2 ? a : b;
            val |= k << 6;

            pattern += 16*2;
        #else
            #error "unknown/undefined WTA_K value; should be 2, 3 or 4"
        #endif
            desc[i] = (uchar)val;
        }
    }
}

#endif