Skip to content

Commit 4a477b2

Browse files
authored
Add Rgb, Image (#3)
1 parent 9117412 commit 4a477b2

File tree

7 files changed

+113
-37
lines changed

7 files changed

+113
-37
lines changed

tray/CMakeLists.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
add_executable(${PROJECT_NAME})
2-
target_sources(${PROJECT_NAME} PRIVATE src/main.cpp)
32
target_include_directories(${PROJECT_NAME} PRIVATE src)
3+
target_sources(${PROJECT_NAME} PRIVATE
4+
src/tray/image.cpp
5+
src/tray/image.hpp
6+
src/tray/io.cpp
7+
src/tray/io.hpp
8+
src/tray/rgb.hpp
9+
src/tray/vec.hpp
10+
11+
src/main.cpp
12+
)
413

514
if(CMAKE_CXX_COMPILER_ID STREQUAL Clang OR CMAKE_CXX_COMPILER_ID STREQUAL GNU)
615
target_compile_options(${PROJECT_NAME} PRIVATE

tray/src/main.cpp

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,23 @@
1+
#include <tray/image.hpp>
2+
#include <tray/io.hpp>
13
#include <tray/vec.hpp>
2-
#include <array>
3-
#include <cassert>
44
#include <iostream>
5-
#include <ostream>
65
#include <span>
76

87
using namespace tray;
98

10-
namespace {
11-
struct Rgb : Vec<std::uint8_t, 3> {};
12-
13-
struct ImageData {
14-
std::span<Rgb const> data{};
15-
uvec2 extent{};
16-
};
17-
18-
std::ostream& operator<<(std::ostream& out, ImageData const& image) {
19-
assert(image.data.size() == image.extent.x() * image.extent.y());
20-
// write header
21-
out << "P3\n" << image.extent.x() << ' ' << image.extent.y() << "\n255\n";
22-
// write each row
23-
for (std::uint32_t row = 0; row < image.extent.y(); ++row) {
24-
// write each column
25-
for (std::uint32_t col = 0; col < image.extent.x(); ++col) {
26-
// compute index
27-
auto const index = row * image.extent.x() + col;
28-
// obtain corresponding Rgb
29-
auto const& rgb = image.data[index];
30-
// write out each channel
31-
for (auto const channel : rgb.values) { out << static_cast<int>(channel) << ' '; }
9+
int main() {
10+
static constexpr auto extent = uvec2{400U, 300U};
11+
auto image = Image{extent};
12+
for (std::uint32_t row = 0; row < image.extent().y(); ++row) {
13+
auto const ratio = static_cast<float>(row) / static_cast<float>(image.extent().y());
14+
auto const tint = ratio * static_cast<float>(0xff);
15+
for (std::uint32_t col = 0; col < image.extent().x(); ++col) {
16+
auto& rgb = image[{row, col}];
17+
rgb.x() = 0xff;
18+
rgb.y() = static_cast<std::uint8_t>(tint);
3219
}
33-
out << '\n';
3420
}
35-
return out;
36-
}
37-
} // namespace
3821

39-
int main() {
40-
static constexpr auto extent = uvec2{40U, 30U};
41-
static constexpr auto white_v = Rgb{0xff, 0xff, 0xff};
42-
auto buffer = std::array<Rgb, extent.x() * extent.y()>{};
43-
std::fill_n(buffer.data(), buffer.size(), white_v);
44-
auto const image_data = ImageData{.data = buffer, .extent = extent};
45-
std::cout << image_data;
22+
io::write(image, "test.ppm");
4623
}

tray/src/tray/image.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <tray/image.hpp>
2+
#include <cassert>
3+
#include <utility>
4+
5+
namespace tray {
6+
void Image::resize(uvec2 extent) {
7+
m_data.resize(extent.x() * extent.y());
8+
m_extent = extent;
9+
}
10+
11+
Rgb const& Image::operator[](Index2D i) const {
12+
auto const index = i.index(m_extent);
13+
assert(index < m_data.size());
14+
return m_data[index];
15+
}
16+
17+
Rgb& Image::operator[](Index2D i) { return const_cast<Rgb&>(std::as_const(*this)[i]); }
18+
} // namespace tray

tray/src/tray/image.hpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#pragma once
2+
#include <tray/rgb.hpp>
3+
#include <vector>
4+
5+
namespace tray {
6+
struct Index2D {
7+
std::uint32_t row{};
8+
std::uint32_t col{};
9+
10+
constexpr std::size_t index(uvec2 const extent) { return row * extent.x() + col; }
11+
};
12+
13+
class Image {
14+
public:
15+
Image() = default;
16+
Image(uvec2 extent) { resize(extent); }
17+
18+
void resize(uvec2 extent);
19+
20+
Rgb const& operator[](Index2D i) const;
21+
Rgb& operator[](Index2D i);
22+
23+
uvec2 extent() const { return m_extent; }
24+
25+
private:
26+
std::vector<Rgb> m_data{};
27+
uvec2 m_extent{};
28+
};
29+
} // namespace tray

tray/src/tray/io.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include <tray/io.hpp>
2+
#include <fstream>
3+
4+
namespace tray {
5+
std::ostream& operator<<(std::ostream& out, Image const& image) {
6+
// write header
7+
out << "P3\n" << image.extent().x() << ' ' << image.extent().y() << "\n255\n";
8+
// write each row
9+
for (std::uint32_t row = 0; row < image.extent().y(); ++row) {
10+
// write each column
11+
for (std::uint32_t col = 0; col < image.extent().x(); ++col) {
12+
// obtain corresponding Rgb
13+
auto const& rgb = image[{row, col}];
14+
// write out each channel
15+
for (auto const channel : rgb.values) { out << static_cast<int>(channel) << ' '; }
16+
}
17+
out << '\n';
18+
}
19+
return out;
20+
}
21+
22+
bool io::write(Image const& image, char const* path) {
23+
if (auto file = std::ofstream(path)) { return static_cast<bool>(file << image); }
24+
return false;
25+
}
26+
} // namespace tray

tray/src/tray/io.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#pragma once
2+
#include <tray/image.hpp>
3+
#include <ostream>
4+
5+
namespace tray {
6+
std::ostream& operator<<(std::ostream& out, Image const& image);
7+
8+
namespace io {
9+
bool write(Image const& image, char const* path);
10+
}
11+
} // namespace tray

tray/src/tray/rgb.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#pragma once
2+
#include <tray/vec.hpp>
3+
4+
namespace tray {
5+
struct Rgb : Vec<std::uint8_t, 3> {};
6+
} // namespace tray

0 commit comments

Comments
 (0)