summaryrefslogtreecommitdiff
path: root/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'main.cpp')
-rw-r--r--main.cpp208
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;
+
+}