summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Bergli Heier <snakebite@jvnv.net>2011-06-01 19:28:24 +0200
committerJon Bergli Heier <snakebite@jvnv.net>2011-06-01 19:28:24 +0200
commit9fa6460f22be5482239d0b903af985a519f77166 (patch)
tree7f4be0d51977ad90b184cd01aa9300f8efd2eb4d
Initial commit.
-rw-r--r--.gitignore6
-rw-r--r--.gitmodules3
-rw-r--r--SConstruct33
m---------common0
-rw-r--r--connection.cpp59
-rw-r--r--connection.h30
-rw-r--r--main.cpp28
-rw-r--r--noiseutils/COPYING.txt504
-rw-r--r--noiseutils/noiseutils.cpp1298
-rw-r--r--noiseutils/noiseutils.h2540
-rw-r--r--noiseutils/readme.txt4
-rw-r--r--noiseutils/warnings.diff56
-rw-r--r--server.cpp105
-rw-r--r--server.h33
-rw-r--r--terrain_generator.cpp48
-rw-r--r--terrain_generator.h18
16 files changed, 4765 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7163e7a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+*.swp
+/.sconsign.dblite
+*.vim
+*.o
+/gressd
+*.exe
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..c496c3d
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "common"]
+ path = common
+ url = git://git.jvnv.net/gress-common
diff --git a/SConstruct b/SConstruct
new file mode 100644
index 0000000..2952dbc
--- /dev/null
+++ b/SConstruct
@@ -0,0 +1,33 @@
+import os
+
+env = Environment(
+ ENV = os.environ,
+)
+
+AddOption('--release', action = 'store_true')
+AddOption('--profiling', action = 'store_true')
+AddOption('--mingw32', action = 'store_true')
+
+env.Append(CPPPATH = ['.', 'common'])
+
+# cross-compiling
+if GetOption('mingw32'):
+ env.Append(LIBS = ['winmm', 'wsock32', 'ws2_32', 'mingw32', 'noise', 'boost_filesystem-mt-s', 'boost_system-mt-s', 'boost_thread_win32-mt-s'])
+ env.Append(LINKFLAGS = ['-static-libgcc', '-static-libstdc++'])
+ env.Append(CPPFLAGS = ['-D_WIN32_WINDOWS', '-DBOOST_THREAD_USE_LIB'])
+ env['CXX'] = 'i486-mingw32-g++'
+else:
+ env.Append(LIBS = ['noise', 'boost_filesystem', 'boost_thread'])
+
+if not GetOption('release'):
+ env.Append(CPPFLAGS = ['-Wall', '-g'])
+
+if GetOption('profiling'):
+ env.Append(CPPFLAGS = ['-pg'])
+ env.Append(LINKFLAGS = ['-pg'])
+
+Export('env')
+
+env.Program('gressd.exe' if GetOption('mingw32') else 'gressd', Glob('*.cpp') + Glob('common/*.cpp') + ['noiseutils/noiseutils.cpp'])
+
+# vim: syn=python
diff --git a/common b/common
new file mode 160000
+Subproject 1211f632092db824fb2c880063599f7642c34f3
diff --git a/connection.cpp b/connection.cpp
new file mode 100644
index 0000000..3b5076c
--- /dev/null
+++ b/connection.cpp
@@ -0,0 +1,59 @@
+#include "connection.h"
+#include "vector.h"
+
+using std::min;
+using std::max;
+
+Connection::Connection(boost::asio::io_service& io_service_) : io_service(io_service_), socket(io_service_) {
+}
+
+float Connection::distance(float px, float pz) {
+ bool in_width = px > pos.x && px < pos.x+1;
+ bool in_height = pz > pos.z && pz < pos.z+1;
+
+ if(in_width && in_height)
+ return 0;
+
+ Vector2 p(px, pz);
+
+ float a = (p - pos.xz()).length();
+ float b = (p - (pos.xz() + Vector2(1, 0))).length();
+ float c = (p - (pos.xz() + Vector2(0, 1))).length();
+ float d = (p - (pos.xz() + Vector2(1, 1))).length();
+
+ float dist = min(min(min(a, b), c), d);
+
+ if(in_width)
+ dist = min(dist, (float)min(abs(pos.z - pz), abs(pos.z+1 - pz)));
+ if(in_height)
+ dist = min(dist, (float)min(abs(pos.x - px), abs(pos.x+1 - px)));
+
+ return dist;
+}
+
+std::set<std::pair<int64_t, int64_t> > Connection::check_chunks() {
+ // TODO: make configurable
+ const int chunk_size = 32;
+ const int chunk_dist_threshold = chunk_size*4;
+
+ // list of chunks client should hold
+ std::set<std::pair<int64_t, int64_t> > new_chunks;
+ int i = pos.x - chunk_dist_threshold;
+ i -= i % chunk_size;
+ for(; i < pos.x + chunk_dist_threshold; i += chunk_size) {
+ int j = pos.z - chunk_dist_threshold;
+ j -= j % chunk_size;
+ for(; j < pos.z + chunk_dist_threshold; j += chunk_size) {
+ if(chunk_indices.find(std::pair<int64_t, int64_t>(i, j)) != chunk_indices.end())
+ continue;
+ float a = i - pos.x + chunk_size/2;
+ float b = j - pos.z + chunk_size/2;
+ if(sqrtf(a*a + b*b) < chunk_dist_threshold) {
+ chunk_indices.insert(std::pair<int64_t, int64_t>(i, j));
+ new_chunks.insert(std::pair<int64_t, int64_t>(i, j));
+ }
+ }
+ }
+
+ return new_chunks;
+}
diff --git a/connection.h b/connection.h
new file mode 100644
index 0000000..78603e4
--- /dev/null
+++ b/connection.h
@@ -0,0 +1,30 @@
+#ifndef CONNECTION_H
+#define CONNECTION_H
+
+#include "vector.h"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/asio.hpp>
+
+#include <set>
+
+class Connection {
+ private:
+ boost::asio::io_service& io_service;
+
+ public:
+ typedef boost::shared_ptr<Connection> p;
+
+ boost::asio::ip::tcp::socket socket;
+
+ Connection(boost::asio::io_service& io_service_);
+
+ float distance(float px, float pz);
+ std::set<std::pair<int64_t, int64_t> > check_chunks();
+
+ /* data */
+ Vector3 pos;
+ std::set<std::pair<int64_t, int64_t> > chunk_indices;
+};
+
+#endif
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..a7a1c34
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,28 @@
+#include "server.h"
+
+#include <boost/asio.hpp>
+#include <boost/thread.hpp>
+
+#ifdef WIN32
+/* hachish fix for mingw builds */
+namespace boost {
+ void tss_cleanup_implemented() { }
+}
+#endif
+
+int main(int argc, char **argv) {
+ boost::asio::io_service io_service;
+ Server server(io_service);
+
+ std::size_t num_threads = 1;
+ std::vector<boost::shared_ptr<boost::thread> > threads;
+ for(std::size_t i = 0; i < num_threads; i++) {
+ boost::shared_ptr<boost::thread> thread(new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service)));
+ threads.push_back(thread);
+ }
+ for(std::size_t i = 0; i < num_threads; i++) {
+ threads[i]->join();
+ }
+
+ return 0;
+}
diff --git a/noiseutils/COPYING.txt b/noiseutils/COPYING.txt
new file mode 100644
index 0000000..cbee875
--- /dev/null
+++ b/noiseutils/COPYING.txt
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/noiseutils/noiseutils.cpp b/noiseutils/noiseutils.cpp
new file mode 100644
index 0000000..ddcac1b
--- /dev/null
+++ b/noiseutils/noiseutils.cpp
@@ -0,0 +1,1298 @@
+// noiseutils.cpp
+//
+// Copyright (C) 2003-2005 Jason Bevins
+//
+// This library is free software; you can redistribute it and/or modify it
+// under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation; either version 2.1 of the License, or (at
+// your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+// License (COPYING.txt) for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// The developer's email is jlbezigvins@gmzigail.com (for great email, take
+// off every 'zig'.)
+//
+
+#include <fstream>
+
+#include <noise/interp.h>
+#include <noise/mathconsts.h>
+
+#include "noiseutils.h"
+
+using namespace noise;
+using namespace noise::model;
+using namespace noise::module;
+
+// Bitmap header size.
+const int BMP_HEADER_SIZE = 54;
+
+// Direction of the light source, in compass degrees (0 = north, 90 = east,
+// 180 = south, 270 = east)
+const double DEFAULT_LIGHT_AZIMUTH = 45.0;
+
+// Amount of contrast between light and dark areas.
+const double DEFAULT_LIGHT_CONTRAST = 1.0;
+
+// Elevation of the light source above the horizon, in degrees (0 = on
+// horizon, 90 = directly overhead)
+const double DEFAULT_LIGHT_ELEVATION = 45.0;
+
+//////////////////////////////////////////////////////////////////////////////
+// Miscellaneous functions
+
+namespace noise
+{
+
+ namespace utils
+ {
+
+ // Performs linear interpolation between two 8-bit channel values.
+ inline noise::uint8 BlendChannel (const uint8 channel0,
+ const uint8 channel1, float alpha)
+ {
+ float c0 = (float)channel0 / 255.0;
+ float c1 = (float)channel1 / 255.0;
+ return (noise::uint8)(((c1 * alpha) + (c0 * (1.0f - alpha))) * 255.0f);
+ }
+
+ // Performs linear interpolation between two colors and stores the result
+ // in out.
+ inline void LinearInterpColor (const Color& color0, const Color& color1,
+ float alpha, Color& out)
+ {
+ out.alpha = BlendChannel (color0.alpha, color1.alpha, alpha);
+ out.blue = BlendChannel (color0.blue , color1.blue , alpha);
+ out.green = BlendChannel (color0.green, color1.green, alpha);
+ out.red = BlendChannel (color0.red , color1.red , alpha);
+ }
+
+ // Unpacks a floating-point value into four bytes. This function is
+ // specific to Intel machines. A portable version will come soon (I
+ // hope.)
+ inline noise::uint8* UnpackFloat (noise::uint8* bytes, float value)
+ {
+ noise::uint8* pBytes = (noise::uint8*)(&value);
+ bytes[0] = *pBytes++;
+ bytes[1] = *pBytes++;
+ bytes[2] = *pBytes++;
+ bytes[3] = *pBytes++;
+ return bytes;
+ }
+
+ // Unpacks a 16-bit integer value into two bytes in little endian format.
+ inline noise::uint8* UnpackLittle16 (noise::uint8* bytes,
+ noise::uint16 integer)
+ {
+ bytes[0] = (noise::uint8)((integer & 0x00ff) );
+ bytes[1] = (noise::uint8)((integer & 0xff00) >> 8 );
+ return bytes;
+ }
+
+ // Unpacks a 32-bit integer value into four bytes in little endian format.
+ inline noise::uint8* UnpackLittle32 (noise::uint8* bytes,
+ noise::uint32 integer)
+ {
+ bytes[0] = (noise::uint8)((integer & 0x000000ff) );
+ bytes[1] = (noise::uint8)((integer & 0x0000ff00) >> 8 );
+ bytes[2] = (noise::uint8)((integer & 0x00ff0000) >> 16);
+ bytes[3] = (noise::uint8)((integer & 0xff000000) >> 24);
+ return bytes;
+ }
+
+ }
+
+}
+
+using namespace noise;
+
+using namespace noise::utils;
+
+//////////////////////////////////////////////////////////////////////////////
+// GradientColor class
+
+GradientColor::GradientColor ()
+{
+ m_pGradientPoints = NULL;
+}
+
+GradientColor::~GradientColor ()
+{
+ delete[] m_pGradientPoints;
+}
+
+void GradientColor::AddGradientPoint (double gradientPos,
+ const Color& gradientColor)
+{
+ // Find the insertion point for the new gradient point and insert the new
+ // gradient point at that insertion point. The gradient point array will
+ // remain sorted by gradient position.
+ int insertionPos = FindInsertionPos (gradientPos);
+ InsertAtPos (insertionPos, gradientPos, gradientColor);
+}
+
+void GradientColor::Clear ()
+{
+ delete[] m_pGradientPoints;
+ m_pGradientPoints = NULL;
+ m_gradientPointCount = 0;
+}
+
+int GradientColor::FindInsertionPos (double gradientPos)
+{
+ int insertionPos;
+ for (insertionPos = 0; insertionPos < m_gradientPointCount;
+ insertionPos++) {
+ if (gradientPos < m_pGradientPoints[insertionPos].pos) {
+ // We found the array index in which to insert the new gradient point.
+ // Exit now.
+ break;
+ } else if (gradientPos == m_pGradientPoints[insertionPos].pos) {
+ // Each gradient point is required to contain a unique gradient
+ // position, so throw an exception.
+ throw noise::ExceptionInvalidParam ();
+ }
+ }
+ return insertionPos;
+}
+
+const Color& GradientColor::GetColor (double gradientPos) const
+{
+ assert (m_gradientPointCount >= 2);
+
+ // Find the first element in the gradient point array that has a gradient
+ // position larger than the gradient position passed to this method.
+ int indexPos;
+ for (indexPos = 0; indexPos < m_gradientPointCount; indexPos++) {
+ if (gradientPos < m_pGradientPoints[indexPos].pos) {
+ break;
+ }
+ }
+
+ // Find the two nearest gradient points so that we can perform linear
+ // interpolation on the color.
+ int index0 = ClampValue (indexPos - 1, 0, m_gradientPointCount - 1);
+ int index1 = ClampValue (indexPos , 0, m_gradientPointCount - 1);
+
+ // If some gradient points are missing (which occurs if the gradient
+ // position passed to this method is greater than the largest gradient
+ // position or less than the smallest gradient position in the array), get
+ // the corresponding gradient color of the nearest gradient point and exit
+ // now.
+ if (index0 == index1) {
+ m_workingColor = m_pGradientPoints[index1].color;
+ return m_workingColor;
+ }
+
+ // Compute the alpha value used for linear interpolation.
+ double input0 = m_pGradientPoints[index0].pos;
+ double input1 = m_pGradientPoints[index1].pos;
+ double alpha = (gradientPos - input0) / (input1 - input0);
+
+ // Now perform the linear interpolation given the alpha value.
+ const Color& color0 = m_pGradientPoints[index0].color;
+ const Color& color1 = m_pGradientPoints[index1].color;
+ LinearInterpColor (color0, color1, (float)alpha, m_workingColor);
+ return m_workingColor;
+}
+
+void GradientColor::InsertAtPos (int insertionPos, double gradientPos,
+ const Color& gradientColor)
+{
+ // Make room for the new gradient point at the specified insertion position
+ // within the gradient point array. The insertion position is determined by
+ // the gradient point's position; the gradient points must be sorted by
+ // gradient position within that array.
+ GradientPoint* newGradientPoints;
+ newGradientPoints = new GradientPoint[m_gradientPointCount + 1];
+ for (int i = 0; i < m_gradientPointCount; i++) {
+ if (i < insertionPos) {
+ newGradientPoints[i] = m_pGradientPoints[i];
+ } else {
+ newGradientPoints[i + 1] = m_pGradientPoints[i];
+ }
+ }
+ delete[] m_pGradientPoints;
+ m_pGradientPoints = newGradientPoints;
+ ++m_gradientPointCount;
+
+ // Now that we've made room for the new gradient point within the array, add
+ // the new gradient point.
+ m_pGradientPoints[insertionPos].pos = gradientPos ;
+ m_pGradientPoints[insertionPos].color = gradientColor;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// NoiseMap class
+
+NoiseMap::NoiseMap ()
+{
+ InitObj ();
+}
+
+NoiseMap::NoiseMap (int width, int height)
+{
+ InitObj ();
+ SetSize (width, height);
+}
+
+NoiseMap::NoiseMap (const NoiseMap& rhs)
+{
+ InitObj ();
+ CopyNoiseMap (rhs);
+}
+
+NoiseMap::~NoiseMap ()
+{
+ delete[] m_pNoiseMap;
+}
+
+NoiseMap& NoiseMap::operator= (const NoiseMap& rhs)
+{
+ CopyNoiseMap (rhs);
+
+ return *this;
+}
+
+void NoiseMap::Clear (float value)
+{
+ if (m_pNoiseMap != NULL) {
+ for (int y = 0; y < m_height; y++) {
+ float* pDest = GetSlabPtr (0, y);
+ for (int x = 0; x < m_width; x++) {
+ *pDest++ = value;
+ }
+ }
+ }
+}
+
+void NoiseMap::CopyNoiseMap (const NoiseMap& source)
+{
+ // Resize the noise map buffer, then copy the slabs from the source noise
+ // map buffer to this noise map buffer.
+ SetSize (source.GetWidth (), source.GetHeight ());
+ for (int y = 0; y < source.GetHeight (); y++) {
+ const float* pSource = source.GetConstSlabPtr (0, y);
+ float* pDest = GetSlabPtr (0, y);
+ memcpy (pDest, pSource, (size_t)source.GetWidth () * sizeof (float));
+ }
+
+ // Copy the border value as well.
+ m_borderValue = source.m_borderValue;
+}
+
+void NoiseMap::DeleteNoiseMapAndReset ()
+{
+ delete[] m_pNoiseMap;
+ InitObj ();
+}
+
+float NoiseMap::GetValue (int x, int y) const
+{
+ if (m_pNoiseMap != NULL) {
+ if (x >= 0 && x < m_width && y >= 0 && y < m_height) {
+ return *(GetConstSlabPtr (x, y));
+ }
+ }
+ // The coordinates specified are outside the noise map. Return the border
+ // value.
+ return m_borderValue;
+}
+
+void NoiseMap::InitObj ()
+{
+ m_pNoiseMap = NULL;
+ m_height = 0;
+ m_width = 0;
+ m_stride = 0;
+ m_memUsed = 0;
+ m_borderValue = 0.0;
+}
+
+void NoiseMap::ReclaimMem ()
+{
+ size_t newMemUsage = CalcMinMemUsage (m_width, m_height);
+ if (m_memUsed > newMemUsage) {
+ // There is wasted memory. Create the smallest buffer that can fit the
+ // data and copy the data to it.
+ float* pNewNoiseMap = NULL;
+ try {
+ pNewNoiseMap = new float[newMemUsage];
+ }
+ catch (...) {
+ throw noise::ExceptionOutOfMemory ();
+ }
+ memcpy (pNewNoiseMap, m_pNoiseMap, newMemUsage * sizeof (float));
+ delete[] m_pNoiseMap;
+ m_pNoiseMap = pNewNoiseMap;
+ m_memUsed = newMemUsage;
+ }
+}
+
+void NoiseMap::SetSize (int width, int height)
+{
+ if (width < 0 || height < 0
+ || width > RASTER_MAX_WIDTH || height > RASTER_MAX_HEIGHT) {
+ // Invalid width or height.
+ throw noise::ExceptionInvalidParam ();
+ } else if (width == 0 || height == 0) {
+ // An empty noise map was specified. Delete it and zero out the size
+ // member variables.
+ DeleteNoiseMapAndReset ();
+ } else {
+ // A new noise map size was specified. Allocate a new noise map buffer
+ // unless the current buffer is large enough for the new noise map (we
+ // don't want costly reallocations going on.)
+ size_t newMemUsage = CalcMinMemUsage (width, height);
+ if (m_memUsed < newMemUsage) {
+ // The new size is too big for the current noise map buffer. We need to
+ // reallocate.
+ DeleteNoiseMapAndReset ();
+ try {
+ m_pNoiseMap = new float[newMemUsage];
+ }
+ catch (...) {
+ throw noise::ExceptionOutOfMemory ();
+ }
+ m_memUsed = newMemUsage;
+ }
+ m_stride = (int)CalcStride (width);
+ m_width = width;
+ m_height = height;
+ }
+}
+
+void NoiseMap::SetValue (int x, int y, float value)
+{
+ if (m_pNoiseMap != NULL) {
+ if (x >= 0 && x < m_width && y >= 0 && y < m_height) {
+ *(GetSlabPtr (x, y)) = value;
+ }
+ }
+}
+
+void NoiseMap::TakeOwnership (NoiseMap& source)
+{
+ // Copy the values and the noise map buffer from the source noise map to
+ // this noise map. Now this noise map pwnz the source buffer.
+ delete[] m_pNoiseMap;
+ m_memUsed = source.m_memUsed;
+ m_height = source.m_height;
+ m_pNoiseMap = source.m_pNoiseMap;
+ m_stride = source.m_stride;
+ m_width = source.m_width;
+
+ // Now that the source buffer is assigned to this noise map, reset the
+ // source noise map object.
+ source.InitObj ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Image class
+
+Image::Image ()
+{
+ InitObj ();
+}
+
+Image::Image (int width, int height)
+{
+ InitObj ();
+ SetSize (width, height);
+}
+
+Image::Image (const Image& rhs)
+{
+ InitObj ();
+ CopyImage (rhs);
+}
+
+Image::~Image ()
+{
+ delete[] m_pImage;
+}
+
+Image& Image::operator= (const Image& rhs)
+{
+ CopyImage (rhs);
+
+ return *this;
+}
+
+void Image::Clear (const Color& value)
+{
+ if (m_pImage != NULL) {
+ for (int y = 0; y < m_height; y++) {
+ Color* pDest = GetSlabPtr (0, y);
+ for (int x = 0; x < m_width; x++) {
+ *pDest++ = value;
+ }
+ }
+ }
+}
+
+void Image::CopyImage (const Image& source)
+{
+ // Resize the image buffer, then copy the slabs from the source image
+ // buffer to this image buffer.
+ SetSize (source.GetWidth (), source.GetHeight ());
+ for (int y = 0; y < source.GetHeight (); y++) {
+ const Color* pSource = source.GetConstSlabPtr (0, y);
+ Color* pDest = GetSlabPtr (0, y);
+ memcpy (pDest, pSource, (size_t)source.GetWidth () * sizeof (float));
+ }
+
+ // Copy the border value as well.
+ m_borderValue = source.m_borderValue;
+}
+
+void Image::DeleteImageAndReset ()
+{
+ delete[] m_pImage;
+ InitObj ();
+}
+
+Color Image::GetValue (int x, int y) const
+{
+ if (m_pImage != NULL) {
+ if (x >= 0 && x < m_width && y >= 0 && y < m_height) {
+ return *(GetConstSlabPtr (x, y));
+ }
+ }
+ // The coordinates specified are outside the image. Return the border
+ // value.
+ return m_borderValue;
+}
+
+void Image::InitObj ()
+{
+ m_pImage = NULL;
+ m_height = 0;
+ m_width = 0;
+ m_stride = 0;
+ m_memUsed = 0;
+ m_borderValue = Color (0, 0, 0, 0);
+}
+
+void Image::ReclaimMem ()
+{
+ size_t newMemUsage = CalcMinMemUsage (m_width, m_height);
+ if (m_memUsed > newMemUsage) {
+ // There is wasted memory. Create the smallest buffer that can fit the
+ // data and copy the data to it.
+ Color* pNewImage = NULL;
+ try {
+ pNewImage = new Color[newMemUsage];
+ }
+ catch (...) {
+ throw noise::ExceptionOutOfMemory ();
+ }
+ memcpy (pNewImage, m_pImage, newMemUsage * sizeof (float));
+ delete[] m_pImage;
+ m_pImage = pNewImage;
+ m_memUsed = newMemUsage;
+ }
+}
+
+void Image::SetSize (int width, int height)
+{
+ if (width < 0 || height < 0
+ || width > RASTER_MAX_WIDTH || height > RASTER_MAX_HEIGHT) {
+ // Invalid width or height.
+ throw noise::ExceptionInvalidParam ();
+ } else if (width == 0 || height == 0) {
+ // An empty image was specified. Delete it and zero out the size member
+ // variables.
+ DeleteImageAndReset ();
+ } else {
+ // A new image size was specified. Allocate a new image buffer unless
+ // the current buffer is large enough for the new image (we don't want
+ // costly reallocations going on.)
+ size_t newMemUsage = CalcMinMemUsage (width, height);
+ if (m_memUsed < newMemUsage) {
+ // The new size is too big for the current image buffer. We need to
+ // reallocate.
+ DeleteImageAndReset ();
+ try {
+ m_pImage = new Color[newMemUsage];
+ }
+ catch (...) {
+ throw noise::ExceptionOutOfMemory ();
+ }
+ m_memUsed = newMemUsage;
+ }
+ m_stride = (int)CalcStride (width);
+ m_width = width;
+ m_height = height;
+ }
+}
+
+void Image::SetValue (int x, int y, const Color& value)
+{
+ if (m_pImage != NULL) {
+ if (x >= 0 && x < m_width && y >= 0 && y < m_height) {
+ *(GetSlabPtr (x, y)) = value;
+ }
+ }
+}
+
+void Image::TakeOwnership (Image& source)
+{
+ // Copy the values and the image buffer from the source image to this image.
+ // Now this image pwnz the source buffer.
+ delete[] m_pImage;
+ m_memUsed = source.m_memUsed;
+ m_height = source.m_height;
+ m_pImage = source.m_pImage;
+ m_stride = source.m_stride;
+ m_width = source.m_width;
+
+ // Now that the source buffer is assigned to this image, reset the source
+ // image object.
+ source.InitObj ();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// WriterBMP class
+
+int WriterBMP::CalcWidthByteCount (int width) const
+{
+ return ((width * 3) + 3) & ~0x03;
+}
+
+void WriterBMP::WriteDestFile ()
+{
+ if (m_pSourceImage == NULL) {
+ throw noise::ExceptionInvalidParam ();
+ }
+
+ int width = m_pSourceImage->GetWidth ();
+ int height = m_pSourceImage->GetHeight ();
+
+ // The width of one line in the file must be aligned on a 4-byte boundary.
+ int bufferSize = CalcWidthByteCount (width);
+ int destSize = bufferSize * height;
+
+ // This buffer holds one horizontal line in the destination file.
+ noise::uint8* pLineBuffer = NULL;
+
+ // File object used to write the file.
+ std::ofstream os;
+ os.clear ();
+
+ // Allocate a buffer to hold one horizontal line in the bitmap.
+ try {
+ pLineBuffer = new noise::uint8[bufferSize];
+ }
+ catch (...) {
+ throw noise::ExceptionOutOfMemory ();
+ }
+
+ // Open the destination file.
+ os.open (m_destFilename.c_str (), std::ios::out | std::ios::binary);
+ if (os.fail () || os.bad ()) {
+ delete[] pLineBuffer;
+ throw noise::ExceptionUnknown ();
+ }
+
+ // Build the header.
+ noise::uint8 d[4];
+ os.write ("BM", 2);
+ os.write ((char*)UnpackLittle32 (d, destSize + BMP_HEADER_SIZE), 4);
+ os.write ("\0\0\0\0", 4);
+ os.write ((char*)UnpackLittle32 (d, (noise::uint32)BMP_HEADER_SIZE), 4);
+ os.write ((char*)UnpackLittle32 (d, 40), 4); // Palette offset
+ os.write ((char*)UnpackLittle32 (d, (noise::uint32)width ), 4);
+ os.write ((char*)UnpackLittle32 (d, (noise::uint32)height), 4);
+ os.write ((char*)UnpackLittle16 (d, 1 ), 2); // Planes per pixel
+ os.write ((char*)UnpackLittle16 (d, 24), 2); // Bits per plane
+ os.write ("\0\0\0\0", 4); // Compression (0 = none)
+ os.write ((char*)UnpackLittle32 (d, (noise::uint32)destSize), 4);
+ os.write ((char*)UnpackLittle32 (d, 2834), 4); // X pixels per meter
+ os.write ((char*)UnpackLittle32 (d, 2834), 4); // Y pixels per meter
+ os.write ("\0\0\0\0", 4);
+ os.write ("\0\0\0\0", 4);
+ if (os.fail () || os.bad ()) {
+ os.clear ();
+ os.close ();
+ os.clear ();
+ delete[] pLineBuffer;
+ throw noise::ExceptionUnknown ();
+ }
+
+ // Build and write each horizontal line to the file.
+ for (int y = 0; y < height; y++) {
+ memset (pLineBuffer, 0, bufferSize);
+ Color* pSource = m_pSourceImage->GetSlabPtr (y);
+ noise::uint8* pDest = pLineBuffer;
+ for (int x = 0; x < width; x++) {
+ *pDest++ = pSource->blue ;
+ *pDest++ = pSource->green;
+ *pDest++ = pSource->red ;
+ ++pSource;
+ }
+ os.write ((char*)pLineBuffer, (size_t)bufferSize);
+ if (os.fail () || os.bad ()) {
+ os.clear ();
+ os.close ();
+ os.clear ();
+ delete[] pLineBuffer;
+ throw noise::ExceptionUnknown ();
+ }
+ }
+
+ os.close ();
+ os.clear ();
+ delete[] pLineBuffer;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// WriterTER class
+
+int WriterTER::CalcWidthByteCount (int width) const
+{
+ return (width * sizeof (int16));
+}
+
+void WriterTER::WriteDestFile ()
+{
+ if (m_pSourceNoiseMap == NULL) {
+ throw noise::ExceptionInvalidParam ();
+ }
+
+ int width = m_pSourceNoiseMap->GetWidth ();
+ int height = m_pSourceNoiseMap->GetHeight ();
+
+ int bufferSize = CalcWidthByteCount (width);
+
+ // This buffer holds one horizontal line in the destination file.
+ noise::uint8* pLineBuffer = NULL;
+
+ // File object used to write the file.
+ std::ofstream os;
+ os.clear ();
+
+ // Allocate a buffer to hold one horizontal line in the height map.
+ try {
+ pLineBuffer = new noise::uint8[bufferSize];
+ }
+ catch (...) {
+ throw noise::ExceptionOutOfMemory ();
+ }
+
+ // Open the destination file.
+ os.open (m_destFilename.c_str (), std::ios::out | std::ios::binary);
+ if (os.fail () || os.bad ()) {
+ os.clear ();
+ delete[] pLineBuffer;
+ throw noise::ExceptionUnknown ();
+ }
+
+ // Build the header.
+ noise::uint8 d[4];
+ int16 heightScale = (int16)(floor (32768.0 / (double)m_metersPerPoint));
+ os.write ("TERRAGENTERRAIN ", 16);
+ os.write ("SIZE", 4);
+ os.write ((char*)UnpackLittle16 (d, GetMin (width, height) - 1), 2);
+ os.write ("\0\0", 2);
+ os.write ("XPTS", 4);
+ os.write ((char*)UnpackLittle16 (d, width), 2);
+ os.write ("\0\0", 2);
+ os.write ("YPTS", 4);
+ os.write ((char*)UnpackLittle16 (d, height), 2);
+ os.write ("\0\0", 2);
+ os.write ("SCAL", 4);
+ os.write ((char*)UnpackFloat (d, m_metersPerPoint), 4);
+ os.write ((char*)UnpackFloat (d, m_metersPerPoint), 4);
+ os.write ((char*)UnpackFloat (d, m_metersPerPoint), 4);
+ os.write ("ALTW", 4);
+ os.write ((char*)UnpackLittle16 (d, heightScale), 2);
+ os.write ("\0\0", 2);
+ if (os.fail () || os.bad ()) {
+ os.clear ();
+ os.close ();
+ os.clear ();
+ delete[] pLineBuffer;
+ throw noise::ExceptionUnknown ();
+ }
+
+ // Build and write each horizontal line to the file.
+ for (int y = 0; y < height; y++) {
+ float* pSource = m_pSourceNoiseMap->GetSlabPtr (y);
+ noise::uint8* pDest = pLineBuffer;
+ for (int x = 0; x < width; x++) {
+ int16 scaledHeight = (int16)(floor (*pSource * 2.0));
+ UnpackLittle16 (pDest, scaledHeight);
+ pDest += 2;
+ ++pSource;
+ }
+ os.write ((char*)pLineBuffer, (size_t)bufferSize);
+ if (os.fail () || os.bad ()) {
+ os.clear ();
+ os.close ();
+ os.clear ();
+ delete[] pLineBuffer;
+ throw noise::ExceptionUnknown ();
+ }
+ }
+
+ os.close ();
+ os.clear ();
+ delete[] pLineBuffer;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// NoiseMapBuilder class
+
+NoiseMapBuilder::NoiseMapBuilder ():
+ m_pCallback (NULL),
+ m_destHeight (0),
+ m_destWidth (0),
+ m_pDestNoiseMap (NULL),
+ m_pSourceModule (NULL)
+{
+}
+
+void NoiseMapBuilder::SetCallback (NoiseMapCallback pCallback)
+{
+ m_pCallback = pCallback;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// NoiseMapBuilderCylinder class
+
+NoiseMapBuilderCylinder::NoiseMapBuilderCylinder ():
+ m_lowerAngleBound (0.0),
+ m_lowerHeightBound (0.0),
+ m_upperAngleBound (0.0),
+ m_upperHeightBound (0.0)
+{
+}
+
+void NoiseMapBuilderCylinder::Build ()
+{
+ if ( m_upperAngleBound <= m_lowerAngleBound
+ || m_upperHeightBound <= m_lowerHeightBound
+ || m_destWidth <= 0
+ || m_destHeight <= 0
+ || m_pSourceModule == NULL
+ || m_pDestNoiseMap == NULL) {
+ throw noise::ExceptionInvalidParam ();
+ }
+
+ // Resize the destination noise map so that it can store the new output
+ // values from the source model.
+ m_pDestNoiseMap->SetSize (m_destWidth, m_destHeight);
+
+ // Create the cylinder model.
+ model::Cylinder cylinderModel;
+ cylinderModel.SetModule (*m_pSourceModule);
+
+ double angleExtent = m_upperAngleBound - m_lowerAngleBound ;
+ double heightExtent = m_upperHeightBound - m_lowerHeightBound;
+ double xDelta = angleExtent / (double)m_destWidth ;
+ double yDelta = heightExtent / (double)m_destHeight;
+ double curAngle = m_lowerAngleBound ;
+ double curHeight = m_lowerHeightBound;
+
+ // Fill every point in the noise map with the output values from the model.
+ for (int y = 0; y < m_destHeight; y++) {
+ float* pDest = m_pDestNoiseMap->GetSlabPtr (y);
+ curAngle = m_lowerAngleBound;
+ for (int x = 0; x < m_destWidth; x++) {
+ float curValue = (float)cylinderModel.GetValue (curAngle, curHeight);
+ *pDest++ = curValue;
+ curAngle += xDelta;
+ }
+ curHeight += yDelta;
+ if (m_pCallback != NULL) {
+ m_pCallback (y);
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// NoiseMapBuilderPlane class
+
+NoiseMapBuilderPlane::NoiseMapBuilderPlane ():
+ m_isSeamlessEnabled (false),
+ m_lowerXBound (0.0),
+ m_lowerZBound (0.0),
+ m_upperXBound (0.0),
+ m_upperZBound (0.0)
+{
+}
+
+void NoiseMapBuilderPlane::Build ()
+{
+ if ( m_upperXBound <= m_lowerXBound
+ || m_upperZBound <= m_lowerZBound
+ || m_destWidth <= 0
+ || m_destHeight <= 0
+ || m_pSourceModule == NULL
+ || m_pDestNoiseMap == NULL) {
+ throw noise::ExceptionInvalidParam ();
+ }
+
+ // Resize the destination noise map so that it can store the new output
+ // values from the source model.
+ m_pDestNoiseMap->SetSize (m_destWidth, m_destHeight);
+
+ // Create the plane model.
+ model::Plane planeModel;
+ planeModel.SetModule (*m_pSourceModule);
+
+ double xExtent = m_upperXBound - m_lowerXBound;
+ double zExtent = m_upperZBound - m_lowerZBound;
+ double xDelta = xExtent / (double)m_destWidth ;
+ double zDelta = zExtent / (double)m_destHeight;
+ double xCur = m_lowerXBound;
+ double zCur = m_lowerZBound;
+
+ // Fill every point in the noise map with the output values from the model.
+ for (int z = 0; z < m_destHeight; z++) {
+ float* pDest = m_pDestNoiseMap->GetSlabPtr (z);
+ xCur = m_lowerXBound;
+ for (int x = 0; x < m_destWidth; x++) {
+ float finalValue;
+ if (!m_isSeamlessEnabled) {
+ finalValue = planeModel.GetValue (xCur, zCur);
+ } else {
+ double swValue, seValue, nwValue, neValue;
+ swValue = planeModel.GetValue (xCur , zCur );
+ seValue = planeModel.GetValue (xCur + xExtent, zCur );
+ nwValue = planeModel.GetValue (xCur , zCur + zExtent);
+ neValue = planeModel.GetValue (xCur + xExtent, zCur + zExtent);
+ double xBlend = 1.0 - ((xCur - m_lowerXBound) / xExtent);
+ double zBlend = 1.0 - ((zCur - m_lowerZBound) / zExtent);
+ double z0 = LinearInterp (swValue, seValue, xBlend);
+ double z1 = LinearInterp (nwValue, neValue, xBlend);
+ finalValue = (float)LinearInterp (z0, z1, zBlend);
+ }
+ *pDest++ = finalValue;
+ xCur += xDelta;
+ }
+ zCur += zDelta;
+ if (m_pCallback != NULL) {
+ m_pCallback (z);
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// NoiseMapBuilderSphere class
+
+NoiseMapBuilderSphere::NoiseMapBuilderSphere ():
+ m_eastLonBound (0.0),
+ m_northLatBound (0.0),
+ m_southLatBound (0.0),
+ m_westLonBound (0.0)
+{
+}
+
+void NoiseMapBuilderSphere::Build ()
+{
+ if ( m_eastLonBound <= m_westLonBound
+ || m_northLatBound <= m_southLatBound
+ || m_destWidth <= 0
+ || m_destHeight <= 0
+ || m_pSourceModule == NULL
+ || m_pDestNoiseMap == NULL) {
+ throw noise::ExceptionInvalidParam ();
+ }
+
+ // Resize the destination noise map so that it can store the new output
+ // values from the source model.
+ m_pDestNoiseMap->SetSize (m_destWidth, m_destHeight);
+
+ // Create the plane model.
+ model::Sphere sphereModel;
+ sphereModel.SetModule (*m_pSourceModule);
+
+ double lonExtent = m_eastLonBound - m_westLonBound ;
+ double latExtent = m_northLatBound - m_southLatBound;
+ double xDelta = lonExtent / (double)m_destWidth ;
+ double yDelta = latExtent / (double)m_destHeight;
+ double curLon = m_westLonBound ;
+ double curLat = m_southLatBound;
+
+ // Fill every point in the noise map with the output values from the model.
+ for (int y = 0; y < m_destHeight; y++) {
+ float* pDest = m_pDestNoiseMap->GetSlabPtr (y);
+ curLon = m_westLonBound;
+ for (int x = 0; x < m_destWidth; x++) {
+ float curValue = (float)sphereModel.GetValue (curLat, curLon);
+ *pDest++ = curValue;
+ curLon += xDelta;
+ }
+ curLat += yDelta;
+ if (m_pCallback != NULL) {
+ m_pCallback (y);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// RendererImage class
+
+RendererImage::RendererImage ():
+ m_isLightEnabled (false),
+ m_isWrapEnabled (false),
+ m_lightAzimuth (45.0),
+ m_lightBrightness (1.0),
+ m_lightColor (255, 255, 255, 255),
+ m_lightContrast (1.0),
+ m_lightElev (45.0),
+ m_lightIntensity (1.0),
+ m_pBackgroundImage (NULL),
+ m_pDestImage (NULL),
+ m_pSourceNoiseMap (NULL),
+ m_recalcLightValues (true)
+{
+ BuildGrayscaleGradient ();
+};
+
+void RendererImage::AddGradientPoint (double gradientPos,
+ const Color& gradientColor)
+{
+ m_gradient.AddGradientPoint (gradientPos, gradientColor);
+}
+
+void RendererImage::BuildGrayscaleGradient ()
+{
+ ClearGradient ();
+ m_gradient.AddGradientPoint (-1.0, Color ( 0, 0, 0, 255));
+ m_gradient.AddGradientPoint ( 1.0, Color (255, 255, 255, 255));
+}
+
+void RendererImage::BuildTerrainGradient ()
+{
+ ClearGradient ();
+ m_gradient.AddGradientPoint (-1.00, Color ( 0, 0, 128, 255));
+ m_gradient.AddGradientPoint (-0.20, Color ( 32, 64, 128, 255));
+ m_gradient.AddGradientPoint (-0.04, Color ( 64, 96, 192, 255));
+ m_gradient.AddGradientPoint (-0.02, Color (192, 192, 128, 255));
+ m_gradient.AddGradientPoint ( 0.00, Color ( 0, 192, 0, 255));
+ m_gradient.AddGradientPoint ( 0.25, Color (192, 192, 0, 255));
+ m_gradient.AddGradientPoint ( 0.50, Color (160, 96, 64, 255));
+ m_gradient.AddGradientPoint ( 0.75, Color (128, 255, 255, 255));
+ m_gradient.AddGradientPoint ( 1.00, Color (255, 255, 255, 255));
+}
+
+Color RendererImage::CalcDestColor (const Color& sourceColor,
+ const Color& backgroundColor, double lightValue) const
+{
+ double sourceRed = (double)sourceColor.red / 255.0;
+ double sourceGreen = (double)sourceColor.green / 255.0;
+ double sourceBlue = (double)sourceColor.blue / 255.0;
+ double sourceAlpha = (double)sourceColor.alpha / 255.0;
+ double backgroundRed = (double)backgroundColor.red / 255.0;
+ double backgroundGreen = (double)backgroundColor.green / 255.0;
+ double backgroundBlue = (double)backgroundColor.blue / 255.0;
+
+ // First, blend the source color to the background color using the alpha
+ // of the source color.
+ double red = LinearInterp (backgroundRed, sourceRed , sourceAlpha);
+ double green = LinearInterp (backgroundGreen, sourceGreen, sourceAlpha);
+ double blue = LinearInterp (backgroundBlue, sourceBlue , sourceAlpha);
+
+ if (m_isLightEnabled) {
+
+ // Now calculate the light color.
+ double lightRed = lightValue * (double)m_lightColor.red / 255.0;
+ double lightGreen = lightValue * (double)m_lightColor.green / 255.0;
+ double lightBlue = lightValue * (double)m_lightColor.blue / 255.0;
+
+ // Apply the light color to the new color.
+ red *= lightRed ;
+ green *= lightGreen;
+ blue *= lightBlue ;
+ }
+
+ // Clamp the color channels to the (0..1) range.
+ red = (red < 0.0)? 0.0: red ;
+ red = (red > 1.0)? 1.0: red ;
+ green = (green < 0.0)? 0.0: green;
+ green = (green > 1.0)? 1.0: green;
+ blue = (blue < 0.0)? 0.0: blue ;
+ blue = (blue > 1.0)? 1.0: blue ;
+
+ // Rescale the color channels to the noise::uint8 (0..255) range and return
+ // the new color.
+ Color newColor (
+ (noise::uint8)((noise::uint)(red * 255.0) & 0xff),
+ (noise::uint8)((noise::uint)(green * 255.0) & 0xff),
+ (noise::uint8)((noise::uint)(blue * 255.0) & 0xff),
+ GetMax (sourceColor.alpha, backgroundColor.alpha));
+ return newColor;
+}
+
+double RendererImage::CalcLightIntensity (double center, double left,
+ double right, double down, double up) const
+{
+ // Recalculate the sine and cosine of the various light values if
+ // necessary so it does not have to be calculated each time this method is
+ // called.
+ if (m_recalcLightValues) {
+ m_cosAzimuth = cos (m_lightAzimuth * DEG_TO_RAD);
+ m_sinAzimuth = sin (m_lightAzimuth * DEG_TO_RAD);
+ m_cosElev = cos (m_lightElev * DEG_TO_RAD);
+ m_sinElev = sin (m_lightElev * DEG_TO_RAD);
+ m_recalcLightValues = false;
+ }
+
+ // Now do the lighting calculations.
+ const double I_MAX = 1.0;
+ double io = I_MAX * SQRT_2 * m_sinElev / 2.0;
+ double ix = (I_MAX - io) * m_lightContrast * SQRT_2 * m_cosElev
+ * m_cosAzimuth;
+ double iy = (I_MAX - io) * m_lightContrast * SQRT_2 * m_cosElev
+ * m_sinAzimuth;
+ double intensity = (ix * (left - right) + iy * (down - up) + io);
+ if (intensity < 0.0) {
+ intensity = 0.0;
+ }
+ return intensity;
+}
+
+void RendererImage::ClearGradient ()
+{
+ m_gradient.Clear ();
+}
+
+void RendererImage::Render ()
+{
+ if ( m_pSourceNoiseMap == NULL
+ || m_pDestImage == NULL
+ || m_pSourceNoiseMap->GetWidth () <= 0
+ || m_pSourceNoiseMap->GetHeight () <= 0
+ || m_gradient.GetGradientPointCount () < 2) {
+ throw noise::ExceptionInvalidParam ();
+ }
+
+ int width = m_pSourceNoiseMap->GetWidth ();
+ int height = m_pSourceNoiseMap->GetHeight ();
+
+ // If a background image was provided, make sure it is the same size the
+ // source noise map.
+ if (m_pBackgroundImage != NULL) {
+ if ( m_pBackgroundImage->GetWidth () != width
+ || m_pBackgroundImage->GetHeight () != height) {
+ throw noise::ExceptionInvalidParam ();
+ }
+ }
+
+ // Create the destination image. It is safe to reuse it if this is also the
+ // background image.
+ if (m_pDestImage != m_pBackgroundImage) {
+ m_pDestImage->SetSize (width, height);
+ }
+
+ for (int y = 0; y < height; y++) {
+ const Color* pBackground = NULL;
+ if (m_pBackgroundImage != NULL) {
+ pBackground = m_pBackgroundImage->GetConstSlabPtr (y);
+ }
+ const float* pSource = m_pSourceNoiseMap->GetConstSlabPtr (y);
+ Color* pDest = m_pDestImage->GetSlabPtr (y);
+ for (int x = 0; x < width; x++) {
+
+ // Get the color based on the value at the current point in the noise
+ // map.
+ Color destColor = m_gradient.GetColor (*pSource);
+
+ // If lighting is enabled, calculate the light intensity based on the
+ // rate of change at the current point in the noise map.
+ double lightIntensity;
+ if (m_isLightEnabled) {
+
+ // Calculate the positions of the current point's four-neighbors.
+ int xLeftOffset, xRightOffset;
+ int yUpOffset , yDownOffset ;
+ if (m_isWrapEnabled) {
+ if (x == 0) {
+ xLeftOffset = (int)width - 1;
+ xRightOffset = 1;
+ } else if (x == (int)width - 1) {
+ xLeftOffset = -1;
+ xRightOffset = -((int)width - 1);
+ } else {
+ xLeftOffset = -1;
+ xRightOffset = 1;
+ }
+ if (y == 0) {
+ yDownOffset = (int)height - 1;
+ yUpOffset = 1;
+ } else if (y == (int)height - 1) {
+ yDownOffset = -1;
+ yUpOffset = -((int)height - 1);
+ } else {
+ yDownOffset = -1;
+ yUpOffset = 1;
+ }
+ } else {
+ if (x == 0) {
+ xLeftOffset = 0;
+ xRightOffset = 1;
+ } else if (x == (int)width - 1) {
+ xLeftOffset = -1;
+ xRightOffset = 0;
+ } else {
+ xLeftOffset = -1;
+ xRightOffset = 1;
+ }
+ if (y == 0) {
+ yDownOffset = 0;
+ yUpOffset = 1;
+ } else if (y == (int)height - 1) {
+ yDownOffset = -1;
+ yUpOffset = 0;
+ } else {
+ yDownOffset = -1;
+ yUpOffset = 1;
+ }
+ }
+ yDownOffset *= m_pSourceNoiseMap->GetStride ();
+ yUpOffset *= m_pSourceNoiseMap->GetStride ();
+
+ // Get the noise value of the current point in the source noise map
+ // and the noise values of its four-neighbors.
+ double nc = (double)(*pSource);
+ double nl = (double)(*(pSource + xLeftOffset ));
+ double nr = (double)(*(pSource + xRightOffset));
+ double nd = (double)(*(pSource + yDownOffset ));
+ double nu = (double)(*(pSource + yUpOffset ));
+
+ // Now we can calculate the lighting intensity.
+ lightIntensity = CalcLightIntensity (nc, nl, nr, nd, nu);
+ lightIntensity *= m_lightBrightness;
+
+ } else {
+
+ // These values will apply no lighting to the destination image.
+ lightIntensity = 1.0;
+ }
+
+ // Get the current background color from the background image.
+ Color backgroundColor (255, 255, 255, 255);
+ if (m_pBackgroundImage != NULL) {
+ backgroundColor = *pBackground;
+ }
+
+ // Blend the destination color, background color, and the light
+ // intensity together, then update the destination image with that
+ // color.
+ *pDest = CalcDestColor (destColor, backgroundColor, lightIntensity);
+
+ // Go to the next point.
+ ++pSource;
+ ++pDest;
+ if (m_pBackgroundImage != NULL) {
+ ++pBackground;
+ }
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// RendererNormalMap class
+
+RendererNormalMap::RendererNormalMap ():
+ m_bumpHeight (1.0),
+ m_isWrapEnabled (false),
+ m_pDestImage (NULL),
+ m_pSourceNoiseMap (NULL)
+{
+};
+
+Color RendererNormalMap::CalcNormalColor (double nc, double nr, double nu,
+ double bumpHeight) const
+{
+ // Calculate the surface normal.
+ nc *= bumpHeight;
+ nr *= bumpHeight;
+ nu *= bumpHeight;
+ double ncr = (nc - nr);
+ double ncu = (nc - nu);
+ double d = sqrt ((ncu * ncu) + (ncr * ncr) + 1);
+ double vxc = (nc - nr) / d;
+ double vyc = (nc - nu) / d;
+ double vzc = 1.0 / d;
+
+ // Map the normal range from the (-1.0 .. +1.0) range to the (0 .. 255)
+ // range.
+ noise::uint8 xc, yc, zc;
+ xc = (noise::uint8)((noise::uint)((floor)((vxc + 1.0) * 127.5)) & 0xff);
+ yc = (noise::uint8)((noise::uint)((floor)((vyc + 1.0) * 127.5)) & 0xff);
+ zc = (noise::uint8)((noise::uint)((floor)((vzc + 1.0) * 127.5)) & 0xff);
+
+ return Color (xc, yc, zc, 0);
+}
+
+void RendererNormalMap::Render ()
+{
+ if ( m_pSourceNoiseMap == NULL
+ || m_pDestImage == NULL
+ || m_pSourceNoiseMap->GetWidth () <= 0
+ || m_pSourceNoiseMap->GetHeight () <= 0) {
+ throw noise::ExceptionInvalidParam ();
+ }
+
+ int width = m_pSourceNoiseMap->GetWidth ();
+ int height = m_pSourceNoiseMap->GetHeight ();
+
+ for (int y = 0; y < height; y++) {
+ const float* pSource = m_pSourceNoiseMap->GetConstSlabPtr (y);
+ Color* pDest = m_pDestImage->GetSlabPtr (y);
+ for (int x = 0; x < width; x++) {
+
+ // Calculate the positions of the current point's right and up
+ // neighbors.
+ int xRightOffset, yUpOffset;
+ if (m_isWrapEnabled) {
+ if (x == (int)width - 1) {
+ xRightOffset = -((int)width - 1);
+ } else {
+ xRightOffset = 1;
+ }
+ if (y == (int)height - 1) {
+ yUpOffset = -((int)height - 1);
+ } else {
+ yUpOffset = 1;
+ }
+ } else {
+ if (x == (int)width - 1) {
+ xRightOffset = 0;
+ } else {
+ xRightOffset = 1;
+ }
+ if (y == (int)height - 1) {
+ yUpOffset = 0;
+ } else {
+ yUpOffset = 1;
+ }
+ }
+ yUpOffset *= m_pSourceNoiseMap->GetStride ();
+
+ // Get the noise value of the current point in the source noise map
+ // and the noise values of its right and up neighbors.
+ double nc = (double)(*pSource);
+ double nr = (double)(*(pSource + xRightOffset));
+ double nu = (double)(*(pSource + yUpOffset ));
+
+ // Calculate the normal product.
+ *pDest = CalcNormalColor (nc, nr, nu, m_bumpHeight);
+
+ // Go to the next point.
+ ++pSource;
+ ++pDest;
+ }
+ }
+}
diff --git a/noiseutils/noiseutils.h b/noiseutils/noiseutils.h
new file mode 100644
index 0000000..d54f61d
--- /dev/null
+++ b/noiseutils/noiseutils.h
@@ -0,0 +1,2540 @@
+// noiseutils.h
+//
+// Copyright (C) 2003-2005 Jason Bevins
+//
+// This library is free software; you can redistribute it and/or modify it
+// under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation; either version 2.1 of the License, or (at
+// your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+// License (COPYING.txt) for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// The developer's email is jlbezigvins@gmzigail.com (for great email, take
+// off every 'zig'.)
+//
+
+#ifndef NOISEUTILS_H
+#define NOISEUTILS_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+
+#include <noise/noise.h>
+
+using namespace noise;
+
+namespace noise
+{
+
+ namespace utils
+ {
+
+ /// @mainpage noiseutils
+ ///
+ /// @section intro Introduction
+ ///
+ /// This library contains useful classes for creating and rendering
+ /// two-dimensional noise maps containing coherent noise that was
+ /// generated from the libnoise library. These classes are used to create
+ /// procedural textures and terrain height maps.
+ ///
+ /// noiseutils is known to compile under Windows 2000 Service Pack 4
+ /// (using Microsoft Visual C++ 5.0) and under Gentoo Linux 10.0 (using
+ /// gcc 3.3.4). It should be portable across all platforms that can
+ /// compile libnoise.
+ ///
+ /// @section classes Classes
+ ///
+ /// This library contains the following classes:
+ /// - A <i>noise map</i> class: This class implements a two-dimensional
+ /// array that stores floating-point values. It's designed to store
+ /// coherent-noise values generated by a noise module.
+ /// - Several <i>noise-map builder</i> classes: Each of these classes
+ /// fills a noise map with coherent-noise values generated by a noise
+ /// module. While filling a noise map, it iterates the coordinates of
+ /// the input value along the surface of a specific mathematical object.
+ /// Each of these classes implements a different mathematical object,
+ /// such as a plane, a cylinder, or a sphere.
+ /// - An <i>image</i> class: This class implements a two-dimensional array
+ /// that stores color values.
+ /// - Several <i>image-renderer</i> classes: these classes render images
+ /// given the contents of a noise map. Each of these classes renders an
+ /// image in a different way.
+ ///
+ /// @section contact Contact
+ ///
+ /// Contact jas for questions about noiseutils. The spam-resistant email
+ /// address is jlbezigvins@gmzigail.com (For great email, take off every
+ /// <a href=http://www.planettribes.com/allyourbase/story.shtml>zig</a>.)
+
+ /// The maximum width of a raster.
+ const int RASTER_MAX_WIDTH = 32767;
+
+ /// The maximum height of a raster.
+ const int RASTER_MAX_HEIGHT = 32767;
+
+ #ifndef DOXYGEN_SHOULD_SKIP_THIS
+ // The raster's stride length must be a multiple of this constant.
+ const int RASTER_STRIDE_BOUNDARY = 4;
+ #endif
+
+ /// A pointer to a callback function used by the NoiseMapBuilder class.
+ ///
+ /// The NoiseMapBuilder::Build() method calls this callback function each
+ /// time it fills a row of the noise map with coherent-noise values.
+ ///
+ /// This callback function has a single integer parameter that contains
+ /// a count of the rows that have been completed. It returns void. Pass
+ /// a function with this signature to the NoiseMapBuilder::SetCallback()
+ /// method.
+ typedef void(*NoiseMapCallback) (int row);
+
+ /// Number of meters per point in a Terragen terrain (TER) file.
+ const double DEFAULT_METERS_PER_POINT = 30.0;
+
+ /// Same as the DEFAULT_METERS_PER_POINT constant, but for us
+ /// canuckleheads.
+ const double DEFAULT_METRES_PER_POINT = DEFAULT_METERS_PER_POINT;
+
+ /// Defines a color.
+ ///
+ /// A color object contains four 8-bit channels: red, green, blue, and an
+ /// alpha (transparency) channel. Channel values range from 0 to 255.
+ ///
+ /// The alpha channel defines the transparency of the color. If the alpha
+ /// channel has a value of 0, the color is completely transparent. If the
+ /// alpha channel has a value of 255, the color is completely opaque.
+ class Color
+ {
+
+ public:
+
+ /// Constructor.
+ Color ()
+ {
+ }
+
+ /// Constructor.
+ ///
+ /// @param r Value of the red channel.
+ /// @param g Value of the green channel.
+ /// @param b Value of the blue channel.
+ /// @param a Value of the alpha (transparency) channel.
+ Color (noise::uint8 r, noise::uint8 g, noise::uint8 b,
+ noise::uint8 a):
+ red (r), green (g), blue (b), alpha (a)
+ {
+ }
+
+ /// Value of the red channel.
+ noise::uint8 red;
+
+ /// Value of the green channel.
+ noise::uint8 green;
+
+ /// Value of the blue channel.
+ noise::uint8 blue;
+
+ /// Value of the alpha (transparency) channel.
+ noise::uint8 alpha;
+
+ };
+
+ /// Defines a point used to build a color gradient.
+ ///
+ /// A color gradient is a list of gradually-changing colors. A color
+ /// gradient is defined by a list of <i>gradient points</i>. Each
+ /// gradient point has a position and a color. In a color gradient, the
+ /// colors between two adjacent gradient points are linearly interpolated.
+ ///
+ /// The ColorGradient class defines a color gradient by a list of these
+ /// objects.
+ struct GradientPoint
+ {
+
+ /// The position of this gradient point.
+ double pos;
+
+ /// The color of this gradient point.
+ Color color;
+
+ };
+
+ /// Defines a color gradient.
+ ///
+ /// A color gradient is a list of gradually-changing colors. A color
+ /// gradient is defined by a list of <i>gradient points</i>. Each
+ /// gradient point has a position and a color. In a color gradient, the
+ /// colors between two adjacent gradient points are linearly interpolated.
+ ///
+ /// To add a gradient point to the color gradient, pass its position and
+ /// color to the AddGradientPoint() method.
+ ///
+ /// To retrieve a color from a specific position in the color gradient,
+ /// pass that position to the GetColor() method.
+ ///
+ /// This class is a useful tool for coloring height maps based on
+ /// elevation.
+ ///
+ /// <b>Gradient example</b>
+ ///
+ /// Suppose a gradient object contains the following gradient points:
+ /// - -1.0 maps to black.
+ /// - 0.0 maps to white.
+ /// - 1.0 maps to red.
+ ///
+ /// If an application passes -0.5 to the GetColor() method, this method
+ /// will return a gray color that is halfway between black and white.
+ ///
+ /// If an application passes 0.25 to the GetColor() method, this method
+ /// will return a very light pink color that is one quarter of the way
+ /// between white and red.
+ class GradientColor
+ {
+
+ public:
+
+ /// Constructor.
+ GradientColor ();
+
+ /// Destructor.
+ ~GradientColor ();
+
+ /// Adds a gradient point to this gradient object.
+ ///
+ /// @param gradientPos The position of this gradient point.
+ /// @param gradientColor The color of this gradient point.
+ ///
+ /// @pre No two gradient points have the same position.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the precondition.
+ ///
+ /// It does not matter which order these gradient points are added.
+ void AddGradientPoint (double gradientPos,
+ const Color& gradientColor);
+
+ /// Deletes all the gradient points from this gradient object.
+ ///
+ /// @post All gradient points from this gradient object are deleted.
+ void Clear ();
+
+ /// Returns the color at the specified position in the color gradient.
+ ///
+ /// @param gradientPos The specified position.
+ ///
+ /// @returns The color at that position.
+ const Color& GetColor (double gradientPos) const;
+
+ /// Returns a pointer to the array of gradient points in this object.
+ ///
+ /// @returns A pointer to the array of gradient points.
+ ///
+ /// Before calling this method, call GetGradientPointCount() to
+ /// determine the number of gradient points in this array.
+ ///
+ /// It is recommended that an application does not store this pointer
+ /// for later use since the pointer to the array may change if the
+ /// application calls another method of this object.
+ const GradientPoint* GetGradientPointArray () const
+ {
+ return m_pGradientPoints;
+ }
+
+ /// Returns the number of gradient points stored in this object.
+ ///
+ /// @returns The number of gradient points stored in this object.
+ int GetGradientPointCount () const
+ {
+ return m_gradientPointCount;
+ }
+
+ private:
+
+ /// Determines the array index in which to insert the gradient point
+ /// into the internal gradient-point array.
+ ///
+ /// @param gradientPos The position of this gradient point.
+ ///
+ /// @returns The array index in which to insert the gradient point.
+ ///
+ /// @pre No two gradient points have the same input value.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the precondition.
+ ///
+ /// By inserting the gradient point at the returned array index, this
+ /// object ensures that the gradient-point array is sorted by input
+ /// value. The code that maps a value to a color requires a sorted
+ /// gradient-point array.
+ int FindInsertionPos (double gradientPos);
+
+ /// Inserts the gradient point at the specified position in the
+ /// internal gradient-point array.
+ ///
+ /// @param insertionPos The zero-based array position in which to
+ /// insert the gradient point.
+ /// @param gradientPos The position of this gradient point.
+ /// @param gradientColor The color of this gradient point.
+ ///
+ /// To make room for this new gradient point, this method reallocates
+ /// the gradient-point array and shifts all gradient points occurring
+ /// after the insertion position up by one.
+ ///
+ /// Because this object requires that all gradient points in the array
+ /// must be sorted by the position, the new gradient point should be
+ /// inserted at the position in which the order is still preserved.
+ void InsertAtPos (int insertionPos, double gradientPos,
+ const Color& gradientColor);
+
+ /// Number of gradient points.
+ int m_gradientPointCount;
+
+ /// Array that stores the gradient points.
+ GradientPoint* m_pGradientPoints;
+
+ /// A color object that is used by a gradient object to store a
+ /// temporary value.
+ mutable Color m_workingColor;
+ };
+
+ /// Implements a noise map, a 2-dimensional array of floating-point
+ /// values.
+ ///
+ /// A noise map is designed to store coherent-noise values generated by a
+ /// noise module, although it can store values from any source. A noise
+ /// map is often used as a terrain height map or a grayscale texture.
+ ///
+ /// The size (width and height) of the noise map can be specified during
+ /// object construction or at any other time.
+ ///
+ /// The GetValue() and SetValue() methods can be used to access individual
+ /// values stored in the noise map.
+ ///
+ /// This class manages its own memory. If you copy a noise map object
+ /// into another noise map object, the original contents of the noise map
+ /// object will be freed.
+ ///
+ /// If you specify a new size for the noise map and the new size is
+ /// smaller than the current size, the allocated memory will not be
+ /// reallocated.
+ /// Call ReclaimMem() to reclaim the wasted memory.
+ ///
+ /// <b>Border Values</b>
+ ///
+ /// All of the values outside of the noise map are assumed to have a
+ /// common value known as the <i>border value</i>.
+ ///
+ /// To set the border value, call the SetBorderValue() method.
+ ///
+ /// The GetValue() method returns the border value if the specified value
+ /// lies outside of the noise map.
+ ///
+ /// <b>Internal Noise Map Structure</b>
+ ///
+ /// Internally, the values are organized into horizontal rows called @a
+ /// slabs. Slabs are ordered from bottom to top.
+ ///
+ /// Each slab contains a contiguous row of values in memory. The values
+ /// in a slab are organized left to right.
+ ///
+ /// The offset between the starting points of any two adjacent slabs is
+ /// called the <i>stride amount</i>. The stride amount is measured by
+ /// the number of @a float values between these two starting points, not
+ /// by the number of bytes. For efficiency reasons, the stride is often a
+ /// multiple of the machine word size.
+ ///
+ /// The GetSlabPtr() and GetConstSlabPtr() methods allow you to retrieve
+ /// pointers to the slabs themselves.
+ class NoiseMap
+ {
+
+ public:
+
+ /// Constructor.
+ ///
+ /// Creates an empty noise map.
+ NoiseMap ();
+
+ /// Constructor.
+ ///
+ /// @param width The width of the new noise map.
+ /// @param height The height of the new noise map.
+ ///
+ /// @pre The width and height values are positive.
+ /// @pre The width and height values do not exceed the maximum
+ /// possible width and height for the noise map.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ /// @throw noise::ExceptionOutOfMemory Out of memory.
+ ///
+ /// Creates a noise map with uninitialized values.
+ ///
+ /// It is considered an error if the specified dimensions are not
+ /// positive.
+ NoiseMap (int width, int height);
+
+ /// Copy constructor.
+ ///
+ /// @throw noise::ExceptionOutOfMemory Out of memory.
+ NoiseMap (const NoiseMap& rhs);
+
+ /// Destructor.
+ ///
+ /// Frees the allocated memory for the noise map.
+ ~NoiseMap ();
+
+ /// Assignment operator.
+ ///
+ /// @throw noise::ExceptionOutOfMemory Out of memory.
+ ///
+ /// @returns Reference to self.
+ ///
+ /// Creates a copy of the noise map.
+ NoiseMap& operator= (const NoiseMap& rhs);
+
+ /// Clears the noise map to a specified value.
+ ///
+ /// @param value The value that all positions within the noise map are
+ /// cleared to.
+ void Clear (float value);
+
+ /// Returns the value used for all positions outside of the noise map.
+ ///
+ /// @returns The value used for all positions outside of the noise
+ /// map.
+ ///
+ /// All positions outside of the noise map are assumed to have a
+ /// common value known as the <i>border value</i>.
+ float GetBorderValue () const
+ {
+ return m_borderValue;
+ }
+
+ /// Returns a const pointer to a slab.
+ ///
+ /// @returns A const pointer to a slab at the position (0, 0), or
+ /// @a NULL if the noise map is empty.
+ const float* GetConstSlabPtr () const
+ {
+ return m_pNoiseMap;
+ }
+
+ /// Returns a const pointer to a slab at the specified row.
+ ///
+ /// @param row The row, or @a y coordinate.
+ ///
+ /// @returns A const pointer to a slab at the position ( 0, @a row ),
+ /// or @a NULL if the noise map is empty.
+ ///
+ /// @pre The coordinates must exist within the bounds of the noise
+ /// map.
+ ///
+ /// This method does not perform bounds checking so be careful when
+ /// calling it.
+ const float* GetConstSlabPtr (int row) const
+ {
+ return GetConstSlabPtr (0, row);
+ }
+
+ /// Returns a const pointer to a slab at the specified position.
+ ///
+ /// @param x The x coordinate of the position.
+ /// @param y The y coordinate of the position.
+ ///
+ /// @returns A const pointer to a slab at the position ( @a x, @a y ),
+ /// or @a NULL if the noise map is empty.
+ ///
+ /// @pre The coordinates must exist within the bounds of the noise
+ /// map.
+ ///
+ /// This method does not perform bounds checking so be careful when
+ /// calling it.
+ const float* GetConstSlabPtr (int x, int y) const
+ {
+ return m_pNoiseMap + (size_t)x + (size_t)m_stride * (size_t)y;
+ }
+
+ /// Returns the height of the noise map.
+ ///
+ /// @returns The height of the noise map.
+ int GetHeight () const
+ {
+ return m_height;
+ }
+
+ /// Returns the amount of memory allocated for this noise map.
+ ///
+ /// @returns The amount of memory allocated for this noise map.
+ ///
+ /// This method returns the number of @a float values allocated.
+ size_t GetMemUsed () const
+ {
+ return m_memUsed;
+ }
+
+ /// Returns a pointer to a slab.
+ ///
+ /// @returns A pointer to a slab at the position (0, 0), or @a NULL if
+ /// the noise map is empty.
+ float* GetSlabPtr ()
+ {
+ return m_pNoiseMap;
+ }
+
+ /// Returns a pointer to a slab at the specified row.
+ ///
+ /// @param row The row, or @a y coordinate.
+ ///
+ /// @returns A pointer to a slab at the position ( 0, @a row ), or
+ /// @a NULL if the noise map is empty.
+ ///
+ /// @pre The coordinates must exist within the bounds of the noise
+ /// map.
+ ///
+ /// This method does not perform bounds checking so be careful when
+ /// calling it.
+ float* GetSlabPtr (int row)
+ {
+ return GetSlabPtr (0, row);
+ }
+
+ /// Returns a pointer to a slab at the specified position.
+ ///
+ /// @param x The x coordinate of the position.
+ /// @param y The y coordinate of the position.
+ ///
+ /// @returns A pointer to a slab at the position ( @a x, @a y ) or
+ /// @a NULL if the noise map is empty.
+ ///
+ /// @pre The coordinates must exist within the bounds of the noise
+ /// map.
+ ///
+ /// This method does not perform bounds checking so be careful when
+ /// calling it.
+ float* GetSlabPtr (int x, int y)
+ {
+ return m_pNoiseMap + (size_t)x + (size_t)m_stride * (size_t)y;
+ }
+
+ /// Returns the stride amount of the noise map.
+ ///
+ /// @returns The stride amount of the noise map.
+ ///
+ /// - The <i>stride amount</i> is the offset between the starting
+ /// points of any two adjacent slabs in a noise map.
+ /// - The stride amount is measured by the number of @a float values
+ /// between these two points, not by the number of bytes.
+ int GetStride () const
+ {
+ return m_stride;
+ }
+
+ /// Returns a value from the specified position in the noise map.
+ ///
+ /// @param x The x coordinate of the position.
+ /// @param y The y coordinate of the position.
+ ///
+ /// @returns The value at that position.
+ ///
+ /// This method returns the border value if the coordinates exist
+ /// outside of the noise map.
+ float GetValue (int x, int y) const;
+
+ /// Returns the width of the noise map.
+ ///
+ /// @returns The width of the noise map.
+ int GetWidth () const
+ {
+ return m_width;
+ }
+
+ /// Reallocates the noise map to recover wasted memory.
+ ///
+ /// @throw noise::ExceptionOutOfMemory Out of memory. (Yes, this
+ /// method can return an out-of-memory exception because two noise
+ /// maps will temporarily exist in memory during this call.)
+ ///
+ /// The contents of the noise map is unaffected.
+ void ReclaimMem ();
+
+ /// Sets the value to use for all positions outside of the noise map.
+ ///
+ /// @param borderValue The value to use for all positions outside of
+ /// the noise map.
+ ///
+ /// All positions outside of the noise map are assumed to have a
+ /// common value known as the <i>border value</i>.
+ void SetBorderValue (float borderValue)
+ {
+ m_borderValue = borderValue;
+ }
+
+ /// Sets the new size for the noise map.
+ ///
+ /// @param width The new width for the noise map.
+ /// @param height The new height for the noise map.
+ ///
+ /// @pre The width and height values are positive.
+ /// @pre The width and height values do not exceed the maximum
+ /// possible width and height for the noise map.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ /// @throw noise::ExceptionOutOfMemory Out of memory.
+ ///
+ /// On exit, the contents of the noise map are undefined.
+ ///
+ /// If the @a OUT_OF_MEMORY exception occurs, this noise map object
+ /// becomes empty.
+ ///
+ /// If the @a INVALID_PARAM exception occurs, the noise map is
+ /// unmodified.
+ void SetSize (int width, int height);
+
+ /// Sets a value at a specified position in the noise map.
+ ///
+ /// @param x The x coordinate of the position.
+ /// @param y The y coordinate of the position.
+ /// @param value The value to set at the given position.
+ ///
+ /// This method does nothing if the noise map object is empty or the
+ /// position is outside the bounds of the noise map.
+ void SetValue (int x, int y, float value);
+
+ /// Takes ownership of the buffer within the source noise map.
+ ///
+ /// @param source The source noise map.
+ ///
+ /// On exit, the source noise map object becomes empty.
+ ///
+ /// This method only moves the buffer pointer so this method is very
+ /// quick.
+ void TakeOwnership (NoiseMap& source);
+
+ private:
+
+ /// Returns the minimum amount of memory required to store a noise map
+ /// of the specified size.
+ ///
+ /// @param width The width of the noise map.
+ /// @param height The height of the noise map.
+ ///
+ /// @returns The minimum amount of memory required to store the noise
+ /// map.
+ ///
+ /// The returned value is measured by the number of @a float values
+ /// required to store the noise map, not by the number of bytes.
+ size_t CalcMinMemUsage (int width, int height) const
+ {
+ return CalcStride ((size_t)width) * (size_t)height;
+ }
+
+ /// Calculates the stride amount for a noise map.
+ ///
+ /// @param width The width of the noise map.
+ ///
+ /// @returns The stride amount.
+ ///
+ /// - The <i>stride amount</i> is the offset between the starting
+ /// points of any two adjacent slabs in a noise map.
+ /// - The stride amount is measured by the number of @a float values
+ /// between these two points, not by the number of bytes.
+ size_t CalcStride (int width) const
+ {
+ return (size_t)(((width + RASTER_STRIDE_BOUNDARY - 1)
+ / RASTER_STRIDE_BOUNDARY) * RASTER_STRIDE_BOUNDARY);
+ }
+
+ /// Copies the contents of the buffer in the source noise map into
+ /// this noise map.
+ ///
+ /// @param source The source noise map.
+ ///
+ /// @throw noise::ExceptionOutOfMemory Out of memory.
+ ///
+ /// This method reallocates the buffer in this noise map object if
+ /// necessary.
+ ///
+ /// @warning This method calls the standard library function
+ /// @a memcpy, which probably violates the DMCA because it can be used
+ //. to make a bitwise copy of anything, like, say, a DVD. Don't call
+ /// this method if you live in the USA.
+ void CopyNoiseMap (const NoiseMap& source);
+
+ /// Resets the noise map object.
+ ///
+ /// This method is similar to the InitObj() method, except this method
+ /// deletes the buffer in this noise map.
+ void DeleteNoiseMapAndReset ();
+
+ /// Initializes the noise map object.
+ ///
+ /// @pre Must be called during object construction.
+ /// @pre The noise map buffer must not exist.
+ void InitObj ();
+
+ /// Value used for all positions outside of the noise map.
+ float m_borderValue;
+
+ /// The current height of the noise map.
+ int m_height;
+
+ /// The amount of memory allocated for this noise map.
+ ///
+ /// This value is equal to the number of @a float values allocated for
+ /// the noise map, not the number of bytes.
+ size_t m_memUsed;
+
+ /// A pointer to the noise map buffer.
+ float* m_pNoiseMap;
+
+ /// The stride amount of the noise map.
+ int m_stride;
+
+ /// The current width of the noise map.
+ int m_width;
+
+ };
+
+ /// Implements an image, a 2-dimensional array of color values.
+ ///
+ /// An image can be used to store a color texture.
+ ///
+ /// These color values are of type Color.
+ ///
+ /// The size (width and height) of the image can be specified during
+ /// object construction or at any other time.
+ ///
+ /// The GetValue() and SetValue() methods can be used to access individual
+ /// color values stored in the image.
+ ///
+ /// This class manages its own memory. If you copy an image object into
+ /// another image object, the original contents of the image object will
+ /// be freed.
+ ///
+ /// If you specify a new size for the image and the new size is smaller
+ /// than the current size, the allocated memory will not be reallocated.
+ /// Call ReclaimMem() to reclaim the wasted memory.
+ ///
+ /// <b>Border Values</b>
+ ///
+ /// All of the color values outside of the image are assumed to have a
+ /// common color value known as the <i>border value</i>.
+ ///
+ /// To set the border value, call the SetBorderValue() method.
+ ///
+ /// The GetValue() method returns the border value if the specified
+ /// position lies outside of the image.
+ ///
+ /// <b>Internal Image Structure</b>
+ ///
+ /// Internally, the color values are organized into horizontal rows called
+ /// @a slabs. Slabs are ordered from bottom to top.
+ ///
+ /// Each slab contains a contiguous row of color values in memory. The
+ /// color values in a slab are organized left to right. These values are
+ /// of type Color.
+ ///
+ /// The offset between the starting points of any two adjacent slabs is
+ /// called the <i>stride amount</i>. The stride amount is measured by the
+ /// number of Color objects between these two starting points, not by the
+ /// number of bytes. For efficiency reasons, the stride is often a
+ /// multiple of the machine word size.
+ ///
+ /// The GetSlabPtr() methods allow you to retrieve pointers to the slabs
+ /// themselves.
+ class Image
+ {
+
+ public:
+
+ /// Constructor.
+ ///
+ /// Creates an empty image.
+ Image ();
+
+ /// Constructor.
+ ///
+ /// @param width The width of the new image.
+ /// @param height The height of the new image.
+ ///
+ /// @pre The width and height values are positive.
+ /// @pre The width and height values do not exceed the maximum
+ /// possible width and height for the image.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ /// @throw noise::ExceptionOutOfMemory Out of memory.
+ ///
+ /// Creates an image with uninitialized color values.
+ ///
+ /// It is considered an error if the specified dimensions are not
+ /// positive.
+ Image (int width, int height);
+
+ /// Copy constructor.
+ ///
+ /// @throw noise::ExceptionOutOfMemory Out of memory.
+ Image (const Image& rhs);
+
+ /// Destructor.
+ ///
+ /// Frees the allocated memory for the image.
+ ~Image ();
+
+ /// Assignment operator.
+ ///
+ /// @throw noise::ExceptionOutOfMemory Out of memory.
+ ///
+ /// @returns Reference to self.
+ ///
+ /// Creates a copy of the image.
+ Image& operator= (const Image& rhs);
+
+ /// Clears the image to a specified color value.
+ ///
+ /// @param value The color value that all positions within the image
+ /// are cleared to.
+ void Clear (const Color& value);
+
+ /// Returns the color value used for all positions outside of the
+ /// image.
+ ///
+ /// @returns The color value used for all positions outside of the
+ /// image.
+ ///
+ /// All positions outside of the image are assumed to have a common
+ /// color value known as the <i>border value</i>.
+ Color GetBorderValue () const
+ {
+ return m_borderValue;
+ }
+
+ /// Returns a const pointer to a slab.
+ ///
+ /// @returns A const pointer to a slab at the position (0, 0), or
+ /// @a NULL if the image is empty.
+ const Color* GetConstSlabPtr () const
+ {
+ return m_pImage;
+ }
+
+ /// Returns a const pointer to a slab at the specified row.
+ ///
+ /// @param row The row, or @a y coordinate.
+ ///
+ /// @returns A const pointer to a slab at the position ( 0, @a row ),
+ /// or @a NULL if the image is empty.
+ ///
+ /// @pre The coordinates must exist within the bounds of the image.
+ ///
+ /// This method does not perform bounds checking so be careful when
+ /// calling it.
+ const Color* GetConstSlabPtr (int row) const
+ {
+ return GetConstSlabPtr (0, row);
+ }
+
+ /// Returns a const pointer to a slab at the specified position.
+ ///
+ /// @param x The x coordinate of the position.
+ /// @param y The y coordinate of the position.
+ ///
+ /// @returns A const pointer to a slab at the position ( @a x, @a y ),
+ /// or @a NULL if the image is empty.
+ ///
+ /// @pre The coordinates must exist within the bounds of the image.
+ ///
+ /// This method does not perform bounds checking so be careful when
+ /// calling it.
+ const Color* GetConstSlabPtr (int x, int y) const
+ {
+ return m_pImage + (size_t)x + (size_t)m_stride * (size_t)y;
+ }
+
+ /// Returns the height of the image.
+ ///
+ /// @returns The height of the image.
+ int GetHeight () const
+ {
+ return m_height;
+ }
+
+ /// Returns the amount of memory allocated for this image.
+ ///
+ /// @returns The amount of memory allocated for this image.
+ ///
+ /// This method returns the number of Color objects allocated.
+ size_t GetMemUsed () const
+ {
+ return m_memUsed;
+ }
+
+ /// Returns a pointer to a slab.
+ ///
+ /// @returns A pointer to a slab at the position (0, 0), or @a NULL if
+ /// the image is empty.
+ Color* GetSlabPtr ()
+ {
+ return m_pImage;
+ }
+
+ /// Returns a pointer to a slab at the specified row.
+ ///
+ /// @param row The row, or @a y coordinate.
+ ///
+ /// @returns A pointer to a slab at the position ( 0, @a row ), or
+ /// @a NULL if the image is empty.
+ ///
+ /// @pre The coordinates must exist within the bounds of the image.
+ ///
+ /// This method does not perform bounds checking so be careful when
+ /// calling it.
+ Color* GetSlabPtr (int row)
+ {
+ return GetSlabPtr (0, row);
+ }
+
+ /// Returns a pointer to a slab at the specified position.
+ ///
+ /// @param x The x coordinate of the position.
+ /// @param y The y coordinate of the position.
+ ///
+ /// @returns A pointer to a slab at the position ( @a x, @a y ), or
+ /// @a NULL if the image is empty.
+ ///
+ /// @pre The coordinates must exist within the bounds of the image.
+ ///
+ /// This method does not perform bounds checking so be careful when
+ /// calling it.
+ Color* GetSlabPtr (int x, int y)
+ {
+ return m_pImage + (size_t)x + (size_t)m_stride * (size_t)y;
+ }
+
+ /// Returns the stride amount of the image.
+ ///
+ /// @returns The stride amount of the image.
+ ///
+ /// - The <i>stride amount</i> is the offset between the starting
+ /// points of any two adjacent slabs in an image.
+ /// - The stride amount is measured by the number of Color objects
+ /// between these two points, not by the number of bytes.
+ int GetStride () const
+ {
+ return m_stride;
+ }
+
+ /// Returns a color value from the specified position in the image.
+ ///
+ /// @param x The x coordinate of the position.
+ /// @param y The y coordinate of the position.
+ ///
+ /// @returns The color value at that position.
+ ///
+ /// This method returns the border value if the coordinates exist
+ /// outside of the image.
+ Color GetValue (int x, int y) const;
+
+ /// Returns the width of the image.
+ ///
+ /// @returns The width of the image.
+ int GetWidth () const
+ {
+ return m_width;
+ }
+
+ /// Reallocates the image to recover wasted memory.
+ ///
+ /// @throw noise::ExceptionOutOfMemory Out of memory. (Yes, this
+ /// method can return an out-of-memory exception because two images
+ /// will exist temporarily in memory during this call.)
+ ///
+ /// The contents of the image is unaffected.
+ void ReclaimMem ();
+
+ /// Sets the color value to use for all positions outside of the
+ /// image.
+ ///
+ /// @param borderValue The color value to use for all positions
+ /// outside of the image.
+ ///
+ /// All positions outside of the image are assumed to have a common
+ /// color value known as the <i>border value</i>.
+ void SetBorderValue (const Color& borderValue)
+ {
+ m_borderValue = borderValue;
+ }
+
+ /// Sets the new size for the image.
+ ///
+ /// @param width The new width for the image.
+ /// @param height The new height for the image.
+ ///
+ /// @pre The width and height values are positive.
+ /// @pre The width and height values do not exceed the maximum
+ /// possible width and height for the image.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ /// @throw noise::ExceptionOutOfMemory Out of memory.
+ ///
+ /// On exit, the contents of the image are undefined.
+ ///
+ /// If the @a OUT_OF_MEMORY exception occurs, this image becomes
+ /// empty.
+ ///
+ /// If the @a INVALID_PARAM exception occurs, the image is unmodified.
+ void SetSize (int width, int height);
+
+ /// Sets a color value at a specified position in the image.
+ ///
+ /// @param x The x coordinate of the position.
+ /// @param y The y coordinate of the position.
+ /// @param value The color value to set at the given position.
+ ///
+ /// This method does nothing if the image is empty or the position is
+ /// outside the bounds of the image.
+ void SetValue (int x, int y, const Color& value);
+
+ /// Takes ownership of the buffer within the source image.
+ ///
+ /// @param source The source image.
+ ///
+ /// On exit, the source image object becomes empty.
+ ///
+ /// This method only moves the buffer pointer so this method is very
+ /// quick.
+ void TakeOwnership (Image& source);
+
+ private:
+
+ /// Returns the minimum amount of memory required to store an image of
+ /// the specified size.
+ ///
+ /// @param width The width of the image.
+ /// @param height The height of the image.
+ ///
+ /// @returns The minimum amount of memory required to store the image.
+ ///
+ /// The returned color value is measured by the number of Color
+ /// objects required to store the image, not by the number of bytes.
+ size_t CalcMinMemUsage (int width, int height) const
+ {
+ return CalcStride ((size_t)width) * (size_t)height;
+ }
+
+ /// Calculates the stride amount for an image.
+ ///
+ /// @param width The width of the image.
+ ///
+ /// @returns The stride amount.
+ ///
+ /// - The <i>stride amount</i> is the offset between the starting
+ /// points of any two adjacent slabs in an image.
+ /// - The stride amount is measured by the number of Color objects
+ /// between these two points, not by the number of bytes.
+ size_t CalcStride (int width) const
+ {
+ return (size_t)(((width + RASTER_STRIDE_BOUNDARY - 1)
+ / RASTER_STRIDE_BOUNDARY) * RASTER_STRIDE_BOUNDARY);
+ }
+
+ /// Copies the contents of the buffer in the source image into this
+ /// image.
+ ///
+ /// @param source The source image.
+ ///
+ /// @throw noise::ExceptionOutOfMemory Out of memory.
+ ///
+ /// This method reallocates the buffer in this image object if
+ /// necessary.
+ ///
+ /// @warning This method calls the standard library function
+ /// @a memcpy, which probably violates the DMCA because it can be used
+ /// to make a bitwise copy of anything, like, say, a DVD. Don't call
+ /// this method if you live in the USA.
+ void CopyImage (const Image& source);
+
+ /// Resets the image object.
+ ///
+ /// This method is similar to the InitObj() method, except this method
+ /// deletes the memory allocated to the image.
+ void DeleteImageAndReset ();
+
+ /// Initializes the image object.
+ ///
+ /// @pre Must be called during object construction.
+ /// @pre The image buffer must not exist.
+ void InitObj ();
+
+ /// The Color value used for all positions outside of the image.
+ Color m_borderValue;
+
+ /// The current height of the image.
+ int m_height;
+
+ /// The amount of memory allocated for the image.
+ ///
+ /// This value is equal to the number of Color objects allocated for
+ /// the image, not the number of bytes.
+ size_t m_memUsed;
+
+ /// A pointer to the image buffer.
+ Color* m_pImage;
+
+ /// The stride amount of the image.
+ int m_stride;
+
+ /// The current width of the image.
+ int m_width;
+
+ };
+
+ /// Windows bitmap image writer class.
+ ///
+ /// This class creates a file in Windows bitmap (*.bmp) format given the
+ /// contents of an image object.
+ ///
+ /// <b>Writing the image</b>
+ ///
+ /// To write the image to a file, perform the following steps:
+ /// - Pass the filename to the SetDestFilename() method.
+ /// - Pass an Image object to the SetSourceImage() method.
+ /// - Call the WriteDestFile() method.
+ ///
+ /// The SetDestFilename() and SetSourceImage() methods must be called
+ /// before calling the WriteDestFile() method.
+ class WriterBMP
+ {
+
+ public:
+
+ /// Constructor.
+ WriterBMP ():
+ m_pSourceImage (NULL)
+ {
+ }
+
+ /// Returns the name of the file to write.
+ ///
+ /// @returns The name of the file to write.
+ std::string GetDestFilename () const
+ {
+ return m_destFilename;
+ }
+
+ /// Sets the name of the file to write.
+ ///
+ /// @param filename The name of the file to write.
+ ///
+ /// Call this method before calling the WriteDestFile() method.
+ void SetDestFilename (const std::string& filename)
+ {
+ m_destFilename = filename;
+ }
+
+ /// Sets the image object that is written to the file.
+ ///
+ /// @param sourceImage The image object to write.
+ ///
+ /// This object only stores a pointer to an image object, so make sure
+ /// this object exists before calling the WriteDestFile() method.
+ void SetSourceImage (Image& sourceImage)
+ {
+ m_pSourceImage = &sourceImage;
+ }
+
+ /// Writes the contents of the image object to the file.
+ ///
+ /// @pre SetDestFilename() has been previously called.
+ /// @pre SetSourceImage() has been previously called.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ /// @throw noise::ExceptionOutOfMemory Out of memory.
+ /// @throw noise::ExceptionUnknown An unknown exception occurred.
+ /// Possibly the file could not be written.
+ ///
+ /// This method encodes the contents of the image and writes it to a
+ /// file. Before calling this method, call the SetSourceImage()
+ /// method to specify the image, then call the SetDestFilename()
+ /// method to specify the name of the file to write.
+ void WriteDestFile ();
+
+ protected:
+
+ /// Calculates the width of one horizontal line in the file, in bytes.
+ ///
+ /// @param width The width of the image, in points.
+ ///
+ /// @returns The width of one horizontal line in the file.
+ ///
+ /// Windows bitmap files require that the width of one horizontal line
+ /// must be aligned to a 32-bit boundary.
+ int CalcWidthByteCount (int width) const;
+
+ /// Name of the file to write.
+ std::string m_destFilename;
+
+ /// A pointer to the image object that will be written to the file.
+ Image* m_pSourceImage;
+
+ };
+
+ /// Terragen Terrain writer class.
+ ///
+ /// This class creates a file in Terrage Terrain (*.ter) format given the
+ /// contents of a noise map object. This class treats the values in the
+ /// noise map as elevations measured in meters.
+ ///
+ /// <a href=http://www.planetside.co.uk/terragen/>Terragen</a> is a
+ /// terrain application that renders realistic landscapes. Terragen is
+ /// available for Windows and MacOS; unfortunately, Terragen does not have
+ /// UN*X versions.
+ ///
+ /// <b>Writing the noise map</b>
+ ///
+ /// To write the noise map, perform the following steps:
+ /// - Pass the filename to the SetDestFilename() method.
+ /// - Pass a NoiseMap object to the SetSourceNoiseMap() method.
+ /// - Call the WriteDestFile() method.
+ ///
+ /// The SetDestFilename() and SetSourceNoiseMap() methods must be called
+ /// before calling the WriteDestFile() method.
+ class WriterTER
+ {
+
+ public:
+
+ /// Constructor.
+ WriterTER ():
+ m_pSourceNoiseMap (NULL),
+ m_metersPerPoint (DEFAULT_METERS_PER_POINT)
+ {
+ }
+
+ /// Returns the name of the file to write.
+ ///
+ /// @returns The name of the file to write.
+ std::string GetDestFilename () const
+ {
+ return m_destFilename;
+ }
+
+ /// Returns the distance separating adjacent points in the noise map,
+ /// in meters.
+ ///
+ /// @returns The distance separating adjacent points in the noise map.
+ float GetMetersPerPoint () const
+ {
+ return m_metersPerPoint;
+ }
+
+ /// Sets the name of the file to write.
+ ///
+ /// @param filename The name of the file to write.
+ ///
+ /// Call this method before calling the WriteDestFile() method.
+ void SetDestFilename (const std::string& filename)
+ {
+ m_destFilename = filename;
+ }
+
+ /// Sets the distance separating adjacent points in the noise map, in
+ /// meters.
+ ///
+ /// @param metersPerPoint The distance separating adjacent points in
+ /// the noise map.
+ void SetMetersPerPoint (float metersPerPoint)
+ {
+ m_metersPerPoint = metersPerPoint;
+ }
+
+ /// Sets the noise map object that is written to the file.
+ ///
+ /// @param sourceNoiseMap The noise map object to write.
+ ///
+ /// This object only stores a pointer to a noise map object, so make
+ /// sure this object exists before calling the WriteDestFile() method.
+ void SetSourceNoiseMap (NoiseMap& sourceNoiseMap)
+ {
+ m_pSourceNoiseMap = &sourceNoiseMap;
+ }
+
+ /// Writes the contents of the noise map object to the file.
+ ///
+ /// @pre SetDestFilename() has been previously called.
+ /// @pre SetSourceNoiseMap() has been previously called.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ /// @throw noise::ExceptionOutOfMemory Out of memory.
+ /// @throw noise::ExceptionUnknown An unknown exception occurred.
+ /// Possibly the file could not be written.
+ ///
+ /// This method encodes the contents of the noise map and writes it to
+ /// a file. Before calling this method, call the SetSourceNoiseMap()
+ /// method to specify the noise map, then call the SetDestFilename()
+ /// method to specify the name of the file to write.
+ ///
+ /// This object assumes that the noise values represent elevations in
+ /// meters.
+ void WriteDestFile ();
+
+ protected:
+
+ /// Calculates the width of one horizontal line in the file, in bytes.
+ ///
+ /// @param width The width of the noise map, in points.
+ ///
+ /// @returns The width of one horizontal line in the file.
+ int CalcWidthByteCount (int width) const;
+
+ /// Name of the file to write.
+ std::string m_destFilename;
+
+ /// A pointer to the noise map that will be written to the file.
+ NoiseMap* m_pSourceNoiseMap;
+
+ /// The distance separating adjacent points in the noise map, in
+ /// meters.
+ float m_metersPerPoint;
+
+ };
+
+ /// Abstract base class for a noise-map builder
+ ///
+ /// A builder class builds a noise map by filling it with coherent-noise
+ /// values generated from the surface of a three-dimensional mathematical
+ /// object. Each builder class defines a specific three-dimensional
+ /// surface, such as a cylinder, sphere, or plane.
+ ///
+ /// A builder class describes these input values using a coordinate system
+ /// applicable for the mathematical object (e.g., a latitude/longitude
+ /// coordinate system for the spherical noise-map builder.) It then
+ /// "flattens" these coordinates onto a plane so that it can write the
+ /// coherent-noise values into a two-dimensional noise map.
+ ///
+ /// <b>Building the Noise Map</b>
+ ///
+ /// To build the noise map, perform the following steps:
+ /// - Pass the bounding coordinates to the SetBounds() method.
+ /// - Pass the noise map size, in points, to the SetDestSize() method.
+ /// - Pass a NoiseMap object to the SetDestNoiseMap() method.
+ /// - Pass a noise module (derived from noise::module::Module) to the
+ /// SetSourceModule() method.
+ /// - Call the Build() method.
+ ///
+ /// You may also pass a callback function to the SetCallback() method.
+ /// The Build() method calls this callback function each time it fills a
+ /// row of the noise map with coherent-noise values. This callback
+ /// function has a single integer parameter that contains a count of the
+ /// rows that have been completed. It returns void.
+ ///
+ /// Note that SetBounds() is not defined in the abstract base class; it is
+ /// only defined in the derived classes. This is because each model uses
+ /// a different coordinate system.
+ class NoiseMapBuilder
+ {
+
+ public:
+
+ /// Constructor.
+ NoiseMapBuilder ();
+
+ /// Builds the noise map.
+ ///
+ /// @pre SetBounds() was previously called.
+ /// @pre SetDestNoiseMap() was previously called.
+ /// @pre SetSourceModule() was previously called.
+ /// @pre The width and height values specified by SetDestSize() are
+ /// positive.
+ /// @pre The width and height values specified by SetDestSize() do not
+ /// exceed the maximum possible width and height for the noise map.
+ ///
+ /// @post The original contents of the destination noise map is
+ /// destroyed.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ /// @throw noise::ExceptionOutOfMemory Out of memory.
+ ///
+ /// If this method is successful, the destination noise map contains
+ /// the coherent-noise values from the noise module specified by
+ /// SetSourceModule().
+ virtual void Build () = 0;
+
+ /// Returns the height of the destination noise map.
+ ///
+ /// @returns The height of the destination noise map, in points.
+ ///
+ /// This object does not change the height in the destination noise
+ /// map object until the Build() method is called.
+ double GetDestHeight () const
+ {
+ return m_destHeight;
+ }
+
+ /// Returns the width of the destination noise map.
+ ///
+ /// @returns The width of the destination noise map, in points.
+ ///
+ /// This object does not change the height in the destination noise
+ /// map object until the Build() method is called.
+ double GetDestWidth () const
+ {
+ return m_destWidth;
+ }
+
+ /// Sets the callback function that Build() calls each time it fills a
+ /// row of the noise map with coherent-noise values.
+ ///
+ /// @param pCallback The callback function.
+ ///
+ /// This callback function has a single integer parameter that
+ /// contains a count of the rows that have been completed. It returns
+ /// void. Pass a function with this signature to the SetCallback()
+ /// method.
+ void SetCallback (NoiseMapCallback pCallback);
+
+ /// Sets the destination noise map.
+ ///
+ /// @param destNoiseMap The destination noise map.
+ ///
+ /// The destination noise map will contain the coherent-noise values
+ /// from this noise map after a successful call to the Build() method.
+ ///
+ /// The destination noise map must exist throughout the lifetime of
+ /// this object unless another noise map replaces that noise map.
+ void SetDestNoiseMap (NoiseMap& destNoiseMap)
+ {
+ m_pDestNoiseMap = &destNoiseMap;
+ }
+
+ /// Sets the source module.
+ ///
+ /// @param sourceModule The source module.
+ ///
+ /// This object fills in a noise map with the coherent-noise values
+ /// from this source module.
+ ///
+ /// The source module must exist throughout the lifetime of this
+ /// object unless another noise module replaces that noise module.
+ void SetSourceModule (const module::Module& sourceModule)
+ {
+ m_pSourceModule = &sourceModule;
+ }
+
+ /// Sets the size of the destination noise map.
+ ///
+ /// @param destWidth The width of the destination noise map, in
+ /// points.
+ /// @param destHeight The height of the destination noise map, in
+ /// points.
+ ///
+ /// This method does not change the size of the destination noise map
+ /// until the Build() method is called.
+ void SetDestSize (int destWidth, int destHeight)
+ {
+ m_destWidth = destWidth ;
+ m_destHeight = destHeight;
+ }
+
+ protected:
+
+ /// The callback function that Build() calls each time it fills a row
+ /// of the noise map with coherent-noise values.
+ ///
+ /// This callback function has a single integer parameter that
+ /// contains a count of the rows that have been completed. It returns
+ /// void. Pass a function with this signature to the SetCallback()
+ /// method.
+ NoiseMapCallback m_pCallback;
+
+ /// Height of the destination noise map, in points.
+ int m_destHeight;
+
+ /// Width of the destination noise map, in points.
+ int m_destWidth;
+
+ /// Destination noise map that will contain the coherent-noise values.
+ NoiseMap* m_pDestNoiseMap;
+
+ /// Source noise module that will generate the coherent-noise values.
+ const module::Module* m_pSourceModule;
+
+ };
+
+ /// Builds a cylindrical noise map.
+ ///
+ /// This class builds a noise map by filling it with coherent-noise values
+ /// generated from the surface of a cylinder.
+ ///
+ /// This class describes these input values using an (angle, height)
+ /// coordinate system. After generating the coherent-noise value from the
+ /// input value, it then "flattens" these coordinates onto a plane so that
+ /// it can write the values into a two-dimensional noise map.
+ ///
+ /// The cylinder model has a radius of 1.0 unit and has infinite height.
+ /// The cylinder is oriented along the @a y axis. Its center is at the
+ /// origin.
+ ///
+ /// The x coordinate in the noise map represents the angle around the
+ /// cylinder's y axis. The y coordinate in the noise map represents the
+ /// height above the x-z plane.
+ ///
+ /// The application must provide the lower and upper angle bounds of the
+ /// noise map, in degrees, and the lower and upper height bounds of the
+ /// noise map, in units.
+ class NoiseMapBuilderCylinder: public NoiseMapBuilder
+ {
+
+ public:
+
+ /// Constructor.
+ NoiseMapBuilderCylinder ();
+
+ virtual void Build ();
+
+ /// Returns the lower angle boundary of the cylindrical noise map.
+ ///
+ /// @returns The lower angle boundary of the noise map, in degrees.
+ double GetLowerAngleBound () const
+ {
+ return m_lowerAngleBound;
+ }
+
+ /// Returns the lower height boundary of the cylindrical noise map.
+ ///
+ /// @returns The lower height boundary of the noise map, in units.
+ ///
+ /// One unit is equal to the radius of the cylinder.
+ double GetLowerHeightBound () const
+ {
+ return m_lowerHeightBound;
+ }
+
+ /// Returns the upper angle boundary of the cylindrical noise map.
+ ///
+ /// @returns The upper angle boundary of the noise map, in degrees.
+ double GetUpperAngleBound () const
+ {
+ return m_upperAngleBound;
+ }
+
+ /// Returns the upper height boundary of the cylindrical noise map.
+ ///
+ /// @returns The upper height boundary of the noise map, in units.
+ ///
+ /// One unit is equal to the radius of the cylinder.
+ double GetUpperHeightBound () const
+ {
+ return m_upperHeightBound;
+ }
+
+ /// Sets the coordinate boundaries of the noise map.
+ ///
+ /// @param lowerAngleBound The lower angle boundary of the noise map,
+ /// in degrees.
+ /// @param upperAngleBound The upper angle boundary of the noise map,
+ /// in degrees.
+ /// @param lowerHeightBound The lower height boundary of the noise
+ /// map, in units.
+ /// @param upperHeightBound The upper height boundary of the noise
+ /// map, in units.
+ ///
+ /// @pre The lower angle boundary is less than the upper angle
+ /// boundary.
+ /// @pre The lower height boundary is less than the upper height
+ /// boundary.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ ///
+ /// One unit is equal to the radius of the cylinder.
+ void SetBounds (double lowerAngleBound, double upperAngleBound,
+ double lowerHeightBound, double upperHeightBound)
+ {
+ if (lowerAngleBound >= upperAngleBound
+ || lowerHeightBound >= upperHeightBound) {
+ throw noise::ExceptionInvalidParam ();
+ }
+
+ m_lowerAngleBound = lowerAngleBound ;
+ m_upperAngleBound = upperAngleBound ;
+ m_lowerHeightBound = lowerHeightBound;
+ m_upperHeightBound = upperHeightBound;
+ }
+
+ private:
+
+ /// Lower angle boundary of the cylindrical noise map, in degrees.
+ double m_lowerAngleBound;
+
+ /// Lower height boundary of the cylindrical noise map, in units.
+ double m_lowerHeightBound;
+
+ /// Upper angle boundary of the cylindrical noise map, in degrees.
+ double m_upperAngleBound;
+
+ /// Upper height boundary of the cylindrical noise map, in units.
+ double m_upperHeightBound;
+
+ };
+
+ /// Builds a planar noise map.
+ ///
+ /// This class builds a noise map by filling it with coherent-noise values
+ /// generated from the surface of a plane.
+ ///
+ /// This class describes these input values using (x, z) coordinates.
+ /// Their y coordinates are always 0.0.
+ ///
+ /// The application must provide the lower and upper x coordinate bounds
+ /// of the noise map, in units, and the lower and upper z coordinate
+ /// bounds of the noise map, in units.
+ ///
+ /// To make a tileable noise map with no seams at the edges, call the
+ /// EnableSeamless() method.
+ class NoiseMapBuilderPlane: public NoiseMapBuilder
+ {
+
+ public:
+
+ /// Constructor.
+ NoiseMapBuilderPlane ();
+
+ virtual void Build ();
+
+ /// Enables or disables seamless tiling.
+ ///
+ /// @param enable A flag that enables or disables seamless tiling.
+ ///
+ /// Enabling seamless tiling builds a noise map with no seams at the
+ /// edges. This allows the noise map to be tileable.
+ void EnableSeamless (bool enable = true)
+ {
+ m_isSeamlessEnabled = enable;
+ }
+
+ /// Returns the lower x boundary of the planar noise map.
+ ///
+ /// @returns The lower x boundary of the planar noise map, in units.
+ double GetLowerXBound () const
+ {
+ return m_lowerXBound;
+ }
+
+ /// Returns the lower z boundary of the planar noise map.
+ ///
+ /// @returns The lower z boundary of the noise map, in units.
+ double GetLowerZBound () const
+ {
+ return m_lowerZBound;
+ }
+
+ /// Returns the upper x boundary of the planar noise map.
+ ///
+ /// @returns The upper x boundary of the noise map, in units.
+ double GetUpperXBound () const
+ {
+ return m_upperXBound;
+ }
+
+ /// Returns the upper z boundary of the planar noise map.
+ ///
+ /// @returns The upper z boundary of the noise map, in units.
+ double GetUpperZBound () const
+ {
+ return m_upperZBound;
+ }
+
+ /// Determines if seamless tiling is enabled.
+ ///
+ /// @returns
+ /// - @a true if seamless tiling is enabled.
+ /// - @a false if seamless tiling is disabled.
+ ///
+ /// Enabling seamless tiling builds a noise map with no seams at the
+ /// edges. This allows the noise map to be tileable.
+ bool IsSeamlessEnabled () const
+ {
+ return m_isSeamlessEnabled;
+ }
+
+ /// Sets the boundaries of the planar noise map.
+ ///
+ /// @param lowerXBound The lower x boundary of the noise map, in
+ /// units.
+ /// @param upperXBound The upper x boundary of the noise map, in
+ /// units.
+ /// @param lowerZBound The lower z boundary of the noise map, in
+ /// units.
+ /// @param upperZBound The upper z boundary of the noise map, in
+ /// units.
+ ///
+ /// @pre The lower x boundary is less than the upper x boundary.
+ /// @pre The lower z boundary is less than the upper z boundary.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ void SetBounds (double lowerXBound, double upperXBound,
+ double lowerZBound, double upperZBound)
+ {
+ if (lowerXBound >= upperXBound
+ || lowerZBound >= upperZBound) {
+ throw noise::ExceptionInvalidParam ();
+ }
+
+ m_lowerXBound = lowerXBound;
+ m_upperXBound = upperXBound;
+ m_lowerZBound = lowerZBound;
+ m_upperZBound = upperZBound;
+ }
+
+ private:
+
+ /// A flag specifying whether seamless tiling is enabled.
+ bool m_isSeamlessEnabled;
+
+ /// Lower x boundary of the planar noise map, in units.
+ double m_lowerXBound;
+
+ /// Lower z boundary of the planar noise map, in units.
+ double m_lowerZBound;
+
+ /// Upper x boundary of the planar noise map, in units.
+ double m_upperXBound;
+
+ /// Upper z boundary of the planar noise map, in units.
+ double m_upperZBound;
+
+ };
+
+
+ /// Builds a spherical noise map.
+ ///
+ /// This class builds a noise map by filling it with coherent-noise values
+ /// generated from the surface of a sphere.
+ ///
+ /// This class describes these input values using a (latitude, longitude)
+ /// coordinate system. After generating the coherent-noise value from the
+ /// input value, it then "flattens" these coordinates onto a plane so that
+ /// it can write the values into a two-dimensional noise map.
+ ///
+ /// The sphere model has a radius of 1.0 unit. Its center is at the
+ /// origin.
+ ///
+ /// The x coordinate in the noise map represents the longitude. The y
+ /// coordinate in the noise map represents the latitude.
+ ///
+ /// The application must provide the southern, northern, western, and
+ /// eastern bounds of the noise map, in degrees.
+ class NoiseMapBuilderSphere: public NoiseMapBuilder
+ {
+
+ public:
+
+ /// Constructor.
+ NoiseMapBuilderSphere ();
+
+ virtual void Build ();
+
+ /// Returns the eastern boundary of the spherical noise map.
+ ///
+ /// @returns The eastern boundary of the noise map, in degrees.
+ double GetEastLonBound () const
+ {
+ return m_eastLonBound;
+ }
+
+ /// Returns the northern boundary of the spherical noise map
+ ///
+ /// @returns The northern boundary of the noise map, in degrees.
+ double GetNorthLatBound () const
+ {
+ return m_northLatBound;
+ }
+
+ /// Returns the southern boundary of the spherical noise map
+ ///
+ /// @returns The southern boundary of the noise map, in degrees.
+ double GetSouthLatBound () const
+ {
+ return m_southLatBound;
+ }
+
+ /// Returns the western boundary of the spherical noise map
+ ///
+ /// @returns The western boundary of the noise map, in degrees.
+ double GetWestLonBound () const
+ {
+ return m_westLonBound;
+ }
+
+ /// Sets the coordinate boundaries of the noise map.
+ ///
+ /// @param southLatBound The southern boundary of the noise map, in
+ /// degrees.
+ /// @param northLatBound The northern boundary of the noise map, in
+ /// degrees.
+ /// @param westLonBound The western boundary of the noise map, in
+ /// degrees.
+ /// @param eastLonBound The eastern boundary of the noise map, in
+ /// degrees.
+ ///
+ /// @pre The southern boundary is less than the northern boundary.
+ /// @pre The western boundary is less than the eastern boundary.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ void SetBounds (double southLatBound, double northLatBound,
+ double westLonBound, double eastLonBound)
+ {
+ if (southLatBound >= northLatBound
+ || westLonBound >= eastLonBound) {
+ throw noise::ExceptionInvalidParam ();
+ }
+
+ m_southLatBound = southLatBound;
+ m_northLatBound = northLatBound;
+ m_westLonBound = westLonBound ;
+ m_eastLonBound = eastLonBound ;
+ }
+
+ private:
+
+ /// Eastern boundary of the spherical noise map, in degrees.
+ double m_eastLonBound;
+
+ /// Northern boundary of the spherical noise map, in degrees.
+ double m_northLatBound;
+
+ /// Southern boundary of the spherical noise map, in degrees.
+ double m_southLatBound;
+
+ /// Western boundary of the spherical noise map, in degrees.
+ double m_westLonBound;
+
+ };
+
+ /// Renders an image from a noise map.
+ ///
+ /// This class renders an image given the contents of a noise-map object.
+ ///
+ /// An application can configure the output of the image in three ways:
+ /// - Specify the color gradient.
+ /// - Specify the light source parameters.
+ /// - Specify the background image.
+ ///
+ /// <b>Specify the color gradient</b>
+ ///
+ /// This class uses a color gradient to calculate the color for each pixel
+ /// in the destination image according to the value from the corresponding
+ /// position in the noise map.
+ ///
+ /// A color gradient is a list of gradually-changing colors. A color
+ /// gradient is defined by a list of <i>gradient points</i>. Each
+ /// gradient point has a position and a color. In a color gradient, the
+ /// colors between two adjacent gradient points are linearly interpolated.
+ ///
+ /// For example, suppose this class contains the following color gradient:
+ ///
+ /// - -1.0 maps to dark blue.
+ /// - -0.2 maps to light blue.
+ /// - -0.1 maps to tan.
+ /// - 0.0 maps to green.
+ /// - 1.0 maps to white.
+ ///
+ /// The value 0.5 maps to a greenish-white color because 0.5 is halfway
+ /// between 0.0 (mapped to green) and 1.0 (mapped to white).
+ ///
+ /// The value -0.6 maps to a medium blue color because -0.6 is halfway
+ /// between -1.0 (mapped to dark blue) and -0.2 (mapped to light blue).
+ ///
+ /// The color gradient requires a minimum of two gradient points.
+ ///
+ /// This class contains two pre-made gradients: a grayscale gradient and a
+ /// color gradient suitable for terrain. To use these pre-made gradients,
+ /// call the BuildGrayscaleGradient() or BuildTerrainGradient() methods,
+ /// respectively.
+ ///
+ /// @note The color value passed to AddGradientPoint() has an alpha
+ /// channel. This alpha channel specifies how a pixel in the background
+ /// image (if specified) is blended with the calculated color. If the
+ /// alpha value is high, this class weighs the blend towards the
+ /// calculated color, and if the alpha value is low, this class weighs the
+ /// blend towards the color from the corresponding pixel in the background
+ /// image.
+ ///
+ /// <b>Specify the light source parameters</b>
+ ///
+ /// This class contains a parallel light source that lights the image. It
+ /// interprets the noise map as a bump map.
+ ///
+ /// To enable or disable lighting, pass a Boolean value to the
+ /// EnableLight() method.
+ ///
+ /// To set the position of the light source in the "sky", call the
+ /// SetLightAzimuth() and SetLightElev() methods.
+ ///
+ /// To set the color of the light source, call the SetLightColor() method.
+ ///
+ /// To set the intensity of the light source, call the SetLightIntensity()
+ /// method. A good intensity value is 2.0, although that value tends to
+ /// "wash out" very light colors from the image.
+ ///
+ /// To set the contrast amount between areas in light and areas in shadow,
+ /// call the SetLightContrast() method. Determining the correct contrast
+ /// amount requires some trial and error, but if your application
+ /// interprets the noise map as a height map that has its elevation values
+ /// measured in meters and has a horizontal resolution of @a h meters, a
+ /// good contrast amount to use is ( 1.0 / @a h ).
+ ///
+ /// <b>Specify the background image</b>
+ ///
+ /// To specify a background image, pass an Image object to the
+ /// SetBackgroundImage() method.
+ ///
+ /// This class determines the color of a pixel in the destination image by
+ /// blending the calculated color with the color of the corresponding
+ /// pixel from the background image.
+ ///
+ /// The blend amount is determined by the alpha of the calculated color.
+ /// If the alpha value is high, this class weighs the blend towards the
+ /// calculated color, and if the alpha value is low, this class weighs the
+ /// blend towards the color from the corresponding pixel in the background
+ /// image.
+ ///
+ /// <b>Rendering the image</b>
+ ///
+ /// To render the image, perform the following steps:
+ /// - Pass a NoiseMap object to the SetSourceNoiseMap() method.
+ /// - Pass an Image object to the SetDestImage() method.
+ /// - Pass an Image object to the SetBackgroundImage() method (optional)
+ /// - Call the Render() method.
+ class RendererImage
+ {
+
+ public:
+
+ /// Constructor.
+ RendererImage ();
+
+ /// Adds a gradient point to this gradient object.
+ ///
+ /// @param gradientPos The position of this gradient point.
+ /// @param gradientColor The color of this gradient point.
+ ///
+ /// @pre No two gradient points have the same position.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ ///
+ /// This object uses a color gradient to calculate the color for each
+ /// pixel in the destination image according to the value from the
+ /// corresponding position in the noise map.
+ ///
+ /// The gradient requires a minimum of two gradient points.
+ ///
+ /// The specified color value passed to this method has an alpha
+ /// channel. This alpha channel specifies how a pixel in the
+ /// background image (if specified) is blended with the calculated
+ /// color. If the alpha value is high, this object weighs the blend
+ /// towards the calculated color, and if the alpha value is low, this
+ /// object weighs the blend towards the color from the corresponding
+ /// pixel in the background image.
+ void AddGradientPoint (double gradientPos,
+ const Color& gradientColor);
+
+ /// Builds a grayscale gradient.
+ ///
+ /// @post The original gradient is cleared and a grayscale gradient is
+ /// created.
+ ///
+ /// This color gradient contains the following gradient points:
+ /// - -1.0 maps to black
+ /// - 1.0 maps to white
+ void BuildGrayscaleGradient ();
+
+ /// Builds a color gradient suitable for terrain.
+ ///
+ /// @post The original gradient is cleared and a terrain gradient is
+ /// created.
+ ///
+ /// This gradient color at position 0.0 is the "sea level". Above
+ /// that value, the gradient contains greens, browns, and whites.
+ /// Below that value, the gradient contains various shades of blue.
+ void BuildTerrainGradient ();
+
+ /// Clears the color gradient.
+ ///
+ /// Before calling the Render() method, the application must specify a
+ /// new color gradient with at least two gradient points.
+ void ClearGradient ();
+
+ /// Enables or disables the light source.
+ ///
+ /// @param enable A flag that enables or disables the light source.
+ ///
+ /// If the light source is enabled, this object will interpret the
+ /// noise map as a bump map.
+ void EnableLight (bool enable = true)
+ {
+ m_isLightEnabled = enable;
+ }
+
+ /// Enables or disables noise-map wrapping.
+ ///
+ /// @param enable A flag that enables or disables noise-map wrapping.
+ ///
+ /// This object requires five points (the initial point and its four
+ /// neighbors) to calculate light shading. If wrapping is enabled,
+ /// and the initial point is on the edge of the noise map, the
+ /// appropriate neighbors that lie outside of the noise map will
+ /// "wrap" to the opposite side(s) of the noise map. Otherwise, the
+ /// appropriate neighbors are cropped to the edge of the noise map.
+ ///
+ /// Enabling wrapping is useful when creating spherical renderings and
+ /// tileable textures.
+ void EnableWrap (bool enable = true)
+ {
+ m_isWrapEnabled = enable;
+ }
+
+ /// Returns the azimuth of the light source, in degrees.
+ ///
+ /// @returns The azimuth of the light source.
+ ///
+ /// The azimuth is the location of the light source around the
+ /// horizon:
+ /// - 0.0 degrees is east.
+ /// - 90.0 degrees is north.
+ /// - 180.0 degrees is west.
+ /// - 270.0 degrees is south.
+ double GetLightAzimuth () const
+ {
+ return m_lightAzimuth;
+ }
+
+ /// Returns the brightness of the light source.
+ ///
+ /// @returns The brightness of the light source.
+ double GetLightBrightness () const
+ {
+ return m_lightBrightness;
+ }
+
+ /// Returns the color of the light source.
+ ///
+ /// @returns The color of the light source.
+ Color GetLightColor () const
+ {
+ return m_lightColor;
+ }
+
+ /// Returns the contrast of the light source.
+ ///
+ /// @returns The contrast of the light source.
+ ///
+ /// The contrast specifies how sharp the boundary is between the
+ /// light-facing areas and the shadowed areas.
+ ///
+ /// The contrast determines the difference between areas in light and
+ /// areas in shadow. Determining the correct contrast amount requires
+ /// some trial and error, but if your application interprets the noise
+ /// map as a height map that has a spatial resolution of @a h meters
+ /// and an elevation resolution of 1 meter, a good contrast amount to
+ /// use is ( 1.0 / @a h ).
+ double GetLightContrast () const
+ {
+ return m_lightContrast;
+ }
+
+ /// Returns the elevation of the light source, in degrees.
+ ///
+ /// @returns The elevation of the light source.
+ ///
+ /// The elevation is the angle above the horizon:
+ /// - 0 degrees is on the horizon.
+ /// - 90 degrees is straight up.
+ double GetLightElev () const
+ {
+ return m_lightElev;
+ }
+
+ /// Returns the intensity of the light source.
+ ///
+ /// @returns The intensity of the light source.
+ double GetLightIntensity () const
+ {
+ return m_lightIntensity;
+ }
+
+ /// Determines if the light source is enabled.
+ ///
+ /// @returns
+ /// - @a true if the light source is enabled.
+ /// - @a false if the light source is disabled.
+ bool IsLightEnabled () const
+ {
+ return m_isLightEnabled;
+ }
+
+ /// Determines if noise-map wrapping is enabled.
+ ///
+ /// @returns
+ /// - @a true if noise-map wrapping is enabled.
+ /// - @a false if noise-map wrapping is disabled.
+ ///
+ /// This object requires five points (the initial point and its four
+ /// neighbors) to calculate light shading. If wrapping is enabled,
+ /// and the initial point is on the edge of the noise map, the
+ /// appropriate neighbors that lie outside of the noise map will
+ /// "wrap" to the opposite side(s) of the noise map. Otherwise, the
+ /// appropriate neighbors are cropped to the edge of the noise map.
+ ///
+ /// Enabling wrapping is useful when creating spherical renderings and
+ /// tileable textures
+ bool IsWrapEnabled () const
+ {
+ return m_isWrapEnabled;
+ }
+
+ /// Renders the destination image using the contents of the source
+ /// noise map and an optional background image.
+ ///
+ /// @pre SetSourceNoiseMap() has been previously called.
+ /// @pre SetDestImage() has been previously called.
+ /// @pre There are at least two gradient points in the color gradient.
+ /// @pre No two gradient points have the same position.
+ /// @pre If a background image was specified, it has the exact same
+ /// size as the source height map.
+ ///
+ /// @post The original contents of the destination image is destroyed.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ ///
+ /// The background image and the destination image can safely refer to
+ /// the same image, although in this case, the destination image is
+ /// irretrievably blended into the background image.
+ void Render ();
+
+ /// Sets the background image.
+ ///
+ /// @param backgroundImage The background image.
+ ///
+ /// If a background image has been specified, the Render() method
+ /// blends the pixels from the background image onto the corresponding
+ /// pixels in the destination image. The blending weights are
+ /// determined by the alpha channel in the pixels in the destination
+ /// image.
+ ///
+ /// The destination image must exist throughout the lifetime of this
+ /// object unless another image replaces that image.
+ void SetBackgroundImage (const Image& backgroundImage)
+ {
+ m_pBackgroundImage = &backgroundImage;
+ }
+
+ /// Sets the destination image.
+ ///
+ /// @param destImage The destination image.
+ ///
+ /// The destination image will contain the rendered image after a
+ /// successful call to the Render() method.
+ ///
+ /// The destination image must exist throughout the lifetime of this
+ /// object unless another image replaces that image.
+ void SetDestImage (Image& destImage)
+ {
+ m_pDestImage = &destImage;
+ }
+
+ /// Sets the azimuth of the light source, in degrees.
+ ///
+ /// @param lightAzimuth The azimuth of the light source.
+ ///
+ /// The azimuth is the location of the light source around the
+ /// horizon:
+ /// - 0.0 degrees is east.
+ /// - 90.0 degrees is north.
+ /// - 180.0 degrees is west.
+ /// - 270.0 degrees is south.
+ ///
+ /// Make sure the light source is enabled via a call to the
+ /// EnableLight() method before calling the Render() method.
+ void SetLightAzimuth (double lightAzimuth)
+ {
+ m_lightAzimuth = lightAzimuth;
+ m_recalcLightValues = true;
+ }
+
+ /// Sets the brightness of the light source.
+ ///
+ /// @param lightBrightness The brightness of the light source.
+ ///
+ /// Make sure the light source is enabled via a call to the
+ /// EnableLight() method before calling the Render() method.
+ void SetLightBrightness (double lightBrightness)
+ {
+ m_lightBrightness = lightBrightness;
+ m_recalcLightValues = true;
+ }
+
+ /// Sets the color of the light source.
+ ///
+ /// @param lightColor The light color.
+ ///
+ /// Make sure the light source is enabled via a call to the
+ /// EnableLight() method before calling the Render() method.
+ void SetLightColor (const Color& lightColor)
+ {
+ m_lightColor = lightColor;
+ }
+
+ /// Sets the contrast of the light source.
+ ///
+ /// @param lightContrast The contrast of the light source.
+ ///
+ /// @pre The specified light contrast is positive.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ ///
+ /// The contrast specifies how sharp the boundary is between the
+ /// light-facing areas and the shadowed areas.
+ ///
+ /// The contrast determines the difference between areas in light and
+ /// areas in shadow. Determining the correct contrast amount requires
+ /// some trial and error, but if your application interprets the noise
+ /// map as a height map that has a spatial resolution of @a h meters
+ /// and an elevation resolution of 1 meter, a good contrast amount to
+ /// use is ( 1.0 / @a h ).
+ ///
+ /// Make sure the light source is enabled via a call to the
+ /// EnableLight() method before calling the Render() method.
+ void SetLightContrast (double lightContrast)
+ {
+ if (lightContrast <= 0.0) {
+ throw noise::ExceptionInvalidParam ();
+ }
+
+ m_lightContrast = lightContrast;
+ m_recalcLightValues = true;
+ }
+
+ /// Sets the elevation of the light source, in degrees.
+ ///
+ /// @param lightElev The elevation of the light source.
+ ///
+ /// The elevation is the angle above the horizon:
+ /// - 0 degrees is on the horizon.
+ /// - 90 degrees is straight up.
+ ///
+ /// Make sure the light source is enabled via a call to the
+ /// EnableLight() method before calling the Render() method.
+ void SetLightElev (double lightElev)
+ {
+ m_lightElev = lightElev;
+ m_recalcLightValues = true;
+ }
+
+ /// Returns the intensity of the light source.
+ ///
+ /// @returns The intensity of the light source.
+ ///
+ /// A good value for intensity is 2.0.
+ ///
+ /// Make sure the light source is enabled via a call to the
+ /// EnableLight() method before calling the Render() method.
+ void SetLightIntensity (double lightIntensity)
+ {
+ if (lightIntensity < 0.0) {
+ throw noise::ExceptionInvalidParam ();
+ }
+
+ m_lightIntensity = lightIntensity;
+ m_recalcLightValues = true;
+ }
+
+ /// Sets the source noise map.
+ ///
+ /// @param sourceNoiseMap The source noise map.
+ ///
+ /// The destination image must exist throughout the lifetime of this
+ /// object unless another image replaces that image.
+ void SetSourceNoiseMap (const NoiseMap& sourceNoiseMap)
+ {
+ m_pSourceNoiseMap = &sourceNoiseMap;
+ }
+
+ private:
+
+ /// Calculates the destination color.
+ ///
+ /// @param sourceColor The source color generated from the color
+ /// gradient.
+ /// @param backgroundColor The color from the background image at the
+ /// corresponding position.
+ /// @param lightValue The intensity of the light at that position.
+ ///
+ /// @returns The destination color.
+ Color CalcDestColor (const Color& sourceColor,
+ const Color& backgroundColor, double lightValue) const;
+
+ /// Calculates the intensity of the light given some elevation values.
+ ///
+ /// @param center Elevation of the center point.
+ /// @param left Elevation of the point directly left of the center
+ /// point.
+ /// @param right Elevation of the point directly right of the center
+ /// point.
+ /// @param down Elevation of the point directly below the center
+ /// point.
+ /// @param up Elevation of the point directly above the center point.
+ ///
+ /// These values come directly from the noise map.
+ double CalcLightIntensity (double center, double left, double right,
+ double down, double up) const;
+
+ /// The cosine of the azimuth of the light source.
+ mutable double m_cosAzimuth;
+
+ /// The cosine of the elevation of the light source.
+ mutable double m_cosElev;
+
+ /// The color gradient used to specify the image colors.
+ GradientColor m_gradient;
+
+ /// A flag specifying whether lighting is enabled.
+ bool m_isLightEnabled;
+
+ /// A flag specifying whether wrapping is enabled.
+ bool m_isWrapEnabled;
+
+ /// The azimuth of the light source, in degrees.
+ double m_lightAzimuth;
+
+ /// The brightness of the light source.
+ double m_lightBrightness;
+
+ /// The color of the light source.
+ Color m_lightColor;
+
+ /// The contrast between areas in light and areas in shadow.
+ double m_lightContrast;
+
+ /// The elevation of the light source, in degrees.
+ double m_lightElev;
+
+ /// The intensity of the light source.
+ double m_lightIntensity;
+
+ /// A pointer to the background image.
+ const Image* m_pBackgroundImage;
+
+ /// A pointer to the destination image.
+ Image* m_pDestImage;
+
+ /// A pointer to the source noise map.
+ const NoiseMap* m_pSourceNoiseMap;
+
+ /// Used by the CalcLightIntensity() method to recalculate the light
+ /// values only if the light parameters change.
+ ///
+ /// When the light parameters change, this value is set to True. When
+ /// the CalcLightIntensity() method is called, this value is set to
+ /// false.
+ mutable bool m_recalcLightValues;
+
+ /// The sine of the azimuth of the light source.
+ mutable double m_sinAzimuth;
+
+ /// The sine of the elevation of the light source.
+ mutable double m_sinElev;
+
+ };
+
+ /// Renders a normal map from a noise map.
+ ///
+ /// This class renders an image containing the normal vectors from a noise
+ /// map object. This image can then be used as a bump map for a 3D
+ /// application or game.
+ ///
+ /// This class encodes the (x, y, z) components of the normal vector into
+ /// the (red, green, blue) channels of the image. Like any 24-bit
+ /// true-color image, the channel values range from 0 to 255. 0
+ /// represents a normal coordinate of -1.0 and 255 represents a normal
+ /// coordinate of +1.0.
+ ///
+ /// You should also specify the <i>bump height</i> before rendering the
+ /// normal map. The bump height specifies the ratio of spatial resolution
+ /// to elevation resolution. For example, if your noise map has a spatial
+ /// resolution of 30 meters and an elevation resolution of one meter, set
+ /// the bump height to 1.0 / 30.0.
+ ///
+ /// <b>Rendering the normal map</b>
+ ///
+ /// To render the image containing the normal map, perform the following
+ /// steps:
+ /// - Pass a NoiseMap object to the SetSourceNoiseMap() method.
+ /// - Pass an Image object to the SetDestImage() method.
+ /// - Call the Render() method.
+ class RendererNormalMap
+ {
+
+ public:
+
+ /// Constructor.
+ RendererNormalMap ();
+
+ /// Enables or disables noise-map wrapping.
+ ///
+ /// @param enable A flag that enables or disables noise-map wrapping.
+ ///
+ /// This object requires three points (the initial point and the right
+ /// and up neighbors) to calculate the normal vector at that point.
+ /// If wrapping is/ enabled, and the initial point is on the edge of
+ /// the noise map, the appropriate neighbors that lie outside of the
+ /// noise map will "wrap" to the opposite side(s) of the noise map.
+ /// Otherwise, the appropriate neighbors are cropped to the edge of
+ /// the noise map.
+ ///
+ /// Enabling wrapping is useful when creating spherical and tileable
+ /// normal maps.
+ void EnableWrap (bool enable = true)
+ {
+ m_isWrapEnabled = enable;
+ }
+
+ /// Returns the bump height.
+ ///
+ /// @returns The bump height.
+ ///
+ /// The bump height specifies the ratio of spatial resolution to
+ /// elevation resolution. For example, if your noise map has a
+ /// spatial resolution of 30 meters and an elevation resolution of one
+ /// meter, set the bump height to 1.0 / 30.0.
+ ///
+ /// The spatial resolution and elevation resolution are determined by
+ /// the application.
+ double GetBumpHeight () const
+ {
+ return m_bumpHeight;
+ }
+
+ /// Determines if noise-map wrapping is enabled.
+ ///
+ /// @returns
+ /// - @a true if noise-map wrapping is enabled.
+ /// - @a false if noise-map wrapping is disabled.
+ ///
+ /// This object requires three points (the initial point and the right
+ /// and up neighbors) to calculate the normal vector at that point.
+ /// If wrapping is/ enabled, and the initial point is on the edge of
+ /// the noise map, the appropriate neighbors that lie outside of the
+ /// noise map will "wrap" to the opposite side(s) of the noise map.
+ /// Otherwise, the appropriate neighbors are cropped to the edge of
+ /// the noise map.
+ ///
+ /// Enabling wrapping is useful when creating spherical and tileable
+ /// normal maps.
+ bool IsWrapEnabled () const
+ {
+ return m_isWrapEnabled;
+ }
+
+ /// Renders the noise map to the destination image.
+ ///
+ /// @pre SetSourceNoiseMap() has been previously called.
+ /// @pre SetDestImage() has been previously called.
+ ///
+ /// @post The original contents of the destination image is destroyed.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ void Render ();
+
+ /// Sets the bump height.
+ ///
+ /// @param bumpHeight The bump height.
+ ///
+ /// The bump height specifies the ratio of spatial resolution to
+ /// elevation resolution. For example, if your noise map has a
+ /// spatial resolution of 30 meters and an elevation resolution of one
+ /// meter, set the bump height to 1.0 / 30.0.
+ ///
+ /// The spatial resolution and elevation resolution are determined by
+ /// the application.
+ void SetBumpHeight (double bumpHeight)
+ {
+ m_bumpHeight = bumpHeight;
+ }
+
+ /// Sets the destination image.
+ ///
+ /// @param destImage The destination image.
+ ///
+ /// The destination image will contain the normal map after a
+ /// successful call to the Render() method.
+ ///
+ /// The destination image must exist throughout the lifetime of this
+ /// object unless another image replaces that image.
+ void SetDestImage (Image& destImage)
+ {
+ m_pDestImage = &destImage;
+ }
+
+ /// Sets the source noise map.
+ ///
+ /// @param sourceNoiseMap The source noise map.
+ ///
+ /// The destination image must exist throughout the lifetime of this
+ /// object unless another image replaces that image.
+ void SetSourceNoiseMap (const NoiseMap& sourceNoiseMap)
+ {
+ m_pSourceNoiseMap = &sourceNoiseMap;
+ }
+
+ private:
+
+ /// Calculates the normal vector at a given point on the noise map.
+ ///
+ /// @param nc The height of the given point in the noise map.
+ /// @param nr The height of the left neighbor.
+ /// @param nu The height of the up neighbor.
+ /// @param bumpHeight The bump height.
+ ///
+ /// @returns The normal vector represented as a color.
+ ///
+ /// This method encodes the (x, y, z) components of the normal vector
+ /// into the (red, green, blue) channels of the returned color. In
+ /// order to represent the vector as a color, each coordinate of the
+ /// normal is mapped from the -1.0 to 1.0 range to the 0 to 255 range.
+ ///
+ /// The bump height specifies the ratio of spatial resolution to
+ /// elevation resolution. For example, if your noise map has a
+ /// spatial resolution of 30 meters and an elevation resolution of one
+ /// meter, set the bump height to 1.0 / 30.0.
+ ///
+ /// The spatial resolution and elevation resolution are determined by
+ /// the application.
+ Color CalcNormalColor (double nc, double nr, double nu,
+ double bumpHeight) const;
+
+ /// The bump height for the normal map.
+ double m_bumpHeight;
+
+ /// A flag specifying whether wrapping is enabled.
+ bool m_isWrapEnabled;
+
+ /// A pointer to the destination image.
+ Image* m_pDestImage;
+
+ /// A pointer to the source noise map.
+ const NoiseMap* m_pSourceNoiseMap;
+
+ };
+
+ }
+
+}
+
+#endif
diff --git a/noiseutils/readme.txt b/noiseutils/readme.txt
new file mode 100644
index 0000000..25d8428
--- /dev/null
+++ b/noiseutils/readme.txt
@@ -0,0 +1,4 @@
+noiseutils library - differences between 0.9.0 and 0.9.0.1
+
+- Added the noiseutils classes to the noise::utils namespace.
+
diff --git a/noiseutils/warnings.diff b/noiseutils/warnings.diff
new file mode 100644
index 0000000..24fc13c
--- /dev/null
+++ b/noiseutils/warnings.diff
@@ -0,0 +1,56 @@
+diff -u /home/snakebite/noiseutils/noiseutils.cpp ./noiseutils.cpp
+--- /home/snakebite/noiseutils/noiseutils.cpp 2005-06-07 21:49:24.000000000 +0200
++++ ./noiseutils.cpp 2011-05-07 14:32:36.000000000 +0200
+@@ -671,7 +671,6 @@
+ int height = m_pSourceNoiseMap->GetHeight ();
+
+ int bufferSize = CalcWidthByteCount (width);
+- int destSize = bufferSize * height;
+
+ // This buffer holds one horizontal line in the destination file.
+ noise::uint8* pLineBuffer = NULL;
+diff -u /home/snakebite/noiseutils/noiseutils.h ./noiseutils.h
+--- /home/snakebite/noiseutils/noiseutils.h 2005-06-07 21:46:42.000000000 +0200
++++ ./noiseutils.h 2011-05-07 14:32:06.000000000 +0200
+@@ -134,17 +134,17 @@
+ {
+ }
+
+- /// Value of the alpha (transparency) channel.
+- noise::uint8 alpha;
+-
+- /// Value of the blue channel.
+- noise::uint8 blue;
++ /// Value of the red channel.
++ noise::uint8 red;
+
+ /// Value of the green channel.
+ noise::uint8 green;
+
+- /// Value of the red channel.
+- noise::uint8 red;
++ /// Value of the blue channel.
++ noise::uint8 blue;
++
++ /// Value of the alpha (transparency) channel.
++ noise::uint8 alpha;
+
+ };
+
+@@ -1296,13 +1296,13 @@
+ /// Name of the file to write.
+ std::string m_destFilename;
+
++ /// A pointer to the noise map that will be written to the file.
++ NoiseMap* m_pSourceNoiseMap;
++
+ /// The distance separating adjacent points in the noise map, in
+ /// meters.
+ float m_metersPerPoint;
+
+- /// A pointer to the noise map that will be written to the file.
+- NoiseMap* m_pSourceNoiseMap;
+-
+ };
+
+ /// Abstract base class for a noise-map builder
diff --git a/server.cpp b/server.cpp
new file mode 100644
index 0000000..18e099c
--- /dev/null
+++ b/server.cpp
@@ -0,0 +1,105 @@
+#include "server.h"
+#include "messages.h"
+#include "terrain_generator.h"
+
+#include <iostream>
+
+Server::Server(boost::asio::io_service& io_service)
+ : acceptor(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), 54321)) {
+ TerrainGenerator::p gen(new TerrainGenerator(0, "map"));
+ cache = TerrainCache::p(new TerrainCache(gen, 500));
+ start_accept();
+}
+
+void Server::start_accept() {
+ Connection::p c(new Connection(acceptor.io_service()));
+ acceptor.async_accept(c->socket, boost::bind(&Server::handle_connect, this, c));
+}
+
+void Server::handle_connect(Connection::p connection) {
+ start_accept();
+
+ uint8_t type = message::MessageBase::read_type(connection->socket);
+ std::cout << "type: " << (int)type << std::endl;
+
+ message::Hello h;
+ //h.b = boost::asio::buffer(&version, sizeof(version));
+ std::cout << "reading payload" << std::endl;
+ h.read(connection->socket);
+ std::cout << "fetching version" << std::endl;
+ uint8_t version = h.read_version();
+ std::cout << "version: " << (int)version << std::endl;
+
+ async_read(connection);
+
+ /*boost::asio::streambuf b;
+ boost::asio::read_until(connection->get_socket(), b, '\n');
+
+ std::istream is(&b);
+ std::string s;
+ is >> s;
+ std::cout << s << std::endl;
+ for(std::list<Connection::p>::iterator it = clients.begin(); it != clients.end(); it++) {
+ boost::asio::write((*it)->get_socket(), boost::asio::buffer(s + "\n"));
+ }*/
+}
+
+void Server::async_read(Connection::p connection) {
+ uint8_t *t = new uint8_t;
+ boost::asio::async_read(connection->socket, boost::asio::buffer(t, sizeof(uint8_t)),
+ boost::asio::transfer_all(),
+ boost::bind(&Server::handle_message, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, connection, t));
+}
+
+void Server::handle_message(const boost::system::error_code& error, size_t bytes_transferred, Connection::p connection, uint8_t *_type) {
+ uint8_t type = *_type;
+ delete _type;
+
+ if(error) {
+ std::cerr << "error: " << error.message() << std::endl;
+ for(std::list<Connection::p>::iterator it = clients.begin(); it != clients.end(); it++) {
+ if(*it == connection) {
+ clients.erase(it);
+ break;
+ }
+ }
+ return;
+ }
+
+ switch(type) {
+ case message::MSG_TYPE_POS:
+ handle_pos(connection);
+ break;
+ case message::MSG_TYPE_CHUNK:
+ handle_chunk(connection);
+ break;
+ default:
+ std::cout << "unknown type: " << (int)type << std::endl;
+ }
+
+ async_read(connection);
+}
+
+void Server::handle_pos(Connection::p c) {
+ message::Pos m;
+
+ m.read(c->socket);
+ m.get_pos(c->pos.x, c->pos.y, c->pos.z);
+
+ std::set<std::pair<int64_t, int64_t> > chunks = c->check_chunks();
+ for(std::set<std::pair<int64_t, int64_t> >::iterator it = chunks.begin(); it != chunks.end(); it++) {
+ // TODO: fix sizes
+ TerrainCacheObject::p obj = cache->get_chunk(it->first, it->second, 35, 35);
+ message::Chunk chunk(it->first, it->second);
+ chunk.set_data(obj->heights);
+ chunk.send(c->socket);
+ }
+}
+
+void Server::handle_chunk(Connection::p c) {
+ message::Chunk m;
+
+ m.read(c->socket);
+ int64_t x, y;
+ m.get_coords(x, y);
+}
diff --git a/server.h b/server.h
new file mode 100644
index 0000000..8b0f637
--- /dev/null
+++ b/server.h
@@ -0,0 +1,33 @@
+#ifndef SERVER_H
+#define SERVER_H
+
+#include "connection.h"
+#include "terrain_cache.h"
+
+#include <boost/asio.hpp>
+#include <boost/bind.hpp>
+
+#include <list>
+
+class Server {
+ private:
+ boost::asio::ip::tcp::acceptor acceptor;
+ std::list<Connection::p> clients;
+
+ TerrainCache::p cache;
+
+ public:
+ Server(boost::asio::io_service& io_service);
+
+ void run();
+ void start_accept();
+
+ void handle_connect(Connection::p connection);
+ void async_read(Connection::p connection);
+ void handle_message(const boost::system::error_code& error, size_t bytes_transferred, Connection::p connection, uint8_t *_type);
+
+ void handle_pos(Connection::p c);
+ void handle_chunk(Connection::p c);
+};
+
+#endif
diff --git a/terrain_generator.cpp b/terrain_generator.cpp
new file mode 100644
index 0000000..a57f5d1
--- /dev/null
+++ b/terrain_generator.cpp
@@ -0,0 +1,48 @@
+#include "terrain_generator.h"
+
+#include <noise/noise.h>
+#include "noiseutils/noiseutils.h"
+
+using namespace noise;
+
+TerrainGenerator::TerrainGenerator(int seed, fs::path root) : TerrainLoader(root) {
+ this->seed = seed;
+}
+
+float *TerrainGenerator::generate_heights(int64_t x, int64_t y, unsigned int width, unsigned int height) {
+ const double scale_factor = 0.004;
+ module::Perlin mod;
+ mod.SetSeed(seed);
+
+ utils::NoiseMap heightmap;
+ utils::NoiseMapBuilderPlane heightmap_builder;
+
+ heightmap_builder.SetSourceModule(mod);
+ heightmap_builder.SetDestNoiseMap(heightmap);
+
+ heightmap_builder.SetDestSize(width, height);
+ // subtract by one due to chunk overlapping
+ heightmap_builder.SetBounds((double)(x-1) * scale_factor, (double)(x-1+width) * scale_factor,
+ (double)(y-1) * scale_factor, (double)(y-1+height) * scale_factor);
+ heightmap_builder.Build();
+
+ float *heights = new float[width*height];
+ for(unsigned int i = 0; i < width; i++) {
+ for(unsigned int j = 0; j < height; j++) {
+ heights[i*height + j] = 50*(1+heightmap.GetValue(i, j));
+ }
+ }
+
+ save_chunk(heights, x, y, width, height);
+
+ return heights;
+}
+
+float *TerrainGenerator::get_chunk(int64_t x, int64_t y, unsigned int width, unsigned int height) {
+ float *h;
+ if(has_chunk(x, y))
+ h = load_chunk(x, y, width, height);
+ else
+ h = generate_heights(x, y, width, height);
+ return h;
+}
diff --git a/terrain_generator.h b/terrain_generator.h
new file mode 100644
index 0000000..e301e7b
--- /dev/null
+++ b/terrain_generator.h
@@ -0,0 +1,18 @@
+#ifndef TERRAIN_GENERATOR_H
+#define TERRAIN_GENERATOR_H
+
+#include "terrain_loader.h"
+
+class TerrainGenerator : public TerrainLoader {
+ private:
+ int seed;
+
+ public:
+ TerrainGenerator(int seed, fs::path root);
+ virtual ~TerrainGenerator() {};
+
+ float *generate_heights(int64_t x, int64_t y, unsigned int width, unsigned int height);
+ virtual float *get_chunk(int64_t x, int64_t y, unsigned int width, unsigned int height);
+};
+
+#endif