diff --git a/TODO.md b/TODO.md index 71f7014..240fbdd 100644 --- a/TODO.md +++ b/TODO.md @@ -14,4 +14,4 @@ [ ] Cut image in tiles # Quality -[ ] Interpolate using SIMD, SSE +[X] Interpolate using SIMD, SSE (no big gain) diff --git a/rotation.cpp b/rotation.cpp index bf2c6d4..305409d 100644 --- a/rotation.cpp +++ b/rotation.cpp @@ -9,7 +9,6 @@ #include - using namespace std; @@ -77,7 +76,7 @@ struct Image { } } - bool save(string const& path) + bool save(string const& path) const { ofstream os(path); if (!os.is_open()) @@ -111,7 +110,7 @@ struct Image { } - private: + protected: bool read_header(std::ifstream& istr) { // check magic @@ -169,7 +168,7 @@ struct Image { return true; } - bool write_header(std::ofstream& ostr) + bool write_header(std::ofstream& ostr) const { ostr << "P6" << endl; ostr << width << " " << height << endl; @@ -177,7 +176,7 @@ struct Image { return true; } - bool read_body(std::ifstream& istr) + virtual bool read_body(std::ifstream& istr) { unsigned int const nb_pixels = width * height; buffer = new uint8_t[nb_pixels * 3]; @@ -192,7 +191,7 @@ struct Image { return true; } - bool write_body(std::ofstream& ostr) + virtual bool write_body(std::ofstream& ostr) const { unsigned int const nb_pixels = width * height; uint8_t* buf_index = buffer; @@ -206,6 +205,121 @@ struct Image { } }; +template +struct TiledImage : public Image { + uint8_t** tiles; + unsigned int static const tile_w = W; + unsigned int static const tile_h = H; + unsigned int static const tile_size = W * H; + unsigned int nb_col_tile; + unsigned int nb_row_tile; + + TiledImage() + : Image() + , tiles(NULL) + , nb_col_tile(0) + , nb_row_tile(0) + {} + + TiledImage(unsigned int w, unsigned int h) + { + allocate_memory(w, h); + } + + TiledImage(string const& path) + : TiledImage() + { + ifstream is(path); + if (!is.is_open()) + { + cerr << "Cannot open file '" << path << "'" << endl; + abort(); + } + + if (!this->read_header(is)) + { + cerr << "Invalid header." << endl; + abort(); + } + + if (!this->read_body(is)) + { + // TODO: delete tiles + cerr << "Invalid header." << endl; + abort(); + } + } + + protected: + void allocate_memory(unsigned int w, unsigned int h) + { + width = w; + height = h; + + nb_col_tile = width / tile_w; + if (width % tile_w != 0) + ++nb_col_tile; + + nb_row_tile = height / tile_h; + if (height % tile_h != 0) + ++nb_row_tile; + + unsigned int const nb_tiles = nb_col_tile * nb_row_tile; + tiles = new uint8_t*[nb_tiles]; + for (unsigned int i = 0; i < nb_tiles; ++i) + { + tiles[i] = new uint8_t[tile_w * tile_h * 3]; + memset(tiles[i], 0, tile_w * tile_h * 3 * sizeof (uint8_t)); + } + } + + virtual bool read_body(std::ifstream& istr) + { + this->allocate_memory(width, height); + + unsigned int const tile_width = tile_w * 3; + + // Pixel loading + for (unsigned int j = 0; j < height; ++j) + for (unsigned int i = 0; i < width; ++i) + { + unsigned int const tile_index = (j / tile_h) * nb_col_tile + (i / tile_w); + uint8_t* tile = tiles[tile_index]; + unsigned int const tile_j = j % tile_h; + unsigned int const tile_i = i % tile_w; + // if (i % 3 == 0) + // cout << "pixel (" << i / 3 << ", " << j << ") goes in tile (" << i / (tile_w * 3) << ", " << j / tile_h << ")" << endl; + tile += tile_j * tile_width + (tile_i * 3); + *(tile++) = istr.get(); + *(tile++) = istr.get(); + *(tile++) = istr.get(); + } + + return true; + } + + virtual bool write_body(std::ofstream& ostr) const override + { + unsigned int const tile_width = tile_w * 3; + + for (unsigned int j = 0; j < height; ++j) + for (unsigned int i = 0; i < width; ++i) + { + unsigned int const tile_index = (j / tile_h) * nb_col_tile + (i / tile_w); + uint8_t* tile = tiles[tile_index]; + unsigned int const tile_j = j % tile_h; + unsigned int const tile_i = i % tile_w; + tile += tile_j * tile_width + (tile_i * 3); + ostr << (char) *(tile++); + ostr << (char) *(tile++); + ostr << (char) *(tile++); + } + + return true; + } + +}; + // @@ -742,6 +856,10 @@ int main(int argc, char* argv[]) } } + TiledImage<8, 8> tiled_img(argv[1]); + tiled_img.save("tiled.ppm"); + return 0; + Image img(argv[1]); for (double rotation = 0; rotation < 360; rotation += 5) @@ -754,6 +872,7 @@ int main(int argc, char* argv[]) auto const after = chrono::high_resolution_clock::now(); auto const duration_ms = std::chrono::duration_cast(after - before); cout << "rotate(" << rotation << "): " << duration_ms.count() << " ms" << endl; + // TODO: compare implementation stringstream filename; // filename << "/tmp/";