Mercurial > vba-clojure
view clojure/com/aurellem/run/adv_choreo.clj @ 602:0e30fd920e6a
fix silly glitch.
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sun, 02 Sep 2012 09:28:08 -0500 |
parents | 31128a10ee28 |
children | b3e5006e23f0 |
line wrap: on
line source
1 ;;;; "Advanced Choreography" -- this is the final video for this project.3 (ns com.aurellem.run.adv-choreo4 (:use (com.aurellem.gb saves gb-driver util constants5 items vbm characters money6 rlm-assembly))7 (:use (com.aurellem.run util music title save-corruption8 bootstrap-0 bootstrap-1 image9 ram-display final-cut basic-choreo))10 (:require clojure.string)11 (:import java.awt.image.BufferedImage)12 (:import (javax.imageio ImageWriteParam IIOImage ImageIO))13 (:import [com.aurellem.gb.gb_driver SaveState])14 (:import java.io.File))18 ;; Use the gameboy's screen to display the new programming19 ;; instead of a side window. This will make it look much20 ;; cooler and create a terminal-like effect as the game is21 ;; being reprogramed. To do this, use a fixed data entry22 ;; region in ram, and run a program that translates this23 ;; region into the screen. Every time this data entry region24 ;; is full, run a program that copies the data to the25 ;; appropriate region in memory. This will cost ~15 seconds26 ;; at the beginning to set up, and then should have minimal27 ;; overhead (~5%) for the rest of the data transfer, but28 ;; will have a good psychological effect for the viewer29 ;; since he can see that something is actually happening in30 ;; the game.33 ;; Symbol size and type.35 ;; use fonts from zophar's domain:36 ;; http://www.zophar.net/utilities/fonts/8x8-font-archive.html38 ;; Green font on black background for matrix look.41 (defn program-data [base-address]42 (let [image-program43 (display-image-kernel44 base-address46 pinkie-pie-mark47 ;;test-image-color48 )51 music-base-address (+ (count image-program) base-address)53 initial-music-data54 (midi-bytes pony-csv 0 0 0 0)56 data-lengths57 (map (comp count :data)58 [(:kernel initial-music-data)59 (:voice-1 initial-music-data)60 (:voice-2 initial-music-data)]);; noise not needed61 addresses62 (map (partial + music-base-address) (reductions + 0 data-lengths))64 final-music-data65 (apply (partial midi-bytes pony-csv) addresses)67 music-program68 (concat69 (:data (:kernel final-music-data))70 (:data (:voice-1 final-music-data))71 (:data (:voice-2 final-music-data))72 (:data (:noise final-music-data)))]74 (concat75 image-program ;; image program falls through to music program76 music-program)))78 (def glyphs79 "The sixteen 8x8 glyphs which make up the \"terminal\" font."80 (mapv #(ImageIO/read81 (File. user-home (str "proj/vba-clojure/font/" % ".png")))82 ["0" "1" "2" "3" "4" "5" "6" "7" "8"83 "9" "A" "B" "C" "D" "E" "F" "_"]))86 (defn glyph-init-program87 [start-address]88 (let [zero-glyph (image->gb-image (glyphs 0))90 ;; write same pallet information to all pallettes91 A (flatten92 [(write-byte LCD-control-register 0x00);; disable LCD protection93 (set-palettes bg-palette-select bg-palette-data94 (repeat 8 (first (:palettes zero-glyph))))95 (select-LCD-bank 0)96 (write-byte SCX-register 0)97 (write-byte SCY-register 0)])98 B (flatten99 [(write-data100 (+ start-address (count A))101 character-data-address102 (flatten103 (map (comp gb-tile->bytes first :tiles image->gb-image)104 glyphs)))107 (write-byte108 LCD-control-register109 (Integer/parseInt110 (str111 "1" ;; LCDC on/off112 "0" ;; Window code area113 "0" ;; Windowing on?114 "1" ;; BG tile base (1 = 0x8000)115 "0" ;; BG-1 or BG-2 ?116 "0" ;; OBJ-block composition117 "0" ;; OBJ-on flag118 "1") ;; no-effect119 2))])]120 (concat A B )))124 (defn glyph-display-program125 [start-address]126 (let [data-start (+ 2 start-address)127 load-data128 (flatten129 [;; data region130 0x18131 2132 0 0;; current row and column133 ;; save all registers134 0xC5 0xD5 0xE5 0xF5136 ;; load data from data region into registers138 0xF5 ;; push A, which contains current glyph140 0x21141 (reverse (disect-bytes-2 data-start))142 ;; load row and column into DE143 0x2A 0x57 ;; row -> D144 0x2A 0x5F ;; column -> E145 ])148 display-glyph149 (let [init*150 (flatten151 [;; clear screen if we are at 0,0152 0x7A 0xB3 ;; D->A, OR E A ==> (= D E 0)153 0x20 ;; skip clear-screen if D and E are not both zero154 :clear-screen-length])156 clear-screen157 (flatten158 [;; save all registers159 0xC5 0xD5 0xE5 0xF5161 (select-LCD-bank 0)162 ;; write 0x00 to memory locations163 ;; 0x9800 to 0x9A34164 0x21165 0x00 0x98 ;; load 0x9800 into HL167 0x16 3 ;; 3 -> D168 0x1E 190 ;; 190 -> E170 ;; Empty space Character ID171 0x3E 16 ;; 0-> A173 ;; begin of do-while loop174 0x22 ;; load A to 0x9800175 0x1D ;; dec E176 0x20177 (->signed-8-bit -4)178 0x15 ;; dec D179 0x1E 190 ;; 188 -> E180 0x20181 (->signed-8-bit -8)182 ;; end of do-while-loop184 ;; restore all registers185 0xF1 0xE1 0xD1 0xC1])188 increment-row-column189 [;; D contains row and E contains column191 ;; every time column (E) reaches 20, set192 ;; column to 0 and increment row193 0x1C ;; inc E194 0x3E 20 0xBB ;; compare E to 20195 0x20196 3197 0x14 ;; increment row198 0x1E 0 ;; set column to 0201 ;; if row==18, set row to 0202 0x3E 18203 0xBA204 0x20205 2206 0x16 0]208 set-HL-from-row-and-column209 (flatten210 [;; formula for memory offset is:211 ;; (+ 0x9800 (* 32 row) column) ==212 0x21 0x00 0x98 ;; load HL with 0x9800214 0x06 0215 0x4B ;; columns (E) -> BC216 0x09 ;; HL += columns219 0xAF ;; 0 -> A221 0x06 0222 0x0E 32 ;; load 32 into BC224 0xBA ;; CP A D225 0x28 ;; skip this next section if A == D226 4227 0x09 ;; HL += 32228 0x3C229 0x18231 (->signed-8-bit -7)])233 render-glyph234 (flatten235 [;; Render each nybble of A as a character236 ;; there are two characters to a glyph.238 set-HL-from-row-and-column240 0xF1 ;; pop A, now A is equal to key input241 0xF5 ;; save A243 0xE6 0xF0 ;; clear second nybble244 0xCB 0x37 ;; swap nybbles245 0x77 ;; store A in video RAM as a character (pun)246 increment-row-column249 set-HL-from-row-and-column251 0xF1 ;; restore A252 0xE6 0x0F ;; select second nybble253 0x77 ;; store second nybble as character254 increment-row-column])257 init (replace258 {:clear-screen-length (count clear-screen)} init*)259 ]261 (concat init clear-screen render-glyph))263 cleanup264 ;; restore all registers265 (flatten266 [;; Reset HL to initial data-start value267 0x21268 (reverse (disect-bytes-2 data-start))269 ;;0x23270 ;; write variables271 0x7A 0x22 ;; D -> rows -> to RAM272 0x7B 0x22 ;; E -> columns273 ])275 stack-cleanup276 [0xF1 0xE1 0xD1 0xC1]277 ]278 (concat load-data279 display-glyph280 cleanup stack-cleanup)))282 (def main-program-base-address 0xC000)284 (defn glyph-bootstrap-program285 [start-address delay-count total-glyph-count]286 (let [init [0xAF 0x4F 0x47] ;; 0->A; 0->C; 0->B287 header (concat (frame-metronome) (read-user-input))289 glyph-display (glyph-display-program290 (+ (count init)291 (count header)292 start-address))294 state-machine-start-address295 (+ start-address (count init) (count header) (count glyph-display))296 state-machine297 (bootstrap-state-machine state-machine-start-address)299 return-to-header300 (flatten301 [0xC3302 (reverse (disect-bytes-2303 (+ (count init) start-address)))])]304 (concat init header glyph-display state-machine return-to-header)))306 (defn begin-glyph-bootstrap307 ([] (begin-glyph-bootstrap (launch-main-bootstrap-program)))308 ([script]309 (let [glyph-init (glyph-init-program relocated-bootstrap-start)310 main-glyph-start (+ relocated-bootstrap-start311 (count glyph-init))312 glyph-program (glyph-bootstrap-program313 main-glyph-start 0 0)]314 (->> script315 (do-nothing 2)316 ;; begin glyph program317 (write-RAM 0xFF1A [0 0 0]) ;; silence remnant music319 (write-RAM320 relocated-bootstrap-start321 (concat glyph-init glyph-program))322 (transfer-control relocated-bootstrap-start)323 (do-nothing 1)))))325 (defn write-all-program-data326 ([] (write-all-program-data (begin-glyph-bootstrap)))327 ([script]328 (let [base-address main-program-base-address]329 (->> script330 (write-RAM base-address (program-data base-address))))))332 (defn activate-program333 ([] (activate-program (write-all-program-data)))334 ([script]335 (->> script336 (transfer-control main-program-base-address)337 (do-nothing 1800))))339 (def advanced-render-dir340 (File. user-home "proj/vba-clojure/render/advanced"))342 (defn advanced-steps [] (first (activate-program)))344 (def gb-button-bar345 (File. user-home "/proj/vba-clojure/images/gb-button-bar.png"))347 (def gb-button-mark348 (File. user-home "/proj/vba-clojure/images/gb-button-mark.png"))350 (defn adv-write-move-image! [move target-file]351 (let [buttons (set move)352 key-positions353 {:l [23 23]354 :u [33 11]355 :r [46 23]356 :d [33 26]358 :start [65 24]359 :select [80 24]361 :b [100 25]362 :a [121 25]}]363 (apply364 clojure.java.shell/sh365 (flatten366 ["convert"367 (.getCanonicalPath gb-button-bar)368 (map369 (fn [key]370 (let [[x y] (key-positions key)]371 (.getCanonicalPath gb-button-mark)372 "-geometry" (str "+" x "+" y) "-composite"))373 buttons)374 (.getCanonicalPath target-file)]))))376 (defn adv-composite-frames-command377 [move-image screenshot target]378 ["convert"379 screenshot380 move-image "-append"381 target])383 (defn adv-generate-composite-frames!384 [^File rendered-dir]385 (let [final-frames (File. rendered-dir "final")386 _ (.mkdir final-frames)387 move-images (file-names (File. rendered-dir "moves"))388 screenshots (file-names (File. rendered-dir "frames"))389 targets (map #(.getCanonicalPath390 (File. final-frames (format "%07d.png" %)))391 (range (count screenshots)))]392 (dorun393 (map394 (comp395 (partial apply clojure.java.shell/sh)396 flatten397 (partial apply adv-composite-frames-command)398 (fn [a b d] (println d) [a b d]))399 move-images screenshots targets))))401 (defn advanced-step-1! []402 (render-files!403 advanced-render-dir404 adv-write-move-image!405 false406 (root) (advanced-steps)))408 (defn advanced-step-2! []409 (adv-generate-composite-frames!410 advanced-render-dir))412 (defn advanced-step-3! [] (final-cut! advanced-render-dir))417 ;; possible screen writing programs419 ;; (program needs to stop executing at some point)420 ;; maybe have total length counter or something?422 ;; automatic counter that reads from program-start and clears the423 ;; screen every 360 (* 18 20) gliphs425 ;; advantages -- very simple and low bandwidth426 ;; disadvantages -- hard to align counter428 ;; implementation -- refactor main-bootstrap-program to provide a429 ;; state-machine code-section which can be recombined into another430 ;; program.