summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeuin <[email protected]>2022-04-11 12:07:58 +0800
committerKeuin <[email protected]>2022-04-11 12:08:11 +0800
commita15c8f6b3658095eb50da4bd75da697e37dbe033 (patch)
treeef4ec60e5c80b3c9031d60fe7caff52b331eb3e8
parentcdb0bdfc60481708ab1a9707c0e1e4458e6396bf (diff)
Implement bitmap and PPM serialization (with a demo program).
-rw-r--r--CMakeLists.txt5
-rw-r--r--bitmap.h74
-rw-r--r--main_image_output.cpp20
3 files changed, 97 insertions, 2 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a5c54e5..b822baa 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,11 +12,12 @@ set(CMAKE_VERBOSE_MAKEFILE on)
# main executable
-add_executable(rt main.cpp vec.h)
+add_executable(rt main.cpp vec.h bitmap.h)
+add_executable(image_output main_image_output.cpp vec.h bitmap.h)
# googletest
-add_executable(all_tests test.cpp)
+add_executable(all_tests test.cpp vec.h bitmap.h)
target_link_libraries(all_tests gtest_main)
include(FetchContent)
diff --git a/bitmap.h b/bitmap.h
new file mode 100644
index 0000000..b94bb25
--- /dev/null
+++ b/bitmap.h
@@ -0,0 +1,74 @@
+//
+// Created by Keuin on 2022/4/11.
+//
+
+#ifndef RT_BITMAP_H
+#define RT_BITMAP_H
+
+#include <vector>
+#include <cstdint>
+#include <ostream>
+#include <cassert>
+
+
+// T is some unsigned integer, do not use float point types!
+template<typename T>
+struct pixel {
+ T r, g, b;
+};
+
+// 8 bit pixel
+using pixel8b = pixel<uint8_t>;
+
+template<typename T>
+class bitmap {
+ const unsigned width, height;
+ std::vector<pixel<T>> content; // pixels scanned by rows, from top to bottom
+
+ pixel<T> &image(unsigned x, unsigned y) {
+ assert(x < width);
+ assert(y < height);
+ return content[x * width + y];
+ }
+
+ pixel<T> &image(unsigned x, unsigned y) const {
+ assert(x < width);
+ assert(y < height);
+ return content[x * width + y];
+ }
+
+public:
+ bitmap(unsigned int width, unsigned int height) : width(width), height(height) {
+ content.resize(width * height, pixel<T>{});
+ }
+
+ void set(unsigned x, unsigned y, const pixel<T> &pixel) {
+ image(x, y) = pixel;
+ }
+
+ pixel<T> get(unsigned x, unsigned y) const {
+ return image(x, y);
+ }
+
+ // Do not use float-point pixels, or this routine will break.
+ void write_plain_ppm(std::ostream &out) const;
+};
+
+template<typename T>
+void bitmap<T>::write_plain_ppm(std::ostream &out) const {
+ const auto depth = (1ULL << (sizeof(T) * 8)) - 1ULL; // color depth of pixels
+ out << "P3\n" // file header
+ << width << ' ' << height << '\n' // image width and height
+ << depth << '\n'; // normalized max color depth (e.g. 255 for 8bit image)
+
+ for (const auto &pixel: content) {
+ out << (unsigned long long) pixel.r << ' '
+ << (unsigned long long) pixel.g << ' '
+ << (unsigned long long) pixel.b << '\n';
+ }
+}
+
+using bitmap8b = bitmap<uint8_t>;
+
+
+#endif //RT_BITMAP_H
diff --git a/main_image_output.cpp b/main_image_output.cpp
new file mode 100644
index 0000000..10301da
--- /dev/null
+++ b/main_image_output.cpp
@@ -0,0 +1,20 @@
+//
+// Created by Keuin on 2022/4/11.
+//
+
+#include <iostream>
+#include "bitmap.h"
+
+// write a test .PPM image
+int main() {
+ bitmap8b image{256, 256};
+ pixel8b p{};
+ for (int x = 0; x < 256; ++x) {
+ for (int y = 0; y < 256; ++y) {
+ p.r = x;
+ p.b = y;
+ image.set(x, y, p);
+ }
+ }
+ image.write_plain_ppm(std::cout);
+} \ No newline at end of file