From 28375aef01c72a0a4bcff1ef54eed1b61db84ffa Mon Sep 17 00:00:00 2001 From: Skittles Date: Sun, 14 Jun 2026 09:18:46 -0700 Subject: [PATCH] Added PPM writer --- app/CMakeLists.txt | 1 + app/main.cpp | 21 ++++++++++++ src/CMakeLists.txt | 3 +- src/image_writers/CMakeLists.txt | 13 +++++++ src/image_writers/Image.hpp | 17 ++++++++++ src/image_writers/PpmImage.cpp | 58 ++++++++++++++++++++++++++++++++ src/image_writers/PpmImage.hpp | 23 +++++++++++++ 7 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 src/image_writers/CMakeLists.txt create mode 100644 src/image_writers/Image.hpp create mode 100644 src/image_writers/PpmImage.cpp create mode 100644 src/image_writers/PpmImage.hpp diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 93ef9ed..d209836 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -9,4 +9,5 @@ target_compile_features(${target} PRIVATE cxx_std_23) target_link_libraries(${target} PRIVATE project_core + project_image_writers ) \ No newline at end of file diff --git a/app/main.cpp b/app/main.cpp index fe602be..7567630 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -1,6 +1,27 @@ +#include "PpmImage.hpp" +#include #include +#include int main(int argc, char **argv) { std::println("Hello, GraphicsSandbox!"); + + // Generate PPM image + constexpr size_t imageWidth = 256; + constexpr size_t imageHeight = 256; + std::vector> imageData; + imageData.resize(imageWidth); + for (auto &row : imageData) { + row.resize(imageHeight); + } + + image_writers::PpmImage ppmImage(imageData); + + if (ppmImage.writeToFile("Image.ppm")) { + std::println("Wrote PPM image"); + } else { + std::println("Failed to write PPM image"); + } + return 0; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 82bfe4a..e613ac7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1 +1,2 @@ -add_subdirectory(core) \ No newline at end of file +add_subdirectory(core) +add_subdirectory(image_writers) \ No newline at end of file diff --git a/src/image_writers/CMakeLists.txt b/src/image_writers/CMakeLists.txt new file mode 100644 index 0000000..f904c6a --- /dev/null +++ b/src/image_writers/CMakeLists.txt @@ -0,0 +1,13 @@ +set(target project_image_writers) + +add_library(${target} + Image.hpp + PpmImage.cpp + PpmImage.hpp +) + +target_compile_features(${target} PRIVATE cxx_std_23) + +target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +# target_link_libraries(${target} PRIVATE) \ No newline at end of file diff --git a/src/image_writers/Image.hpp b/src/image_writers/Image.hpp new file mode 100644 index 0000000..e3388c6 --- /dev/null +++ b/src/image_writers/Image.hpp @@ -0,0 +1,17 @@ +#ifndef IMAGE_HPP +#define IMAGE_HPP + +#include + +namespace image_writers { + +class Image { +public: + virtual ~Image() = default; + + virtual bool writeToFile(const std::filesystem::path &filePath) = 0; +}; + +} // namespace image_writers + +#endif // IMAGE_HPP diff --git a/src/image_writers/PpmImage.cpp b/src/image_writers/PpmImage.cpp new file mode 100644 index 0000000..4fa9d24 --- /dev/null +++ b/src/image_writers/PpmImage.cpp @@ -0,0 +1,58 @@ +#include "PpmImage.hpp" + +#include +#include +#include + +image_writers::PpmImage::PpmImage( + const std::vector> &imageData) + : imageData_(imageData) {} + +bool image_writers::PpmImage::writeToFile( + const std::filesystem::path &filePath) { + + const size_t height = imageData_[0].size(); + const size_t width = imageData_.size(); + + if (width == 0 || height == 0) { + std::println("PpmImage::writeToFile() - Invalid image size"); + return false; + } + + std::println("PpmImage::writeToFile() - Width {}, Height: {}", width, height); + + std::ofstream outFile; + outFile.open(filePath, std::ios_base::out | std::ios_base::binary); + + if (outFile.is_open()) { + // Create PPM header + outFile << "P3\n"; // ASCII + outFile << width << ' ' << height << '\n'; // Width and height + outFile << "255\n"; // Max color + + // Write image data + for (size_t currHeight = 0; currHeight < height; ++currHeight) { + for (size_t currWidth = 0; currWidth < width; ++currWidth) { + // TODO: Currently overriding colors; make logic for colors + const auto r = static_cast(currWidth) / (width - 1); + const auto g = static_cast(currHeight) / (height - 1); + const auto b = 0.0; + + const auto ir = static_cast(255.999 * r); + const auto ig = static_cast(255.999 * g); + const auto ib = static_cast(255.999 * b); + + outFile << std::format("{} {} {}\n", ir, ig, ib); + } + } + + // Cleanup + outFile.close(); + + return true; + } + + std::println("PpmImage::writeToFile() - Failed to write image file"); + + return false; +} diff --git a/src/image_writers/PpmImage.hpp b/src/image_writers/PpmImage.hpp new file mode 100644 index 0000000..671c975 --- /dev/null +++ b/src/image_writers/PpmImage.hpp @@ -0,0 +1,23 @@ +#ifndef PPM_IMAGE_HPP +#define PPM_IMAGE_HPP + +#include "Image.hpp" +#include +#include + +namespace image_writers { + +class PpmImage : public Image { +public: + PpmImage(const std::vector> &imageData); + ~PpmImage() = default; + + bool writeToFile(const std::filesystem::path &filePath) override; + +private: + const std::vector> &imageData_; +}; + +} // namespace image_writers + +#endif