Generalised hieghtmaps so that I can do, for example, rainfall maps,

or various geophysics maps.
This commit is contained in:
simon 2014-08-12 19:07:48 +01:00
parent 64ab0b9dd9
commit 3b1d28d3cd
2 changed files with 58 additions and 17 deletions

View file

@ -12,7 +12,31 @@
[mikera.image.core :as imagez :only [filter-image get-pixels]] [mikera.image.core :as imagez :only [filter-image get-pixels]]
[mikera.image.filters :as filters])) [mikera.image.filters :as filters]))
(defn tag-gradient
(defn- tag-property
"Set the value of this `property` of this cell from the corresponding pixel of this `heightmap`.
If the heightmap you supply is smaller than the world, this will break.
* `world` not actually used, but present to enable this function to be
passed as an argument to `mw-engine.utils/map-world`, q.v.
* `cell` a cell, as discussed in world.clj, q.v. Alternatively, a map;
* `property` the property (normally a keyword) whose value will be set on the cell.
* `heightmap` an (ideally) greyscale image, whose x and y dimensions should
exceed those of the world of which the `cell` forms part."
([world cell property heightmap]
(tag-property cell property heightmap))
([cell property heightmap]
(merge cell
{property
(+ (get-int cell property)
(- 256
(abs
(mod
(.getRGB heightmap
(get-int cell :x)
(get-int cell :y)) 256))))})))
(defn- tag-gradient
"Set the `gradient` property of this `cell` of this `world` to the difference in "Set the `gradient` property of this `cell` of this `world` to the difference in
altitude between its highest and lowest neghbours." altitude between its highest and lowest neghbours."
[world cell] [world cell]
@ -30,36 +54,29 @@
[world] [world]
(map-world world tag-gradient)) (map-world world tag-gradient))
(defn tag-altitude (defn- tag-altitude
"Set the altitude of this cell from the corresponding pixel of this heightmap. "Set the altitude of this cell from the corresponding pixel of this heightmap.
If the heightmap you supply is smaller than the world, this will break. If the heightmap you supply is smaller than the world, this will break.
* `world` not actually used, but present to enable this function to be * `world` not actually used, but present to enable this function to be
passed as an argument to `mw-engine.utils/map-world`, q.v. passed as an argument to `mw-engine.utils/map-world`, q.v.;
* `cell` a cell, as discussed in world.clj, q.v. Alternatively, a map; * `cell` a cell, as discussed in world.clj, q.v. Alternatively, a map;
* `heightmap` an (ideally) greyscale image, whose x and y dimensions should * `heightmap` an (ideally) greyscale image, whose x and y dimensions should
exceed those of the world of which the `cell` forms part." exceed those of the world of which the `cell` forms part."
([world cell heightmap] ([world cell heightmap]
(tag-altitude cell heightmap)) (tag-property cell :altitude heightmap))
([cell heightmap] ([cell heightmap]
(merge cell (tag-property cell :altitude heightmap)))
{:altitude
(+ (get-int cell :altitude)
(- 256
(abs
(mod
(.getRGB heightmap
(get-int cell :x)
(get-int cell :y)) 256))))})))
(defn apply-heightmap (defn apply-heightmap
"Apply the image file loaded from this path to this world, and return a world whose "Apply the image file loaded from this path to this world, and return a world whose
altitudes are modified (added to) by the altitudes in the heightmap. It is assumed that altitudes are modified (added to) by the altitudes in the heightmap. It is assumed that
the heightmap is at least as large in x and y dimensions as the world. the heightmap is at least as large in x and y dimensions as the world. Note that, in
addition to setting the `:altitude` of each cell, this function also sets the `:gradient`.
* `world` a world, as defined in `world.clj`, q.v.; if world is not supplied, * `world` a world, as defined in `world.clj`, q.v.; if world is not supplied,
a world the size of the heightmap will be created. a world the size of the heightmap will be created;
* `imagepath` a file path or URL which indicates an image file." * `imagepath` a file path or URL which indicates an (ideally greyscale) image file."
([world imagepath] ([world imagepath]
(let [heightmap (imagez/filter-image (let [heightmap (imagez/filter-image
(filters/grayscale) (filters/grayscale)
@ -75,3 +92,17 @@
(map-world (map-world
(map-world world tag-altitude (list heightmap)) (map-world world tag-altitude (list heightmap))
tag-gradient)))) tag-gradient))))
(defn apply-valuemap
"Generalised from apply-heightmap, set an arbitrary property on each cell
of this `world` from the values in this (ideally greyscale) heightmap.
* `world` a world, as defined in `world.clj`, q.v.;
* `imagepath` a file path or URL which indicates an (ideally greyscale) image file;
* `property` the property of each cell whose value should be added to from the
intensity of the corresponding cell of the image."
[world imagepath property]
(let [heightmap (imagez/filter-image
(filters/grayscale)
(collage/load-image imagepath))]
(map-world world tag-property (list property heightmap))))

View file

@ -22,3 +22,13 @@
"At least some gradients must be positive, none should be negative") "At least some gradients must be positive, none should be negative")
))) )))
(deftest apply-valuemap-test
(testing "Valuemap functionality"
(let [image (as-file "resources/heightmaps/test9x9.png")
world (apply-valuemap (apply-heightmap image) image :arbitrary)
altitudes (map #(:altitude %) (flatten world))
arbitraries (map #(:arbitrary %) (flatten world))]
(is (= altitudes arbitraries) "Altitudes and arbitraries are derived from same map so should be identical.")
)))