408 lines
28 KiB
HTML
408 lines
28 KiB
HTML
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<link rel="stylesheet" href="../coverage.css"/> <title> mw_engine/heightmap.clj </title>
|
|
</head>
|
|
<body>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
001 (ns ^{:doc "Functions to apply a heightmap to a world.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
002
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
003 Heightmaps are considered only as greyscale images, so colour is redundent
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
004 (will be ignored). Darker shades are higher."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
005 :author "Simon Brooke"}
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
006 mw-engine.heightmap
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
007 (:require [mikera.image.core :refer [load-image filter-image]]
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
008 [mikera.image.filters :as filters]
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
009 [mw-engine.utils :refer [get-int get-neighbours map-world]]
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
010 [mw-engine.world :refer [make-world]]))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
011
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
012 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
013 ;;;;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
014 ;;;; mw-engine: the state/transition engine of MicroWorld.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
015 ;;;;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
016 ;;;; This program is free software; you can redistribute it and/or
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
017 ;;;; modify it under the terms of the GNU General Public License
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
018 ;;;; as published by the Free Software Foundation; either version 2
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
019 ;;;; of the License, or (at your option) any later version.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
020 ;;;;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
021 ;;;; This program is distributed in the hope that it will be useful,
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
022 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
023 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
024 ;;;; GNU General Public License for more details.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
025 ;;;;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
026 ;;;; You should have received a copy of the GNU General Public License
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
027 ;;;; along with this program; if not, write to the Free Software
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
028 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
029 ;;;; USA.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
030 ;;;;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
031 ;;;; Copyright (C) 2014 Simon Brooke
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
032 ;;;;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
033 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
034
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
035 (defn abs
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
036 "Prior to Clojure 1.11, there is no native `abs` function. Afterwards, there
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
037 is."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
038 [n]
|
|
</span><br/>
|
|
<span class="covered" title="2 out of 2 forms covered">
|
|
039 (Math/abs n))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
040
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
041 (defn tag-property
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
042 "Set the value of this `property` of this cell from the corresponding pixel of this `heightmap`.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
043 If the heightmap you supply is smaller than the world, this will break.
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
044
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
045 * `world` not actually used, but present to enable this function to be
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
046 passed as an argument to `mw-engine.utils/map-world`, q.v.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
047 * `cell` a cell, as discussed in world.clj, q.v. Alternatively, a map;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
048 * `property` the property (normally a keyword) whose value will be set on the cell.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
049 * `heightmap` an (ideally) greyscale image, whose x and y dimensions should
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
050 exceed those of the world of which the `cell` forms part."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
051 ([_ cell property heightmap]
|
|
</span><br/>
|
|
<span class="covered" title="5 out of 5 forms covered">
|
|
052 (tag-property cell property heightmap))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
053 ([cell property heightmap]
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
054 (merge cell
|
|
</span><br/>
|
|
<span class="covered" title="2 out of 2 forms covered">
|
|
055 {property
|
|
</span><br/>
|
|
<span class="covered" title="5 out of 5 forms covered">
|
|
056 (+ (get-int cell property)
|
|
</span><br/>
|
|
<span class="covered" title="2 out of 2 forms covered">
|
|
057 (- 256
|
|
</span><br/>
|
|
<span class="covered" title="2 out of 2 forms covered">
|
|
058 (abs
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
059 (mod
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
060 (.getRGB heightmap
|
|
</span><br/>
|
|
<span class="covered" title="4 out of 4 forms covered">
|
|
061 (get-int cell :x)
|
|
</span><br/>
|
|
<span class="covered" title="4 out of 4 forms covered">
|
|
062 (get-int cell :y)) 256))))})))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
063
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
064 (defn tag-gradient
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
065 "Set the `gradient` property of this `cell` of this `world` to the difference in
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
066 altitude between its highest and lowest neghbours."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
067 [world cell]
|
|
</span><br/>
|
|
<span class="covered" title="11 out of 11 forms covered">
|
|
068 (let [heights (remove nil? (map :altitude (get-neighbours world cell)))
|
|
</span><br/>
|
|
<span class="partial" title="5 out of 6 forms covered">
|
|
069 highest (cond (empty? heights) 0 ;; shouldn't happen
|
|
</span><br/>
|
|
<span class="covered" title="4 out of 4 forms covered">
|
|
070 :else (apply max heights))
|
|
</span><br/>
|
|
<span class="partial" title="5 out of 6 forms covered">
|
|
071 lowest (cond (empty? heights) 0 ;; shouldn't
|
|
</span><br/>
|
|
<span class="covered" title="4 out of 4 forms covered">
|
|
072 :else (apply min heights))
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
073 gradient (- highest lowest)]
|
|
</span><br/>
|
|
<span class="covered" title="6 out of 6 forms covered">
|
|
074 (merge cell {:gradient gradient})))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
075
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
076 (defn tag-gradients
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
077 "Set the `gradient` property of each cell in this `world` to the difference in
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
078 altitude between its highest and lowest neghbours."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
079 [world]
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 4 forms covered">
|
|
080 (map-world world tag-gradient))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
081
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
082 (defn tag-altitude
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
083 "Set the altitude of this cell from the corresponding pixel of this heightmap.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
084 If the heightmap you supply is smaller than the world, this will break.
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
085
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
086 * `world` not actually used, but present to enable this function to be
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
087 passed as an argument to `mw-engine.utils/map-world`, q.v.;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
088 * `cell` a cell, as discussed in world.clj, q.v. Alternatively, a map;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
089 * `heightmap` an (ideally) greyscale image, whose x and y dimensions should
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
090 exceed those of the world of which the `cell` forms part."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
091 ([_ cell heightmap]
|
|
</span><br/>
|
|
<span class="covered" title="5 out of 5 forms covered">
|
|
092 (tag-property cell :altitude heightmap))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
093 ([cell heightmap]
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 5 forms covered">
|
|
094 (tag-property cell :altitude heightmap)))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
095
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
096 (defn apply-heightmap
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
097 "Apply the image file loaded from this path to this world, and return a world whose
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
098 altitudes are modified (added to) by the altitudes in the heightmap. It is assumed that
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
099 the heightmap is at least as large in x and y dimensions as the world. Note that, in
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
100 addition to setting the `:altitude` of each cell, this function also sets the `:gradient`.
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
101
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
102 * `world` a world, as defined in `world.clj`, q.v.; if world is not supplied,
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
103 a world the size of the heightmap will be created;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
104 * `imagepath` a file path or URL which indicates an (ideally greyscale) image file."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
105 ([world imagepath]
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
106 (let [heightmap (filter-image
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
107 (load-image imagepath)
|
|
</span><br/>
|
|
<span class="covered" title="2 out of 2 forms covered">
|
|
108 (filters/grayscale))]
|
|
</span><br/>
|
|
<span class="covered" title="2 out of 2 forms covered">
|
|
109 (map-world
|
|
</span><br/>
|
|
<span class="covered" title="7 out of 7 forms covered">
|
|
110 (map-world world tag-altitude (list heightmap))
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
111 tag-gradient)))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
112 ([imagepath]
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
113 (let [heightmap (filter-image
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
114 (load-image imagepath)
|
|
</span><br/>
|
|
<span class="covered" title="2 out of 2 forms covered">
|
|
115 (filters/grayscale))
|
|
</span><br/>
|
|
<span class="covered" title="4 out of 4 forms covered">
|
|
116 world (make-world (.getWidth heightmap) (.getHeight heightmap))]
|
|
</span><br/>
|
|
<span class="covered" title="2 out of 2 forms covered">
|
|
117 (map-world
|
|
</span><br/>
|
|
<span class="covered" title="7 out of 7 forms covered">
|
|
118 (map-world world tag-altitude (list heightmap))
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
119 tag-gradient))))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
120
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
121 (defn apply-valuemap
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
122 "Generalised from apply-heightmap, set an arbitrary property on each cell
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
123 of this `world` from the values in this (ideally greyscale) heightmap.
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
124
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
125 * `world` a world, as defined in `world.clj`, q.v.;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
126 * `imagepath` a file path or URL which indicates an (ideally greyscale) image file;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
127 * `property` the property of each cell whose value should be added to from the
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
128 intensity of the corresponding cell of the image."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
129 [world imagepath property]
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
130 (let [heightmap (filter-image
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
131 (load-image imagepath)
|
|
</span><br/>
|
|
<span class="covered" title="2 out of 2 forms covered">
|
|
132 (filters/grayscale))]
|
|
</span><br/>
|
|
<span class="covered" title="8 out of 8 forms covered">
|
|
133 (map-world world tag-property (list property heightmap))))
|
|
</span><br/>
|
|
</body>
|
|
</html>
|