summaryrefslogtreecommitdiff
path: root/src/GFX/Image
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-10-21 01:03:18 +0200
committerMel <einebeere@gmail.com>2022-10-21 01:03:18 +0200
commit6ed978051668c08f5a957c97570f364dd580c807 (patch)
treee3db93c52fcd86e26bc859d46e755290d2a7f40c /src/GFX/Image
parent0464a83dfaebaa75d6e2d3b7431e84ebd83fccfd (diff)
downloadmeowcraft-6ed978051668c08f5a957c97570f364dd580c807.tar.zst
meowcraft-6ed978051668c08f5a957c97570f364dd580c807.zip
Namespace and Folder refactor
Diffstat (limited to 'src/GFX/Image')
-rw-r--r--src/GFX/Image/PPMParser.cpp154
-rw-r--r--src/GFX/Image/PPMParser.hpp44
-rw-r--r--src/GFX/Image/RawImage.cpp29
-rw-r--r--src/GFX/Image/RawImage.hpp37
4 files changed, 264 insertions, 0 deletions
diff --git a/src/GFX/Image/PPMParser.cpp b/src/GFX/Image/PPMParser.cpp
new file mode 100644
index 0000000..7fc2359
--- /dev/null
+++ b/src/GFX/Image/PPMParser.cpp
@@ -0,0 +1,154 @@
+#include <cctype>
+#include <string>
+#include "PPMParser.hpp"
+
+namespace MC::GFX::Image {
+
+RawImage PPMParser::parse() {
+ auto header = parse_header();
+
+ if (header.max_color != 255) {
+ throw std::logic_error("PPM max color values other than 255 are not implemented.");
+ }
+
+ if (header.type != P3) {
+ throw std::logic_error("Raw PPM not implemented.");
+ }
+
+ auto pixel_count = header.width * header.height;
+
+ RawImage image(pixel_count, header.width, header.height, 3);
+ for (uint64_t pixel_index = 0; pixel_index < pixel_count; pixel_index++) {
+ RawImage::Pixel pixel = parse_pixel(header.max_color);
+ image.add(pixel);
+ }
+
+ return image;
+}
+
+PPMParser::PPMHeader PPMParser::parse_header() {
+ PPMHeader header{};
+
+ skip_whitespace();
+
+ auto type_part = chomp_part();
+ skip_whitespace();
+
+ if (type_part == "P3") {
+ header.type = P3;
+ } else if (type_part == "P6") {
+ header.type = P6;
+ } else {
+ throw std::runtime_error("Unknown PPM type.");
+ }
+
+ auto width_part = chomp_number();
+ skip_whitespace();
+ header.width = width_part;
+
+ auto height_part = chomp_number();
+ skip_whitespace();
+ header.height = height_part;
+
+ auto max_color_part = chomp_number();
+ skip_whitespace();
+ header.max_color = max_color_part;
+
+ return header;
+}
+
+RawImage::Pixel PPMParser::parse_pixel(uint8_t max_color) {
+ auto r_sample = parse_sample();
+ auto g_sample = parse_sample();
+ auto b_sample = parse_sample();
+
+ if (r_sample > max_color || g_sample > max_color || b_sample > max_color) {
+ throw std::runtime_error("Sample can not be greater than Maxval.");
+ }
+
+ auto map_to_range = [=](uint64_t s) -> uint8_t { return (s * 255) / max_color; };
+
+ RawImage::Pixel pixel{};
+ pixel.r = map_to_range(r_sample);
+ pixel.g = map_to_range(g_sample);
+ pixel.b = map_to_range(b_sample);
+
+ return pixel;
+}
+
+uint64_t PPMParser::parse_sample() {
+ skip_whitespace();
+ auto sample = chomp_number();
+ skip_whitespace();
+ return sample;
+}
+
+uint64_t PPMParser::chomp_number() {
+ auto raw = chomp_part();
+
+ uint64_t number = 0;
+ for (uint8_t digit_ascii : raw) {
+ if (digit_ascii < '0' || digit_ascii > '9') {
+ throw std::runtime_error("Number contains non ASCII digits.");
+ }
+
+ uint8_t digit = digit_ascii - '0';
+
+ number *= 10;
+ number += digit;
+ }
+
+ return number;
+}
+
+std::string_view PPMParser::chomp_part() {
+ uint64_t length = 0;
+
+ while (!is_eof()) {
+ auto c = m_source[m_cursor + length];
+ if (std::isspace(c)) {
+ break;
+ }
+
+ length++;
+ }
+
+ auto part = m_source.substr(m_cursor, length);
+ m_cursor += length;
+
+ return part;
+}
+
+void PPMParser::skip_whitespace() {
+ uint8_t c;
+ while (!is_eof()) {
+ c = m_source[m_cursor];
+ if (c == '#') {
+ skip_comment();
+ continue;
+ }
+
+ if (!std::isspace(c)) {
+ break;
+ }
+
+ m_cursor++;
+ }
+}
+
+void PPMParser::skip_comment() {
+ uint8_t c = m_source[m_cursor];
+ if (c != '#') {
+ return;
+ }
+
+ while (c != '\n' && !is_eof()) {
+ c = m_source[++m_cursor];
+ }
+}
+
+bool PPMParser::is_eof() {
+ return m_cursor >= m_source.size();
+}
+
+} \ No newline at end of file
diff --git a/src/GFX/Image/PPMParser.hpp b/src/GFX/Image/PPMParser.hpp
new file mode 100644
index 0000000..3909cee
--- /dev/null
+++ b/src/GFX/Image/PPMParser.hpp
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <cstdint>
+#include <string_view>
+#include "RawImage.hpp"
+
+namespace MC::GFX::Image {
+
+class PPMParser {
+public:
+ explicit PPMParser(std::string_view source) : m_source(source) {};
+
+ RawImage parse();
+private:
+ enum PPMType {
+ None,
+ P3,
+ P6
+ };
+
+ struct PPMHeader {
+ PPMType type;
+ uint32_t width;
+ uint32_t height;
+ uint8_t max_color;
+ };
+
+ PPMHeader parse_header();
+ RawImage::Pixel parse_pixel(uint8_t max_color);
+ uint64_t parse_sample();
+
+ uint64_t chomp_number();
+ std::string_view chomp_part();
+
+ void skip_whitespace();
+ void skip_comment();
+
+ bool is_eof();
+
+ std::string_view m_source;
+ uint64_t m_cursor = 0;
+};
+
+}
diff --git a/src/GFX/Image/RawImage.cpp b/src/GFX/Image/RawImage.cpp
new file mode 100644
index 0000000..aca8fbc
--- /dev/null
+++ b/src/GFX/Image/RawImage.cpp
@@ -0,0 +1,29 @@
+#include "RawImage.hpp"
+
+namespace MC::GFX::Image {
+
+void RawImage::add(RawImage::Pixel pixel) {
+ m_pixels.push_back(pixel);
+}
+
+size_t RawImage::size() const {
+ return m_pixels.size();
+}
+
+uint8_t* RawImage::raw() const {
+ return (uint8_t*)m_pixels.data();
+}
+
+uint32_t RawImage::width() const {
+ return m_width;
+}
+
+uint32_t RawImage::height() const {
+ return m_height;
+}
+
+uint8_t RawImage::channels() const {
+ return m_channels;
+}
+
+} \ No newline at end of file
diff --git a/src/GFX/Image/RawImage.hpp b/src/GFX/Image/RawImage.hpp
new file mode 100644
index 0000000..916671b
--- /dev/null
+++ b/src/GFX/Image/RawImage.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include <cstdint>
+#include <cstddef>
+#include <vector>
+
+namespace MC::GFX::Image {
+
+class RawImage {
+public:
+ RawImage() : m_pixels(), m_width(0), m_height(0), m_channels(0) {};
+
+ explicit RawImage(size_t pixel_count, uint32_t width, uint32_t height, uint8_t channels)
+ : m_pixels(), m_width(width), m_height(height), m_channels(channels) {
+ m_pixels.reserve(pixel_count);
+ }
+
+ struct Pixel {
+ uint8_t r, g, b;
+ };
+
+ void add(Pixel pixel);
+
+ size_t size() const;
+ uint8_t* raw() const;
+
+ uint32_t width() const;
+ uint32_t height() const;
+ uint8_t channels() const;
+private:
+ std::vector<Pixel> m_pixels;
+
+ uint32_t m_width, m_height;
+ uint8_t m_channels;
+};
+
+}