From 43d96ffb6d9bc1580a8dc5c74603460eb0798dd0 Mon Sep 17 00:00:00 2001 From: Joshua Moerman Date: Wed, 2 Nov 2011 15:39:07 +0100 Subject: [PATCH] turns out that a vector of vectors is just as fast --- AwesomeAttractorND.xcodeproj/project.pbxproj | 14 ++ AwesomeAttractorND/Canvas.hpp | 36 ++++- AwesomeAttractorND/Image.hpp | 24 +++- AwesomeAttractorND/Logging.hpp | 139 +++++++++++++++++++ AwesomeAttractorND/Tonemapper.hpp | 19 ++- AwesomeAttractorND/main.cpp | 101 ++++---------- AwesomeAttractorND/nd_array.hpp | 6 +- 7 files changed, 247 insertions(+), 92 deletions(-) create mode 100644 AwesomeAttractorND/Logging.hpp diff --git a/AwesomeAttractorND.xcodeproj/project.pbxproj b/AwesomeAttractorND.xcodeproj/project.pbxproj index 26964e2..b8bc8e3 100644 --- a/AwesomeAttractorND.xcodeproj/project.pbxproj +++ b/AwesomeAttractorND.xcodeproj/project.pbxproj @@ -28,6 +28,7 @@ 428EFECF145AF6E0001DBE1B /* Canvas.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Canvas.hpp; sourceTree = ""; }; 428EFED4145AFAB4001DBE1B /* Tonemapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Tonemapper.hpp; sourceTree = ""; }; 42C2D1521461676B001BF28D /* Image.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Image.hpp; sourceTree = ""; }; + 42C2D1611461894E001BF28D /* Logging.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Logging.hpp; sourceTree = ""; }; 42D2E11D1456175C00FBC16A /* AwesomeAttractorND */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = AwesomeAttractorND; sourceTree = BUILT_PRODUCTS_DIR; }; 42D2E1211456175C00FBC16A /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; 42D2E1231456175C00FBC16A /* AwesomeAttractorND.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = AwesomeAttractorND.1; sourceTree = ""; }; @@ -65,6 +66,7 @@ isa = PBXGroup; children = ( 42D2E1211456175C00FBC16A /* main.cpp */, + 42C2D1611461894E001BF28D /* Logging.hpp */, 42D2E12A1456176800FBC16A /* nd_array.hpp */, 428EFECF145AF6E0001DBE1B /* Canvas.hpp */, 428EFED4145AFAB4001DBE1B /* Tonemapper.hpp */, @@ -151,9 +153,15 @@ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = /usr/local/include/; MACOSX_DEPLOYMENT_TARGET = 10.7; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; + WARNING_CFLAGS = ( + "-Weffc++", + "-Wextra", + "-Wall", + ); }; name = Debug; }; @@ -171,8 +179,14 @@ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = /usr/local/include/; MACOSX_DEPLOYMENT_TARGET = 10.7; SDKROOT = macosx; + WARNING_CFLAGS = ( + "-Weffc++", + "-Wextra", + "-Wall", + ); }; name = Release; }; diff --git a/AwesomeAttractorND/Canvas.hpp b/AwesomeAttractorND/Canvas.hpp index 0503ea4..0236a28 100644 --- a/AwesomeAttractorND/Canvas.hpp +++ b/AwesomeAttractorND/Canvas.hpp @@ -9,6 +9,7 @@ #ifndef AwesomeAttractorND_Canvas_hpp #define AwesomeAttractorND_Canvas_hpp +#include #include "nd_array.hpp" class Canvas2D : public nd_array{ @@ -24,14 +25,45 @@ public: const size_t width = get_size(0); const size_t height = get_size(1); - const size_t x = position[0]*width + width*.5; - const size_t y = position[1]*width + height*.5; + const size_t x = 0.5*position[0]*width + width*.5; + const size_t y = 0.5*position[1]*width + height*.5; if(x < width && y < height) { (*this)[x][y]++; } } +}; + +class Canvas2Db : public std::vector > { + typedef Canvas2Db self; + typedef std::vector > super; + +public: + Canvas2Db(size_t width, size_t height) + : super(width, super::value_type(height, 0)) + {} + void plot(double const * const position){ + const size_t width = get_size(0); + const size_t height = get_size(1); + + const size_t x = 0.5*position[0]*width + width*.5; + const size_t y = 0.5*position[1]*width + height*.5; + + if(x < width && y < height) { + (*this)[x][y]++; + } + } + + size_t get_size(size_t n) const { + switch (n) { + case 0: + return size(); + case 1: + return front().size(); + } + return 0; + } }; #endif diff --git a/AwesomeAttractorND/Image.hpp b/AwesomeAttractorND/Image.hpp index 74c26c6..df1f545 100644 --- a/AwesomeAttractorND/Image.hpp +++ b/AwesomeAttractorND/Image.hpp @@ -14,9 +14,7 @@ #include #include -struct pixel { - friend class Image; - +struct pixel { pixel(double red, double green, double blue) : red(clamp(255*red)) , green(clamp(255*green)) @@ -29,6 +27,10 @@ struct pixel { , blue(clamp(blue)) {} + void swapRB(){ + std::swap(red, blue); + } + private: uint8_t clamp(int n){ return std::min(255, std::max(0, n)); @@ -116,21 +118,29 @@ namespace ImageFormats { : dib_header(width, height) , header(dib_header) , file(filename.c_str()) + , x(0) + , y(0) { + if(!file) + throw std::runtime_error("bitmap file could not be opened."); header.write(file); dib_header.write(file); } bitmap_stream& operator<<(pixel const & p){ - file.write(&p, 3); + if (y >= dib_header.height){ + throw std::out_of_range("Writing BMP image out of bounds."); + } + + pixel p2(p); + p2.swapRB(); + file.write((char const *)&p2, 3); ++x; if (x >= dib_header.width){ x = 0; ++y; } - if (y >= dib_header.height){ - throw std::out_of_range("Writing BMP image out of bounds."); - } + return *this; } private: diff --git a/AwesomeAttractorND/Logging.hpp b/AwesomeAttractorND/Logging.hpp new file mode 100644 index 0000000..8383594 --- /dev/null +++ b/AwesomeAttractorND/Logging.hpp @@ -0,0 +1,139 @@ +// +// Logging.hpp +// AwesomeAttractorND +// +// Created by Joshua Moerman on 11/2/11. +// Copyright 2011 Vadovas. All rights reserved. +// + +#ifndef AwesomeAttractorND_Logging_hpp +#define AwesomeAttractorND_Logging_hpp + +#pragma once + +#include + +#define INFORMATION __FILE__ << ":" << __LINE__ << "(" << __FUNCTION__ << ")" +#define COUT std::cout << INFORMATION << "\n" +#define CERR std::cerr << INFORMATION << "\n" + +#define VCOUT if(verbose) COUT +#define VCERR if(verbose) CERR + +#pragma once + +#include +#include +#include +#include + +#include + +#include + +/* Usage: + When timing anything: + Before starting the task: start("with a string"); + When the task is done: stop(); + + The shorthand for that is + { + start("foo"); + foo(); + stop(); + } + + Note that a call to stop without parameters, stops the last started event. This works like a stack: + { + start("Task of several small tasks"); + start("Small task 1"); + small_task_1(); + stop(); + + start("Small task 2"); + small_task_2(); + stop(); + stop(); // Stops "Task of several small tasks" + } + The indenting is, of course, only to help you understand what's going on. + + Questions/Suggestions mail nick@astrant.net + */ + +struct Logger { + Logger(std::ostream& logging_stream_, std::string prefix_ = std::string("")) + : logging_stream(&logging_stream_) + , prefix(prefix_) + {} + + void log(std::string what){ + *logging_stream << get_prefix() << "(" << what << ") took place at (" << boost::posix_time::microsec_clock::local_time() << std::endl; + } + + void start(std::string what){ + Event e; + e.start = boost::posix_time::microsec_clock::local_time(); + e.name = what; + + EventMap::iterator it = event_map.find(what); + if(it != event_map.end()){ + *logging_stream << get_prefix() << "WARNING: Overwriting event(" << e.name << "), did you forget to call stop()?"; + } else { + event_name_stack.push(what); + } + + event_map.insert(it, std::make_pair(what, e)); + } + + void stop() { + assert(!event_name_stack.empty()); + stop(event_name_stack.top()); + } + +private: + void stop(std::string what){ + EventMap::iterator it = event_map.find(what); + if(it == event_map.end()){ + *logging_stream << get_prefix() << "WARNING: No such, or already stopped, event(" << what << "), did you forget to call start()?"; + } else { + it->second.end = boost::posix_time::microsec_clock::local_time(); + log_event(it->second); + event_map.erase(it); + } + + event_name_stack.pop(); + } + + struct Event { + boost::posix_time::ptime start; + boost::posix_time::ptime end; + std::string name; + }; + + // A map containing strings -> Event, used by start() and stop() + typedef std::map EventMap; + EventMap event_map; + + // A stack used by 0-parameter stop() to stop the last start()ed event. + std::stack event_name_stack; + + std::ostream* logging_stream; + + std::string prefix; + + void log_event(Event const& e){ + *logging_stream << get_prefix() << "Event(" << e.name << ") started at (" << e.start << ") ended at (" << e.end << ") duration (" << e.end - e.start << " ms) " << std::endl; + } + + std::string get_prefix() const { + if(prefix == std::string("")){ + return prefix; + } else { + return prefix + ": "; + } + } +}; + + + +#endif diff --git a/AwesomeAttractorND/Tonemapper.hpp b/AwesomeAttractorND/Tonemapper.hpp index b6306a1..8e175a7 100644 --- a/AwesomeAttractorND/Tonemapper.hpp +++ b/AwesomeAttractorND/Tonemapper.hpp @@ -10,15 +10,23 @@ #define AwesomeAttractorND_Tonemapper_hpp #include +#include namespace Tonemappers { - class Normalizer2D { - unsigned int max; + struct Normalizer2D { + Normalizer2D() + : max(0) + {} template void analyse(C const & canvas){ - max = *std::max_element(canvas.cbegin(), canvas.cend()); + //max = *std::max_element(canvas.cbegin(), canvas.cend()); + for (size_t x = 0; x < canvas.get_size(0); ++x) { + for (size_t y = 0; y < canvas.get_size(1); ++y) { + max = std::max(max, (unsigned int)canvas[x][y]); + } + } } template @@ -26,10 +34,13 @@ namespace Tonemappers { for (size_t x = 0; x < canvas.get_size(0); ++x) { for (size_t y = 0; y < canvas.get_size(1); ++y) { const double grayscale = (double) canvas[x][y] / (double) max; - image << I::pixel(grayscale, grayscale, grayscale); + image << typename I::pixel(std::pow(grayscale, 0.2), std::pow(grayscale, 0.6), grayscale*1.5); } } } + + private: + unsigned int max; }; } diff --git a/AwesomeAttractorND/main.cpp b/AwesomeAttractorND/main.cpp index 65341c3..ed5c034 100644 --- a/AwesomeAttractorND/main.cpp +++ b/AwesomeAttractorND/main.cpp @@ -12,91 +12,40 @@ #include "Canvas.hpp" #include "Tonemapper.hpp" #include "Image.hpp" +#include "Logging.hpp" -const size_t width = 512; -const size_t height = 64; -const size_t depth = 32; +typedef Canvas2D Canvas; -typedef nd_array array; - -double calculate1(array & c){ - double mean = 0.0; - for (unsigned int x = 0; x < width; ++x) { - for (unsigned int y = 0; y < height; ++y) { - for (unsigned int z = 0; z < depth; ++z) { - mean += 1.0/(width*height*depth) * c[x][y][z]; - } - } - } - return mean; -} - -void calculate2(array & c, double mean){ - for (unsigned int x = 0; x < width; ++x) { - for (unsigned int y = 0; y < height; ++y) { - for (unsigned int z = 0; z < depth; ++z) { - c[x][y][z] = c[x/3][y][z/2] * mean / 200.0 + mean - x; - } - } - } -} - -void calculate(array & c){ - std::cout << "Calculating..." << std::endl; - - for (unsigned int i = 0; i < 1000; ++i) { - double mean = calculate1(c); - calculate2(c, mean); - } -} - -void fill(array & c){ - std::cout << "Filling..." << std::endl; +void fill(Canvas & canvas){ + const unsigned int it = 100000000/2; - for (unsigned int x = 0; x < width; ++x) { - for (unsigned int y = 0; y < height; ++y) { - for (unsigned int z = 0; z < depth; ++z) { - c[x][y][z] = x + z; - if (y == 5) { - c[x][y][z] = 5; - } - } - } + for (unsigned int i = 0; i < it; ++i){ + double x = 2.0 * (rand() / (double) RAND_MAX - 0.5); + double y = 2.0 * (rand() / (double) RAND_MAX - 0.5); + double position[2] = {sin(x / (y*y - 1)), sin(y / (x*x - 1))}; + canvas.plot(position); } } -void output(array & c){ - std::cout << "Outputting..." << std::endl; +void output(Canvas const & canvas){ + ImageFormats::bmp::bitmap_stream<> image(canvas.get_size(0), canvas.get_size(1), "test.bmp"); + Tonemappers::Normalizer2D tonemapper; - for (unsigned int y = 0; y < 10; ++y) { - for (unsigned int x = 0; x < 10; ++x) { - std::cout << c[x][y][2] << '\t'; - } - std::cout << '\n'; - } - - std::cout << "Outputting addresses..." << std::endl; - - for (unsigned int z = 20; z < 30; ++z) { - double & n = c[32][64][z]; - std::cout << &n << '\n'; - } + tonemapper.analyse(canvas); + tonemapper.process(canvas, image); } -int main (int argc, const char * argv[]){ - - std::cout << "Creating..." << std::endl; - - array c(width, height, depth); +int main (int, const char * []){ + Logger l(std::cout); + l.start("all"); - fill(c); - - calculate(c); - - output(c); - - std::cout << "Done" << std::endl; + l.log("creating canvas"); + Canvas canvas(2048, 2048); + l.log("filling canvas"); + fill(canvas); + l.log("outputting canvas"); + output(canvas); + l.stop(); return 0; -} - +} \ No newline at end of file diff --git a/AwesomeAttractorND/nd_array.hpp b/AwesomeAttractorND/nd_array.hpp index 4202066..202439c 100644 --- a/AwesomeAttractorND/nd_array.hpp +++ b/AwesomeAttractorND/nd_array.hpp @@ -76,7 +76,7 @@ public: const_proxy operator[](size_t y) const { if (N == 0) throw std::logic_error("called operator[] on a value"); - return proxy(data, data->sizes[dimension - N]*offset + y); + return const_proxy(data, data->sizes[dimension - N]*offset + y); } operator const_reference() const { @@ -115,7 +115,7 @@ public: } size_type size() const { - return std::accumulate(sizes.begin(), sizes.end(), 0, std::multiplies()); + return std::accumulate(sizes.begin(), sizes.end(), 1, std::multiplies()); } proxy operator[](size_t x){ @@ -123,7 +123,7 @@ public: } const_proxy operator[](size_t x) const { - return proxy(this, x); + return const_proxy(this, x); } iterator begin(){