 
 #+clj (def DEG-TO-RAD (/ PI (float 180.0)))
 #+clj (def RAD-TO-DEG (/ (float 180.0) PI))
-
-;; Sketch creation
-
-#+clj
-(defn ^{:requires-bindings false
-        :category "Environment"
-        :subcategory nil
-        :added "1.0"}
-  sketch
-  "Create and start a new visualisation applet.
-
-   :size           - a vector of width and height for the sketch or :fullscreen.
-                     Defaults to [500 300].
-
-   :renderer       - Specify the renderer type. One of :p2d, :p3d,
-                     :java2d, :opengl, :pdf). Defaults to :java2d.
-                     :dxf renderer can't be used as sketch renderer.
-                     Use begin-raw method for :dxf instead.
-
-   :output-file    - Specify an output file path. Only used in :pdf
-                     mode.
-
-   :title          - a string which will be displayed at the top of
-                     the sketch window.
-
-   :setup          - a fn to be called once when setting the sketch up.
-
-   :draw           - a fn to be repeatedly called at most n times per
-                     second where n is the target frame-rate set for
-                     the visualisation.
-
-   :features       - A vector of keywords customizing sketch behaviour.
-                     Supported features:
-
-                     :keep-on-top - Sketch window will always be above other windows.
-                                    Note: some platforms might not support
-                                    always-on-top windows.
-
-                     :exit-on-close - Shutdown JVM  when sketch is closed.
-
-                     :resizable - Makes sketch resizable.
-
-                     :no-safe-draw - Do not catche and print exception in the draw fn.
-                                     By default all exceptions thrown inside draw function are
-                                     catched so sketch doesn't break if something goes wrong.
-
-                     :present - Switch to present mode (fullscreen without borders, OS panels). You may
-                                want to use this feature together with :size :fullscreen.
-
-                     Usage example: :features [:keep-on-top :present]
-
-   :focus-gained   - Called when the sketch gains focus.
-
-   :focus-lost     - Called when the sketch loses focus.
-
-   :mouse-entered  - Called when the mouse enters the sketch window.
-
-   :mouse-exited   - Called when the mouse leaves the sketch window
-
-   :mouse-pressed  - Called every time a mouse button is pressed.
-
-   :mouse-released - Called every time a mouse button is released.
-
-   :mouse-clicked  - called once after a mouse button has been pressed
-                     and then released.
-
-   :mouse-moved    - Called every time the mouse moves and a button is
-                     not pressed.
-
-   :mouse-dragged  - Called every time the mouse moves and a button is
-                     pressed.
-
-   :mouse-wheel    - Called every time mouse wheel is rotated.
-                     Takes 1 argument - wheel rotation, an int.
-                     Negative values if the mouse wheel was rotated
-                     up/away from the user, and positive values
-                     if the mouse wheel was rotated down/ towards the user
-
-   :key-pressed    - Called every time any key is pressed.
-
-   :key-released   - Called every time any key is released.
-
-   :key-typed      - Called once every time non-modifier keys are
-                     pressed.
-
-   :on-close       - Called once, when sketch is closed"
-    [& opts]
-    (apply applet opts))
-
-(defmacro ^{:requires-bindings false
-            :category "Environment"
-            :subcategory nil
-            :added "1.0"}
-  defsketch
-  "Define and start a sketch and bind it to a var with the symbol
-  app-name. If any of the options to the various callbacks are
-  symbols, it wraps them in a call to var to ensure they aren't
-  inlined and that redefinitions to the original fns are reflected in
-  the visualisation. See sketch for the available options."
-  [app-name & opts]
-  `(defapplet ~app-name ~@opts))
-
-#+clj
-(defn ^{:requires-bindings false
-        :processing-name nil
-        :category "Input"
-        :subcategory "Keyboard"
-        :added "1.6"}
-  key-coded?
-  "Returns true if char c is a 'coded' char i.e. it is necessary to
-  fetch the key-code as an integer and use that to determine the
-  specific key pressed. See key-keyword."
-  [c]
-  (= PConstants/CODED (int c)))
 
 #+clj
 (def  ^{:private true}

               :alpha (int 4)
               :cmyk (int 5)})

(defn
  ^{:requires-bindings true
    :processing-name "colorMode()"
    :category "Color"
    :subcategory "Creating & Reading"
    :added "1.0"}
  color-mode
  "Changes the way Processing interprets color data. Available modes
  are :rgb and :hsb.By default, the parameters for fill, stroke,
  background, and color are defined by values between 0 and 255 using
  the :rgb color model. The color-mode fn is used to change the
  numerical range used for specifying colors and to switch color
  systems. For example, calling
  (color-mode :rgb 1.0) will specify that values are specified between
  0 and 1. The limits for defining colors are altered by setting the
  parameters range1, range2, range3, and range 4."
  ([mode]
     (let [mode (resolve-constant-key mode color-modes)]
       (.colorMode (current-graphics) (int mode))))
  ([mode max]
     (let [mode (resolve-constant-key mode color-modes)]
       (.colorMode (current-graphics) (int mode) (float max))))
  ([mode max-x max-y max-z]
     (let [mode (resolve-constant-key mode color-modes)]
       (.colorMode (current-graphics) (int mode) (float max-x) (float max-y) (float max-z))))
  ([mode max-x max-y max-z max-a]
     (let [mode (resolve-constant-key mode color-modes)]
       (.colorMode (current-graphics) (int mode) (float max-x) (float max-y) (float max-z) (float max-a)))))

#+clj
(defn
  ^{:requires-bindings false
    :processing-name "constrain()"
    :category "Math"
    :subcategory "Calculation"
    :added "1.0"}
  constrain-float
  "Constrains a value to not exceed a maximum and minimum value. All
  args are cast to floats."
  [amt low high]
  (PApplet/constrain (float amt) (float low) (float high)))

#+clj
(defn
  ^{:requires-bindings false
    :processing-name "constrain()"
    :category "Math"
    :subcategory "Calculation"
    :added "1.0"}
  constrain-int
  "Constrains a value to not exceed a maximum and minimum value. All
  args are cast to ints."
  [amt low high]
  (PApplet/constrain (int amt) (int low) (int high)))

#+clj
(defn
  ^{:requires-bindings false
    :processing-name "constrain()"
    :category "Math"
    :subcategory "Calculation"
    :added "1.0"}
  constrain
  "Constrains a value to not exceed a maximum and minimum value."
  [amt low high]
  (if (int-like? amt)
    (constrain-int amt low high)
    (constrain-float amt low high)))

#+clj
(defn
  ^{:requires-bindings true
    :processing-name "copy()"
    :category "Image"
    :subcategory "Pixels"
    :added "1.0"}
  copy
  "Copies a region of pixels from the one image to another. If src-img
  is not specified it defaults to current-graphics. If dest-img is not
  specified - it defaults to current-graphics. If the source
  and destination regions aren't the same size, it will automatically
  resize the source pixels to fit the specified target region. No
  alpha information is used in the process, however if the source
  image has an alpha channel set, it will be copied as well. "
  ([[sx sy swidth sheight] [dx dy dwidth dheight]]
     (copy (current-graphics) (current-graphics) [sx sy swidth sheight] [dx dy dwidth dheight]))

  ([^PImage src-img [sx sy swidth sheight] [dx dy dwidth dheight]]
     (copy src-img (current-graphics) [sx sy swidth sheight] [dx dy dwidth dheight]))

  ([^PImage src-img ^PImage dest-img [sx sy swidth sheight] [dx dy dwidth dheight]]
     (.copy dest-img src-img (int sx) (int sy) (int swidth) (int sheight)
            (int dx) (int dy) (int dwidth) (int dheight))))

#+clj
(defn
  ^{:requires-bindings false
    :processing-name "cos()"
    :category "Math"
    :subcategory "Trigonometry"
    :added "1.0"}
  cos
  "Calculates the cosine of an angle. This function expects the values
  of the angle parameter to be provided in radians (values from 0 to
  Math/PI*2). Values are returned in the range -1 to 1."
  [angle]
  (PApplet/cos (float angle)))

#+clj
(defn
  ^{:requires-bindings false
    :processing-name nil
    :category "Typography"
    :subcategory "Loading & Displaying"
    :added "1.0"}
  font-available?
  "Returns true if font (specified as a string) is available on this
  system, false otherwise"
  [font-str]
  (if (some #{font-str} (available-fonts))
    true
    false))

(defn
  ^{:requires-bindings true
    :processing-name "createFont()"
    :category "Typography"
    :subcategory "Loading & Displaying"
    :added "1.0"}
  create-font
  "Dynamically converts a font to the format used by Processing (a
  PFont) from either a font name that's installed on the computer, or
  from a .ttf or .otf file inside the sketches 'data' folder. This
  function is an advanced feature for precise control.

  Use available-fonts to obtain the names for the fonts recognized by
  the computer and are compatible with this function.

  The size parameter states the font size you want to generate. The
  smooth parameter specifies if the font should be antialiased or not,
  and the charset parameter is an array of chars that specifies the
  characters to generate.

  This function creates a bitmapped version of a font It loads a font
  by name, and converts it to a series of images based on the size of
  the font. When possible, the text function will use a native font
  rather than the bitmapped version created behind the scenes with
  create-font. For instance, when using the default renderer
  setting (JAVA2D), the actual native version of the font will be
  employed by the sketch, improving drawing quality and
  performance. With the :p2d, :p3d, and :opengl renderer settings, the
  bitmapped version will be used. While this can drastically improve
  speed and appearance, results are poor when exporting if the sketch
  does not include the .otf or .ttf file, and the requested font is
  not available on the machine running the sketch."
  ([name size] (.createFont (current-applet) (str name) (float size)))
  ([name size smooth] (.createFont (current-applet) (str name) (float size) smooth))
  ([name size smooth ^chars charset]
     (.createFont (current-applet) (str name) (float size) smooth charset)))

#+clj
(defn
  ^{:requires-bindings true
    :processing-name "createGraphics()"
    :category "Image"
    :subcategory "Rendering"
    :added "1.0"}
  create-graphics
  "Creates and returns a new PGraphics object of the types :p2d, :p3d,
  :java2d, :pdf. By default :java2d is used. Use this class if you
  need to draw into an off-screen graphics buffer. It's not possible
  to use create-graphics with the :opengl renderer, because it doesn't
  allow offscreen use. The :pdf renderer requires the filename parameter.

  It's important to call any drawing commands between (.beginDraw graphics) and
  (.endDraw graphics) statements or use with-graphics macro. This is also true
  for any commands that affect drawing, such as smooth or color-mode.

  If you're using :pdf renderer - don't forget to call (.dispose graphics)
  as last command inside with-graphics macro, otherwise graphics won't be
  saved.

  Unlike the main drawing surface which is completely opaque, surfaces
  created with create-graphics can have transparency. This makes it
  possible to draw into a graphics and maintain the alpha channel. By
  using save to write a PNG or TGA file, the transparency of the
  graphics object will be honored. Note that transparency levels are
  binary: pixels are either complete opaque or transparent. This means
  that text characters will be opaque blocks."
  ([w h]
     (.createGraphics (current-applet) (int w) (int h)))
  ([w h renderer]
     (.createGraphics (current-applet) (int w) (int h) (resolve-renderer renderer)))
  ([w h renderer path]
     (.createGraphics (current-applet) (int w) (int h) (resolve-renderer renderer)
                      (absolute-path path))))

#+clj
(def ^{:private true}
  image-formats {:rgb PApplet/RGB
                :argb PApplet/ARGB
                :alpha PApplet/ALPHA})

#+clj
(defn
  ^{:requires-bindings true
    :processing-name "createImage()"
    :category "Image"
    :subcategory nil
    :added "1.0"}
  create-image
  "Creates a new PImage (the datatype for storing images). This
  provides a fresh buffer of pixels to play with. Set the size of the
  buffer with the width and height parameters. The format parameter
  defines how the pixels are stored. See the PImage reference for more
  information.

  Possible formats: :rgb, :argb, :alpha (grayscale alpha channel)

  Prefer using create-image over initialising new PImage instances
  directly."
  [w h format]
  (let [format (resolve-constant-key format image-formats)]
    (.createImage (current-applet) (int w) (int h) (int format))))

(defn
  ^{:requires-bindings true
    :processing-name "fillColor()"
    :category "Color"
    :subcategory "Creating & Reading"}
  current-fill
  "Return the current fill color."
  []
  (.fillColor (current-graphics)))

(defn
  ^{:requires-bindings true
    :processing-name "strokeColor()"
    :category "Color"
    :subcategory "Creating & Reading"}
  current-stroke
  "Return the current stroke color."
  []
  (.strokeColor (current-graphics)))

#+clj
(def ^{:private true}
  cursor-modes {:arrow PConstants/ARROW
                :cross PConstants/CROSS
                :hand PConstants/HAND
                :move PConstants/MOVE
                :text PConstants/TEXT
                :wait PConstants/WAIT})

#+clj
(defn
  ^{:requires-bindings true
    :processing-name "cursor()"
    :category "Environment"
    :subcategory nil
    :added "1.0"}
  cursor
  "Sets the cursor to a predefined symbol or makes it
  visible if already hidden (after no-cursor was called).

  Available modes: :arrow, :cross, :hand, :move, :text, :wait

  See cursor-image for specifying a generic image as the cursor
  symbol."
  ([] (.cursor (current-applet)))
  #+clj ([cursor-mode] (.cursor (current-applet) (int (resolve-constant-key cursor-mode cursor-modes)))))

(defn
  ^{:requires-bindings true
    :processing-name "cursor()"
    :category "Environment"
    :subcategory nil
    :added "1.0"}
    cursor-image
  "Set the cursor to a predefined image. The horizontal and vertical
  active spots of the cursor may be specified with hx and hy.
  It is recommended to make the size 16x16 or 32x32 pixels."
  ([^PImage img] (.cursor (current-applet) img))
  ([^PImage img hx hy] (.cursor (current-applet) img (int hx) (int hy))))

(defn
  ^{:requires-bindings true
    :processing-name "curve()"
    :category "Shape"
    :subcategory "Curves"
    :added "1.0"}
  curve
  "Draws a curved line on the screen. The first and second parameters
  specify the beginning control point and the last two parameters
  specify the ending control point. The middle parameters specify the
  start and stop of the curve. Longer curves can be created by putting
  a series of curve fns together or using curve-vertex. An additional
  fn called curve-tightness provides control for the visual quality of
  the curve. The curve fn is an implementation of Catmull-Rom
  splines."
  ([x1 y1 x2 y2 x3 y3 x4 y4]
     (.curve (current-graphics)
             (float x1) (float y1)
             (float x2) (float y2)
             (float x3) (float y3)
             (float x4) (float y4)))
  ([x1 y1 z1 x2 y2 z2 x3 y3 z3 x4 y4 z4]
     (.curve (current-graphics)
             (float x1) (float y1) (float z1)
             (float x2) (float y2) (float z2)
             (float x3) (float y3) (float z3)
             (float x4) (float y4) (float z4))))

(defn
  ^{:requires-bindings true
    :processing-name "curveDetail()"
    :category "Shape"
    :subcategory "Curves"
    :added "1.0"}
  curve-detail
  "Sets the resolution at which curves display. The default value is
  20. This function is only useful when using the :p3d or :opengl
  renderer as the default (:java2d) renderer does not use this
  information."
  [detail]
  (.curveDetail (current-graphics) (int detail)))

(defn
  ^{:requires-bindings true
    :processing-name "curvePoint()"
    :category "Shape"
    :subcategory "Curves"
    :added "1.0"}
  curve-point
  "Evalutes the curve at point t for points a, b, c, d. The parameter
  t varies between 0 and 1, a and d are points on the curve, and b c
  and are the control points. This can be done once with the x
  coordinates and a second time with the y coordinates to get the
  location of a curve at t."
  [a b c d t]
  (.curvePoint (current-graphics) (float a) (float b) (float c) (float d) (float t)))

(defn
  ^{:requires-bindings true
    :processing-name "curveTangent()"
    :category "Shape"
    :subcategory "Curves"
    :added "1.0"}
  curve-tangent
  "Calculates the tangent of a point on a curve.
  See: http://en.wikipedia.org/wiki/Tangent"
  [a b c d t]
  (.curveTangent (current-graphics) (float a) (float b) (float c) (float d) (float t)))

(defn
  ^{:requires-bindings true
   :processing-name "curveTightness()"
    :category "Shape"
    :subcategory "Curves"
    :added "1.0"}
  curve-tightness
  "Modifies the quality of forms created with curve and
  curve-vertex. The parameter squishy determines how the curve fits
  to the vertex points. The value 0.0 is the default value for
  squishy (this value defines the curves to be Catmull-Rom splines)
  and the value 1.0 connects all the points with straight
  lines. Values within the range -5.0 and 5.0 will deform the curves
  but will leave them recognizable and as values increase in
  magnitude, they will continue to deform."
  [ti]
  (.curveTightness (current-graphics) (float ti)))

(defn
  ^{:requires-bindings true
    :processing-name "curveVertex()"
    :category "Shape"
    :subcategory "Vertex"
    :added "1.0"}
  curve-vertex
  "Specifies vertex coordinates for curves. This function may only be
  used between begin-shape and end-shape and only when there is no
  mode keyword specified to begin-hape. The first and last points in a
  series of curve-vertex lines will be used to guide the beginning and
  end of a the curve. A minimum of four points is required to draw a
  tiny curve between the second and third points. Adding a fifth point
  with curveVertex will draw the curve between the second, third, and
  fourth points. The curveVertex function is an implementation of
  Catmull-Rom splines."
  ([x y] (.curveVertex (current-graphics) (float x) (float y)))
  ([x y z] (.curveVertex (current-graphics) (float x) (float y) (float z))))

#+clj
(defn
  ^{:requires-bindings false
    :processing-name "day()"
    :category "Input"
    :subcategory "Time & Date"
    :added "1.0"}
  day
  "Get the current day of the month (1 through 31)."
  []
  (PApplet/day))

#+clj
(defn
  ^{:requires-bindings false
    :processing-name "degrees()"
    :category "Math"
    :subcategory "Trigonometry"
    :added "1.0"}
  degrees
  "Converts a radian measurement to its corresponding value in
  degrees. Radians and degrees are two ways of measuring the same
  thing. There are 360 degrees in a circle and (* 2 Math/PI) radians
  in a circle. For example, (= 90° (/ Math/PI 2) 1.5707964). All
  trigonometric methods in Processing require their parameters to be
  specified in radians."
  [radians]
  (PApplet/degrees (float radians)))

(defn
  ^{:requires-bindings true
    :processing-name "delay()"
    :category "Structure"
    :subcategory nil
    :added "1.0"}
  delay-frame
  "Forces the program to stop running for a specified time. Delay
  times are specified in thousandths of a second, therefore the
  function call (delay 3000) will stop the program for three
  seconds. Because the screen is updated only at the end of draw,
  the program may appear to 'freeze', because the screen will not
  update when the delay fn is used. This function has no affect
  inside setup."
  [freeze-ms]
  (.delay (current-applet) (int freeze-ms)))

(defn
  ^{:requires-bindings true
    :processing-name "directionalLight()"
    :category "Lights, Camera"
    :subcategory "Lights"
    :added "1.0"}
  directional-light
  "Adds a directional light. Directional light comes from one
  direction and is stronger when hitting a surface squarely and weaker
  if it hits at a a gentle angle. After hitting a surface, a
  directional lights scatters in all directions. Lights need to be
  included in the draw fn to remain persistent in a looping
  program. Placing them in the setup fn of a looping program will cause
  them to only have an effect the first time through the loop. The
  affect of the r, g, and b parameters is determined by the current
  color mode. The nx, ny, and nz parameters specify the direction the
  light is facing. For example, setting ny to -1 will cause the
  geometry to be lit from below (the light is facing directly upward)"
  [r g b nx ny nz]
  (.directionalLight (current-graphics) (float r) (float g) (float b)
                     (float nx) (float ny) (float nz)))

#+clj
(defn
  ^{:requires-bindings false
    :processing-name "dist()"
    :category "Math"
    :subcategory "Calculation"
    :added "1.0"}
  dist
  "Calculates the distance between two points"
  ([x1 y1 x2 y2] (PApplet/dist (float x1) (float y1) (float x2) (float y2)))
  ([x1 y1 z1 x2 y2 z2] (PApplet/dist (float x1) (float y1) (float z1)
                               (float x2) (float y2) (float z2))))

(defn
  ^{:requires-bindings true
    :processing-name "ellipse()"
    :category "Shape"
    :subcategory "2D Primitives"
    :added "1.0"}
  ellipse
  "Draws an ellipse (oval) in the display window. An ellipse with an
  equal width and height is a circle.  The origin may be changed with
  the ellipse-mode function"
  [x y width height]
  (.ellipse (current-graphics) (float x) (float y) (float width) (float height)))

#+clj
(def ^{:private true}

              :radius PApplet/RADIUS})

#+clj
(def ^{:private true}
  p-shape-modes {:corner PApplet/CORNER
                 :corners PApplet/CORNERS
                 :center PApplet/CENTER})

#+clj
(def ^{:private true}
