diff options
| author | Gemini Lasswell | 2017-10-16 08:30:51 -0700 |
|---|---|---|
| committer | Gemini Lasswell | 2017-10-24 09:02:49 -0700 |
| commit | cb73c70180f57f3fb99fae3aaefbacf0a61cea3f (patch) | |
| tree | 67dab0331e0b70c3176ca5f536f35b0bd3591eff | |
| parent | 4ec0d2dc6f149c4c14833793f20e1e54270b85f2 (diff) | |
| download | emacs-cb73c70180f57f3fb99fae3aaefbacf0a61cea3f.tar.gz emacs-cb73c70180f57f3fb99fae3aaefbacf0a61cea3f.zip | |
Make Snake, Tetris and Pong adjust to display DPI
Replace gamegrid's constant 16x16 glyph with a generated one based
on display dimensions (bug#24658).
* lisp/play/gamegrid.el (gamegrid-glyph-height-mm): New variable.
(gamegrid-glyph-height): Deleted.
(gamegrid-xpm, gamegrid-xbm): Constants replaced with functions.
(gamegrid-colorize-glyph): Use new functions instead of constants.
(gamegrid-calculate-glyph-size, gamegrid-insert-xbm-bits): New
functions.
| -rw-r--r-- | etc/NEWS | 7 | ||||
| -rw-r--r-- | lisp/play/gamegrid.el | 178 |
2 files changed, 150 insertions, 35 deletions
| @@ -82,6 +82,13 @@ globally or for individual definitions. | |||
| 82 | the XTerm window title. This feature is experimental and is disabled | 82 | the XTerm window title. This feature is experimental and is disabled |
| 83 | by default. | 83 | by default. |
| 84 | 84 | ||
| 85 | ** Gamegrid | ||
| 86 | |||
| 87 | --- | ||
| 88 | *** Gamegrid now determines its default glyph size based on display | ||
| 89 | dimensions, instead of always using 16 pixels. As a result, Tetris, | ||
| 90 | Snake and Pong are more playable on HiDPI displays. | ||
| 91 | |||
| 85 | 92 | ||
| 86 | * New Modes and Packages in Emacs 27.1 | 93 | * New Modes and Packages in Emacs 27.1 |
| 87 | 94 | ||
diff --git a/lisp/play/gamegrid.el b/lisp/play/gamegrid.el index 6214e07506d..641ef7f2462 100644 --- a/lisp/play/gamegrid.el +++ b/lisp/play/gamegrid.el | |||
| @@ -86,49 +86,157 @@ directory will be used.") | |||
| 86 | (defvar gamegrid-mono-x-face nil) | 86 | (defvar gamegrid-mono-x-face nil) |
| 87 | (defvar gamegrid-mono-tty-face nil) | 87 | (defvar gamegrid-mono-tty-face nil) |
| 88 | 88 | ||
| 89 | ;; ;;;;;;;;;;;;; constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | 89 | (defvar gamegrid-glyph-height-mm 7.0 |
| 90 | 90 | "Desired glyph height in mm.") | |
| 91 | (defconst gamegrid-glyph-height 16) | 91 | |
| 92 | 92 | ;; ;;;;;;;;;;;;; glyph generation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| 93 | (defconst gamegrid-xpm "\ | 93 | |
| 94 | (defun gamegrid-calculate-glyph-size () | ||
| 95 | "Calculate appropriate glyph size in pixels based on display resolution. | ||
| 96 | Return a multiple of 8 no less than 16." | ||
| 97 | (if (and (display-pixel-height) (display-mm-height)) | ||
| 98 | (let* ((y-pitch (/ (display-pixel-height) (float (display-mm-height)))) | ||
| 99 | (pixels (* y-pitch gamegrid-glyph-height-mm)) | ||
| 100 | (rounded (* (floor (/ (+ pixels 4) 8)) 8))) | ||
| 101 | (max 16 rounded)) | ||
| 102 | 16)) | ||
| 103 | |||
| 104 | ;; Example of glyph in XPM format: | ||
| 105 | ;; | ||
| 106 | ;; /* XPM */ | ||
| 107 | ;; static char *noname[] = { | ||
| 108 | ;; /* width height ncolors chars_per_pixel */ | ||
| 109 | ;; \"16 16 3 1\", | ||
| 110 | ;; /* colors */ | ||
| 111 | ;; \"+ s col1\", | ||
| 112 | ;; \". s col2\", | ||
| 113 | ;; \"- s col3\", | ||
| 114 | ;; /* pixels */ | ||
| 115 | ;; \"---------------+\", | ||
| 116 | ;; \"--------------++\", | ||
| 117 | ;; \"--............++\", | ||
| 118 | ;; \"--............++\", | ||
| 119 | ;; \"--............++\", | ||
| 120 | ;; \"--............++\", | ||
| 121 | ;; \"--............++\", | ||
| 122 | ;; \"--............++\", | ||
| 123 | ;; \"--............++\", | ||
| 124 | ;; \"--............++\", | ||
| 125 | ;; \"--............++\", | ||
| 126 | ;; \"--............++\", | ||
| 127 | ;; \"--............++\", | ||
| 128 | ;; \"--............++\", | ||
| 129 | ;; \"-+++++++++++++++\", | ||
| 130 | ;; \"++++++++++++++++\" | ||
| 131 | ;; }; | ||
| 132 | |||
| 133 | (defun gamegrid-xpm () | ||
| 134 | "Generate the XPM format image used for each square." | ||
| 135 | (let* ((glyph-pixel-count (gamegrid-calculate-glyph-size)) | ||
| 136 | (border-pixel-count (/ glyph-pixel-count 8)) | ||
| 137 | (center-pixel-count (- glyph-pixel-count (* border-pixel-count 2)))) | ||
| 138 | (with-temp-buffer | ||
| 139 | (insert (format "\ | ||
| 94 | /* XPM */ | 140 | /* XPM */ |
| 95 | static char *noname[] = { | 141 | static char *noname[] = { |
| 96 | /* width height ncolors chars_per_pixel */ | 142 | /* width height ncolors chars_per_pixel */ |
| 97 | \"16 16 3 1\", | 143 | \"%s %s 3 1\", |
| 98 | /* colors */ | 144 | /* colors */ |
| 99 | \"+ s col1\", | 145 | \"+ s col1\", |
| 100 | \". s col2\", | 146 | \". s col2\", |
| 101 | \"- s col3\", | 147 | \"- s col3\", |
| 102 | /* pixels */ | 148 | /* pixels */ |
| 103 | \"---------------+\", | 149 | " glyph-pixel-count glyph-pixel-count)) |
| 104 | \"--------------++\", | 150 | |
| 105 | \"--............++\", | 151 | (dotimes (row border-pixel-count) |
| 106 | \"--............++\", | 152 | (let ((edge-pixel-count (+ row 1))) |
| 107 | \"--............++\", | 153 | (insert "\"") |
| 108 | \"--............++\", | 154 | (dotimes (_ (- glyph-pixel-count edge-pixel-count)) (insert "-")) |
| 109 | \"--............++\", | 155 | (dotimes (_ edge-pixel-count) (insert "+")) |
| 110 | \"--............++\", | 156 | (insert "\",\n"))) |
| 111 | \"--............++\", | 157 | |
| 112 | \"--............++\", | 158 | (let ((middle (format "\"%s%s%s\",\n" |
| 113 | \"--............++\", | 159 | (make-string border-pixel-count ?-) |
| 114 | \"--............++\", | 160 | (make-string center-pixel-count ?.) |
| 115 | \"--............++\", | 161 | (make-string border-pixel-count ?+)))) |
| 116 | \"--............++\", | 162 | (dotimes (_ center-pixel-count) (insert middle))) |
| 117 | \"-+++++++++++++++\", | 163 | |
| 118 | \"++++++++++++++++\" | 164 | (dotimes (row border-pixel-count) |
| 119 | }; | 165 | (let ((edge-pixel-count (- border-pixel-count row 1))) |
| 120 | " | 166 | (insert "\"") |
| 121 | "XPM format image used for each square") | 167 | (dotimes (_ edge-pixel-count) (insert "-")) |
| 122 | 168 | (dotimes (_ (- glyph-pixel-count edge-pixel-count)) (insert "+")) | |
| 123 | (defvar gamegrid-xbm "\ | 169 | (insert "\"") |
| 170 | (if (/= row (1- border-pixel-count)) | ||
| 171 | (insert ",\n") | ||
| 172 | (insert "\n};\n")))) | ||
| 173 | (buffer-string)))) | ||
| 174 | |||
| 175 | ;; Example of glyph in XBM format: | ||
| 176 | ;; | ||
| 177 | ;; /* gamegrid XBM */ | ||
| 178 | ;; #define gamegrid_width 16 | ||
| 179 | ;; #define gamegrid_height 16 | ||
| 180 | ;; static unsigned char gamegrid_bits[] = { | ||
| 181 | ;; 0xff, 0xff, 0xff, 0x7f, 0xff, 0x3f, 0xaf, 0x0a, 0x57, 0x15, 0xaf, 0x0a, | ||
| 182 | ;; 0x57, 0x15, 0xaf, 0x0a, 0x57, 0x15, 0xaf, 0x0a, 0x57, 0x15, 0xaf, 0x0a, | ||
| 183 | ;; 0x57, 0x15, 0x07, 0x00, 0x03, 0x00, 0x01, 0x00 }; | ||
| 184 | |||
| 185 | (defun gamegrid-xbm () | ||
| 186 | "Generate XBM format image used for each square." | ||
| 187 | (let* ((glyph-pixel-count (gamegrid-calculate-glyph-size)) | ||
| 188 | (border-pixel-count (1- (/ glyph-pixel-count 4))) | ||
| 189 | (center-pixel-count (- glyph-pixel-count (* 2 border-pixel-count)))) | ||
| 190 | (with-temp-buffer | ||
| 191 | (insert (format "\ | ||
| 124 | /* gamegrid XBM */ | 192 | /* gamegrid XBM */ |
| 125 | #define gamegrid_width 16 | 193 | #define gamegrid_width %s |
| 126 | #define gamegrid_height 16 | 194 | #define gamegrid_height %s |
| 127 | static unsigned char gamegrid_bits[] = { | 195 | static unsigned char gamegrid_bits[] = { |
| 128 | 0xff, 0xff, 0xff, 0x7f, 0xff, 0x3f, 0xaf, 0x0a, 0x57, 0x15, 0xaf, 0x0a, | 196 | " glyph-pixel-count glyph-pixel-count)) |
| 129 | 0x57, 0x15, 0xaf, 0x0a, 0x57, 0x15, 0xaf, 0x0a, 0x57, 0x15, 0xaf, 0x0a, | 197 | (dotimes (row border-pixel-count) |
| 130 | 0x57, 0x15, 0x07, 0x00, 0x03, 0x00, 0x01, 0x00 };" | 198 | (gamegrid-insert-xbm-bits |
| 131 | "XBM format image used for each square.") | 199 | (concat (make-string (- glyph-pixel-count row) ?1) |
| 200 | (make-string row ?0))) | ||
| 201 | (insert ", \n")) | ||
| 202 | |||
| 203 | (let* ((left-border (make-string border-pixel-count ?1)) | ||
| 204 | (right-border (make-string border-pixel-count ?0)) | ||
| 205 | (even-line (apply 'concat | ||
| 206 | (append (list left-border) | ||
| 207 | (make-list (/ center-pixel-count 2) "10") | ||
| 208 | (list right-border)))) | ||
| 209 | (odd-line (apply 'concat | ||
| 210 | (append (list left-border) | ||
| 211 | (make-list (/ center-pixel-count 2) "01") | ||
| 212 | (list right-border))))) | ||
| 213 | (dotimes (row center-pixel-count) | ||
| 214 | (gamegrid-insert-xbm-bits (if (eq (logand row 1) 1) odd-line even-line)) | ||
| 215 | (insert ", \n"))) | ||
| 216 | |||
| 217 | (dotimes (row border-pixel-count) | ||
| 218 | (let ((edge-pixel-count (- border-pixel-count row))) | ||
| 219 | (gamegrid-insert-xbm-bits | ||
| 220 | (concat (make-string edge-pixel-count ?1) | ||
| 221 | (make-string (- glyph-pixel-count edge-pixel-count) ?0)))) | ||
| 222 | (if (/= row (1- border-pixel-count)) | ||
| 223 | (insert ", \n") | ||
| 224 | (insert " };\n"))) | ||
| 225 | (buffer-string)))) | ||
| 226 | |||
| 227 | (defun gamegrid-insert-xbm-bits (str) | ||
| 228 | "Convert binary to hex and insert in current buffer. | ||
| 229 | STR should be a string composed of 1s and 0s and be a multiple of | ||
| 230 | 8 in length. Divide it into 8 bit bytes, reverse the order of | ||
| 231 | each, convert them to hex and insert them in comma separated C | ||
| 232 | format." | ||
| 233 | (let ((byte-count (/ (length str) 8))) | ||
| 234 | (dotimes (i byte-count) | ||
| 235 | (let* ((byte (reverse (substring str (* i 8) (+ (* i 8) 8)))) | ||
| 236 | (value (string-to-number byte 2))) | ||
| 237 | (insert (format "0x%02x" value)) | ||
| 238 | (unless (= i (1- byte-count)) | ||
| 239 | (insert ", ")))))) | ||
| 132 | 240 | ||
| 133 | ;; ;;;;;;;;;;;;;;;; miscellaneous functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | 241 | ;; ;;;;;;;;;;;;;;;; miscellaneous functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 134 | 242 | ||
| @@ -228,13 +336,13 @@ static unsigned char gamegrid_bits[] = { | |||
| 228 | gamegrid-mono-tty-face)))) | 336 | gamegrid-mono-tty-face)))) |
| 229 | 337 | ||
| 230 | (defun gamegrid-colorize-glyph (color) | 338 | (defun gamegrid-colorize-glyph (color) |
| 231 | (find-image `((:type xpm :data ,gamegrid-xpm | 339 | (find-image `((:type xpm :data ,(gamegrid-xpm) |
| 232 | :ascent center | 340 | :ascent center |
| 233 | :color-symbols | 341 | :color-symbols |
| 234 | (("col1" . ,(gamegrid-color color 0.6)) | 342 | (("col1" . ,(gamegrid-color color 0.6)) |
| 235 | ("col2" . ,(gamegrid-color color 0.8)) | 343 | ("col2" . ,(gamegrid-color color 0.8)) |
| 236 | ("col3" . ,(gamegrid-color color 1.0)))) | 344 | ("col3" . ,(gamegrid-color color 1.0)))) |
| 237 | (:type xbm :data ,gamegrid-xbm | 345 | (:type xbm :data ,(gamegrid-xbm) |
| 238 | :ascent center | 346 | :ascent center |
| 239 | :foreground ,(gamegrid-color color 1.0) | 347 | :foreground ,(gamegrid-color color 1.0) |
| 240 | :background ,(gamegrid-color color 0.5))))) | 348 | :background ,(gamegrid-color color 0.5))))) |