(ffi:clines "
#include <SDL2/SDL.h>

SDL_Renderer *renderer;
SDL_Window *window;
SDL_Event e;

const Uint8 *state;

int mx, my; Uint32 mdown;
int quitted;
")

(Defpackage "jam-no-theme" (:use cl) (:nicknames :ja))

(in-package :ja)

(defmacro game ((&rest shared-vars)
               (&rest shared-declares)
               &rest update-closures)
`(let ,shared-vars
  ,(append '(declare) shared-declares)
  (ffi:c-progn ,(mapcar 'car shared-vars)
   "

if (SDL_Init(SDL_INIT_VIDEO) < 0) {
       SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
           \"Failed to init %s\",
           SDL_GetError());
       " (error "failed to SDL_Init(video)") "
}

if (SDL_CreateWindowAndRenderer(640,480,SDL_WINDOW_RESIZABLE,
       &window, &renderer)) {
       SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
           \"Failed to create w & r%s\",
           SDL_GetError());
       " (error "failed to create window and renderer") "
}

quitted = 0;
for (;;) {"
       "
       while(SDL_PollEvent(&e))
           if (e.type == SDL_QUIT) quitted = 1;
           else if (e.type == SDL_KEYDOWN)
               switch (e.key.keysym.sym) {
               case SDLK_q:
                   quitted = 1;
                   break;
               }
       if (quitted) break;

       mdown = SDL_GetMouseState(&mx, &my);
       "
       "
       SDL_SetRenderDrawColor(renderer, 0, 10, 20, 255);
       SDL_RenderClear(renderer);"
       ,@(loop for clos in update-closures collect `(funcall ,clos))
       "
       SDL_RenderPresent(renderer);
       SDL_Delay(25);
       "
"}

SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();")))

(defmacro internally-counts (from below &aux (count (gensym)))
`(let ((,count ,from))
  (lambda ()
   (prog1 ,count
    (when (equal (incf ,count) ,below) (setf ,count ,below))))))

(defmacro colorer (r g b a)
`(lambda ()
  (ffi:c-inline (,r ,g ,b ,a) (:int :int :int :int) nil
    "SDL_SetRenderDrawColor(renderer, #0, #1, #2, #3)"
    :one-liner t)))

(defmacro line-drawer (x1 y1 x2 y2)
`(lambda ()
  (ffi:c-inline (,x1 ,y1 ,x2 ,y2)
   (:int :int :int :int) nil
    "SDL_RenderDrawLine(renderer, #0, #1, #2, #3)"
    :one-liner t)))

(defmacro incfer (var amount)
`(lambda () (incf ,var ,amount)))

(defmacro funcall-on-2 (function (&rest vars) form)
`(lambda ()
  ,@(loop for var in vars collect
     `(,function ,var ,form))))

(defun play ()
(game ((a 100) (b 200) (c 300) (d 400))
      ((:int a b c d))
 (funcall-on-2 incf (a b c d) (1- (random 3)))
 ;; This would copy the variables, and end up doing nothing:
 #| and is hence commented out.
 (lambda ()
  (loop for var in (list a b c d)
   do (incf var (1- (random 3)))))
 |#
 (colorer 255 10 10 255)
 (line-drawer a b c d)
 (colorer 0 255 100 255)
 (line-drawer 0 100 100 111)))