diff options
Diffstat (limited to 'main.cpp')
-rw-r--r-- | main.cpp | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..e801015 --- /dev/null +++ b/main.cpp @@ -0,0 +1,208 @@ +#include <thread> +#include <vector> +#include <iostream> +#include <chrono> +#include <complex> +#include <atomic> +#include <unistd.h> +#include <sstream> +#include "libpng_wrapper.hpp" +#include "mthread.hpp" +#include "test.hpp" + +using namespace std; + +//defaults + +//TODO remove temp_settings +const uint32_t DEFAULT_WIDTH = 1920; +const uint32_t DEFAULT_HEIGHT = 1080; +const int DEFAULT_JOBS = 1; +const string DEFAULT_IMG_PATH = "out.png"; + +//CONTENDOR_HI REPLACEMENT - 50000 iterations +const complex<double> DEFAULT_MIN_CORD (-0.74364386269 - 0.00000003000, 0.13182590271 - 0.00000003000); +const complex<double> DEFAULT_MAX_CORD (-0.74364386269 + 0.00000003000, 0.13182590271 + 0.00000003000); + +//CONTENDOR_ZOOM- 50000 iterations +//const complex<double> DEFAULT_MIN_CORD (-0.74364386269 - 0.00000001000, 0.13182590271 - 0.00000001000); +//const complex<double> DEFAULT_MAX_CORD (-0.74364386269 + 0.00000001000, 0.13182590271 + 0.00000001000); + +const unsigned int DEFAULT_ITERS = 50000; +const unsigned int DEFAULT_BAILOUT = 256; + +void print_help(char *arg, bool error) { + stringstream help_text; + help_text.precision(numeric_limits<double>::max_digits10); + help_text << "Usage: " << arg << " [options]\n" + "Options:\n" + "\t-h\tthis cruft\n" + "\t-w\timage width \t\t\t\tdefault: " << DEFAULT_WIDTH << "\n" + "\t-H\timage height\t\t\t\tdefault: " << DEFAULT_HEIGHT << "\n" + "\t-o\timage output path\t\t\tdefault: " << DEFAULT_IMG_PATH << "\n" + "\t-j\tjobs -- set this to your corecount\tdefault: " << DEFAULT_JOBS << "\n" + "\t-c\tcomplex bottom border\t\t\tdefault: " << DEFAULT_MIN_CORD << "\n" + "\t-C\tcomplex top border\t\t\tdefualt: " << DEFAULT_MAX_CORD << " \n" + "\t-i\tfractal iterations\t\t\tdefault: " << DEFAULT_ITERS << "\n" + "\t-I\tbailout value\t\t\t\tdefault: " << DEFAULT_BAILOUT << "\n" + "\nFOR COMPLEX NUMBERS: if you want to input, say, 2-3i, your option argument will be \"(2,-3)\".\n"; + cout << help_text.str() << endl; + exit(error); +} + +template <class t> +bool getopt_int(t& number, char *optarg, char opt, char *arg) { + try { number = stoi(optarg); } + catch(invalid_argument const&) { + cout << "You must supply an integer for option -" << opt << "." << endl; + print_help(arg, true); + return true; + } + catch(out_of_range const&) { + cout << "You must supply an integer under " << numeric_limits<t>::max() << " for option -" << opt << "." << endl; + print_help(arg, true); + return true; + } + return false; +} + + + +int main(int argc, char **argv) { + + //argument options + uint32_t width = DEFAULT_WIDTH; + uint32_t height = DEFAULT_HEIGHT; + unsigned int jobs = DEFAULT_JOBS; + string img_path = DEFAULT_IMG_PATH; + complex<double> min_cord = DEFAULT_MIN_CORD; + complex<double> max_cord = DEFAULT_MAX_CORD; + unsigned int m_iters = DEFAULT_ITERS; + unsigned int bailout = DEFAULT_BAILOUT; + bool jobs_set = false; + + //I could not find a better way to turn a string into a complex variable + stringstream complex_str_buffer; + int arg; + while((arg = getopt(argc, argv, "hw:H:o:j:c:C:i:I:")) != -1) { + switch(arg) { + case 'h': + print_help(argv[0], false); + break; + case 'w': + getopt_int(width, optarg, 'w', argv[0]); + break; + case 'H': + getopt_int(height, optarg, 'H', argv[0]); + break; + case 'o': + img_path = optarg; + break; + case 'j': + getopt_int(jobs, optarg, 'j', argv[0]); + jobs_set = true; + break; + case 'c': + complex_str_buffer << optarg; + complex_str_buffer >> min_cord; + break; + case 'C': + complex_str_buffer << optarg; + complex_str_buffer >> max_cord; + break; + case 'i': + getopt_int(m_iters, optarg, 'i', argv[0]); + break; + case 'I': + getopt_int(bailout, optarg, 'I', argv[0]); + break; + default: + cout << "Invalid option." << endl; + print_help(argv[0], true); + exit(1); + break; + } + } + + if(!jobs_set) { + cout << "\nPERFORMANCE TIP: for best preformance, set jobs to the number of cores in your CPU.\n" + "See " << argv[0] << " -h for help.\n" << endl; + } + + double *vmap = new double[width * height]; + unsigned int *histogram = new unsigned int[m_iters](); + unsigned int histogram_sum = 0; + double *freq_hue = new double[m_iters](); + double current_hue = 0; + + unsigned int width_per_job = width / jobs; + atomic<uint32_t> progress(0); + + png image(img_path, width, height); + thread threads[jobs]; + + + //allocate worker threads, spawn workers + mthread** worker_objects = (mthread **)malloc(sizeof(mthread) * jobs); + + + for(unsigned int j = 0; j < jobs - 1; j++) { + worker_objects[j] = new mthread(j * width_per_job, (j + 1) * width_per_job, + min_cord, max_cord, bailout, m_iters, + image, vmap, histogram, worker_objects, j, jobs, progress); + } + + //last worker thread needs the width to go all the way to the edge of the screen, + //regardless of rounding issues + worker_objects[jobs - 1] = new mthread((jobs - 1) * width_per_job, width - 1, + min_cord, max_cord, bailout, m_iters, + image, vmap, histogram, worker_objects, jobs - 1, jobs, progress); + + + for(unsigned int j = 0; j < jobs; j++) worker_objects[j]->dispatch(); + + //the progress variables is simply how many pixels we have calculated + while(progress < (height * jobs)) { + cout << "\033[2K\033[0GCalculating pixel values... " << ((float)progress / (height * jobs)) * 100 << "\% complete" << flush; + this_thread::sleep_for(chrono::milliseconds(100)); + } + cout << endl; + + for(unsigned int j = 0; j < jobs; j++) worker_objects[j]->join(); + + //now to color the image + cout << "Coloring image... (this shouldn't take more then a few seconds)" << endl; + + //find the sum of all histogram values, we could ajust this to increase or decrease contrast + for(unsigned int p = 0; p < m_iters; p++) histogram_sum += histogram[p]; + + for(unsigned int i = 0; i < m_iters; i++) { + current_hue += histogram[i] / (double)histogram_sum; + freq_hue[i] = current_hue; + } + + //now to calculate the colors + { + double below, above, hue; + int c; + uint32_t x, y; + int rgb[3]; + for(y = 0; y < height; y++) { + for(x = 0; x < width; x++) { + below = freq_hue[(int)vmap[(y * width) + x]]; + above = freq_hue[(int)ceil(vmap[((y * width) + x) + 1])]; + hue = (((above - below) * fmod(vmap[(y * width) + x], 1.0)) + below); + rgb[0] = 255 * cos((M_PI * hue) - M_PI); + rgb[1] = 255 * cos((M_PI * hue) - ((M_PI) / 2.0)); + rgb[2] = 255 * cos(M_PI * hue); + for(c = 0; c < 3; c++) if(rgb[c] < 0) rgb[c] = 0; + image.set_pixel(x, y, (png_byte)rgb[0], (png_byte)rgb[1], (png_byte)rgb[2]); + } + } + } + + for(unsigned int j = 0; j < jobs; j++) delete worker_objects[j]; + + cout << "Image exported to " << img_path << "." << endl; + +} |