diff --git a/AwesomeAttractorND.xcodeproj/project.pbxproj b/AwesomeAttractorND.xcodeproj/project.pbxproj index d7c0a1e..26964e2 100644 --- a/AwesomeAttractorND.xcodeproj/project.pbxproj +++ b/AwesomeAttractorND.xcodeproj/project.pbxproj @@ -25,9 +25,13 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 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 = ""; }; 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 = ""; }; + 42D2E12A1456176800FBC16A /* nd_array.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = nd_array.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -61,6 +65,10 @@ isa = PBXGroup; children = ( 42D2E1211456175C00FBC16A /* main.cpp */, + 42D2E12A1456176800FBC16A /* nd_array.hpp */, + 428EFECF145AF6E0001DBE1B /* Canvas.hpp */, + 428EFED4145AFAB4001DBE1B /* Tonemapper.hpp */, + 42C2D1521461676B001BF28D /* Image.hpp */, 42D2E1231456175C00FBC16A /* AwesomeAttractorND.1 */, ); path = AwesomeAttractorND; @@ -171,6 +179,7 @@ 42D2E1281456175C00FBC16A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -178,6 +187,7 @@ 42D2E1291456175C00FBC16A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -201,6 +211,7 @@ 42D2E1291456175C00FBC16A /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/AwesomeAttractorND/Canvas.hpp b/AwesomeAttractorND/Canvas.hpp new file mode 100644 index 0000000..0503ea4 --- /dev/null +++ b/AwesomeAttractorND/Canvas.hpp @@ -0,0 +1,37 @@ +// +// Canvas.hpp +// AwesomeAttractorND +// +// Created by Joshua Moerman on 10/28/11. +// Copyright 2011 Vadovas. All rights reserved. +// + +#ifndef AwesomeAttractorND_Canvas_hpp +#define AwesomeAttractorND_Canvas_hpp + +#include "nd_array.hpp" + +class Canvas2D : public nd_array{ + typedef Canvas2D self; + typedef nd_array super; + +public: + Canvas2D(size_t width, size_t height) + : super(width, height) + {} + + void plot(double const * const position){ + 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; + + if(x < width && y < height) { + (*this)[x][y]++; + } + } + +}; + +#endif diff --git a/AwesomeAttractorND/Image.hpp b/AwesomeAttractorND/Image.hpp new file mode 100644 index 0000000..74c26c6 --- /dev/null +++ b/AwesomeAttractorND/Image.hpp @@ -0,0 +1,147 @@ +// +// Image.hpp +// AwesomeAttractorND +// +// Created by Joshua Moerman on 11/2/11. +// Copyright 2011 Vadovas. All rights reserved. +// + +#ifndef AwesomeAttractorND_Image_hpp +#define AwesomeAttractorND_Image_hpp + +#include +#include +#include +#include + +struct pixel { + friend class Image; + + pixel(double red, double green, double blue) + : red(clamp(255*red)) + , green(clamp(255*green)) + , blue(clamp(255*blue)) + {} + + pixel(int red, int green, int blue) + : red(clamp(red)) + , green(clamp(green)) + , blue(clamp(blue)) + {} + +private: + uint8_t clamp(int n){ + return std::min(255, std::max(0, n)); + } + + uint8_t red; + uint8_t green; + uint8_t blue; +}; + +namespace ImageFormats { + namespace bmp { + struct bitmap_file_header { + uint32_t filesize; + uint16_t creator1; + uint16_t creator2; + uint32_t bmp_offset; + + template + bitmap_file_header(DIBT dib_header): + filesize(dib_header.bytes() + dib_header.header_sz + 12 + 2), + creator1(0), + creator2(0), + bmp_offset(dib_header.header_sz + 12 + 2){} + + void write(std::ostream& out) const { + out << "BM"; + out.write(reinterpret_cast(this), 12); + } + }; + + struct bitmapcoreheader { + uint32_t header_sz; + uint16_t width; + uint16_t height; + uint16_t nplanes; + uint16_t bitspp; + + bitmapcoreheader(int width, int height, int bitspp = 24): + header_sz(sizeof(bitmapcoreheader)), + width(width), + height(height), + nplanes(1), + bitspp(bitspp){} + + void write(std::ostream& out) const { + out.write(reinterpret_cast(this), header_sz); + } + + unsigned int bytes(){ + return width*height*bitspp/8; + } + }; + + template + struct bitmap { + bitmap(int width, int height) + : dib_header(width, height, sizeof(P)*8) + , header(dib_header) + , data(0) {} + + void write(std::string const & filename){ + std::ofstream file(filename.c_str()); + write(file); + } + + void write(std::ostream& out){ + header.write(out); + dib_header.write(out); + //std::copy_n((char const *)data, dib_header.bytes(), std::ostream_iterator(out)); + std::copy((char const *)data, (char const *)data + dib_header.bytes(), std::ostream_iterator(out)); + } + + private: + DIBT dib_header; + bitmap_file_header header; + P const * data; + }; + + template + struct bitmap_stream { + typedef pixel pixel; + + bitmap_stream(int width, int height, std::string filename) + : dib_header(width, height) + , header(dib_header) + , file(filename.c_str()) + { + header.write(file); + dib_header.write(file); + } + + bitmap_stream& operator<<(pixel const & p){ + file.write(&p, 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."); + } + } + + private: + DIBT dib_header; + bitmap_file_header header; + std::ofstream file; + + uint16_t x; + uint16_t y; + }; + } +} + +#endif diff --git a/AwesomeAttractorND/Tonemapper.hpp b/AwesomeAttractorND/Tonemapper.hpp new file mode 100644 index 0000000..b6306a1 --- /dev/null +++ b/AwesomeAttractorND/Tonemapper.hpp @@ -0,0 +1,37 @@ +// +// Tonemapper.hpp +// AwesomeAttractorND +// +// Created by Joshua Moerman on 10/28/11. +// Copyright 2011 Vadovas. All rights reserved. +// + +#ifndef AwesomeAttractorND_Tonemapper_hpp +#define AwesomeAttractorND_Tonemapper_hpp + +#include + +namespace Tonemappers { + + class Normalizer2D { + unsigned int max; + + template + void analyse(C const & canvas){ + max = *std::max_element(canvas.cbegin(), canvas.cend()); + } + + template + void process(C const & canvas, I & image){ + 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); + } + } + } + }; + +} + +#endif diff --git a/AwesomeAttractorND/main.cpp b/AwesomeAttractorND/main.cpp index 855a111..65341c3 100644 --- a/AwesomeAttractorND/main.cpp +++ b/AwesomeAttractorND/main.cpp @@ -8,11 +8,95 @@ #include -int main (int argc, const char * argv[]) -{ +#include "nd_array.hpp" +#include "Canvas.hpp" +#include "Tonemapper.hpp" +#include "Image.hpp" - // insert code here... - std::cout << "Hello, World!\n"; +const size_t width = 512; +const size_t height = 64; +const size_t depth = 32; + +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; + + 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; + } + } + } + } +} + +void output(array & c){ + std::cout << "Outputting..." << std::endl; + + 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'; + } +} + +int main (int argc, const char * argv[]){ + + std::cout << "Creating..." << std::endl; + + array c(width, height, depth); + + fill(c); + + calculate(c); + + output(c); + + std::cout << "Done" << std::endl; + return 0; } diff --git a/AwesomeAttractorND/nd_array.hpp b/AwesomeAttractorND/nd_array.hpp new file mode 100644 index 0000000..4202066 --- /dev/null +++ b/AwesomeAttractorND/nd_array.hpp @@ -0,0 +1,152 @@ +// +// nd_array.hpp +// AwesomeAttractorND +// +// Created by Joshua Moerman on 10/25/11. +// Copyright 2011 Vadovas. All rights reserved. +// + +/* + Dynamic multi-dimensional array. + With the usual c-syntax: v[x][y][z]. + Memory is allocated as one big block, instead of multiple smaller blocks (which is the case with std::vector>). + Showed no difference in speed compared to std::array> (in release build). + + it is not yet standard compliant. + */ + +#ifndef AwesomeAttractorND_nd_array_hpp +#define AwesomeAttractorND_nd_array_hpp + +#include +#include +#include +#include + +template +class nd_array{ +public: + typedef T & reference; + typedef T const & const_reference; + typedef T * iterator; + typedef T const * const_iterator; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T * pointer; + typedef T const * const_pointer; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + template + struct proxy { + nd_array * const data; + size_t const offset; + + proxy(nd_array * const c, size_t o) + : data(c) + , offset(o) + {} + + proxy operator[](size_t y){ + if (N == 0) throw std::logic_error("called operator[] on a value"); + return proxy(data, data->sizes[dimension - N]*offset + y); + } + + operator reference(){ + if (N != 0) throw std::logic_error("using a non-value"); + return *(data->data + offset); + } + + reference operator=(T const & n){ + if (N != 0) throw std::logic_error("assignment to a non-value"); + return *(data->data + offset) = n; + } + }; + + template + struct const_proxy { + nd_array const * const data; + size_t const offset; + + const_proxy(nd_array const * const c, size_t o) + : data(c) + , offset(o) + {} + + 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); + } + + operator const_reference() const { + if (N != 0) throw std::logic_error("using a non-value"); + return *(data->data + offset); + } + }; + + nd_array(size_type width, size_type height) + : data(0) + , sizes() + { + if (dimension != 2) throw std::logic_error("wrong constructor"); + sizes[0] = width; + sizes[1] = height; + data = new T[width*height]; + } + + nd_array(size_type width, size_type height, size_type depth) + : data(0) + , sizes() + { + if (dimension != 3) throw std::logic_error("wrong constructor"); + sizes[0] = width; + sizes[1] = height; + sizes[2] = depth; + data = new T[width*height*depth]; + } + + ~nd_array(){ + delete[] data; + } + + size_type get_size(size_type d) const { + return sizes[d]; + } + + size_type size() const { + return std::accumulate(sizes.begin(), sizes.end(), 0, std::multiplies()); + } + + proxy operator[](size_t x){ + return proxy(this, x); + } + + const_proxy operator[](size_t x) const { + return proxy(this, x); + } + + iterator begin(){ + return data; + } + + iterator end(){ + size_type length = size(); + return data + length; + } + + const_iterator cbegin() const { + return data; + } + + const_iterator cend() const { + size_type length = size(); + return data + length; + } + +private: + T * data; + std::tr1::array sizes; +}; + +#endif