├── .gitignore
├── LICENSE
├── README.md
├── bocko.jpg
├── project.clj
└── src
└── bocko
├── core.cljc
└── swing.clj
/.gitignore:
--------------------------------------------------------------------------------
1 | pom.xml
2 | pom.xml.asc
3 | *jar
4 | /lib/
5 | /classes/
6 | /target/
7 | /checkouts/
8 | .lein-deps-sum
9 | .lein-repl-history
10 | .lein-plugins/
11 | .lein-failures
12 | .nrepl-port
13 | .idea
14 | bocko.iml
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Eclipse Public License - v 1.0
2 |
3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
4 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
5 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
6 |
7 | 1. DEFINITIONS
8 |
9 | "Contribution" means:
10 |
11 | a) in the case of the initial Contributor, the initial code and documentation
12 | distributed under this Agreement, and
13 | b) in the case of each subsequent Contributor:
14 | i) changes to the Program, and
15 | ii) additions to the Program;
16 |
17 | where such changes and/or additions to the Program originate from and are
18 | distributed by that particular Contributor. A Contribution 'originates'
19 | from a Contributor if it was added to the Program by such Contributor
20 | itself or anyone acting on such Contributor's behalf. Contributions do not
21 | include additions to the Program which: (i) are separate modules of
22 | software distributed in conjunction with the Program under their own
23 | license agreement, and (ii) are not derivative works of the Program.
24 |
25 | "Contributor" means any person or entity that distributes the Program.
26 |
27 | "Licensed Patents" mean patent claims licensable by a Contributor which are
28 | necessarily infringed by the use or sale of its Contribution alone or when
29 | combined with the Program.
30 |
31 | "Program" means the Contributions distributed in accordance with this
32 | Agreement.
33 |
34 | "Recipient" means anyone who receives the Program under this Agreement,
35 | including all Contributors.
36 |
37 | 2. GRANT OF RIGHTS
38 | a) Subject to the terms of this Agreement, each Contributor hereby grants
39 | Recipient a non-exclusive, worldwide, royalty-free copyright license to
40 | reproduce, prepare derivative works of, publicly display, publicly
41 | perform, distribute and sublicense the Contribution of such Contributor,
42 | if any, and such derivative works, in source code and object code form.
43 | b) Subject to the terms of this Agreement, each Contributor hereby grants
44 | Recipient a non-exclusive, worldwide, royalty-free patent license under
45 | Licensed Patents to make, use, sell, offer to sell, import and otherwise
46 | transfer the Contribution of such Contributor, if any, in source code and
47 | object code form. This patent license shall apply to the combination of
48 | the Contribution and the Program if, at the time the Contribution is
49 | added by the Contributor, such addition of the Contribution causes such
50 | combination to be covered by the Licensed Patents. The patent license
51 | shall not apply to any other combinations which include the Contribution.
52 | No hardware per se is licensed hereunder.
53 | c) Recipient understands that although each Contributor grants the licenses
54 | to its Contributions set forth herein, no assurances are provided by any
55 | Contributor that the Program does not infringe the patent or other
56 | intellectual property rights of any other entity. Each Contributor
57 | disclaims any liability to Recipient for claims brought by any other
58 | entity based on infringement of intellectual property rights or
59 | otherwise. As a condition to exercising the rights and licenses granted
60 | hereunder, each Recipient hereby assumes sole responsibility to secure
61 | any other intellectual property rights needed, if any. For example, if a
62 | third party patent license is required to allow Recipient to distribute
63 | the Program, it is Recipient's responsibility to acquire that license
64 | before distributing the Program.
65 | d) Each Contributor represents that to its knowledge it has sufficient
66 | copyright rights in its Contribution, if any, to grant the copyright
67 | license set forth in this Agreement.
68 |
69 | 3. REQUIREMENTS
70 |
71 | A Contributor may choose to distribute the Program in object code form under
72 | its own license agreement, provided that:
73 |
74 | a) it complies with the terms and conditions of this Agreement; and
75 | b) its license agreement:
76 | i) effectively disclaims on behalf of all Contributors all warranties
77 | and conditions, express and implied, including warranties or
78 | conditions of title and non-infringement, and implied warranties or
79 | conditions of merchantability and fitness for a particular purpose;
80 | ii) effectively excludes on behalf of all Contributors all liability for
81 | damages, including direct, indirect, special, incidental and
82 | consequential damages, such as lost profits;
83 | iii) states that any provisions which differ from this Agreement are
84 | offered by that Contributor alone and not by any other party; and
85 | iv) states that source code for the Program is available from such
86 | Contributor, and informs licensees how to obtain it in a reasonable
87 | manner on or through a medium customarily used for software exchange.
88 |
89 | When the Program is made available in source code form:
90 |
91 | a) it must be made available under this Agreement; and
92 | b) a copy of this Agreement must be included with each copy of the Program.
93 | Contributors may not remove or alter any copyright notices contained
94 | within the Program.
95 |
96 | Each Contributor must identify itself as the originator of its Contribution,
97 | if
98 | any, in a manner that reasonably allows subsequent Recipients to identify the
99 | originator of the Contribution.
100 |
101 | 4. COMMERCIAL DISTRIBUTION
102 |
103 | Commercial distributors of software may accept certain responsibilities with
104 | respect to end users, business partners and the like. While this license is
105 | intended to facilitate the commercial use of the Program, the Contributor who
106 | includes the Program in a commercial product offering should do so in a manner
107 | which does not create potential liability for other Contributors. Therefore,
108 | if a Contributor includes the Program in a commercial product offering, such
109 | Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
110 | every other Contributor ("Indemnified Contributor") against any losses,
111 | damages and costs (collectively "Losses") arising from claims, lawsuits and
112 | other legal actions brought by a third party against the Indemnified
113 | Contributor to the extent caused by the acts or omissions of such Commercial
114 | Contributor in connection with its distribution of the Program in a commercial
115 | product offering. The obligations in this section do not apply to any claims
116 | or Losses relating to any actual or alleged intellectual property
117 | infringement. In order to qualify, an Indemnified Contributor must:
118 | a) promptly notify the Commercial Contributor in writing of such claim, and
119 | b) allow the Commercial Contributor to control, and cooperate with the
120 | Commercial Contributor in, the defense and any related settlement
121 | negotiations. The Indemnified Contributor may participate in any such claim at
122 | its own expense.
123 |
124 | For example, a Contributor might include the Program in a commercial product
125 | offering, Product X. That Contributor is then a Commercial Contributor. If
126 | that Commercial Contributor then makes performance claims, or offers
127 | warranties related to Product X, those performance claims and warranties are
128 | such Commercial Contributor's responsibility alone. Under this section, the
129 | Commercial Contributor would have to defend claims against the other
130 | Contributors related to those performance claims and warranties, and if a
131 | court requires any other Contributor to pay any damages as a result, the
132 | Commercial Contributor must pay those damages.
133 |
134 | 5. NO WARRANTY
135 |
136 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
137 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
138 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
140 | Recipient is solely responsible for determining the appropriateness of using
141 | and distributing the Program and assumes all risks associated with its
142 | exercise of rights under this Agreement , including but not limited to the
143 | risks and costs of program errors, compliance with applicable laws, damage to
144 | or loss of data, programs or equipment, and unavailability or interruption of
145 | operations.
146 |
147 | 6. DISCLAIMER OF LIABILITY
148 |
149 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
150 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
151 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
152 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
153 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
154 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
155 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY
156 | OF SUCH DAMAGES.
157 |
158 | 7. GENERAL
159 |
160 | If any provision of this Agreement is invalid or unenforceable under
161 | applicable law, it shall not affect the validity or enforceability of the
162 | remainder of the terms of this Agreement, and without further action by the
163 | parties hereto, such provision shall be reformed to the minimum extent
164 | necessary to make such provision valid and enforceable.
165 |
166 | If Recipient institutes patent litigation against any entity (including a
167 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself
168 | (excluding combinations of the Program with other software or hardware)
169 | infringes such Recipient's patent(s), then such Recipient's rights granted
170 | under Section 2(b) shall terminate as of the date such litigation is filed.
171 |
172 | All Recipient's rights under this Agreement shall terminate if it fails to
173 | comply with any of the material terms or conditions of this Agreement and does
174 | not cure such failure in a reasonable period of time after becoming aware of
175 | such noncompliance. If all Recipient's rights under this Agreement terminate,
176 | Recipient agrees to cease use and distribution of the Program as soon as
177 | reasonably practicable. However, Recipient's obligations under this Agreement
178 | and any licenses granted by Recipient relating to the Program shall continue
179 | and survive.
180 |
181 | Everyone is permitted to copy and distribute copies of this Agreement, but in
182 | order to avoid inconsistency the Agreement is copyrighted and may only be
183 | modified in the following manner. The Agreement Steward reserves the right to
184 | publish new versions (including revisions) of this Agreement from time to
185 | time. No one other than the Agreement Steward has the right to modify this
186 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The
187 | Eclipse Foundation may assign the responsibility to serve as the Agreement
188 | Steward to a suitable separate entity. Each new version of the Agreement will
189 | be given a distinguishing version number. The Program (including
190 | Contributions) may always be distributed subject to the version of the
191 | Agreement under which it was received. In addition, after a new version of the
192 | Agreement is published, Contributor may elect to distribute the Program
193 | (including its Contributions) under the new version. Except as expressly
194 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or
195 | licenses to the intellectual property of any Contributor under this Agreement,
196 | whether expressly, by implication, estoppel or otherwise. All rights in the
197 | Program not expressly granted under this Agreement are reserved.
198 |
199 | This Agreement is governed by the laws of the State of New York and the
200 | intellectual property laws of the United States of America. No party to this
201 | Agreement will bring a legal action under this Agreement more than one year
202 | after the cause of action arose. Each party waives its rights to a jury trial in
203 | any resulting litigation.
204 |
205 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Bocko
2 |
3 | A small library making it extremely simple to play around with low-res graphics from Clojure, as well as from ClojureScript on [iOS](https://github.com/mfikes/bocko-ios), [Android](https://github.com/nvbn/bocko-android)[1](#bockoandroid), and an [HTML canvas](https://github.com/mfikes/bocko-canvas). ([Read the blog post.](http://blog.fikesfarm.com/posts/2015-05-24-bocko-low-res-clojure-graphics.html))
4 |
5 |
6 |
7 | # Usage
8 |
9 | ```
10 | lein new bocko my-project
11 | ```
12 |
13 | Then find a short `README.md` at the top-level of the generated project, explaining how to get up and running.
14 |
15 | # Detailed Usage
16 |
17 | ```clojure
18 | (require '[bocko.core :refer :all])
19 |
20 | (plot 2 3) ;; plots a point on the screen
21 |
22 | (color :pink) ;; changes the color to pink
23 | (plot 5 5)
24 |
25 | (scrn 5 5) ;; => :pink
26 |
27 | (hlin 3 9 10) ;; draws a horizontal line
28 |
29 | (clear) ;; clears screen
30 | ```
31 |
32 | The commands comprise `color`, `plot`, `scrn`, `hlin`, `vlin`, and `clear`.
33 |
34 | # Demo
35 |
36 | Watch a demo to see it in action:
37 |
38 | [](http://www.youtube.com/watch?v=piJPrP3BKIk "Bocko Clojure simple graphics")
39 |
40 | # Examples
41 |
42 | Draw an American flag:
43 | ```clojure
44 | ;; Draw 13 stripes cycling over red/white
45 |
46 | (doseq [[n c] (take 13
47 | (map vector (range) (cycle [:red :white])))]
48 | (color c)
49 | (let [x1 10
50 | x2 25
51 | y (+ 10 n)]
52 | (hlin x1 x2 y)))
53 |
54 | ;; Fill in a dark blue field in the corner
55 |
56 | (color :dark-blue)
57 | (doseq [x (range 10 19)
58 | y (range 10 17)]
59 | (plot x y))
60 |
61 | ;; Add some stars to the field by skipping by 2
62 |
63 | (color :white)
64 | (doseq [x (range 11 19 2)
65 | y (range 11 17 2)]
66 | (plot x y))
67 | ```
68 |
69 | Display all the colors:
70 |
71 | ```clojure
72 | (doseq [[c n] (map vector
73 | [:black :red :dark-blue :purple
74 | :dark-green :dark-gray :medium-blue :light-blue
75 | :brown :orange :light-gray :pink
76 | :light-green :yellow :aqua :white]
77 | (range))]
78 | (color c)
79 | (let [x' (* 10 (rem n 4))
80 | y' (* 10 (quot n 4))]
81 | (doseq [x (range x' (+ 10 x'))
82 | y (range y' (+ 10 y'))]
83 | (plot x y))))
84 | ```
85 |
86 |
87 | Animated bouncing ball using `loop`/`recur`:
88 | ```clojure
89 | (loop [x 5 y 23 vx 1 vy 1]
90 | ; First determine new location and velocity,
91 | ; reversing direction if bouncing off edge.
92 | (let [x' (+ x vx)
93 | y' (+ y vy)
94 | vx' (if (< 0 x' 39) vx (- vx))
95 | vy' (if (< 0 y' 39) vy (- vy))]
96 | ; Erase drawing at previous location
97 | (color :black)
98 | (plot x y)
99 | ; Draw ball in new location
100 | (color :dark-blue)
101 | (plot x' y')
102 | ; Sleep a little and then loop around again
103 | (Thread/sleep 50)
104 | (recur x' y' vx' vy')))
105 | ```
106 |
107 | Random colors and locations:
108 | ```clojure
109 | (loop []
110 | (let [c (rand-nth [:black :red :dark-blue :purple
111 | :dark-green :dark-gray :medium-blue :light-blue
112 | :brown :orange :light-gray :pink
113 | :light-green :yellow :aqua :white])
114 | x (rand-int 40)
115 | y (rand-int 40)]
116 | (color c)
117 | (plot x y)
118 | (Thread/sleep 1)
119 | (recur)))
120 | ```
121 |
122 | Game-of-Life Glider: (Credit: [Christophe Grand](http://clj-me.cgrand.net/2011/08/19/conways-game-of-life/))
123 | ```
124 | (defn neighbours [[x y]]
125 | (for [dx [-1 0 1] dy (if (zero? dx) [-1 1] [-1 0 1])]
126 | [(+ dx x) (+ dy y)]))
127 |
128 | (defn step [cells]
129 | (set (for [[loc n] (frequencies (mapcat neighbours cells))
130 | :when (or (= n 3) (and (= n 2) (cells loc)))]
131 | loc)))
132 |
133 | (loop [board #{[0 2] [1 0] [1 2] [2 1] [2 2]}]
134 | (clear)
135 | (run! (partial apply plot) board)
136 | (Thread/sleep 100)
137 | (recur (step board)))
138 | ```
139 |
140 | # Multi-threading
141 |
142 | You can use Bocko from multiple threads. The underlying canvas is thread-safe.
143 |
144 | In that scenario, establishing thread-local bindings for the `*color*` dynamic var will allow each thread to plot independently. For example, the following code will not interfere with the color being used for plotting in other threads:
145 |
146 | ```clojure
147 | (future
148 | (binding [*color* :orange]
149 | (plot 3 3) ; Will plot an orange point
150 | (set! *color* :aqua)
151 | (plot 4 4))) ; Will plot an aqua point
152 | ```
153 |
154 | In fact, a form like `(color :red)` is just a simple wrapper that will set a thread-local binding if one is in effect, otherwise it will set the root binding.
155 |
156 | Here is an example. This makes use of thread-local bindings and "does the right thing":
157 |
158 | ```clojure
159 | (do
160 |
161 | ;; Repeatedly display all the colors
162 |
163 | (future
164 | (loop []
165 | (clear)
166 | (doseq [[c n] (map vector
167 | [:black :red :dark-blue :purple
168 | :dark-green :dark-gray :medium-blue :light-blue
169 | :brown :orange :light-gray :pink
170 | :light-green :yellow :aqua :white]
171 | (range))]
172 | (binding [*color* c]
173 | (let [x' (* 10 (rem n 4))
174 | y' (* 10 (quot n 4))]
175 | (doseq [x (range x' (+ 10 x'))
176 | y (range y' (+ 10 y'))]
177 | (plot x y)
178 | (Thread/sleep 1)))))
179 | (recur)))
180 |
181 | ;; Add a bouncing ball
182 |
183 | (future
184 | (loop [x 5 y 23 vx 1 vy 1]
185 | ; First determine new location and velocity,
186 | ; reversing direction if bouncing off edge.
187 | (let [x' (+ x vx)
188 | y' (+ y vy)
189 | vx' (if (< 0 x' 39) vx (- vx))
190 | vy' (if (< 0 y' 39) vy (- vy))]
191 | ; Erase drawing at previous location
192 | (binding [*color* :black]
193 | (plot x y))
194 | ; Draw ball in new location
195 | (binding [*color* :dark-blue]
196 | (plot x' y'))
197 | ; Sleep a little and then loop around again
198 | (Thread/sleep 50)
199 | (recur x' y' vx' vy')))))
200 | ```
201 |
202 | This, on the other hand, illustrates contention / interference with the color being used for plotting:
203 |
204 | ```clojure
205 | (do
206 |
207 | ;; Repeatedly display all the colors
208 |
209 | (future
210 | (loop []
211 | (clear)
212 | (doseq [[c n] (map vector
213 | [:black :red :dark-blue :purple
214 | :dark-green :dark-gray :medium-blue :light-blue
215 | :brown :orange :light-gray :pink
216 | :light-green :yellow :aqua :white]
217 | (range))]
218 | (color c)
219 | (let [x' (* 10 (rem n 4))
220 | y' (* 10 (quot n 4))]
221 | (doseq [x (range x' (+ 10 x'))
222 | y (range y' (+ 10 y'))]
223 | (plot x y)
224 | (Thread/sleep 1))))
225 | (recur)))
226 |
227 | ;; Add a bouncing ball
228 |
229 | (future
230 | (loop [x 5 y 23 vx 1 vy 1]
231 | ; First determine new location and velocity,
232 | ; reversing direction if bouncing off edge.
233 | (let [x' (+ x vx)
234 | y' (+ y vy)
235 | vx' (if (< 0 x' 39) vx (- vx))
236 | vy' (if (< 0 y' 39) vy (- vy))]
237 | ; Erase drawing at previous location
238 | (color :black)
239 | (plot x y)
240 | ; Draw ball in new location
241 | (color :dark-blue)
242 | (plot x' y')
243 | ; Sleep a little and then loop around again
244 | (Thread/sleep 50)
245 | (recur x' y' vx' vy')))))
246 | ```
247 |
248 |
249 | # License
250 |
251 | Copyright © 2015–2016 Mike Fikes and Contributors
252 |
253 | Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.
254 |
255 | # Footnotes
256 |
257 | 1: Bocko for Android is by [Vladimir Iakovlev](https://github.com/nvbn).
258 |
--------------------------------------------------------------------------------
/bocko.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mfikes/bocko/2889b2529d7549d56e1000900d996b47fa2da0eb/bocko.jpg
--------------------------------------------------------------------------------
/project.clj:
--------------------------------------------------------------------------------
1 | (defproject bocko "1.0.0"
2 | :description "Simple imperative graphics"
3 | :url "https://github.com/mfikes/bocko"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 | :dependencies [[org.clojure/clojure "1.8.0"]])
7 |
--------------------------------------------------------------------------------
/src/bocko/core.cljc:
--------------------------------------------------------------------------------
1 | (ns bocko.core)
2 |
3 | (def ^:private ^:const width 40)
4 | (def ^:private ^:const height 40)
5 | (def ^:private ^:const pixel-width 28)
6 | (def ^:private ^:const pixel-height 16)
7 | (def ^:private clear-color :black)
8 | (def ^:private default-color :white)
9 | (def ^:private clear-screen (vec (repeat height (vec (repeat width clear-color)))))
10 |
11 | (defonce ^:private raster (atom clear-screen))
12 |
13 | (def ^:private color-map
14 | {:black [0 0 0]
15 | :red [157 9 102]
16 | :dark-blue [42 42 229]
17 | :purple [199 52 255]
18 | :dark-green [0 118 26]
19 | :dark-gray [128 128 128]
20 | :medium-blue [13 161 255]
21 | :light-blue [170 170 255]
22 | :brown [85 85 0]
23 | :orange [242 94 0]
24 | :light-gray [192 192 192]
25 | :pink [255 137 229]
26 | :light-green [56 203 0]
27 | :yellow [213 213 26]
28 | :aqua [98 246 153]
29 | :white [255 255 254]})
30 |
31 | (defonce ^:private create-canvas-fn (atom nil))
32 |
33 | (defn set-create-canvas
34 | "Sets a function that creates a 'canvas'. The function will
35 | be passed the color-map, the raster atom, and raster width and
36 | height and desires pixel-width and pixel-height."
37 | [f]
38 | (reset! create-canvas-fn f))
39 |
40 | (defonce ^:private canvas
41 | (delay (@create-canvas-fn color-map raster width height pixel-width pixel-height)))
42 |
43 | ;; If we are in Clojure, set up a Swing canvas
44 | #?(:clj
45 | (set-create-canvas
46 | (fn [color-map raster width height pixel-width pixel-height]
47 | (require 'bocko.swing)
48 | (let [make-panel (eval 'bocko.swing/make-panel)]
49 | (make-panel color-map raster width height pixel-width pixel-height)))))
50 |
51 | (defn clear
52 | "Clears this screen."
53 | []
54 | (force canvas)
55 | (reset! raster clear-screen)
56 | nil)
57 |
58 | (defonce ^:dynamic
59 | ^{:doc "The color used for plotting."}
60 | *color* default-color)
61 |
62 | (set-validator! #'*color*
63 | (fn [c] (contains? color-map c)))
64 |
65 | (defn color
66 | "Sets the color for plotting.
67 |
68 | The color must be one of the following:
69 |
70 | :black :red :dark-blue :purple
71 | :dark-green :dark-gray :medium-blue :light-blue
72 | :brown :orange :light-gray :pink
73 | :light-green :yellow :aqua :white"
74 | [c]
75 | {:pre [(keyword? c)
76 | (c #{:black :red :dark-blue :purple
77 | :dark-green :dark-gray :medium-blue :light-blue
78 | :brown :orange :light-gray :pink
79 | :light-green :yellow :aqua :white})]}
80 | (force canvas)
81 | #?(:clj (if (thread-bound? #'*color*)
82 | (set! *color* c)
83 | (alter-var-root #'*color* (constantly c)))
84 | :cljs (set! *color* c))
85 | nil)
86 |
87 | (defn- plot*
88 | [r x y c]
89 | (assoc-in r [x y] c))
90 |
91 | (defn plot
92 | "Plots a point at a given x and y.
93 |
94 | Both x and y must be between 0 and 39."
95 | [x y]
96 | {:pre [(integer? x) (integer? y) (<= 0 x 39) (<= 0 y 39)]}
97 | (force canvas)
98 | (swap! raster plot* x y *color*)
99 | nil)
100 |
101 | (defn- lin
102 | [r a1 a2 b c f]
103 | (if (< a2 a1)
104 | (lin r a2 a1 b c f)
105 | (reduce (fn [r x]
106 | (assoc-in r (f [x b]) c))
107 | r
108 | (range a1 (inc a2)))))
109 |
110 | (defn- hlin*
111 | [r x1 x2 y c]
112 | (lin r x1 x2 y c identity))
113 |
114 | (defn hlin
115 | "Plots a horizontal line from x1 to x2 at a given y.
116 |
117 | The x and y numbers must be between 0 and 39."
118 | [x1 x2 y]
119 | {:pre [(integer? x1) (integer? x2) (integer? y) (<= 0 x1 39) (<= 0 x2 39) (<= 0 y 39)]}
120 | (force canvas)
121 | (swap! raster hlin* x1 x2 y *color*)
122 | nil)
123 |
124 | (defn- vlin*
125 | [r y1 y2 x c]
126 | (lin r y1 y2 x c reverse))
127 |
128 | (defn vlin
129 | "Plots a vertical line from y1 to y2 at a given x.
130 |
131 | The x and y numbers must be between 0 and 39."
132 | [y1 y2 x]
133 | {:pre [(integer? y1) (integer? y2) (integer? x) (<= 0 y1 39) (<= 0 y2 39) (<= 0 x 39)]}
134 | (force canvas)
135 | (swap! raster vlin* y1 y2 x *color*)
136 | nil)
137 |
138 | (defn- scrn*
139 | [r x y]
140 | (get-in r [x y]))
141 |
142 | (defn scrn
143 | "Gets the color at a given x and y.
144 |
145 | Both x and y must be between 0 and 39."
146 | [x y]
147 | {:pre [(integer? x) (integer? y) (<= 0 x 39) (<= 0 y 39)]}
148 | (force canvas)
149 | (scrn* @raster x y))
--------------------------------------------------------------------------------
/src/bocko/swing.clj:
--------------------------------------------------------------------------------
1 | (ns bocko.swing
2 | (:import (java.awt Dimension Color)
3 | (javax.swing JPanel JFrame)))
4 |
5 | (defn- rgb->color
6 | [[r g b]]
7 | (Color. r g b))
8 |
9 | (defn make-panel
10 | [color-map raster width height pixel-width pixel-height]
11 | (let [frame (JFrame. "Bocko")
12 | rgb->color (memoize rgb->color)
13 | paint-point (fn [x y c g]
14 | (.setColor g (rgb->color (c color-map)))
15 | (.fillRect g
16 | (* x pixel-width) (* y pixel-height)
17 | pixel-width pixel-height))
18 | panel (proxy [JPanel] []
19 | (paintComponent [g]
20 | (proxy-super paintComponent g)
21 | (let [r @raster]
22 | (doseq [x (range width)
23 | y (range height)]
24 | (paint-point x y (get-in r [x y]) g))))
25 | (getPreferredSize []
26 | (Dimension.
27 | (* width pixel-width)
28 | (* height pixel-height))))]
29 | (doto frame
30 | (.add panel)
31 | (.pack)
32 | (.setVisible true))
33 | (add-watch raster :monitor
34 | (fn [_ _ o n]
35 | (when (not= o n)
36 | (.repaint panel))))
37 | panel))
38 |
--------------------------------------------------------------------------------