Creating a spritesheet instead of many surfaces.
[uxul-world.git] / files.lisp
1 ;;; Copyright 2009-2011 Christoph Senjak
2
3 ;; This file declares the constants for loading different files and
4 ;; file-formats.
5
6 (in-package :uxul-world)
7
8 (defun si (var val)
9   (setf (symbol-value (intern var)) val))
10
11 (defun stretch-image (x y img)
12   "Resize that file to x times y."
13   (uxul-world::resize-bmp-blob img x y))
14
15 ;; (defun init-bmp-file (file)
16 ;;   "Load an image file into a Variable. Set |filename| (without .png
17 ;; and path) to a list with all sizes of that image."
18 ;;   (si (pathname-name file)
19 ;;        (with-open-file (in file :element-type '(unsigned-byte 8)) 
20 ;;       (let* ((length (file-length in))
21 ;;              (content (make-array (list length)
22 ;;                                   :element-type '(unsigned-byte 8)
23 ;;                                   :adjustable nil)))
24 ;;         (read-sequence content in)
25 ;;         content))))
26
27 (defun bmp-p (file)
28   "Is the file relevant for initialization? So far only .png-files are
29 relevant."
30   (string= (pathname-type file) "bmp"))
31
32 ;; (defun init-bmp-files ()
33 ;;   (cl-fad:walk-directory
34 ;;    (asdf:component-pathname (asdf:find-system :uxul-world))
35 ;;    #'init-bmp-file :test #'bmp-p))
36
37 (defvar *spritesheet*)
38 (defvar *spritesheet-id*)
39
40 (defun init-bmp-files ()
41   (let* ((names (remove-if-not #'bmp-p
42                                (cl-fad:list-directory
43                                 (asdf:component-pathname
44                                  (asdf:find-system :uxul-world)))))
45          (number (length names))
46          (imagedata (mapcar #'load-file-to-sequence names))
47          (pixeldata (mapcar
48                      (lambda (x)
49                        (bmp-pixel-data x :destructive t))
50                      imagedata))
51          (widths (mapcar #'bmp-width imagedata))
52          (heights (mapcar #'bmp-height imagedata))
53          (max-width (apply #'max widths))
54          (max-height (apply #'max heights))
55          ;; minimize max-height * optimal-x-num + max-width *
56          ;; optimal-y-num, keeping optimal-x-num * optimal-y-num
57          ;; constant at the number of files (of course, round
58          ;; everything up)
59          (optimal-x-num (ceiling
60                          (sqrt (/ (* max-height number) max-width))))
61          (optimal-y-num (ceiling
62                          (sqrt (/ (* max-width number) max-height))))
63          ;; find the smallest powers of two such that both fit in it
64          (sidelength (expt 2 (max
65                               (ceiling (log (* max-width optimal-x-num) 2))
66                               (ceiling (log (* max-height optimal-y-num) 2)))))
67          (new-image-data (make-array (list (* 4 sidelength sidelength))
68                                      :element-type '(unsigned-byte 8)
69                                      :adjustable nil
70                                      :initial-element #x00))
71          (cx 0) (cy 0)
72          (cx* 0) (cy* 0))
73     (mapcar
74      (lambda (name pixels width height)
75        (blit-image cx* cy* width height pixels
76                    sidelength sidelength new-image-data)
77        (si (pathname-name name)
78            `(,width ,height
79                     ,@(mapcar #'(lambda (x) (/ x sidelength 1.0))
80                               (list cx* cy* (+ cx* width) (+ cy* height)))))
81        (incf cx)
82        (cond ((= cx optimal-x-num)
83               (incf cy)
84               (incf cy* max-height)
85               (setf cx 0 cx* 0))
86              (T (incf cx* max-width))))
87      names pixeldata widths heights)
88     (setf *spritesheet* (list new-image-data sidelength))))
89
90
91 (defun init-files ()
92   "Load the relevant files into variables"
93   (init-bmp-files))
94
95 (init-files)