#include "map.h" #include #include #include #include #include #include #include #include using namespace std::chrono; #include using std::vector; using std::string; using std::cin; using std::cout; using std::cerr; using std::clog; using std::endl; extern char** environ; static constexpr inline float plateau(const float r) { return r*r/(r*r+1); } template static constexpr inline T square(const T x) { return x*x; } template static constexpr inline T polar_r(const T x, const T y) { return sqrt(x*x*.1f+y*y*.1f); } template static constexpr inline T polar_t(const T x, const T y) { return atan2(x,y); } vector>& genSpiral( const bool archimedian, vector>& buf, const vector& x_vals, const vector& y_vals); vector>& genWeather( vector>& buf, const vector& x_vals, const vector& y_vals); template class pixel_traits { public: static P to_pix(size_t i, const png::palette& cmap [[maybe_unused]]) { return i; } }; template <> class pixel_traits { public: static png::rgb_pixel to_pix(size_t i, const png::palette& cmap) { auto c = cmap[i]; return png::rgb_pixel(c.red, c.green, c.blue); } }; //filename left lower width pixels template void genMap(vector inList) { float seed = 5867; std::deque> ts; ts.push_back({steady_clock::now(),"Begin"}); //generate a square image tile //const static unsigned short tileSize = 256; unsigned short tileSize = pFromStr(unsigned short, inList[5]); png::image image(tileSize,tileSize); png::palette cmap; auto a = string::npos; unsigned cmapID; if ((a = inList[0].find_first_of("0123456789ABCDEFabcdef")) != string::npos) { cmapID = stoi(inList[0].substr(a,1), nullptr, 16); std::string name; std::tie(name, cmap) = current_cmap.at(cmapID); #ifdef _DEBUG // clog<<"Using colormap "< x_vals(tileSize), y_vals(tileSize); float xdiff = (xmax-xmin)/tileSize, ydiff = (ymax-ymin)/tileSize; for (int i = 0; i < tileSize; ++i) { x_vals[i] = xmin + xdiff*i; y_vals[i] = ymin + ydiff*i; } // ts.push_back({steady_clock::now(),"Setup noise"}); SimplexNoise noise(10, 0.65, 2.06, 0.0009f, 65); vector> imgBuf(tileSize,vector(tileSize,0.f)); //noise.makeSomeNoise(imgBuf, seed); imgBuf = noise.genNoise(x_vals, y_vals, seed); ts.push_back({steady_clock::now(),"Simplex"}); genSpiral(inList[0][1] != 'l', imgBuf, x_vals, y_vals); // genWeather(imgBuf, x_vals, y_vals); ts.push_back({steady_clock::now(),"Apply spiral"}); size_t V = 0, clipmin = 0, clipmax = cmap.size()-1; float limmin = 0+.5f, limmax = static_cast(cmap.size())-0.5f; for (size_t x = 0; x < tileSize; ++x) { for (size_t y = 0; y < tileSize; ++y) { // double temp = imgBuf[x][y] + 255 - fabs(imgBuf[x][y]-255); // V = (temp + fabs(temp)) * 0.25; auto h = (imgBuf[x][y]/256)*cmap.size(); V = (h < limmin) ? clipmin : ( (h > limmax) ? clipmax : static_cast(h) ); image[x][y] = pixel_traits::to_pix(V, cmap); } } ts.push_back({steady_clock::now(),"Fill image"}); if (inList[1] != "-") image.write(inList[1]); else image.template write_stream(cout); ts.push_back({steady_clock::now(),"Write Image"}); if (verbose) { auto prev = ts[0]; ts.pop_front(); for (auto i : ts) { clog<(i.first-prev.first).count()<<"ms\t"<(std::vector); template void genMap(std::vector); template png::image genMap_impl( unsigned cmapID, bool archimedian, float xmin, float ymin, float width, int tileSize) { float seed = 5867; std::deque> ts; ts.push_back({steady_clock::now(),"Begin"}); //generate a square image tile png::image image(tileSize,tileSize); png::palette cmap = current_cmap[cmapID].second; image.set_palette(cmap); // ts.push_back({steady_clock::now(),"Setup image"}); float xmax = xmin+width, ymax = ymin+width; vector x_vals(tileSize), y_vals(tileSize); float xdiff = (xmax-xmin)/tileSize, ydiff = (ymax-ymin)/tileSize; for (int i = 0; i < tileSize; ++i) { x_vals[i] = xmin + xdiff*i; y_vals[i] = ymin + ydiff*i; } ts.push_back({steady_clock::now(),"Setup noise"}); SimplexNoise noise(7, 0.65, 2.06, 0.0009f, 65); vector> imgBuf(tileSize,vector(tileSize,0.f)); //noise.makeSomeNoise(imgBuf, seed); imgBuf = noise.genNoise(x_vals, y_vals, seed); ts.push_back({steady_clock::now(),"Simplex"}); genSpiral(archimedian, imgBuf, x_vals, y_vals); // genWeather(imgBuf, x_vals, y_vals); ts.push_back({steady_clock::now(),"Apply spiral"}); size_t V = 0, clipmin = 0, clipmax = cmap.size()-1; float limmin = 0+.5f, limmax = static_cast(cmap.size())-0.5f; for (int x = 0; x < tileSize; ++x) { for (int y = 0; y < tileSize; ++y) { // double temp = imgBuf[x][y] + 255 - fabs(imgBuf[x][y]-255); // V = (temp + fabs(temp)) * 0.25; auto h = (imgBuf[x][y]/256)*cmap.size(); V = (h < limmin) ? clipmin : ( (h > limmax) ? clipmax : static_cast(h) ); image[x][y] = pixel_traits::to_pix(V, cmap); } } ts.push_back({steady_clock::now(),"Fill image"}); if (verbose) { auto prev = ts[0]; ts.pop_front(); for (auto i : ts) { clog<(i.first-prev.first).count()<<"ms\t"< genMap_impl( unsigned cmapID, bool archimedian, float xmin, float ymin, float width, int tileSize); template png::image genMap_impl( unsigned cmapID, bool archimedian, float xmin, float ymin, float width, int tileSize); vector>& genSpiral( const bool archimedian, vector>& buf, const vector& x_vals, const vector& y_vals) { //Some constants constexpr float pi_up = 3.141593, //Pi, rounded slightly up // pi_down = 3.141592, //and down //Spiral term (shared) spiral_strength = 60, //How strong the spiral motif is //Spiral term (archimedian) spiral_tightness = 0.05, //turning pitch of spiral spiral_sharpness = 1.40, //how much to exaggerate peaks by (exponential) spiral_negative_bias = 1.2, //how much to subtract from spiral term spiral_flatness = 1/1.25, //how much to dampen peaks by (linear) //Plateau term plt_radius = 150, //Radius of the central plateau in ADU // plt_height = 24, //How high the central plateau is (logarithmic) plt_height_a = 48, //How high the central plateau is (archimedian) plt_cliffiness = 20, //How smooth the slope to the central plateau is plt_cliffiness_x = 1/plt_cliffiness, // plt_prescale = 1.15, //Scales the plateau term before normalization plt_flatness = 1.3, //How much to flatten the central plateau by // plt_l10n_adj = plt_height_a/35-pi_down, //Reduces the large-scale effect of the plateau term plateau_hinge = 160, // plt_l10n_adj2 = plt_l10n_adj/24, //Noise term noise_hinge = 155, //Hinge which noise will be scaled away from noise_scale = 1.20, //How much to scale noise by //Adjustment // sea_level = 135, sea_adjustment = noise_hinge - 8; //Overall factor to adjust the map height by const float //Spiral term (log) spiral_curviness = 1.12, //Base of the logarithm used for the spiral spiral_curviness_x = 1/log(spiral_curviness); // vector>> pc(x_vals.size(), vector>(y_vals.size())); // ts.push_back({steady_clock::now(),"Process setup"}); for (size_t x = 0; x < x_vals.size(); ++x) { for (size_t y = 0; y < y_vals.size(); ++y) { auto r = polar_r(x_vals[x],y_vals[y]), t = polar_t(x_vals[x],y_vals[y]); // float r = sqrt(x_vals[x]*x_vals[x]*.1f+y_vals[y]*y_vals[y]*.1f); // float t = atan2(x_vals[x],y_vals[y]); buf[x][y] = (buf[x][y]-noise_hinge)*noise_scale +sea_adjustment; if (archimedian) { buf[x][y] += spiral_strength *(pow( (sin( t +spiral_tightness*r )+1.f), spiral_sharpness) *spiral_flatness -spiral_negative_bias); } else { buf[x][y] += spiral_strength *(pow( (sin( t +spiral_curviness_x*log(r) )+1.f), spiral_sharpness) *spiral_flatness -spiral_negative_bias); } auto p = atan(plt_cliffiness_x*(r-plt_radius))/(pi_up)+0.5; buf[x][y] = (buf[x][y]-plateau_hinge) /((1+square(plt_flatness))-square(plt_flatness*p)) +plt_height_a*(1-p)+plateau_hinge; } } return buf; } static inline bool absLess(float a, float b) { return std::abs(a) < std::abs(b); } template auto deref(std::pair&& p) { return std::tie(*p.first, *p.second); } vector>& genWeather( vector>& buf, const vector& x_vals, const vector& y_vals) { assert(x_vals.size() == y_vals.size() && x_vals.size() > 0); double minx, miny, maxx, maxy; std::tie(minx, maxx) = deref(std::minmax_element( x_vals.begin(), x_vals.end(), absLess )); std::tie(miny, maxy) = deref(std::minmax_element( y_vals.begin(), y_vals.end(), absLess )); double minr{sqrt(square(minx)+square(miny))}, maxr{sqrt(square(maxx)+square(maxy))+1}; clog<= numMaps) return ret; switch (type) { case 0://Greyscale for (short x = 0; x < 256; ++x) { ret[x] = png::color(x,x,x); } break; case 1://Natural for (short x = 0; x < 256; ++x) { if (x < 132) {//ocean ret[x] = png::color( 0,x/3+4*static_cast(static_cast(x)*x/768.),x+70 ); } else if (x < 136) {//beach ret[x] = png::color(240,240,64); } else if (x < 200) {//grass, forests ret[x] = png::color(48-(x-168),180-(x-168),(x-100)/2); } else if (x < 248) {//Prevent underflow of red ret[x] = png::color(0 ,180-(x-168),(x-160)); } else if (x < 252) {//snowy forest ret[x] = png::color(x-64,248,x-24); } else { //snow ret[x] = png::color(x-24,x-12,x-8);//Make snow bluish } } break; case 2://Arctic //Broken for (short x = 0; x < 256; ++x) { if (x < 149) { ret[x] = png::color(0,0,x+77); } else if (x == 149) { ret[x] = png::color(0,128,255); } else if (x < 155) { ret[x] = png::color(240-3*(x-155),240,64+4*(x-155)); } else if (x < 162) { ret[x] = png::color(32-(x-162),180-(x-162),0+(x-162)); } else if (x < 210) { ret[x] = png::color(0,128,32); } else { ret[x] = png::color(x-4,x-2,x);//Make snow bluish } } break; case 3://Alien //Broken for (short x = 0; x < 256; ++x) { if (x < 149) {//0+ ret[x] = png::color(0,0,x+77); } else if (x == 149) {//149+ ret[x] = png::color(0,128,255); } else if (x < 162) {//150+ ret[x] = png::color(240-3*(x-155),240,64+4*(x-155)); } else if (x < 182) {//162+ ret[x] = png::color(32-(x-162),180-(x-162),(x-162)); } else if (x < 210) { ret[x] = png::color(0,128,32); } else {//182+ ret[x] = png::color(x-4,x-2,x);//Make snow bluish } } break; case 4://Purple, red (Natural * RGB=>GRB) for (short x = 0; x < 256; ++x) { ret[x] = png::color(cmap[1][x][1],cmap[1][x][0],cmap[1][x][2]); } break; case 5://Water ratio map for (short x = 0; x < 256; ++x) { if (x < 132) {//ocean ret[x] = png::color(0,0,100); } else {//land ret[x] = png::color(48,180,48); } } break; case 6://Elevation for (short x = 0; x < 256; ++x) { if (x >= 132 && x <= 135) {//shore ret[x] = png::color(64,64,64); } else if (x < 132 && ((x-132)%10 == 0)) {//ocean depth marks ret[x] = png::color(128,128,128); } else if (x > 135 && ((x-135)%10 == 0)) {//land height marks ret[x] = png::color(192,192,192); } else { ret[x] = png::color(255,255,255); } } break; case 7://Elevation-color for (short x = 0; x < 256; ++x) { if (x >= 132 && x <= 135) {//shore ret[x] = png::color(64,64,64); } else if (x < 132 && ((x-132)%10 == 0)) {//ocean depth marks ret[x] = png::color(128,128,128); } else if (x > 135 && ((x-135)%10 == 0)) {//land height marks ret[x] = png::color(192,192,192); } else { ret[x] = png::color(255,255,255); } } break; case 15: //Hash { int h = -1; for (size_t x = 0; x < 256; ++x) { h = FNV32a(&h,sizeof(h)); ret[x] = png::color(h&255,(h>>8)&255,(h>>16)&255); } } break; default: //Fill cmap.h yourself and rebuild to get new maps return current_cmap[type].second; // for (short x = 0; x < 256; ++x) { // ret[x] = png::color(cmap[type][x][0],cmap[type][x][1],cmap[type][x][2]); // } break; } return ret; }