Skip to content

Add Rgb, Image #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion tray/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
add_executable(${PROJECT_NAME})
target_sources(${PROJECT_NAME} PRIVATE src/main.cpp)
target_include_directories(${PROJECT_NAME} PRIVATE src)
target_sources(${PROJECT_NAME} PRIVATE
src/tray/image.cpp
src/tray/image.hpp
src/tray/io.cpp
src/tray/io.hpp
src/tray/rgb.hpp
src/tray/vec.hpp

src/main.cpp
)

if(CMAKE_CXX_COMPILER_ID STREQUAL Clang OR CMAKE_CXX_COMPILER_ID STREQUAL GNU)
target_compile_options(${PROJECT_NAME} PRIVATE
Expand Down
49 changes: 13 additions & 36 deletions tray/src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,46 +1,23 @@
#include <tray/image.hpp>
#include <tray/io.hpp>
#include <tray/vec.hpp>
#include <array>
#include <cassert>
#include <iostream>
#include <ostream>
#include <span>

using namespace tray;

namespace {
struct Rgb : Vec<std::uint8_t, 3> {};

struct ImageData {
std::span<Rgb const> data{};
uvec2 extent{};
};

std::ostream& operator<<(std::ostream& out, ImageData const& image) {
assert(image.data.size() == image.extent.x() * image.extent.y());
// write header
out << "P3\n" << image.extent.x() << ' ' << image.extent.y() << "\n255\n";
// write each row
for (std::uint32_t row = 0; row < image.extent.y(); ++row) {
// write each column
for (std::uint32_t col = 0; col < image.extent.x(); ++col) {
// compute index
auto const index = row * image.extent.x() + col;
// obtain corresponding Rgb
auto const& rgb = image.data[index];
// write out each channel
for (auto const channel : rgb.values) { out << static_cast<int>(channel) << ' '; }
int main() {
static constexpr auto extent = uvec2{400U, 300U};
auto image = Image{extent};
for (std::uint32_t row = 0; row < image.extent().y(); ++row) {
auto const ratio = static_cast<float>(row) / static_cast<float>(image.extent().y());
auto const tint = ratio * static_cast<float>(0xff);
for (std::uint32_t col = 0; col < image.extent().x(); ++col) {
auto& rgb = image[{row, col}];
rgb.x() = 0xff;
rgb.y() = static_cast<std::uint8_t>(tint);
}
out << '\n';
}
return out;
}
} // namespace

int main() {
static constexpr auto extent = uvec2{40U, 30U};
static constexpr auto white_v = Rgb{0xff, 0xff, 0xff};
auto buffer = std::array<Rgb, extent.x() * extent.y()>{};
std::fill_n(buffer.data(), buffer.size(), white_v);
auto const image_data = ImageData{.data = buffer, .extent = extent};
std::cout << image_data;
io::write(image, "test.ppm");
}
18 changes: 18 additions & 0 deletions tray/src/tray/image.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <tray/image.hpp>
#include <cassert>
#include <utility>

namespace tray {
void Image::resize(uvec2 extent) {
m_data.resize(extent.x() * extent.y());
m_extent = extent;
}

Rgb const& Image::operator[](Index2D i) const {
auto const index = i.index(m_extent);
assert(index < m_data.size());
return m_data[index];
}

Rgb& Image::operator[](Index2D i) { return const_cast<Rgb&>(std::as_const(*this)[i]); }
} // namespace tray
29 changes: 29 additions & 0 deletions tray/src/tray/image.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once
#include <tray/rgb.hpp>
#include <vector>

namespace tray {
struct Index2D {
std::uint32_t row{};
std::uint32_t col{};

constexpr std::size_t index(uvec2 const extent) { return row * extent.x() + col; }
};

class Image {
public:
Image() = default;
Image(uvec2 extent) { resize(extent); }

void resize(uvec2 extent);

Rgb const& operator[](Index2D i) const;
Rgb& operator[](Index2D i);

uvec2 extent() const { return m_extent; }

private:
std::vector<Rgb> m_data{};
uvec2 m_extent{};
};
} // namespace tray
26 changes: 26 additions & 0 deletions tray/src/tray/io.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <tray/io.hpp>
#include <fstream>

namespace tray {
std::ostream& operator<<(std::ostream& out, Image const& image) {
// write header
out << "P3\n" << image.extent().x() << ' ' << image.extent().y() << "\n255\n";
// write each row
for (std::uint32_t row = 0; row < image.extent().y(); ++row) {
// write each column
for (std::uint32_t col = 0; col < image.extent().x(); ++col) {
// obtain corresponding Rgb
auto const& rgb = image[{row, col}];
// write out each channel
for (auto const channel : rgb.values) { out << static_cast<int>(channel) << ' '; }
}
out << '\n';
}
return out;
}

bool io::write(Image const& image, char const* path) {
if (auto file = std::ofstream(path)) { return static_cast<bool>(file << image); }
return false;
}
} // namespace tray
11 changes: 11 additions & 0 deletions tray/src/tray/io.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once
#include <tray/image.hpp>
#include <ostream>

namespace tray {
std::ostream& operator<<(std::ostream& out, Image const& image);

namespace io {
bool write(Image const& image, char const* path);
}
} // namespace tray
6 changes: 6 additions & 0 deletions tray/src/tray/rgb.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once
#include <tray/vec.hpp>

namespace tray {
struct Rgb : Vec<std::uint8_t, 3> {};
} // namespace tray