netpbm: move netpbm into image library
This commit is contained in:
parent
379e652e83
commit
c31082716a
@ -196,8 +196,6 @@ UTIL_FILES = \
|
|||||||
net/socket.hpp \
|
net/socket.hpp \
|
||||||
net/types.cpp \
|
net/types.cpp \
|
||||||
net/types.hpp \
|
net/types.hpp \
|
||||||
netpbm.cpp \
|
|
||||||
netpbm.hpp \
|
|
||||||
nocopy.hpp \
|
nocopy.hpp \
|
||||||
noise.hpp \
|
noise.hpp \
|
||||||
noise.ipp \
|
noise.ipp \
|
||||||
|
156
netpbm.cpp
156
netpbm.cpp
@ -1,156 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* Copyright 2011-2015 Danny Robson <danny@nerdcruft.net>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "netpbm.hpp"
|
|
||||||
|
|
||||||
#include "io.hpp"
|
|
||||||
#include "except.hpp"
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// HACK: This does not support the full header structure with any robustness.
|
|
||||||
// In particular it will abort when it sees a comment. If you want better
|
|
||||||
// support use waif, or port its implementation.
|
|
||||||
util::image::buffer<1,uint8_t>
|
|
||||||
util::pgm::read (const boost::filesystem::path &path)
|
|
||||||
{
|
|
||||||
util::mapped_file raw (path.string ().c_str ());
|
|
||||||
|
|
||||||
std::ifstream cooked (path.string (), std::ios::binary);
|
|
||||||
char magic[2];
|
|
||||||
size_t width, height, scale;
|
|
||||||
char space;
|
|
||||||
|
|
||||||
cooked >> magic[0] >> magic[1] >> width >> height >> scale >> space;
|
|
||||||
|
|
||||||
if (magic[0] != 'P' && magic[1] != '5')
|
|
||||||
throw std::runtime_error ("invalid header magic");
|
|
||||||
|
|
||||||
if (width == 0 || height == 0 || scale == 0)
|
|
||||||
throw std::runtime_error ("zero width, height, or scale");
|
|
||||||
|
|
||||||
size_t expected = width * height;
|
|
||||||
size_t remain = raw.size () - cooked.tellg ();
|
|
||||||
if (expected != remain)
|
|
||||||
throw std::runtime_error ("expected data size mismatch");
|
|
||||||
|
|
||||||
util::image::buffer<1,uint8_t> out ({width, height});
|
|
||||||
|
|
||||||
CHECK (out.is_packed ());
|
|
||||||
std::copy (raw.begin () + cooked.tellg () - 1, raw.end (), out.begin ());
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static void
|
|
||||||
write_netpbm (const uint8_t *restrict pixels,
|
|
||||||
size_t components,
|
|
||||||
size_t width,
|
|
||||||
size_t height,
|
|
||||||
size_t stride,
|
|
||||||
std::ostream &output,
|
|
||||||
const char* MAGIC) {
|
|
||||||
CHECK (pixels);
|
|
||||||
CHECK_GT (components, 0);
|
|
||||||
CHECK_GT (width, 0);
|
|
||||||
CHECK_GE (stride, width);
|
|
||||||
CHECK_GT (height, 0);
|
|
||||||
|
|
||||||
// Write the PPM header.
|
|
||||||
output << MAGIC << "\n"
|
|
||||||
<< width << "\n"
|
|
||||||
<< height << "\n"
|
|
||||||
<< (size_t)std::numeric_limits<uint8_t>::max () << "\n";
|
|
||||||
|
|
||||||
// Write the data rows
|
|
||||||
for (size_t y = 0; y < height; ++y)
|
|
||||||
output.write (reinterpret_cast<const char*> (pixels + y * stride), width * components);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void
|
|
||||||
util::pgm::write (const util::image::buffer<1,uint8_t> &src,
|
|
||||||
std::ostream &dst)
|
|
||||||
{
|
|
||||||
write (src.begin (), src.extent ().w, src.extent ().h, src.stride ().y, dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void
|
|
||||||
util::pgm::write (const util::image::buffer<1,uint8_t> &src,
|
|
||||||
const boost::filesystem::path &path)
|
|
||||||
{
|
|
||||||
std::ofstream dst (path.string ());
|
|
||||||
write (src.begin (), src.extent ().w, src.extent ().h, src.stride ().y, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void
|
|
||||||
util::pgm::write (const uint8_t *restrict pixels,
|
|
||||||
size_t width,
|
|
||||||
size_t height,
|
|
||||||
size_t stride,
|
|
||||||
const boost::filesystem::path &path)
|
|
||||||
{
|
|
||||||
std::ofstream dst (path.string ());
|
|
||||||
write (pixels, width, height, stride, dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void
|
|
||||||
util::pgm::write (const uint8_t *restrict pixels,
|
|
||||||
size_t width,
|
|
||||||
size_t height,
|
|
||||||
size_t stride,
|
|
||||||
std::ostream &dst)
|
|
||||||
{
|
|
||||||
// TODO: We should switch between P2 (ascii) and P5 (binary)
|
|
||||||
static const char MAGIC[] = "P5";
|
|
||||||
write_netpbm (pixels, 1, width, height, stride, dst, MAGIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void
|
|
||||||
util::ppm::write (const uint8_t *restrict pixels,
|
|
||||||
size_t width,
|
|
||||||
size_t height,
|
|
||||||
size_t stride,
|
|
||||||
const boost::filesystem::path &path)
|
|
||||||
{
|
|
||||||
std::ofstream dst (path.string ());
|
|
||||||
write (pixels, width, height, stride, dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void
|
|
||||||
util::ppm::write (const uint8_t *restrict pixels,
|
|
||||||
size_t width,
|
|
||||||
size_t height,
|
|
||||||
size_t stride,
|
|
||||||
std::ostream &dst)
|
|
||||||
{
|
|
||||||
// TODO: We should switch between P3 (ascii) and P6 (binary)
|
|
||||||
static const char MAGIC[] = "P6";
|
|
||||||
write_netpbm (pixels, 3, width, height, stride, dst, MAGIC);
|
|
||||||
}
|
|
64
netpbm.hpp
64
netpbm.hpp
@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* Copyright 2011-2015 Danny Robson <danny@nerdcruft.net>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __UTIL_NETPBM_HPP
|
|
||||||
#define __UTIL_NETPBM_HPP
|
|
||||||
|
|
||||||
#include "./image/buffer.hpp"
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <ostream>
|
|
||||||
#include <boost/filesystem/path.hpp>
|
|
||||||
|
|
||||||
namespace util {
|
|
||||||
// Portable GrayMap: single component greyscale.
|
|
||||||
struct pgm {
|
|
||||||
static image::buffer<1,uint8_t> read (const boost::filesystem::path&);
|
|
||||||
|
|
||||||
static void write (const image::buffer<1,uint8_t> &src,
|
|
||||||
const boost::filesystem::path &dst);
|
|
||||||
static void write (const image::buffer<1,uint8_t> &src,
|
|
||||||
std::ostream &dst);
|
|
||||||
|
|
||||||
static void write (const uint8_t *restrict pixels,
|
|
||||||
size_t width,
|
|
||||||
size_t height,
|
|
||||||
size_t stride,
|
|
||||||
std::ostream &dst);
|
|
||||||
static void write (const uint8_t *restrict pixels,
|
|
||||||
size_t width,
|
|
||||||
size_t height,
|
|
||||||
size_t stride,
|
|
||||||
const boost::filesystem::path &path);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Portable PixMap: 3-component colour images.
|
|
||||||
struct ppm {
|
|
||||||
static void write (const uint8_t *restrict pixels,
|
|
||||||
size_t width,
|
|
||||||
size_t height,
|
|
||||||
size_t stride,
|
|
||||||
const boost::filesystem::path &path);
|
|
||||||
static void write (const uint8_t *restrict pixels,
|
|
||||||
size_t width,
|
|
||||||
size_t height,
|
|
||||||
size_t stride,
|
|
||||||
std::ostream &dst);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
397
tools/noise.cpp
397
tools/noise.cpp
@ -1,397 +0,0 @@
|
|||||||
#include "image/buffer.hpp"
|
|
||||||
#include "noise.hpp"
|
|
||||||
|
|
||||||
#include "noise/fractal/fbm.hpp"
|
|
||||||
#include "noise/fractal/hetero.hpp"
|
|
||||||
#include "noise/fractal/hmf.hpp"
|
|
||||||
#include "noise/fractal/rmf.hpp"
|
|
||||||
#include "noise/fractal/runtime.hpp"
|
|
||||||
#include "noise/lerp.hpp"
|
|
||||||
#include "noise/basis/constant.hpp"
|
|
||||||
#include "noise/basis/gradient/exp.hpp"
|
|
||||||
#include "noise/basis/value.hpp"
|
|
||||||
#include "noise/basis/patch.hpp"
|
|
||||||
#include "noise/basis/perlin.hpp"
|
|
||||||
#include "noise/basis/worley.hpp"
|
|
||||||
#include "noise/turbulence.hpp"
|
|
||||||
#include "noise/basis/runtime.hpp"
|
|
||||||
#include "noise/midpoint.hpp"
|
|
||||||
#include "extent.hpp"
|
|
||||||
#include "colour.hpp"
|
|
||||||
#include "netpbm.hpp"
|
|
||||||
#include "types.hpp"
|
|
||||||
#include "cmdopt.hpp"
|
|
||||||
#include "hash.hpp"
|
|
||||||
#include "region.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
constexpr size_t S = 2;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
template struct util::noise::fractal::rmf<util::noise::basis::constant<S,float>>;
|
|
||||||
|
|
||||||
template struct util::noise::fractal::fbm<
|
|
||||||
util::noise::basis::perlin<
|
|
||||||
S,float,util::lerp::cubic,util::noise::basis::gradient::uniform
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
|
|
||||||
template struct util::noise::fractal::fbm<
|
|
||||||
util::noise::basis::perlin<
|
|
||||||
S,float,util::lerp::quintic,util::noise::basis::gradient::exp
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
|
|
||||||
template struct util::noise::fractal::hmf<
|
|
||||||
util::noise::basis::value<
|
|
||||||
S,float,util::lerp::cubic
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
|
|
||||||
template struct util::noise::fractal::hetero<util::noise::basis::worley<S,float>>;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
enum basis_t {
|
|
||||||
VALUE,
|
|
||||||
PERLIN,
|
|
||||||
WORLEY,
|
|
||||||
PATCH,
|
|
||||||
EXPDIST
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
enum fractal_t {
|
|
||||||
FBM,
|
|
||||||
HMF,
|
|
||||||
RMF,
|
|
||||||
HETERO,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
enum lerp_t {
|
|
||||||
LINEAR,
|
|
||||||
CUBIC,
|
|
||||||
QUINTIC,
|
|
||||||
COSINE,
|
|
||||||
TRUNC
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
std::istream&
|
|
||||||
operator>> (std::istream &is, basis_t &b)
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
is >> name;
|
|
||||||
|
|
||||||
b = name == "value" ? VALUE :
|
|
||||||
name == "perlin" ? PERLIN :
|
|
||||||
name == "worley" ? WORLEY :
|
|
||||||
name == "patch" ? PATCH :
|
|
||||||
name == "expgrad" ? EXPDIST :
|
|
||||||
(is.setstate (std::istream::failbit), b);
|
|
||||||
|
|
||||||
return is;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
std::ostream&
|
|
||||||
operator<< (std::ostream &os, basis_t b)
|
|
||||||
{
|
|
||||||
switch (b) {
|
|
||||||
case VALUE: os << "value"; return os;
|
|
||||||
case PERLIN: os << "perlin"; return os;
|
|
||||||
case WORLEY: os << "worley"; return os;
|
|
||||||
case PATCH: os << "patch"; return os;
|
|
||||||
case EXPDIST: os << "expgrad"; return os;
|
|
||||||
|
|
||||||
default:
|
|
||||||
unreachable ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
std::istream&
|
|
||||||
operator>> (std::istream &is, fractal_t &f)
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
is >> name;
|
|
||||||
|
|
||||||
f = name == "fbm" ? FBM :
|
|
||||||
name == "hmf" ? HMF :
|
|
||||||
name == "rmf" ? RMF :
|
|
||||||
name == "hetero" ? HETERO :
|
|
||||||
(is.setstate (std::istream::failbit), f);
|
|
||||||
|
|
||||||
return is;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
std::ostream&
|
|
||||||
operator<< (std::ostream &os, fractal_t f)
|
|
||||||
{
|
|
||||||
switch (f) {
|
|
||||||
case FBM: os << "fbm"; return os;
|
|
||||||
case HMF: os << "hmf"; return os;
|
|
||||||
case RMF: os << "rmf"; return os;
|
|
||||||
case HETERO: os << "hetero"; return os;
|
|
||||||
|
|
||||||
default:
|
|
||||||
unreachable ();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
std::istream&
|
|
||||||
operator>> (std::istream &is, lerp_t &l)
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
is >> name;
|
|
||||||
|
|
||||||
l = name == "linear" ? LINEAR :
|
|
||||||
name == "cubic" ? CUBIC :
|
|
||||||
name == "quintic" ? QUINTIC :
|
|
||||||
name == "cosine" ? COSINE :
|
|
||||||
name == "trunc" ? TRUNC :
|
|
||||||
(is.setstate (std::istream::failbit), l);
|
|
||||||
|
|
||||||
return is;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
std::ostream&
|
|
||||||
operator<< (std::ostream &os, lerp_t &l)
|
|
||||||
{
|
|
||||||
switch (l) {
|
|
||||||
case LINEAR: os << "linear"; return os;
|
|
||||||
case CUBIC: os << "cubic"; return os;
|
|
||||||
case QUINTIC: os << "quintic"; return os;
|
|
||||||
case COSINE: os << "cosine"; return os;
|
|
||||||
case TRUNC: os << "trunc"; return os;
|
|
||||||
|
|
||||||
default:
|
|
||||||
unreachable ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
int
|
|
||||||
main (int argc, char **argv)
|
|
||||||
{
|
|
||||||
// setup default variables
|
|
||||||
#ifdef ENABLE_DEBUGGING
|
|
||||||
util::extent2u res {320, 240};
|
|
||||||
#else
|
|
||||||
util::extent2u res {1920, 1080};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
srand (time (nullptr));
|
|
||||||
uint64_t seed = time (nullptr);
|
|
||||||
|
|
||||||
basis_t basis = PERLIN;
|
|
||||||
fractal_t fractal = FBM;
|
|
||||||
lerp_t lerp = QUINTIC;
|
|
||||||
unsigned octaves = 8;
|
|
||||||
float H = std::numeric_limits<float>::quiet_NaN ();
|
|
||||||
float lacunarity = std::numeric_limits<float>::quiet_NaN ();
|
|
||||||
float amplitude = std::numeric_limits<float>::quiet_NaN ();
|
|
||||||
float gain = std::numeric_limits<float>::quiet_NaN ();
|
|
||||||
float offset = std::numeric_limits<float>::quiet_NaN ();
|
|
||||||
float scale = 1.f;
|
|
||||||
float turbulence = 0.f;
|
|
||||||
unsigned single = 0;
|
|
||||||
float width = 0;
|
|
||||||
|
|
||||||
// fill variables from arguments
|
|
||||||
util::cmdopt::parser args;
|
|
||||||
args.add<util::cmdopt::option::value<size_t>> ('w', "width", "output image width", res.w);
|
|
||||||
args.add<util::cmdopt::option::value<size_t>> ('h', "height", "output image height", res.h);
|
|
||||||
args.add<util::cmdopt::option::value<uint64_t>> ('s', "seed", "random seed", seed);
|
|
||||||
args.add<util::cmdopt::option::value<basis_t>> ('b', "basis", "primary basis function", basis);
|
|
||||||
args.add<util::cmdopt::option::value<fractal_t>> ('f', "fractal", "primary fractal function", fractal);
|
|
||||||
args.add<util::cmdopt::option::value<lerp_t>> ('l', "lerp", "interpolation algorithm", lerp);
|
|
||||||
args.add<util::cmdopt::option::value<unsigned>> ('o', "octaves", "total fractal iterations", octaves);
|
|
||||||
args.add<util::cmdopt::option::count<unsigned>> ('1', "single", "single octave", single);
|
|
||||||
args.add<util::cmdopt::option::value<float>> ('H', "hurst", "Hurst exponent", H);
|
|
||||||
args.add<util::cmdopt::option::value<float>> ('G', "gain", "octave gain", gain);
|
|
||||||
args.add<util::cmdopt::option::value<float>> ('A', "amplitude", "base amplitude", amplitude);
|
|
||||||
args.add<util::cmdopt::option::value<float>> ('L', "lacunarity", "frequency multiplier", lacunarity);
|
|
||||||
args.add<util::cmdopt::option::value<float>> ('x', "scale", "frequency multiplier", scale);
|
|
||||||
args.add<util::cmdopt::option::value<float>> ('O', "offset", "hetero offset", offset);
|
|
||||||
args.add<util::cmdopt::option::value<float>> ('t', "turbulence", "turbulence scale", turbulence);
|
|
||||||
args.add<util::cmdopt::option::value<float>> ('W', "patch-width", "patch blur width", width);
|
|
||||||
|
|
||||||
args.scan (argc, argv);
|
|
||||||
|
|
||||||
#if !defined(ENABLE_DEBUGGING) and !defined(PLATFORM_WIN32)
|
|
||||||
if (isatty (fileno (stdout))) {
|
|
||||||
std::cerr << "cowardly refusing to dump binary data to console\n";
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
util::noise::turbulence<
|
|
||||||
util::noise::fractal::runtime<
|
|
||||||
util::noise::basis::runtime<S,float>
|
|
||||||
>,
|
|
||||||
util::noise::fractal::fbm<
|
|
||||||
util::noise::basis::perlin<
|
|
||||||
S,float,
|
|
||||||
util::lerp::cubic
|
|
||||||
>
|
|
||||||
>
|
|
||||||
> t (seed, util::vectorf<S> (turbulence));
|
|
||||||
|
|
||||||
auto &f = t.data;
|
|
||||||
|
|
||||||
switch (fractal) {
|
|
||||||
using namespace util::noise;
|
|
||||||
|
|
||||||
case FBM: f.reset<fractal::fbm<basis::runtime<S,float>>> (seed); break;
|
|
||||||
case HMF: f.reset<fractal::hmf<basis::runtime<S,float>>> (seed); break;
|
|
||||||
case RMF: f.reset<fractal::rmf<basis::runtime<S,float>>> (seed); break;
|
|
||||||
case HETERO: {
|
|
||||||
auto &child = f.reset<fractal::hetero<basis::runtime<S,float>>> (seed);
|
|
||||||
if (!std::isnan (offset))
|
|
||||||
child.offset (offset);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
unreachable ();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &b = f.basis ();
|
|
||||||
switch (basis) {
|
|
||||||
using namespace util::noise;
|
|
||||||
|
|
||||||
case PERLIN: {
|
|
||||||
switch (lerp) {
|
|
||||||
case LINEAR: b.reset<basis::perlin<S,float,util::lerp::linear>> (seed); break;
|
|
||||||
case CUBIC: b.reset<basis::perlin<S,float,util::lerp::cubic>> (seed); break;
|
|
||||||
case QUINTIC: b.reset<basis::perlin<S,float,util::lerp::quintic>> (seed); break;
|
|
||||||
case COSINE: b.reset<basis::perlin<S,float,util::lerp::cosine>> (seed); break;
|
|
||||||
case TRUNC: b.reset<basis::perlin<S,float,util::lerp::truncate>> (seed); break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
unreachable ();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case EXPDIST: {
|
|
||||||
switch (lerp) {
|
|
||||||
case LINEAR: b.reset<
|
|
||||||
basis::perlin<
|
|
||||||
S,float,util::lerp::linear,basis::gradient::exp
|
|
||||||
>
|
|
||||||
> (seed); break;
|
|
||||||
|
|
||||||
case CUBIC: b.reset<basis::perlin<S,float,util::lerp::cubic,basis::gradient::exp>> (seed); break;
|
|
||||||
case QUINTIC: b.reset<basis::perlin<S,float,util::lerp::quintic,basis::gradient::exp>> (seed); break;
|
|
||||||
case COSINE: b.reset<basis::perlin<S,float,util::lerp::cosine,basis::gradient::exp>> (seed); break;
|
|
||||||
case TRUNC: b.reset<basis::perlin<S,float,util::lerp::truncate,basis::gradient::exp>> (seed); break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
unreachable ();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case VALUE: {
|
|
||||||
switch (lerp) {
|
|
||||||
case LINEAR: b.reset<basis::value<S,float,util::lerp::linear>> (seed); break;
|
|
||||||
case CUBIC: b.reset<basis::value<S,float,util::lerp::cubic>> (seed); break;
|
|
||||||
case QUINTIC: b.reset<basis::value<S,float,util::lerp::quintic>> (seed); break;
|
|
||||||
case COSINE: b.reset<basis::value<S,float,util::lerp::cosine>> (seed); break;
|
|
||||||
case TRUNC: b.reset<basis::value<S,float,util::lerp::truncate>> (seed); break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
unreachable ();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WORLEY: {
|
|
||||||
b.reset<util::noise::basis::worley<S,float>> (seed);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PATCH: {
|
|
||||||
b.reset<util::noise::basis::patch<S,float>> (seed, width);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
unreachable ();
|
|
||||||
}
|
|
||||||
|
|
||||||
t.seed (seed);
|
|
||||||
f.octaves (octaves);
|
|
||||||
f.frequency (scale / res.w);
|
|
||||||
if (!std::isnan (H)) f.H (H);
|
|
||||||
if (!std::isnan (lacunarity)) f.lacunarity (lacunarity);
|
|
||||||
if (!std::isnan (amplitude)) f.amplitude (amplitude);
|
|
||||||
if (!std::isnan (gain)) f.gain (gain);
|
|
||||||
|
|
||||||
for (auto &p: t.perturb)
|
|
||||||
p.frequency (scale / res.w);
|
|
||||||
|
|
||||||
util::image::buffer<1,float> img (res);
|
|
||||||
|
|
||||||
// XXX: offset slightly to avoid origin artefacts in some basis functions
|
|
||||||
const auto OFFSET = util::vector2f {
|
|
||||||
(util::hash::mix ( seed) & 0xFFFF) / float (0xFFFF),
|
|
||||||
(util::hash::mix (util::hash::mix (seed)) & 0xFFFF) / float (0xFFFF)
|
|
||||||
} / f.frequency ();
|
|
||||||
|
|
||||||
{
|
|
||||||
for (size_t y = 0; y < res.h; ++y)
|
|
||||||
for (size_t x = 0; x < res.w; ++x) {
|
|
||||||
util::point2f p (x, y);
|
|
||||||
img[{x, y}] = t ((p + OFFSET).redim<S> ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// working on the assumption that all octave images are based on summation,
|
|
||||||
// subtract the image with one less octave from our current image to leave
|
|
||||||
// us with the highest octave contribution only. this is hideously
|
|
||||||
// inefficient, but it's not an operation we care about in general.
|
|
||||||
if (single && f.octaves () != 1) {
|
|
||||||
auto oldoctaves = f.octaves ();
|
|
||||||
f.octaves (oldoctaves - 1);
|
|
||||||
auto prev = img.clone ();
|
|
||||||
|
|
||||||
for (size_t y = 0; y < res.h; ++y)
|
|
||||||
for (size_t x = 0; x < res.w; ++x) {
|
|
||||||
util::point2f p (x, y);
|
|
||||||
prev[{x,y}] = t ((p + OFFSET).redim<S> ());
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK_EQ (img.stride (), prev.stride ());
|
|
||||||
for (size_t i = 0; i < img.size (); ++i)
|
|
||||||
img[i] -= prev[i];
|
|
||||||
|
|
||||||
f.octaves (oldoctaves);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rescale into the range [0, 1]
|
|
||||||
auto range = std::minmax_element (img.begin (), img.end ());
|
|
||||||
auto inc = *range.first;
|
|
||||||
auto div = *range.second - *range.first;
|
|
||||||
|
|
||||||
std::cerr << '[' << *range.first << ',' << *range.second << "]\n";
|
|
||||||
std::transform (img.begin (), img.end (), img.begin (), [inc,div] (auto i) { return (i - inc) / div; });
|
|
||||||
|
|
||||||
// write the images to disk
|
|
||||||
util::pgm::write (img.cast<uint8_t> (), std::cout);
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user