summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeuin <[email protected]>2022-04-14 12:54:06 +0800
committerKeuin <[email protected]>2022-04-14 12:58:28 +0800
commita41fbf75aff54f4d3bd88793cdf2bf281ea9ee01 (patch)
treef6f65379568a80c2c22692d1914215c582a9b338
parente46e1c4033b9d96325de3295eb442a5b1fa19f19 (diff)
Add pixel and bitmap color depth conversion.
-rw-r--r--CMakeLists.txt2
-rw-r--r--bitmap.h66
-rw-r--r--test_bitmap.cpp33
-rw-r--r--test_vec.cpp (renamed from test.cpp)0
4 files changed, 96 insertions, 5 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c531ea9..91b234c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,7 +18,7 @@ add_executable(simple_scanner main_simple_scanner.cpp vec.h bitmap.h ray.h timer
# googletest
-add_executable(all_tests test.cpp vec.h bitmap.h ray.h)
+add_executable(all_tests test_vec.cpp test_bitmap.cpp vec.h bitmap.h ray.h)
target_link_libraries(all_tests gtest_main)
include(FetchContent)
diff --git a/bitmap.h b/bitmap.h
index 5b07914..b35bf81 100644
--- a/bitmap.h
+++ b/bitmap.h
@@ -12,6 +12,7 @@
#include <vector>
#include "bitfont.h"
+#include "vec.h"
#define COLORMIX_OVERFLOW_CHECK
@@ -29,6 +30,11 @@
template<typename T>
struct pixel {
T r, g, b;
+ static constexpr auto mod = (1ULL << (sizeof(T) * 8U)) - 1ULL; // FIXME
+
+ bool operator==(const pixel<T> &other) const {
+ return r == other.r && g == other.g && b == other.b;
+ }
/**
* Create a pixel of given depth, from normalized color values.
@@ -36,7 +42,6 @@ struct pixel {
* For example: Set color depth to 8bit, for normalized color (1, 0.5, 0.25), we get: (255, 127, 63).
*/
static inline pixel<T> from_normalized(double r, double g, double b) {
- const auto mod = (1ULL << (sizeof(T) * 8U)) - 1ULL;
return pixel<T>{.r = (T) (mod * r), .g = (T) (mod * g), .b = (T) (mod * b)};
}
@@ -45,9 +50,27 @@ struct pixel {
return from_normalized(v3d.x / 2.0 + 0.5, v3d.y / 2.0 + 0.5, v3d.z / 2.0 + 0.5);
}
+ // Convert pixels between different color depths.
+ template<typename U>
+ static inline pixel<T> from(const pixel<U> &orig) {
+ return from_normalized(
+ 1.0 * orig.r / pixel<U>::max_value(),
+ 1.0 * orig.g / pixel<U>::max_value(),
+ 1.0 * orig.b / pixel<U>::max_value()
+ );
+ }
+
static inline pixel<T> black() {
return pixel<T>{(T) 0, (T) 0, (T) 0};
}
+
+ static inline pixel<T> white() {
+ return pixel<T>{(T) mod, (T) mod, (T) mod}; // FIXME float-point values
+ }
+
+ static inline T max_value() {
+ return mod; // FIXME
+ }
};
template<
@@ -106,9 +129,11 @@ class bitmap {
public:
bitmap() = delete;
- bitmap(unsigned int width, unsigned int height) : width(width), height(height) {
- content.resize(width * height, pixel<T>{});
- }
+ bitmap(unsigned int width, unsigned int height) :
+ width(width), height(height), content{width * height, pixel<T>{}} {}
+
+ bitmap(unsigned int width, unsigned int height, std::vector<pixel<T>> &&data) :
+ width(width), height(height), content{data} {}
static bitmap<T> average(const std::vector<bitmap<T>> &images) {
assert(!images.empty());
@@ -138,12 +163,45 @@ public:
return image(x, y);
}
+ const pixel<T> &operator[](size_t loc) const {
+ assert(loc < width * height);
+ return content[loc];
+ }
+
+ pixel<T> &operator[](size_t loc) {
+ assert(loc < width * height);
+ return content[loc];
+ }
+
// Do not use float-point pixels, or this routine will break.
void write_plain_ppm(std::ostream &out) const;
// Draw text on the image. Supports limited visual ASCII characters.
void print(const std::string &s, const pixel<T> &color,
unsigned x, unsigned y, unsigned scale = 1, double alpha = 1.0);
+
+ bool normalized() const {
+ return false;
+ // TODO return true for float-point pixels
+ }
+
+ std::pair<unsigned, unsigned> shape() const {
+ return std::pair<unsigned, unsigned>{width, height};
+ }
+
+ // U: original color depth, T: desired color depth
+ template<typename U>
+ static bitmap<T> from(const bitmap<U> &src) {
+ const auto shape = src.shape();
+ const size_t sz = shape.first * shape.second;
+ bitmap<T> out{shape.first, shape.second};
+ for (size_t i = 0; i < sz; ++i) {
+ out[i] = pixel<T>::from(src[i]);
+ std::cerr << (int) out[i].r << ' ' << (int) out[i].g << ' ' << (int) out[i].b << std::endl;
+ }
+ return out;
+ }
+
};
template<typename T>
diff --git a/test_bitmap.cpp b/test_bitmap.cpp
new file mode 100644
index 0000000..4f20d3f
--- /dev/null
+++ b/test_bitmap.cpp
@@ -0,0 +1,33 @@
+//
+// Created by Keuin on 2022/4/14.
+//
+
+#include <gtest/gtest.h>
+
+#include "bitmap.h"
+
+TEST(Pixel, PixelDepthConvert) {
+ const auto white8 = pixel8b::white();
+ const auto white32 = pixel<uint32_t>::white();
+ ASSERT_EQ(white8, pixel8b::from(white32));
+
+ const auto black8 = pixel8b::black();
+ const auto black32 = pixel<uint32_t>::black();
+ ASSERT_EQ(black8, pixel8b::from(black32));
+
+ const auto gray8 = pixel8b{127, 127, 127};
+ const auto gray32 = pixel<uint32_t>{
+ ((1ULL << 32U) - 1U) >> 1U,
+ ((1ULL << 32U) - 1U) >> 1U,
+ ((1ULL << 32U) - 1U) >> 1U
+ };
+ ASSERT_EQ(gray8, pixel8b::from(gray32));
+
+ const auto mix8 = pixel8b{0, 127, 255};
+ const auto mix32 = pixel<uint32_t>{
+ 0,
+ ((1ULL << 32U) - 1U) >> 1U,
+ ((1ULL << 32U) - 1U)
+ };
+ ASSERT_EQ(mix8, pixel8b::from(mix32));
+} \ No newline at end of file
diff --git a/test.cpp b/test_vec.cpp
index 1b765aa..1b765aa 100644
--- a/test.cpp
+++ b/test_vec.cpp