Clear template-lines after end marker so we can do multiple replacements per file. Check lpp.cl modified to and force regen templates

(defstruct param type name deref funcset)
(defstruct funcdef funcset funcname params returntype)

(setq preprocessor-file-extension "lpp")
(setq begin-marker-left "^^^BEGINREPLACE:")
(setq begin-marker-right "^^^")
(setq end-marker "^^^ENDREPLACE^^^")
(setq auto-header-marker "^^^AUTOGENHEADER^^^")
(setq token-marker #\^)
(setq token-arg-marker #\:)
(setq token-arg-delimiter #\,)

(defstruct lppmacro macro filter)

(setq macro-hash (make-hash-table :test 'equal))
(defun add-macro (&rest args)
  (let ((m (apply #'make-lppmacro args)))
    (setf (gethash (lppmacro-macro m) macro-hash) m)))
(defun get-macro (key) (gethash key macro-hash))

(setq void-param-hash (make-hash-table :test 'equal))
(defun add-void-param (&rest args)
  (let* ((p (apply #'make-param args))
         (funcset-name (param-funcset p)))
    (cond ((not (null funcset-name))
           (setf (gethash funcset-name void-param-hash) p))
          (t (error "Must provide :funcset for add-void-param")))))

(defun get-void-param (funcset-name) (gethash funcset-name void-param-hash))

(add-macro :macro "RETURN"      :filter (lambda (fd len args vp) (funcdef-returntype fd)))
(add-macro :macro "FUNC"        :filter (lambda (fd len args vp) (funcdef-funcname fd)))
(add-macro :macro "PARAMS"      :filter (lambda (fd len args vp) (format-params (funcdef-params fd) len args vp)))

;; PARAMS arguments: types, names, deref, ref, void, voidonly, nowrap
;;;;;;;;;;;;;;;;;;

(defun partial (func &rest args1)
  (lambda (&rest args2) (apply func (append args1 args2))))

(defun newline ()
  (write-string (format nil "~%")))

(defun concat-string-list (s)
  (format nil "~{~A~^~%~}" s))

(defun replace-all (string part replacement &key (test #'char=))
  "Returns a new string in which all the occurences of the part
is replaced with replacement."
  (with-output-to-string (out)
    (loop with part-length = (length part)
       for old-pos = 0 then (+ pos part-length)
       for pos = (search part string
                         :start2 old-pos
                         :test test)
       do (write-string string out
                        :start old-pos
                        :end (or pos (length string)))
       when pos do (write-string replacement out)
       while pos)))

(defun back-to-forward-slashes (str)
  (replace-all str "\\" "/")
)

(defun is-arg-set (target-arg args)
  (not (null (find target-arg args :test 'equal))))

(defun format-paramitem-type (args p)
  (format nil "~A" (param-type p)))

(defun format-paramitem-name (args p)
  ;;in name only format, we can dereference the argument (pointer)
  ;;but only if the macro argument requested it
  ;;and this parameter can be dereferenced
  (if (and (is-arg-set "deref" args) (param-deref p))
      ;;then
      (format nil "*~A" (param-name p))
      ;;else
      (format nil "~A" (param-name p))))

(defun format-paramitem-full (args p)
  (let* ((type-decl (param-type p))
         (last-index (1- (length type-decl))))
    (format nil "~A ~A"
            ;;if macro requested reference mode,
            ;; this parameter is dereferencable,
            ;; and the last char is a *
            (if (and (is-arg-set "ref" args) (param-deref p) (equal "*" (subseq type-decl last-index)))
                ;;then, replace the last * with a &
                (concatenate 'string (subseq type-decl 0 last-index) "&")
                ;;else
                type-decl)
            (param-name p))))

(defun error-if-null (var errmsg) (when (null var) (error errmsg)))

(defun format-params (params token-start-length args void-param)
  ;;full, types, names, deref, ref, void, voidonly, nowrap
  (let*  ((arg-types      (is-arg-set "types" args))
          (arg-names      (is-arg-set "names" args))
          (arg-deref      (is-arg-set "deref" args))
          (arg-ref        (is-arg-set "ref" args))
          (arg-void       (is-arg-set "void" args))
          (arg-voidonly   (is-arg-set "voidonly" args))
          (arg-wrap       (is-arg-set "wrap" args))
          (arg-nowrap     (is-arg-set "nowrap" args))
          (filtered-params (cond  (arg-voidonly
                                   (error-if-null void-param "Void param must be set to use void argument")
                                   (cons void-param nil)) ;;only the void-param
                                  (arg-void
                                   (error-if-null void-param "Void param must be set to use void argument")
                                   (cons void-param params)) ;;prepend the void-param
                                  (t params))) ;;default, just use params
          (types-only (and arg-types (not arg-names)))
          (names-only (and arg-names (not arg-types)))
          (full-decl  (not (xor arg-names arg-types)))
          (format-param-func (cond  (full-decl  #'format-paramitem-full)
                                    (types-only #'format-paramitem-type)
                                    (names-only #'format-paramitem-name)))
          (do-wrap    (or arg-wrap (not (or names-only arg-nowrap))))
          (format-line (if do-wrap "~{~A~^,~%~}" "~{~A~^, ~}")))
    (when filtered-params
      (format nil format-line
              (cons
               ;;first parameter => no indentation
               (apply format-param-func (list args (car filtered-params)))
               (mapcar
                (lambda (p)
                  (concatenate 'string
                               ;;second parameter, indent according to wrap policy
                               (when do-wrap (make-string token-start-length :initial-element #\ ))
                               (apply format-param-func (list args p))))
                (cdr filtered-params)))))))

(defun split-by-delimiter (string delimiter)
  (loop   for start = 0 then (1+ finish)
     for finish = (position delimiter string :start start)
     if (and (not (eq (length string) start))
             (not (eq start finish)))
     collect (subseq string start finish)
     until (null finish)))

(defun process-tokens (line funcdata void-param &optional (line-length 0))
  (let ((token-marker-left (position token-marker line)))
    (if (null token-marker-left)
        ;;then, no left token marker. return line
        line
        ;;else, process more
        (let* ((token-start (1+ token-marker-left))
               (token-stop (position token-marker line :start token-start)))
          (if (null token-stop)
              ;;then, no right token marker. return line
              line
              ;;else, process more
              (let* ((token-full (subseq line token-start token-stop))
                     (seperator-index (position token-arg-marker token-full))
                     (token (subseq token-full 0 seperator-index))
                     (token-args (if (not (null seperator-index))
                                     (split-by-delimiter
                                      (subseq token-full (1+ seperator-index) nil) token-arg-delimiter)
                                     '(nil)))
                     (line-begin (subseq line 0 token-marker-left))
                     (line-end (subseq line (1+ token-stop) nil))
                     (m (get-macro token)))
                ;;m (the macro struct) is nil if no macro found for the token
                (if (null m)
                    ;;then
                    line
                    ;;else
                    (let* ((token-start-length (+ line-length token-marker-left))
                           (expanded-token
                            (funcall (lppmacro-filter m)
                                     funcdata
                                     token-start-length
                                     token-args void-param)))
                      (concatenate 'string
                                   line-begin
                                   expanded-token
                                   (process-tokens
                                    line-end
                                    funcdata
                                    void-param
                                    (+ token-start-length (length expanded-token))))))))))))

(defun expand-template (template-list func-data void-param)
  (concat-string-list
   (mapcar
    (lambda (template-line) (process-tokens template-line func-data void-param))
    template-list)))

(defun expand-methods-with-template (template-list funcset-name)
  (remove nil ;;filter out the nil values (from wrong funcsets)
          (mapcar
           (lambda (func-data)
             (cond ;;only expand this function if it belongs to the target funcset
               ((equal funcset-name (funcdef-funcset func-data))
                (expand-template template-list func-data (get-void-param funcset-name)))
               ;;otherwise return nil
               (t nil)))
           funcs)))

(defun clear-funcs ()
  (setq funcs nil)
  (setq funcs-tail funcs))

(clear-funcs)

(defun add-func (&rest args)
  (let ((func-data (apply #'make-funcdef args)))
    (if (endp funcs)
        ;;then
        (progn
          (setq funcs (cons func-data nil))
          (setq funcs-tail funcs))
        ;;else
        (progn
          (setf (cdr funcs-tail) (cons func-data nil))
          (setq funcs-tail (cdr funcs-tail))))))

(defun outputfuncs (f)
  (write-line (concat-string-list f)))

(defun filter-line (line filename)
  (replace-all line
               auto-header-marker
               (format nil "THIS FILE AUTO-GENERATED FROM ~A. DO NOT EDIT." filename)))

(defmacro prepend-into (var value)
  `(setq ,var (cons ,value ,var)))

(defun strip-end-characters (str numChars)
  (let ((index (- (length str) numChars)))
    (if (>= index 1)
        (subseq str 0 index)
        nil)))

(defun get-funcset-from-begin-marker (line)
  (let ((start-index (search begin-marker-left line)))
    (cond ;;no begin marker, return nil
      ((null start-index) nil)

      ;;begin marker must be at start of line
      ((not (= start-index 0)) nil)

      ;;left side is good
      (t (let*  ((start-param-index (+ start-index (length begin-marker-left)))
                 (end-index (search begin-marker-right line :start2 start-param-index)))
           (cond ;;no right side marker, return nil
             ((null end-index) nil)

             ;;right marker must be at end of line
             ((not (= (length line) (+ end-index (length begin-marker-right)))) nil)

             ;;markers but no funcset parameter, can't process
             ((= start-param-index end-index) nil)
             ;;we have a begin-marker and funcset parameter!
             (t (values (subseq line start-param-index end-index) start-param-index end-index))))))))

(defun is-end-marker (line)
  (equal line end-marker))

(defun in-to-out-filename (fn)
  (strip-end-characters fn 4))

(defun process-file (infilename)
  (let ((infile (open infilename :if-does-not-exist nil))
        (outfile (open (in-to-out-filename infilename) :direction :output :if-exists :supersede))
        (filelines nil)
        (template-lines nil)
        (funcset-name nil))
    (when infile
      (loop
         for line = (read-line infile nil)
         while line
         do
           (cond   ;;outside of a replace block
             ((null funcset-name)
              ;;look for a begin-replace marker (funcset name becomes not nil)
              (setq funcset-name (get-funcset-from-begin-marker line))
              ;;if still no funcset-name
              (when (null funcset-name)
                ;;accumulate filtered lines to filelines
                (prepend-into filelines (filter-line line (file-namestring infilename)))))

             ;;all below: funcset-name is not nil -- inside of a replace block
             ;;check for end marker
             ((is-end-marker line)
              ;;since we have a full template, expand template it
              (mapcar
               (lambda (v) (prepend-into filelines v))
               (expand-methods-with-template (reverse template-lines) funcset-name))
              (setq funcset-name nil)  ;;clear funcset-name -- return to normal operation above
              (setq template-lines nil) ;;clear template so we can process another one in the same file
             )
             ;;inside replace block, accumulate template
             (t (prepend-into template-lines line))))
      (loop for line in (reverse filelines)
         do (write-line line outfile))
      (close infile)
      (close outfile))))

(defvar api-file "apidef.cl")
(defvar lpp-file "lpp.cl")

(load api-file :verbose nil)
(load "cl-fad/load.lisp" :verbose nil)

(defun mapc-directory-tree (fn directory)
  (dolist (entry (cl-fad:list-directory directory))
    (when (cl-fad:directory-pathname-p entry)
      (mapc-directory-tree fn entry))
    (funcall fn entry)))

(defun _ () (load lpp-file :verbose nil))

(defun file-modified-time (f)
  (cond ((probe-file f) (posix:file-stat-mtime (posix:file-stat f)))
        (t 0)
  )
)

(defun process (dir)
  (let* ((target-directory (if (null dir)
                               (ext:cd)
                               dir))
         (cache-file-path (cl-fad:merge-pathnames-as-file
                           (cl-fad:pathname-as-directory target-directory)
                           ".pp-modification-cache.cl"))
         (api-modify (file-modified-time api-file))
         (lpp-modify (file-modified-time lpp-file))
         (pp-cache (with-open-file (fsi cache-file-path :if-does-not-exist nil)
                      (cond ((null fsi) (make-hash-table :test 'equal) )
                            (t (let ((data (read fsi nil)))
                                  (if (hash-table-p data)
                                      data
                                      (make-hash-table :test 'equal)
                                   )
                               ))
                      )
                   ))
        )
    (write-line (format nil "=== LPP processing directory: ~A ===~%" target-directory))
    (mapc-directory-tree (lambda (x)
                           (when (equal (pathname-type x) preprocessor-file-extension)
                             (let* ((fwd-path (back-to-forward-slashes (namestring x)))
                                    (cache-modify (gethash fwd-path pp-cache 0))
                                    (last-modify (max lpp-modify api-modify (file-modified-time x)))
                                   )
                               (when (> last-modify cache-modify)
                                 (write-line (format nil "~A => ~A"
                                                     (enough-namestring x target-directory)
                                                     (in-to-out-filename (file-namestring x))
                                             ))

                                 (process-file (namestring x))
                                 (setf (gethash fwd-path pp-cache) last-modify)
                               )
                             )
                           )
                         )
                         target-directory)
    (with-open-file (fso cache-file-path :direction :output :if-does-not-exist :create :if-exists :supersede)
      (write pp-cache :stream fso)
    )
  )
)

;(process (car *args*))
(process "../include")
(process "../src")

(defstruct param type name deref funcset)
(defstruct funcdef funcset funcname params returntype)

(setq preprocessor-file-extension "lpp")
(setq begin-marker-left "^^^BEGINREPLACE:")
(setq begin-marker-right "^^^")
(setq end-marker "^^^ENDREPLACE^^^")
(setq auto-header-marker "^^^AUTOGENHEADER^^^")
(setq token-marker #\^)
(setq token-arg-marker #\:)
(setq token-arg-delimiter #\,)

(defstruct lppmacro macro filter)

(setq macro-hash (make-hash-table :test 'equal))
(defun add-macro (&rest args)
  (let ((m (apply #'make-lppmacro args)))
    (setf (gethash (lppmacro-macro m) macro-hash) m)))
(defun get-macro (key) (gethash key macro-hash))

(setq void-param-hash (make-hash-table :test 'equal))
(defun add-void-param (&rest args)
  (let* ((p (apply #'make-param args))
         (funcset-name (param-funcset p)))
    (cond ((not (null funcset-name))
           (setf (gethash funcset-name void-param-hash) p))
          (t (error "Must provide :funcset for add-void-param")))))

(defun get-void-param (funcset-name) (gethash funcset-name void-param-hash))

(add-macro :macro "RETURN"      :filter (lambda (fd len args vp) (funcdef-returntype fd)))
(add-macro :macro "FUNC"        :filter (lambda (fd len args vp) (funcdef-funcname fd)))
(add-macro :macro "PARAMS"      :filter (lambda (fd len args vp) (format-params (funcdef-params fd) len args vp)))

;; PARAMS arguments: types, names, deref, ref, void, voidonly, nowrap
;;;;;;;;;;;;;;;;;;

(defun partial (func &rest args1)
  (lambda (&rest args2) (apply func (append args1 args2))))

(defun newline ()
  (write-string (format nil "~%")))

(defun concat-string-list (s)
  (format nil "~{~A~^~%~}" s))

(defun replace-all (string part replacement &key (test #'char=))
  "Returns a new string in which all the occurences of the part
is replaced with replacement."
  (with-output-to-string (out)
    (loop with part-length = (length part)
       for old-pos = 0 then (+ pos part-length)
       for pos = (search part string
                         :start2 old-pos
                         :test test)
       do (write-string string out
                        :start old-pos
                        :end (or pos (length string)))
       when pos do (write-string replacement out)
       while pos)))

(defun back-to-forward-slashes (str)
  (replace-all str "\\" "/")
)

(defun is-arg-set (target-arg args)
  (not (null (find target-arg args :test 'equal))))

(defun format-paramitem-type (args p)
  (format nil "~A" (param-type p)))

(defun format-paramitem-name (args p)
  ;;in name only format, we can dereference the argument (pointer)
  ;;but only if the macro argument requested it
  ;;and this parameter can be dereferenced
  (if (and (is-arg-set "deref" args) (param-deref p))
      ;;then
      (format nil "*~A" (param-name p))
      ;;else
      (format nil "~A" (param-name p))))

(defun format-paramitem-full (args p)
  (let* ((type-decl (param-type p))
         (last-index (1- (length type-decl))))
    (format nil "~A ~A"
            ;;if macro requested reference mode,
            ;; this parameter is dereferencable,
            ;; and the last char is a *
            (if (and (is-arg-set "ref" args) (param-deref p) (equal "*" (subseq type-decl last-index)))
                ;;then, replace the last * with a &
                (concatenate 'string (subseq type-decl 0 last-index) "&")
                ;;else
                type-decl)
            (param-name p))))

(defun error-if-null (var errmsg) (when (null var) (error errmsg)))

(defun format-params (params token-start-length args void-param)
  ;;full, types, names, deref, ref, void, voidonly, nowrap
  (let*  ((arg-types      (is-arg-set "types" args))
          (arg-names      (is-arg-set "names" args))
          (arg-deref      (is-arg-set "deref" args))
          (arg-ref        (is-arg-set "ref" args))
          (arg-void       (is-arg-set "void" args))
          (arg-voidonly   (is-arg-set "voidonly" args))
          (arg-wrap       (is-arg-set "wrap" args))
          (arg-nowrap     (is-arg-set "nowrap" args))
          (filtered-params (cond  (arg-voidonly
                                   (error-if-null void-param "Void param must be set to use void argument")
                                   (cons void-param nil)) ;;only the void-param
                                  (arg-void
                                   (error-if-null void-param "Void param must be set to use void argument")
                                   (cons void-param params)) ;;prepend the void-param
                                  (t params))) ;;default, just use params
          (types-only (and arg-types (not arg-names)))
          (names-only (and arg-names (not arg-types)))
          (full-decl  (not (xor arg-names arg-types)))
          (format-param-func (cond  (full-decl  #'format-paramitem-full)
                                    (types-only #'format-paramitem-type)
                                    (names-only #'format-paramitem-name)))
          (do-wrap    (or arg-wrap (not (or names-only arg-nowrap))))
          (format-line (if do-wrap "~{~A~^,~%~}" "~{~A~^, ~}")))
    (when filtered-params
      (format nil format-line
              (cons
               ;;first parameter => no indentation
               (apply format-param-func (list args (car filtered-params)))
               (mapcar
                (lambda (p)
                  (concatenate 'string
                               ;;second parameter, indent according to wrap policy
                               (when do-wrap (make-string token-start-length :initial-element #\ ))
                               (apply format-param-func (list args p))))
                (cdr filtered-params)))))))

(defun split-by-delimiter (string delimiter)
  (loop   for start = 0 then (1+ finish)
     for finish = (position delimiter string :start start)
     if (and (not (eq (length string) start))
             (not (eq start finish)))
     collect (subseq string start finish)
     until (null finish)))

(defun process-tokens (line funcdata void-param &optional (line-length 0))
  (let ((token-marker-left (position token-marker line)))
    (if (null token-marker-left)
        ;;then, no left token marker. return line
        line
        ;;else, process more
        (let* ((token-start (1+ token-marker-left))
               (token-stop (position token-marker line :start token-start)))
          (if (null token-stop)
              ;;then, no right token marker. return line
              line
              ;;else, process more
              (let* ((token-full (subseq line token-start token-stop))
                     (seperator-index (position token-arg-marker token-full))
                     (token (subseq token-full 0 seperator-index))
                     (token-args (if (not (null seperator-index))
                                     (split-by-delimiter
                                      (subseq token-full (1+ seperator-index) nil) token-arg-delimiter)
                                     '(nil)))
                     (line-begin (subseq line 0 token-marker-left))
                     (line-end (subseq line (1+ token-stop) nil))
                     (m (get-macro token)))
                ;;m (the macro struct) is nil if no macro found for the token
                (if (null m)
                    ;;then
                    line
                    ;;else
                    (let* ((token-start-length (+ line-length token-marker-left))
                           (expanded-token
                            (funcall (lppmacro-filter m)
                                     funcdata
                                     token-start-length
                                     token-args void-param)))
                      (concatenate 'string
                                   line-begin
                                   expanded-token
                                   (process-tokens
                                    line-end
                                    funcdata
                                    void-param
                                    (+ token-start-length (length expanded-token))))))))))))

(defun expand-template (template-list func-data void-param)
  (concat-string-list
   (mapcar
    (lambda (template-line) (process-tokens template-line func-data void-param))
    template-list)))

(defun expand-methods-with-template (template-list funcset-name)
  (remove nil ;;filter out the nil values (from wrong funcsets)
          (mapcar
           (lambda (func-data)
             (cond ;;only expand this function if it belongs to the target funcset
               ((equal funcset-name (funcdef-funcset func-data))
                (expand-template template-list func-data (get-void-param funcset-name)))
               ;;otherwise return nil
               (t nil)))
           funcs)))

(defun clear-funcs ()
  (setq funcs nil)
  (setq funcs-tail funcs))

(clear-funcs)

(defun add-func (&rest args)
  (let ((func-data (apply #'make-funcdef args)))
    (if (endp funcs)
        ;;then
        (progn
          (setq funcs (cons func-data nil))
          (setq funcs-tail funcs))
        ;;else
        (progn
          (setf (cdr funcs-tail) (cons func-data nil))
          (setq funcs-tail (cdr funcs-tail))))))

(defun outputfuncs (f)
  (write-line (concat-string-list f)))

(defun filter-line (line filename)
  (replace-all line
               auto-header-marker
               (format nil "THIS FILE AUTO-GENERATED FROM ~A. DO NOT EDIT." filename)))

(defmacro prepend-into (var value)
  `(setq ,var (cons ,value ,var)))

(defun strip-end-characters (str numChars)
  (let ((index (- (length str) numChars)))
    (if (>= index 1)
        (subseq str 0 index)
        nil)))

(defun get-funcset-from-begin-marker (line)
  (let ((start-index (search begin-marker-left line)))
    (cond ;;no begin marker, return nil
      ((null start-index) nil)

      ;;begin marker must be at start of line
      ((not (= start-index 0)) nil)

      ;;left side is good
      (t (let*  ((start-param-index (+ start-index (length begin-marker-left)))
                 (end-index (search begin-marker-right line :start2 start-param-index)))
           (cond ;;no right side marker, return nil
             ((null end-index) nil)

             ;;right marker must be at end of line
             ((not (= (length line) (+ end-index (length begin-marker-right)))) nil)

             ;;markers but no funcset parameter, can't process
             ((= start-param-index end-index) nil)
             ;;we have a begin-marker and funcset parameter!
             (t (values (subseq line start-param-index end-index) start-param-index end-index))))))))

(defun is-end-marker (line)
  (equal line end-marker))

(defun in-to-out-filename (fn)
  (strip-end-characters fn 4))

(defun process-file (infilename)
  (let ((infile (open infilename :if-does-not-exist nil))
        (outfile (open (in-to-out-filename infilename) :direction :output :if-exists :supersede))
        (filelines nil)
        (templatelines nil)
        (funcset-name nil))
    (when infile
      (loop
         for line = (read-line infile nil)
         while line
         do
           (cond   ;;outside of a replace block
             ((null funcset-name)
              ;;look for a begin-replace marker (funcset name becomes not nil)
              (setq funcset-name (get-funcset-from-begin-marker line))
              ;;if still no funcset-name
              (when (null funcset-name)
                ;;accumulate filtered lines to filelines
                (prepend-into filelines (filter-line line (file-namestring infilename)))))

             ;;all below: funcset-name is not nil -- inside of a replace block
             ;;check for end marker
             ((is-end-marker line)
              ;;since we have a full template, expand template it
              (mapcar
               (lambda (v) (prepend-into filelines v))
               (expand-methods-with-template (reverse templatelines) funcset-name))
              (setq funcset-name nil))  ;;clear funcset-name -- return to normal operation above
             ;;inside replace block, accumulate template
             (t (prepend-into templatelines line))))
      (loop for line in (reverse filelines)
         do (write-line line outfile))
      (close infile)
      (close outfile))))

(defvar api-file "apidef.cl")

(load api-file :verbose nil)
(load "cl-fad/load.lisp" :verbose nil)

(defun mapc-directory-tree (fn directory)
  (dolist (entry (cl-fad:list-directory directory))
    (when (cl-fad:directory-pathname-p entry)
      (mapc-directory-tree fn entry))
    (funcall fn entry)))

(defun _ () (load "lpp.cl" :verbose nil))

(defun file-modified-time (f)
  (cond ((probe-file f) (posix:file-stat-mtime (posix:file-stat f)))
        (t 0)
  )
)

(defun process (dir)
  (let* ((target-directory (if (null dir)
                               (ext:cd)
                               dir))
         (cache-file-path (cl-fad:merge-pathnames-as-file
                           (cl-fad:pathname-as-directory target-directory)
                           ".pp-modification-cache.cl"))
         (api-modify (file-modified-time api-file))
         (pp-cache (with-open-file (fsi cache-file-path :if-does-not-exist nil)
                      (cond ((null fsi) (make-hash-table :test 'equal) )
                            (t (let ((data (read fsi nil)))
                                  (if (hash-table-p data)
                                      data
                                      (make-hash-table :test 'equal)
                                   )
                               ))
                      )
                   ))
        )
    (write-line (format nil "=== LPP processing directory: ~A ===~%" target-directory))
    (mapc-directory-tree (lambda (x)
                           (when (equal (pathname-type x) preprocessor-file-extension)
                             (let* ((fwd-path (back-to-forward-slashes (namestring x)))
                                    (cache-modify (gethash fwd-path pp-cache 0))
                                    (last-modify (max api-modify (file-modified-time x)))
                                   )
                               (when (> last-modify cache-modify)
                                 (write-line (format nil "~A => ~A"
                                                     (enough-namestring x target-directory)
                                                     (in-to-out-filename (file-namestring x))
                                             ))

                                 (process-file (namestring x))
                                 (setf (gethash fwd-path pp-cache) last-modify)
                               )
                             )
                           )
                         )
                         target-directory)
    (with-open-file (fso cache-file-path :direction :output :if-does-not-exist :create :if-exists :supersede)
      (write pp-cache :stream fso)
    )
  )
)

;(process (car *args*))
(process "../include")
(process "../src")


fixed slope limiter bug

fixed slope limiter bug

// common types:

typedef struct {
	real min, max;
} range_t;

// common:

//http://developer.amd.com/resources/documentation-articles/articles-whitepapers/opencl-optimization-case-study-simple-reductions/
//calculate min of all elements on buffer[0..length-1]
__kernel void reduceMin(
	const __global real* buffer,
	__local real* scratch,
	__const int length,
	__global real* result)
{
	int global_index = get_global_id(0);
	real accumulator = INFINITY;

	// Loop sequentially over chunks of input vector
	while (global_index < length) {
		real element = buffer[global_index];
		accumulator = (accumulator < element) ? accumulator : element;
		global_index += get_global_size(0);
	}

	// Perform parallel reduction
	int local_index = get_local_id(0);
	scratch[local_index] = accumulator;
	barrier(CLK_LOCAL_MEM_FENCE);
	for (int offset = get_local_size(0) / 2; offset > 0; offset = offset / 2) {
		if (local_index < offset) {
			real other = scratch[local_index + offset];
			real mine = scratch[local_index];
			scratch[local_index] = (mine < other) ? mine : other;
		}
		barrier(CLK_LOCAL_MEM_FENCE);
	}
	if (local_index == 0) {
		result[get_group_id(0)] = scratch[0];
	}
}

// private:

constant real gamma_1 = gamma - 1;
constant real gamma_3 = gamma - 3;
real calc_hTotal(real rho, real P, real ETotal) {
	return (P + ETotal) / rho;
}

// equation/solver API:

constant int4 gridSize = (int4)(gridSize_x, gridSize_y, gridSize_z, 0);
constant real4 dxs = (real4)(dx, 0, 0, 0);
constant int4 stepsize = (int4)(1,
	gridSize_x,
	gridSize_x * gridSize_y,
	gridSize_x * gridSize_y * gridSize_z);

//donor cell
//real slopeLimiter(real r) { return 0.; }
//Lax-Wendroff:
//real slopeLimiter(real r) { return 1.; }
//Superbee
real slopeLimiter(real r) { return max(0., max(min(1., 2. * r), min(2., r))); }

cons_t consFromPrim(prim_t W) {
	return (cons_t){
		.rho = W.rho,
		.mx = W.rho * W.vx,
		.ETotal = .5 * W.rho * W.vx * W.vx + W.P / (gamma - 1),
	};
}

prim_t primFromCons(cons_t U) {
	real EInt = U.ETotal - .5 * U.mx * U.mx / U.rho;
	return (prim_t){
		.rho = U.rho,
		.vx = U.mx / U.rho,
		.P = EInt / (gamma - 1),
	};
}

__kernel void convertToTex(
	__write_only dstimage_t tex,
	int displayVar,
	const __global real* buf
) {
	SETBOUNDS(0,0);
	real value = 0;
	int intindex = dim * index;	//side 0
	if (displayVar >= display_wave_0 && displayVar < display_wave_0 + numWaves) {
		const __global real* wave = buf + intindex * numWaves;
		value = wave[displayVar - display_wave_0];
	} else if (displayVar >= display_eigen_0 && displayVar < display_eigen_0 + numEigen) {
		const __global real* eigen = buf + intindex * numEigen;
		value = eigen[displayVar - display_eigen_0];
	} else if (displayVar >= display_deltaUTilde_0 && displayVar < display_deltaUTilde_0 + numWaves) {
		const __global real* deltaUTilde = buf + intindex * numWaves;
		value = deltaUTilde[displayVar - display_deltaUTilde_0];
	} else if (displayVar >= display_rTilde_0 && displayVar < display_rTilde_0 + numWaves) {
		const __global real* rTilde = buf + intindex * numWaves;
		value = rTilde[displayVar - display_rTilde_0];
	} else if (displayVar >= display_flux_0 && displayVar < display_flux_0 + numStates) {
		const __global real* flux = buf + intindex * numStates;
		value = flux[displayVar - display_flux_0];
	} else if (displayVar >= display_deriv_0 && displayVar < display_deriv_0 + numStates) {
		const __global real* deriv = buf + index * numStates;
		value = deriv[displayVar - display_deriv_0];
	} else if (displayVar == display_dt_0) {
		value = buf[index];
	} else if (displayVar == display_orthoError_0) {
		value = buf[intindex];
	} else {
		cons_t U = *(const __global cons_t*)(buf + index * numStates);
		prim_t W = primFromCons(U);
		real rho = W.rho;
		real vx = W.vx;
		real P = W.P;
		switch (displayVar) {
		case display_U_rho: value = rho; break;
		case display_U_vx: value = vx; break;
		case display_U_P: value = P; break;
		case display_U_eInt: value = P / (rho * gamma_1); break;
		case display_U_eKin: value = .5 * vx * vx; break;
		case display_U_eTotal: value = U.ETotal / rho; break;
		}
	}
	write_imagef(tex, WRITEIMAGEARGS, (float4)(value, 0., 0., 0.));
}

range_t calcCellMinMaxEigenvalues(cons_t U) {
	prim_t W = primFromCons(U);
	real Cs = sqrt(gamma * W.P / W.rho);
	return (range_t){
		.min = W.vx - Cs,
		.max = W.vx + Cs,
	};
}

typedef struct {
	real rho, vx, hTotal;
} Roe_t;

Roe_t calcEigenBasisSide(cons_t UL, cons_t UR) {
	prim_t WL = primFromCons(UL);
	real sqrtRhoL = sqrt(WL.rho);
	real vxL = WL.vx;
	real hTotalL = calc_hTotal(WL.rho, WL.P, UL.ETotal);

	prim_t WR = primFromCons(UR);
	real sqrtRhoR = sqrt(UR.rho);
	real vxR = WR.vx;
	real hTotalR = calc_hTotal(WR.rho, WR.P, UR.ETotal);

	real invDenom = 1./(sqrtRhoL + sqrtRhoR);

	return (Roe_t){
		.rho = sqrtRhoL * sqrtRhoR,
		.vx = invDenom * (sqrtRhoL * vxL + sqrtRhoR * vxR),
		.hTotal = invDenom * (sqrtRhoL * hTotalL + sqrtRhoR * hTotalR),
	};
}

// Roe solver:

__kernel void initState(
	__global cons_t* UBuf
) {
	SETBOUNDS(0,0);
	real x = (real)(i.x + .5) * dx + xmin;
	UBuf[index] = consFromPrim((prim_t){
		.rho = x < 0 ? 1 : .125,
		.vx = 0,
		.P = x < 0 ? 1 : .1,
	});
}

__kernel void calcDT(
	__global real* dtBuf,
	const __global cons_t* UBuf
) {
	SETBOUNDS(0,0);
	if (i.x < 2 || i.x >= gridSize_x - 2
#if dim > 1
		|| i.y < 2 || i.y >= gridSize_y - 2
#endif
#if dim > 2
		|| i.z < 2 || i.z >= gridSize_z - 2
#endif
	) {
		dtBuf[index] = INFINITY;
		return;
	}

	range_t lambda = calcCellMinMaxEigenvalues(UBuf[index]);
	lambda.min = min(0., lambda.min);
	lambda.max = max(0., lambda.max);
	dtBuf[index] = dx / (fabs(lambda.max - lambda.min) + 1e-9);
}

void fillRow(__global real* ptr, int step, real a, real b, real c) {
	ptr[0*step] = a;
	ptr[1*step] = b;
	ptr[2*step] = c;
}

__kernel void calcEigenBasis(
	__global real* waveBuf,			//[volume][dim][numWaves]
	__global real* eigenBuf,		//[volume][dim][numEigen]
	__global real* fluxMatrixBuf,	//[volume][dim][numStates][numStates]
	const __global cons_t *UBuf		//[volume]
) {
	SETBOUNDS(2,1);
	int indexR = index;
	for (int side = 0; side < dim; ++side) {
		int indexL = index - stepsize[side];

		Roe_t roe = calcEigenBasisSide(UBuf[indexL], UBuf[indexR]);
		real vx = roe.vx;
		real hTotal = roe.hTotal;

		real vxSq = vx * vx;
		real CsSq = gamma_1 * (hTotal - .5 * vx * vx);
		real Cs = sqrt(CsSq);

		int intindex = side + dim * index;
		__global real* wave = waveBuf + numWaves * intindex;
		fillRow(wave, 1, vx - Cs, vx, vx + Cs);

		__global real* fluxMatrix = fluxMatrixBuf + numStates * numStates * intindex;
		fillRow(fluxMatrix+0, 3,	0, 									1, 							0			);
		fillRow(fluxMatrix+1, 3,	.5 * gamma_3 * vxSq, 				-gamma_3 * vx, 				gamma_1		);
		fillRow(fluxMatrix+2, 3, 	vx * (.5 * gamma_1 * vxSq - hTotal), hTotal - gamma_1 * vxSq,	gamma*vx	);

		__global real* evL = eigenBuf + intindex * numEigen;
		fillRow(evL+0, 3, (.5 * gamma_1 * vxSq + Cs * vx) / (2. * CsSq),	-(Cs + gamma_1 * vx) / (2. * CsSq),	gamma_1 / (2. * CsSq)	);
		fillRow(evL+1, 3, 1. - gamma_1 * vxSq / (2. * CsSq),				gamma_1 * vx / CsSq,				-gamma_1 / CsSq			);
		fillRow(evL+2, 3, (.5 * gamma_1 * vxSq - Cs * vx) / (2. * CsSq),	(Cs - gamma_1 * vx) / (2. * CsSq),	gamma_1 / (2. * CsSq)	);

		__global real* evR = evL + 3*3;
		fillRow(evR+0, 3, 1., 				1., 		1.				);
		fillRow(evR+1, 3, vx - Cs, 			vx, 		vx + Cs			);
		fillRow(evR+2, 3, hTotal - Cs * vx, .5 * vxSq, 	hTotal + Cs * vx);
	}
}

void eigenLeftTransform(
	real* y,
	const __global real* eigen,
	real* x)
{
	const __global real* A = eigen;
	for (int i = 0; i < numWaves; ++i) {
		real sum = 0;
		for (int j = 0; j < numStates; ++j) {
			sum += A[i+numWaves*j] * x[j];
		}
		y[i] = sum;
	}
}

void eigenRightTransform(
	real* y,
	const __global real* eigen,
	real* x
) {
	const __global real* A = eigen + numStates * numWaves;
	for (int i = 0; i < numWaves; ++i) {
		real sum = 0;
		for (int j = 0; j < numStates; ++j) {
			sum += A[i+numWaves*j] * x[j];
		}
		y[i] = sum;
	}
}

__kernel void calcErrors(
	__global real* orthoErrorBuf,
	__global real* fluxErrorBuf,
	const __global real* waveBuf,
	const __global real* eigenBuf,
	const __global real* fluxMatrixBuf
) {
	SETBOUNDS(2,1);
	for (int side = 0; side < dim; ++side) {
		int intindex = side + dim * index;
		const __global real* wave = waveBuf + numWaves * intindex;
		const __global real* eigen = eigenBuf + numEigen * intindex;
		const __global real* fluxMatrix = fluxMatrixBuf + numStates * numStates * intindex;

		real orthoError = 0;
		real fluxError = 0;
		for (int k = 0; k < numStates; ++k) {

			real src[numStates];
			for (int j = 0; j < numStates; ++j) {
				src[j] = k == j ? 1 : 0;
			}

			real mid[numWaves];
			eigenLeftTransform(mid, eigen, src);

			real scaled[numWaves];
			for (int j = 0; j < numWaves; ++j) {
				scaled[j] = mid[j] * wave[j];
			}

			real identCheck[numStates];
			eigenRightTransform(identCheck, eigen, mid);

			real fluxCheck[numStates];
			eigenRightTransform(fluxCheck, eigen, scaled);

			for (int j = 0; j < numStates; ++j) {
				orthoError += fabs(identCheck[j] - src[j]);
				fluxError += fabs(fluxCheck[j] - fluxMatrix[j + numStates * k]);
			}
		}
		orthoErrorBuf[intindex] = log(orthoError) / log(10.);
		fluxErrorBuf[intindex] = log(fluxError) / log(10.);
	}
}

__kernel void calcDeltaUTilde(
	__global real* deltaUTildeBuf,
	const __global real* UBuf,
	const __global real* eigenBuf
) {
	SETBOUNDS(2,1);
	int indexR = index;
	for (int side = 0; side < dim; ++side) {
		int indexL = index - stepsize[side];

		const __global real* UL = UBuf + indexL * numStates;
		const __global real* UR = UBuf + indexR * numStates;

		real deltaU[numStates];
		for (int j = 0; j < numStates; ++j) {
			deltaU[j] = UR[j] - UL[j];
		}

		int intindex = side + dim * index;
		real deltaUTilde[numWaves];
		eigenLeftTransform(
			deltaUTilde,
			eigenBuf + intindex * numEigen,
			deltaU);

		//TODO memcpy
		__global real* deltaUTilde_ = deltaUTildeBuf + intindex * numWaves;
		for (int j = 0; j < numWaves; ++j) {
			deltaUTilde_[j] = deltaUTilde[j];
		}
	}
}

__kernel void calcRTilde(
	__global real* rTildeBuf,
	const __global real* deltaUTildeBuf,
	const __global real* waveBuf
) {
	SETBOUNDS(2,1);
	for (int side = 0; side < dim; ++side) {
		int indexL = index - stepsize[side];
		int indexR = index + stepsize[side];
		int intindex = side + dim * index;
		int intindexL = side + dim * indexL;
		int intindexR = side + dim * indexR;
		__global real* rTilde = rTildeBuf + intindex * numWaves;
		const __global real* deltaUTilde = deltaUTildeBuf + intindex * numWaves;
		const __global real* deltaUTildeL = deltaUTildeBuf + intindexL * numWaves;
		const __global real* deltaUTildeR = deltaUTildeBuf + intindexR * numWaves;
		const __global real* wave = waveBuf + intindex * numWaves;
		for (int j = 0; j < numWaves; ++j) {
			if (deltaUTilde[j] == 0) {
				rTilde[j] = 0;
			} else {
				if (wave[j] >= 0) {
					rTilde[j] = deltaUTildeL[j] / deltaUTilde[j];
				} else {
					rTilde[j] = deltaUTildeR[j] / deltaUTilde[j];
				}
			}
		}
	}
}

__kernel void calcFlux(
	__global real* fluxBuf,
	const __global real* UBuf,
	const __global real* waveBuf,
	const __global real* eigenBuf,
	const __global real* deltaUTildeBuf,
	const __global real* rTildeBuf,
	real dt
) {
	SETBOUNDS(2,1);
	for (int side = 0; side < dim; ++side) {
		real dt_dx = dt / dxs[side];

		int indexL = index - stepsize[side];
		int indexR = index;
		const __global real* UL = UBuf + indexL * numStates;
		const __global real* UR = UBuf + indexR * numStates;

		real UAvg[numStates];
		for (int j = 0; j < numStates; ++j) {
			UAvg[j] = .5 * (UL[j] + UR[j]);
		}

		int intindex = side + dim * index;
		const __global real* eigen = eigenBuf + intindex * numEigen;

		real fluxTilde[numWaves];
		eigenLeftTransform(fluxTilde, eigen, UAvg);

		const __global real* lambdas = waveBuf + numWaves * intindex;
		const __global real* deltaUTilde = deltaUTildeBuf + numWaves * intindex;
		const __global real* rTilde = rTildeBuf + numWaves * intindex;

		for (int j = 0; j < numWaves; ++j) {
			real lambda = lambdas[j];
			fluxTilde[j] *= lambda;
			real theta = lambda >= 0 ? 1 : -1;
			real phi = slopeLimiter(rTilde[j]);
			real epsilon = lambda * dt_dx;
			real deltaFluxTilde = lambda * deltaUTilde[j];
			fluxTilde[j] -= .5 * deltaFluxTilde * (theta + phi * (epsilon - theta));
		}

		real flux[numStates];
		eigenRightTransform(flux, eigen, fluxTilde);

		__global real* flux_ = fluxBuf + intindex * numStates;
		for (int j = 0; j < numStates; ++j) {
			flux_[j] = flux[j];
		}
	}
}

__kernel void calcDerivFromFlux(
	__global real* derivBuf,
	const __global real* fluxBuf
) {
	SETBOUNDS(0,0);

	__global real* deriv = derivBuf + numStates * index;
	for (int j = 0; j < numStates; ++j) {
		deriv[j] = 0;
	}

	if (i.x < 2 || i.x >= gridSize_x - 2
#if dim > 1
		|| i.y < 2 || i.y >= gridSize_y - 2
#endif
#if dim > 2
		|| i.z < 2 || i.z >= gridSize_z - 2
#endif
	) {
		return;
	}

	for (int side = 0; side < dim; ++side) {
		int intindexL = side + dim * index;
		int intindexR = intindexL + dim * stepsize[side];
		const __global real* fluxL = fluxBuf + numStates * intindexL;
		const __global real* fluxR = fluxBuf + numStates * intindexR;
		for (int j = 0; j < numStates; ++j) {
			real deltaFlux = fluxR[j] - fluxL[j];
			deriv[j] -= deltaFlux / dxs[side];
		}
	}
}

__kernel void multAdd(
	__global real* a,
	const __global real* b,
	const __global real* c,
	real d
) {
	size_t i = get_global_id(0);
	if (i >= get_global_size(0)) return;
	a[i] = b[i] + c[i] * d;
}

// common types:

typedef struct {
	real min, max;
} range_t;

// common:

//http://developer.amd.com/resources/documentation-articles/articles-whitepapers/opencl-optimization-case-study-simple-reductions/
//calculate min of all elements on buffer[0..length-1]
__kernel void reduceMin(
	const __global real* buffer,
	__local real* scratch,
	__const int length,
	__global real* result)
{
	int global_index = get_global_id(0);
	real accumulator = INFINITY;

	// Loop sequentially over chunks of input vector
	while (global_index < length) {
		real element = buffer[global_index];
		accumulator = (accumulator < element) ? accumulator : element;
		global_index += get_global_size(0);
	}

	// Perform parallel reduction
	int local_index = get_local_id(0);
	scratch[local_index] = accumulator;
	barrier(CLK_LOCAL_MEM_FENCE);
	for (int offset = get_local_size(0) / 2; offset > 0; offset = offset / 2) {
		if (local_index < offset) {
			real other = scratch[local_index + offset];
			real mine = scratch[local_index];
			scratch[local_index] = (mine < other) ? mine : other;
		}
		barrier(CLK_LOCAL_MEM_FENCE);
	}
	if (local_index == 0) {
		result[get_group_id(0)] = scratch[0];
	}
}

// private:

constant real gamma_1 = gamma - 1;
constant real gamma_3 = gamma - 3;
real calc_hTotal(real rho, real P, real ETotal) {
	return (P + ETotal) / rho;
}

// equation/solver API:

constant int4 gridSize = (int4)(gridSize_x, gridSize_y, gridSize_z, 0);
constant real4 dxs = (real4)(dx, 0, 0, 0);
constant int4 stepsize = (int4)(1,
	gridSize_x,
	gridSize_x * gridSize_y,
	gridSize_x * gridSize_y * gridSize_z);

//Superbee
real slopeLimiter(real r) {
	return max(0., max(min(1., 2. * r), min(2., r)));
}

cons_t consFromPrim(prim_t W) {
	return (cons_t){
		.rho = W.rho,
		.mx = W.rho * W.vx,
		.ETotal = .5 * W.rho * W.vx * W.vx + W.P / (gamma - 1),
	};
}

prim_t primFromCons(cons_t U) {
	real EInt = U.ETotal - .5 * U.mx * U.mx / U.rho;
	return (prim_t){
		.rho = U.rho,
		.vx = U.mx / U.rho,
		.P = EInt / (gamma - 1),
	};
}

__kernel void convertToTex(
	__write_only dstimage_t tex,
	int displayVar,
	const __global real* buf
) {
	SETBOUNDS(0,0);
	real value = 0;
	int intindex = dim * index;	//side 0
	if (displayVar >= display_wave_0 && displayVar < display_wave_0 + numWaves) {
		const __global real* wave = buf + intindex * numWaves;
		value = wave[displayVar - display_wave_0];
	} else if (displayVar >= display_eigen_0 && displayVar < display_eigen_0 + numEigen) {
		const __global real* eigen = buf + intindex * numEigen;
		value = eigen[displayVar - display_eigen_0];
	} else if (displayVar >= display_deltaUTilde_0 && displayVar < display_deltaUTilde_0 + numWaves) {
		const __global real* deltaUTilde = buf + intindex * numWaves;
		value = deltaUTilde[displayVar - display_deltaUTilde_0];
	} else if (displayVar >= display_rTilde_0 && displayVar < display_rTilde_0 + numWaves) {
		const __global real* rTilde = buf + intindex * numWaves;
		value = rTilde[displayVar - display_rTilde_0];
	} else if (displayVar >= display_flux_0 && displayVar < display_flux_0 + numStates) {
		const __global real* flux = buf + intindex * numStates;
		value = flux[displayVar - display_flux_0];
	} else if (displayVar >= display_deriv_0 && displayVar < display_deriv_0 + numStates) {
		const __global real* deriv = buf + index * numStates;
		value = deriv[displayVar - display_deriv_0];
	} else if (displayVar == display_dt_0) {
		value = buf[index];
	} else if (displayVar == display_orthoError_0) {
		value = buf[intindex];
	} else {
		cons_t U = *(const __global cons_t*)(buf + index * numStates);
		prim_t W = primFromCons(U);
		real rho = W.rho;
		real vx = W.vx;
		real P = W.P;
		switch (displayVar) {
		case display_U_rho: value = rho; break;
		case display_U_vx: value = vx; break;
		case display_U_P: value = P; break;
		case display_U_eInt: value = P / (rho * gamma_1); break;
		case display_U_eKin: value = .5 * vx * vx; break;
		case display_U_eTotal: value = U.ETotal / rho; break;
		}
	}
	write_imagef(tex, WRITEIMAGEARGS, (float4)(value, 0., 0., 0.));
}

range_t calcCellMinMaxEigenvalues(cons_t U) {
	prim_t W = primFromCons(U);
	real Cs = sqrt(gamma * W.P / W.rho);
	return (range_t){
		.min = W.vx - Cs,
		.max = W.vx + Cs,
	};
}

typedef struct {
	real rho, vx, hTotal;
} Roe_t;

Roe_t calcEigenBasisSide(cons_t UL, cons_t UR) {
	prim_t WL = primFromCons(UL);
	real sqrtRhoL = sqrt(WL.rho);
	real vxL = WL.vx;
	real hTotalL = calc_hTotal(WL.rho, WL.P, UL.ETotal);

	prim_t WR = primFromCons(UR);
	real sqrtRhoR = sqrt(UR.rho);
	real vxR = WR.vx;
	real hTotalR = calc_hTotal(WR.rho, WR.P, UR.ETotal);

	real invDenom = 1./(sqrtRhoL + sqrtRhoR);

	return (Roe_t){
		.rho = sqrtRhoL * sqrtRhoR,
		.vx = invDenom * (sqrtRhoL * vxL + sqrtRhoR * vxR),
		.hTotal = invDenom * (sqrtRhoL * hTotalL + sqrtRhoR * hTotalR),
	};
}

// Roe solver:

__kernel void initState(
	__global cons_t* UBuf
) {
	SETBOUNDS(0,0);
	real x = (real)(i.x + .5) * dx + xmin;
	UBuf[index] = consFromPrim((prim_t){
		.rho = x < 0 ? 1 : .125,
		.vx = 0,
		.P = x < 0 ? 1 : .1,
	});
}

__kernel void calcDT(
	__global real* dtBuf,
	const __global cons_t* UBuf
) {
	SETBOUNDS(0,0);
	if (i.x < 2 || i.x >= gridSize_x - 2
#if dim > 1
		|| i.y < 2 || i.y >= gridSize_y - 2
#endif
#if dim > 2
		|| i.z < 2 || i.z >= gridSize_z - 2
#endif
	) {
		dtBuf[index] = INFINITY;
		return;
	}

	range_t lambda = calcCellMinMaxEigenvalues(UBuf[index]);
	lambda.min = min(0., lambda.min);
	lambda.max = max(0., lambda.max);
	dtBuf[index] = dx / (fabs(lambda.max - lambda.min) + 1e-9);
}

void fillRow(__global real* ptr, int step, real a, real b, real c) {
	ptr[0*step] = a;
	ptr[1*step] = b;
	ptr[2*step] = c;
}

__kernel void calcEigenBasis(
	__global real* waveBuf,			//[volume][dim][numWaves]
	__global real* eigenBuf,		//[volume][dim][numEigen]
	__global real* fluxMatrixBuf,	//[volume][dim][numStates][numStates]
	const __global cons_t *UBuf		//[volume]
) {
	SETBOUNDS(2,1);
	int indexR = index;
	for (int side = 0; side < dim; ++side) {
		int indexL = index - stepsize[side];

		Roe_t roe = calcEigenBasisSide(UBuf[indexL], UBuf[indexR]);
		real vx = roe.vx;
		real hTotal = roe.hTotal;

		real vxSq = vx * vx;
		real CsSq = gamma_1 * (hTotal - .5 * vx * vx);
		real Cs = sqrt(CsSq);

		int intindex = side + dim * index;
		__global real* wave = waveBuf + numWaves * intindex;
		fillRow(wave, 1, vx - Cs, vx, vx + Cs);

		__global real* fluxMatrix = fluxMatrixBuf + numStates * numStates * intindex;
		fillRow(fluxMatrix+0, 3,	0, 									1, 							0			);
		fillRow(fluxMatrix+1, 3,	.5 * gamma_3 * vxSq, 				-gamma_3 * vx, 				gamma_1		);
		fillRow(fluxMatrix+2, 3, 	vx * (.5 * gamma_1 * vxSq - hTotal), hTotal - gamma_1 * vxSq,	gamma*vx	);

		__global real* evL = eigenBuf + intindex * numEigen;
		fillRow(evL+0, 3, (.5 * gamma_1 * vxSq + Cs * vx) / (2. * CsSq),	-(Cs + gamma_1 * vx) / (2. * CsSq),	gamma_1 / (2. * CsSq)	);
		fillRow(evL+1, 3, 1. - gamma_1 * vxSq / (2. * CsSq),				gamma_1 * vx / CsSq,				-gamma_1 / CsSq			);
		fillRow(evL+2, 3, (.5 * gamma_1 * vxSq - Cs * vx) / (2. * CsSq),	(Cs - gamma_1 * vx) / (2. * CsSq),	gamma_1 / (2. * CsSq)	);

		__global real* evR = evL + 3*3;
		fillRow(evR+0, 3, 1., 				1., 		1.				);
		fillRow(evR+1, 3, vx - Cs, 			vx, 		vx + Cs			);
		fillRow(evR+2, 3, hTotal - Cs * vx, .5 * vxSq, 	hTotal + Cs * vx);
	}
}

void eigenLeftTransform(
	real* y,
	const __global real* eigen,
	real* x)
{
	const __global real* A = eigen;
	for (int i = 0; i < numWaves; ++i) {
		real sum = 0;
		for (int j = 0; j < numStates; ++j) {
			sum += A[i+numWaves*j] * x[j];
		}
		y[i] = sum;
	}
}

void eigenRightTransform(
	real* y,
	const __global real* eigen,
	real* x
) {
	const __global real* A = eigen + numStates * numWaves;
	for (int i = 0; i < numWaves; ++i) {
		real sum = 0;
		for (int j = 0; j < numStates; ++j) {
			sum += A[i+numWaves*j] * x[j];
		}
		y[i] = sum;
	}
}

__kernel void calcErrors(
	__global real* orthoErrorBuf,
	__global real* fluxErrorBuf,
	const __global real* waveBuf,
	const __global real* eigenBuf,
	const __global real* fluxMatrixBuf
) {
	SETBOUNDS(2,1);
	for (int side = 0; side < dim; ++side) {
		int intindex = side + dim * index;
		const __global real* wave = waveBuf + numWaves * intindex;
		const __global real* eigen = eigenBuf + numEigen * intindex;
		const __global real* fluxMatrix = fluxMatrixBuf + numStates * numStates * intindex;

		real orthoError = 0;
		real fluxError = 0;
		for (int k = 0; k < numStates; ++k) {

			real src[numStates];
			for (int j = 0; j < numStates; ++j) {
				src[j] = k == j ? 1 : 0;
			}

			real mid[numWaves];
			eigenLeftTransform(mid, eigen, src);

			real scaled[numWaves];
			for (int j = 0; j < numWaves; ++j) {
				scaled[j] = mid[j] * wave[j];
			}

			real identCheck[numStates];
			eigenRightTransform(identCheck, eigen, mid);

			real fluxCheck[numStates];
			eigenRightTransform(fluxCheck, eigen, scaled);

			for (int j = 0; j < numStates; ++j) {
				orthoError += fabs(identCheck[j] - src[j]);
				fluxError += fabs(fluxCheck[j] - fluxMatrix[j + numStates * k]);
			}
		}
		orthoErrorBuf[intindex] = log(orthoError) / log(10.);
		fluxErrorBuf[intindex] = log(fluxError) / log(10.);
	}
}

__kernel void calcDeltaUTilde(
	__global real* deltaUTildeBuf,
	const __global real* UBuf,
	const __global real* eigenBuf
) {
	SETBOUNDS(2,1);
	int indexR = index;
	for (int side = 0; side < dim; ++side) {
		int indexL = index - stepsize[side];

		const __global real* UL = UBuf + indexL * numStates;
		const __global real* UR = UBuf + indexR * numStates;

		real deltaU[numStates];
		for (int j = 0; j < numStates; ++j) {
			deltaU[j] = UR[j] - UL[j];
		}

		int intindex = side + dim * index;
		real deltaUTilde[numWaves];
		eigenLeftTransform(
			deltaUTilde,
			eigenBuf + intindex * numEigen,
			deltaU);

		//TODO memcpy
		__global real* deltaUTilde_ = deltaUTildeBuf + intindex * numWaves;
		for (int j = 0; j < numWaves; ++j) {
			deltaUTilde_[j] = deltaUTilde[j];
		}
	}
}

__kernel void calcRTilde(
	__global real* rTildeBuf,
	const __global real* deltaUTildeBuf,
	const __global real* waveBuf
) {
	SETBOUNDS(2,1);
	for (int side = 0; side < dim; ++side) {
		int indexL = index - stepsize[side];
		int indexR = index + stepsize[side];
		int intindex = side + dim * index;
		int intindexL = side + dim * indexL;
		int intindexR = side + dim * indexR;
		__global real* rTilde = rTildeBuf + intindex * numWaves;
		const __global real* deltaUTilde = deltaUTildeBuf + intindex * numWaves;
		const __global real* deltaUTildeL = deltaUTildeBuf + intindexL * numWaves;
		const __global real* deltaUTildeR = deltaUTildeBuf + intindexR * numWaves;
		const __global real* wave = waveBuf + intindex * numWaves;
		for (int j = 0; j < numWaves; ++j) {
			if (deltaUTilde[j] == 0) {
				rTilde[j] = 0;
			} else {
				if (wave[j] >= 0) {
					rTilde[j] = deltaUTildeR[j] / deltaUTilde[j];
				} else {
					rTilde[j] = deltaUTildeL[j] / deltaUTilde[j];
				}
			}
		}
	}
}

__kernel void calcFlux(
	__global real* fluxBuf,
	const __global real* UBuf,
	const __global real* waveBuf,
	const __global real* eigenBuf,
	const __global real* deltaUTildeBuf,
	const __global real* rTildeBuf,
	real dt
) {
	SETBOUNDS(2,1);
	for (int side = 0; side < dim; ++side) {
		real dt_dx = dt / dxs[side];

		int indexL = index - stepsize[side];
		int indexR = index;
		const __global real* UL = UBuf + indexL * numStates;
		const __global real* UR = UBuf + indexR * numStates;

		real UAvg[numStates];
		for (int j = 0; j < numStates; ++j) {
			UAvg[j] = .5 * (UL[j] + UR[j]);
		}

		int intindex = side + dim * index;
		const __global real* eigen = eigenBuf + intindex * numEigen;

		real fluxTilde[numWaves];
		eigenLeftTransform(fluxTilde, eigen, UAvg);

		const __global real* lambdas = waveBuf + intindex * numWaves;
		const __global real* deltaUTilde = deltaUTildeBuf + intindex * numWaves;

		for (int j = 0; j < numWaves; ++j) {
			real lambda = lambdas[j];
			fluxTilde[j] *= lambda;
			real rTilde = rTildeBuf[j + numWaves * intindex];
			real theta = lambda >= 0 ? 1 : -1;
			real phi = slopeLimiter(rTilde);
			real epsilon = lambda * dt_dx;
			real deltaFluxTilde = lambda * deltaUTilde[j];
			fluxTilde[j] -= .5 * deltaFluxTilde * (theta + phi * (epsilon - theta));
		}

		real flux[numStates];
		eigenRightTransform(flux, eigen, fluxTilde);

		__global real* flux_ = fluxBuf + intindex * numStates;
		for (int j = 0; j < numStates; ++j) {
			flux_[j] = flux[j];
		}
	}
}

__kernel void calcDerivFromFlux(
	__global real* derivBuf,
	const __global real* fluxBuf
) {
	SETBOUNDS(0,0);

	__global real* deriv = derivBuf + numStates * index;
	for (int j = 0; j < numStates; ++j) {
		deriv[j] = 0;
	}

	if (i.x < 2 || i.x >= gridSize_x - 2
#if dim > 1
		|| i.y < 2 || i.y >= gridSize_y - 2
#endif
#if dim > 2
		|| i.z < 2 || i.z >= gridSize_z - 2
#endif
	) {
		return;
	}

	for (int side = 0; side < dim; ++side) {
		int intindexL = side + dim * index;
		int intindexR = intindexL + dim * stepsize[side];
		const __global real* fluxL = fluxBuf + numStates * intindexL;
		const __global real* fluxR = fluxBuf + numStates * intindexR;
		for (int j = 0; j < numStates; ++j) {
			real deltaFlux = fluxR[j] - fluxL[j];
			deriv[j] -= deltaFlux / dxs[side];
		}
	}
}

__kernel void multAdd(
	__global real* a,
	const __global real* b,
	const __global real* c,
	real d
) {
	size_t i = get_global_id(0);
	if (i >= get_global_size(0)) return;
	a[i] = b[i] + c[i] * d;
}


Replaced modulus with ternary in OpenCL Mersenne

/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

/********************************************************
 * Copyright (c) 2009, 2010 Mutsuo Saito, Makoto Matsumoto and Hiroshima
 * University.
 * Copyright (c) 2011, 2012 Mutsuo Saito, Makoto Matsumoto, Hiroshima
 * University and University of Tokyo.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of the Hiroshima University, The Uinversity
 *       of Tokyo nor the names of its contributors may be used to
 *       endorse or promote products derived from this software without
 *       specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************/

#define divup(N, D) (((N) + (D) - 1)/(D));

void read_table(__local uint * const localTable, __global const uint * const table)
{
    __global const uint * const t = table + (get_group_id(0) * TABLE_SIZE);
    if (get_local_id(0) < TABLE_SIZE) {
        localTable[get_local_id(0)] = t[get_local_id(0)];
    }
}

void state_read(__local uint * const localState, __global const uint * const state)
{
    __global const uint * const g = state + (get_group_id(0) * N);
    localState[STATE_SIZE - N + get_local_id(0)] = g[get_local_id(0)];
    if (get_local_id(0) < N - THREADS) {
        localState[STATE_SIZE - N + THREADS + get_local_id(0)] = g[THREADS + get_local_id(0)];
    }
}

void state_write(__global uint * const state, __local const uint * const localState)
{
    __global uint * const g = state + (get_group_id(0) * N);
    g[get_local_id(0)] = localState[STATE_SIZE - N + get_local_id(0)];
    if (get_local_id(0) < N - THREADS) {
        g[THREADS + get_local_id(0)] = localState[STATE_SIZE - N + THREADS + get_local_id(0)];
    }
}

uint recursion(__local const uint * const recursion_table, const uint mask,
        const uint sh1, const uint sh2, const uint x1, const uint x2, uint y)
{
    uint x = (x1 & mask) ^ x2;
    x ^= x << sh1;
    y = x ^ (y >> sh2);
    uint mat = recursion_table[y & 0x0f];
    return y ^ mat;
}

uint temper(__local const uint * const temper_table, const uint v, uint t)
{
     t ^= t >> 16;
     t ^= t >> 8;
     uint mat = temper_table[t & 0x0f];
     return v ^ mat;
}

__kernel void generate(__global T *output,
        __global uint * const state,
        __global const uint * const pos_tbl,
        __global const uint * const sh1_tbl,
        __global const uint * const sh2_tbl,
        uint mask,
        __global const uint * const recursion_table,
        __global const uint * const temper_table,
        uint elements_per_block, uint elements)
{
    __local uint l_state[STATE_SIZE];
    __local uint l_recursion_table[TABLE_SIZE];
    __local uint l_temper_table[TABLE_SIZE];
    uint start = get_group_id(0)*elements_per_block;
    uint end = start + elements_per_block;
    end = (end > elements)? elements : end;
    int iter = divup((end - start)*sizeof(T), THREADS*4*sizeof(uint));
    uint pos = pos_tbl[get_group_id(0)];
    uint sh1 = sh1_tbl[get_group_id(0)];
    uint sh2 = sh2_tbl[get_group_id(0)];

    state_read(l_state, state);
    read_table(l_recursion_table, recursion_table);
    read_table(l_temper_table, temper_table);
    barrier(CLK_LOCAL_MEM_FENCE);

    uint index = start;
    int elementsPerBlockIteration = THREADS*4*sizeof(uint)/sizeof(T);
    uint o[4];
    int offsetX1 = (STATE_SIZE - N + get_local_id(0)          ) % STATE_SIZE;
    int offsetX2 = (STATE_SIZE - N + get_local_id(0) + 1      ) % STATE_SIZE;
    int offsetY  = (STATE_SIZE - N + get_local_id(0) + pos    ) % STATE_SIZE;
    int offsetT  = (STATE_SIZE - N + get_local_id(0) + pos - 1) % STATE_SIZE;
    int offsetO  = get_local_id(0);

    for (int i = 0; i < iter; ++i) {
        for (int ii = 0; ii < 4; ++ii) {
            uint r = recursion(l_recursion_table, mask, sh1, sh2,
                    l_state[offsetX1],
                    l_state[offsetX2],
                    l_state[offsetY ]);
            l_state[offsetO] = r;
            o[ii] = temper(l_temper_table, r, l_state[offsetT]);
            offsetX1 += THREADS;
            offsetX2 += THREADS;
            offsetY  += THREADS;
            offsetT  += THREADS;
            offsetO  += THREADS;
            offsetX1 = (offsetX1 >= STATE_SIZE)? offsetX1 - STATE_SIZE : offsetX1;
            offsetX2 = (offsetX2 >= STATE_SIZE)? offsetX2 - STATE_SIZE : offsetX2;
            offsetY  = (offsetY  >= STATE_SIZE)? offsetY  - STATE_SIZE : offsetY ;
            offsetT  = (offsetT  >= STATE_SIZE)? offsetT  - STATE_SIZE : offsetT ;
            offsetO  = (offsetO  >= STATE_SIZE)? offsetO  - STATE_SIZE : offsetO ;
            barrier(CLK_LOCAL_MEM_FENCE);
        }
        uint writeIndex = index + get_local_id(0);
        if (i == iter - 1) {
            PARTIAL_WRITE(output, &writeIndex, &o[0], &o[1], &o[2], &o[3], &elements);
        } else {
            WRITE(output, &writeIndex, &o[0], &o[1], &o[2], &o[3]);
        }
        index += elementsPerBlockIteration;
    }
    state_write(state, l_state);
}

/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

/********************************************************
 * Copyright (c) 2009, 2010 Mutsuo Saito, Makoto Matsumoto and Hiroshima
 * University.
 * Copyright (c) 2011, 2012 Mutsuo Saito, Makoto Matsumoto, Hiroshima
 * University and University of Tokyo.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of the Hiroshima University, The Uinversity
 *       of Tokyo nor the names of its contributors may be used to
 *       endorse or promote products derived from this software without
 *       specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************/

#define divup(N, D) (((N) + (D) - 1)/(D));

void read_table(__local uint * const localTable, __global const uint * const table)
{
    __global const uint * const t = table + (get_group_id(0) * TABLE_SIZE);
    if (get_local_id(0) < TABLE_SIZE) {
        localTable[get_local_id(0)] = t[get_local_id(0)];
    }
}

void state_read(__local uint * const localState, __global const uint * const state)
{
    __global const uint * const g = state + (get_group_id(0) * N);
    localState[STATE_SIZE - N + get_local_id(0)] = g[get_local_id(0)];
    if (get_local_id(0) < N - THREADS) {
        localState[STATE_SIZE - N + THREADS + get_local_id(0)] = g[THREADS + get_local_id(0)];
    }
}

void state_write(__global uint * const state, __local const uint * const localState)
{
    __global uint * const g = state + (get_group_id(0) * N);
    g[get_local_id(0)] = localState[STATE_SIZE - N + get_local_id(0)];
    if (get_local_id(0) < N - THREADS) {
        g[THREADS + get_local_id(0)] = localState[STATE_SIZE - N + THREADS + get_local_id(0)];
    }
}

uint recursion(__local const uint * const recursion_table, const uint mask,
        const uint sh1, const uint sh2, const uint x1, const uint x2, uint y)
{
    uint x = (x1 & mask) ^ x2;
    x ^= x << sh1;
    y = x ^ (y >> sh2);
    uint mat = recursion_table[y & 0x0f];
    return y ^ mat;
}

uint temper(__local const uint * const temper_table, const uint v, uint t)
{
     t ^= t >> 16;
     t ^= t >> 8;
     uint mat = temper_table[t & 0x0f];
     return v ^ mat;
}

__kernel void generate(__global T *output,
        __global uint * const state,
        __global const uint * const pos_tbl,
        __global const uint * const sh1_tbl,
        __global const uint * const sh2_tbl,
        uint mask,
        __global const uint * const recursion_table,
        __global const uint * const temper_table,
        uint elements_per_block, uint elements)
{
    __local uint l_state[STATE_SIZE];
    __local uint l_recursion_table[TABLE_SIZE];
    __local uint l_temper_table[TABLE_SIZE];
    uint start = get_group_id(0)*elements_per_block;
    uint end = start + elements_per_block;
    end = (end > elements)? elements : end;
    int iter = divup((end - start)*sizeof(T), THREADS*4*sizeof(uint));
    uint pos = pos_tbl[get_group_id(0)];
    uint sh1 = sh1_tbl[get_group_id(0)];
    uint sh2 = sh2_tbl[get_group_id(0)];

    state_read(l_state, state);
    read_table(l_recursion_table, recursion_table);
    read_table(l_temper_table, temper_table);
    barrier(CLK_LOCAL_MEM_FENCE);

    uint index = start;
    int elementsPerBlockIteration = THREADS*4*sizeof(uint)/sizeof(T);
    uint o[4];
    int offsetX1 = (STATE_SIZE - N + get_local_id(0)          ) % STATE_SIZE;
    int offsetX2 = (STATE_SIZE - N + get_local_id(0) + 1      ) % STATE_SIZE;
    int offsetY  = (STATE_SIZE - N + get_local_id(0) + pos    ) % STATE_SIZE;
    int offsetT  = (STATE_SIZE - N + get_local_id(0) + pos - 1) % STATE_SIZE;
    int offsetO  = get_local_id(0);

    for (int i = 0; i < iter; ++i) {
        for (int ii = 0; ii < 4; ++ii) {
            uint r = recursion(l_recursion_table, mask, sh1, sh2,
                    l_state[offsetX1],
                    l_state[offsetX2],
                    l_state[offsetY ]);
            l_state[offsetO] = r;
            o[ii] = temper(l_temper_table, r, l_state[offsetT]);
            offsetX1 = (offsetX1 + THREADS) % STATE_SIZE;
            offsetX2 = (offsetX2 + THREADS) % STATE_SIZE;
            offsetY  = (offsetY  + THREADS) % STATE_SIZE;
            offsetT  = (offsetT  + THREADS) % STATE_SIZE;
            offsetO  = (offsetO  + THREADS) % STATE_SIZE;
            barrier(CLK_LOCAL_MEM_FENCE);
        }
        uint writeIndex = index + get_local_id(0);
        if (i == iter - 1) {
            PARTIAL_WRITE(output, &writeIndex, &o[0], &o[1], &o[2], &o[3], &elements);
        } else {
            WRITE(output, &writeIndex, &o[0], &o[1], &o[2], &o[3]);
        }
        index += elementsPerBlockIteration;
    }
    state_write(state, l_state);
}


fixed interior destructor spheros

fixed interior destructor spheros

#include "kernel_header.h"

float3			get_abc(float radius, float3 ray, float3 origin)
{
	float3		abc;

	abc.x = dot_vect(ray, ray);
	abc.y = 2 * dot_vect(ray, origin);
	abc.z = dot_vect(origin, origin) - (radius * radius);
	return (abc);
}

float			inter_sphere(float radius, float3 ray, float3 cam_origin, float3 sphere_origin)
{
	float3		abc;
	float		d;
	float		res1;
	float		res2;

	cam_origin.x -= sphere_origin.x;
	cam_origin.y -= sphere_origin.y;
	cam_origin.z -= sphere_origin.z;
	abc = get_abc(radius, ray, cam_origin);
	d = (abc.y * abc.y) - (4 * (abc.x * abc.z));
	if (d < 0)
		return (1000000000);
	if (d == 0)
		return ((-abc[1]) / (2 * abc[0]));
	res1 = (((-abc[1]) + sqrt(d)) / (2 * abc[0]));
	res2 = (((-abc[1]) - sqrt(d)) / (2 * abc[0]));
	if (res1 < res2 && res1 > 0 || res1 > res2 && res2 < 0)
		return(res1);
	return(res2);
}

float			inter_plan(float3 plan_origin, float3 plan_normale, float3 ray, float3 cam_origin)
{
	float		t;

	t = dot_vect(ray, plan_normale);

	t = dot_vect(sub_vect(plan_origin, cam_origin), plan_normale) / t;
	if (t < 0.0000001)
		return (1000000000);
	return (t);
}

float3			get_ray(float3 n, float3 v, float3 h, int x, int y)
{
	float3		res;

	h = mult_fvect(modh_vect(x), h);
	v = mult_fvect(modv_vect(y), v);
	res = add_vect(n, v);
	res = add_vect(res, h);
	return (res);
}

__kernel void	ray_trace(__global char *output,
							float3 mvt,
							__constant t_object *scene)
{
	int		id = get_global_id(0);
	int		x = id % WINX;
	int		y = id / WINX;

	// CAM
	float3	cam_origin;
	cam_origin.x = 0 + mvt.x;
	cam_origin.y = 0 + mvt.y;
	cam_origin.z = 0 + mvt.z;
	float3	hor;
	hor.x = 0.6;
	hor.y = 0;
	hor.z = 0;
	float3	vert;
	vert.x = 0;
	vert.y = 0.6;
	vert.z = 0;
	float3	cam_dir;
	cam_dir.x = 0;
	cam_dir.y = 0;
	cam_dir.z = 1;

	// SPHERE
	float3	boule_origin;
	boule_origin.x = 0;
	boule_origin.y = 10;
	boule_origin.z = 200;
	float	radius = 10;

	// SPHERE2
	float3	boule_origin2;
	boule_origin2.x = 0;
	boule_origin2.y = -10;
	boule_origin2.z = 50;
	float	radius2 = 10;

	// PLANE
	float3	plan_origin;
	plan_origin.x = 0;
	plan_origin.y = 0;
	plan_origin.z = 300;
	float3	plan_normale;
	plan_normale.x = 0;
	plan_normale.y = -1;
	plan_normale.z = 0;

	float plan;
	float sphere;
	float sphere2;

	plan_origin = plan_origin + plan_normale;

	float3 ray = get_ray(cam_dir, vert, hor, x ,y);
	if (( plan = inter_plan(plan_origin, plan_normale, ray, cam_origin)) < 0)
		plan = 1000000000;
	if (( sphere= inter_sphere(radius, ray, cam_origin, boule_origin)) < 0)
		sphere = 1000000000;
	if ((sphere2 = inter_sphere(radius2, ray, cam_origin, boule_origin2)) < 0)
		sphere2 = 1000000000;
	if (sphere == 1000000000 && plan == 1000000000 && sphere2 == 1000000000)
		OUTPUTE = BACKCOLOR;
	else if (sphere < plan && sphere < sphere2)
		OUTPUTE = SCOLOR;
	else if (sphere2 < sphere && sphere2 < plan)
		OUTPUTE = SSCOLOR;
	else
		OUTPUTE = PCOLOR;
}

#include "kernel_header.h"

float3			get_abc(float radius, float3 ray, float3 origin)
{
	float3		abc;

	abc.x = dot_vect(ray, ray);
	abc.y = 2 * dot_vect(ray, origin);
	abc.z = dot_vect(origin, origin) - (radius * radius);
	return (abc);
}

float			inter_sphere(float radius, float3 ray, float3 cam_origin, float3 sphere_origin)
{
	float3		abc;
	float		d;
	float		res1;
	float		res2;

	cam_origin.x -= sphere_origin.x;
	cam_origin.y -= sphere_origin.y;
	cam_origin.z -= sphere_origin.z;
	abc = get_abc(radius, ray, cam_origin);
	d = (abc.y * abc.y) - (4 * (abc.x * abc.z));
	if (d < 0)
		return (1000000000);
	if (d == 0)
		return ((-abc[1]) / (2 * abc[0]));
	res1 = (((-abc[1]) + sqrt(d)) / (2 * abc[0]));
	res2 = (((-abc[1]) - sqrt(d)) / (2 * abc[0]));
	if (res1 < res2 && res1 > 0)
		return(res1);
	return(res2);
}

float			inter_plan(float3 plan_origin, float3 plan_normale, float3 ray, float3 cam_origin)
{
	float		t;

	t = dot_vect(ray, plan_normale);

	t = dot_vect(sub_vect(plan_origin, cam_origin), plan_normale) / t;
	if (t < 0.0000001)
		return (1000000000);
	return (t);
}

float3			get_ray(float3 n, float3 v, float3 h, int x, int y)
{
	float3		res;

	h = mult_fvect(modh_vect(x), h);
	v = mult_fvect(modv_vect(y), v);
	res = add_vect(n, v);
	res = add_vect(res, h);
	return (res);
}

__kernel void	ray_trace(__global char *output,
							float3 mvt,
							__constant t_object *scene)
{
	int		id = get_global_id(0);
	int		x = id % WINX;
	int		y = id / WINX;

	// CAM
	float3	cam_origin;
	cam_origin.x = 0 + mvt.x;
	cam_origin.y = 0 + mvt.y;
	cam_origin.z = 0 + mvt.z;
	float3	hor;
	hor.x = 0.6;
	hor.y = 0;
	hor.z = 0;
	float3	vert;
	vert.x = 0;
	vert.y = 0.6;
	vert.z = 0;
	float3	cam_dir;
	cam_dir.x = 0;
	cam_dir.y = 0;
	cam_dir.z = 1;

	// SPHERE
	float3	boule_origin;
	boule_origin.x = 0;
	boule_origin.y = 10;
	boule_origin.z = 200;
	float	radius = 10;

	// SPHERE2
	float3	boule_origin2;
	boule_origin2.x = 0;
	boule_origin2.y = -10;
	boule_origin2.z = 50;
	float	radius2 = 10;

	// PLANE
	float3	plan_origin;
	plan_origin.x = 0;
	plan_origin.y = 0;
	plan_origin.z = 300;
	float3	plan_normale;
	plan_normale.x = 0;
	plan_normale.y = -1;
	plan_normale.z = 0;

	float plan;
	float sphere;
	float sphere2;

	plan_origin = plan_origin + plan_normale;

	float3 ray = get_ray(cam_dir, vert, hor, x ,y);
	if (( plan = inter_plan(plan_origin, plan_normale, ray, cam_origin)) < 0)
		plan = 1000000000;
	if (( sphere= inter_sphere(radius, ray, cam_origin, boule_origin)) < 0)
		sphere = 1000000000;
	if ((sphere2 = inter_sphere(radius2, ray, cam_origin, boule_origin2)) < 0)
		sphere2 = 1000000000;
	if (sphere == 1000000000 && plan == 1000000000 && sphere2 == 1000000000)
		OUTPUTE = BACKCOLOR;
	else if (sphere < plan && sphere < sphere2)
		OUTPUTE = SCOLOR;
	else if (sphere2 < sphere && sphere2 < plan)
		OUTPUTE = SSCOLOR;
	else
		OUTPUTE = PCOLOR;
}