Porytiles
Loading...
Searching...
No Matches
jasc_pal_loader.cpp
Go to the documentation of this file.
2
3#include <expected>
4#include <filesystem>
5#include <fstream>
6
7#include "fmt/format.h"
9
12
13namespace {
14
15using namespace porytiles2;
16
17Result<Rgba32> parse_jasc_line(std::string_view line)
18{
19 std::vector<std::string> color_components = split(std::string{line}, " ");
20
21 if (color_components.size() != 3) {
22 return std::unexpected{fmt::format("invalid JASC color format, expected line in format 'R G B'")};
23 }
24
25 auto red_result = parse_int<int>(color_components[0]);
26 auto green_result = parse_int<int>(color_components[1]);
27 auto blue_result = parse_int<int>(color_components[2]);
28
29 if (!red_result.has_value()) {
30 return std::unexpected{fmt::format("invalid rgb red component: {}", red_result.error())};
31 }
32 if (!green_result.has_value()) {
33 return std::unexpected{fmt::format("invalid rgb green component: {}", green_result.error())};
34 }
35 if (!blue_result.has_value()) {
36 return std::unexpected{fmt::format("invalid rgb blue component: {}", blue_result.error())};
37 }
38
39 const auto red = red_result.value();
40 const auto green = green_result.value();
41 const auto blue = blue_result.value();
42
43 if (red < 0 || red > 255) {
44 return std::unexpected{fmt::format("invalid rgb red component '{}': range must be 0 <= red <= 255", red)};
45 }
46
47 if (green < 0 || green > 255) {
48 return std::unexpected{fmt::format("invalid rgb green component '{}': range must be 0 <= green <= 255", green)};
49 }
50
51 if (blue < 0 || blue > 255) {
52 return std::unexpected{fmt::format("invalid rgb blue component '{}': range must be 0 <= blue <= 255", blue)};
53 }
54
55 return Rgba32{
56 static_cast<std::uint8_t>(red),
57 static_cast<std::uint8_t>(green),
58 static_cast<std::uint8_t>(blue),
60}
61
62} // namespace
63
64namespace porytiles2 {
65
66Result<Palette<Rgba32>> JascPalLoader::load(const std::filesystem::path &path) const
67{
68 if (!exists(path)) {
69 return std::unexpected{fmt::format("does not exist: {}", path.string())};
70 }
71
72 Palette<Rgba32> pal{};
73 std::string line_buf{};
74 std::ifstream stream{path};
75
76 // First line of file *must* be "JASC-PAL"
77 std::getline(stream, line_buf);
78 trim_line_ending(line_buf);
79 if (line_buf != "JASC-PAL") {
80 return std::unexpected{fmt::format("{}: expected 'JASC-PAL' on line 1, saw '{}'", path.c_str(), line_buf)};
81 }
82
83 // Next line of file *must* be "0100"
84 std::getline(stream, line_buf);
85 trim_line_ending(line_buf);
86 if (line_buf != "0100") {
87 return std::unexpected{fmt::format("{}: expected '0100' on line 2, saw '{}'", path.c_str(), line_buf)};
88 }
89
90 // Next line of file *must* be the declared size of the palette
91 std::getline(stream, line_buf);
92 trim_line_ending(line_buf);
93 const auto declared_size_result = parse_int<unsigned int>(line_buf);
94 if (!declared_size_result.has_value()) {
95 return std::unexpected{fmt::format(
96 "{}: expected integral value on line 3: {}", path.c_str(), line_buf, declared_size_result.error())};
97 }
98 const auto declared_size = declared_size_result.value();
99 if (declared_size < 1) {
100 return std::unexpected{fmt::format("{}: expected declared size >= 1, saw '{}'", path.c_str(), declared_size)};
101 }
102
103 // Rest of file lines are the colors
104 unsigned int color_index = 0;
105 while (std::getline(stream, line_buf)) {
106 const auto color_result = parse_jasc_line(trim_line_ending(line_buf));
107 if (!color_result.has_value()) {
108 return std::unexpected{fmt::format(
109 "{}: error parsing color on line {}: {}", path.c_str(), color_index + 4, color_result.error())};
110 }
111 pal.add(color_result.value());
112 color_index++;
113 }
114
115 if (color_index != declared_size) {
116 return std::unexpected{fmt::format(
117 "{}: declared size was '{}' but only saw {} defined colors", path.c_str(), declared_size, color_index)};
118 }
119
120 return pal;
121}
122
123} // namespace porytiles2
Result< Palette< Rgba32 > > load(const std::filesystem::path &path) const override
A palette container for colors that support transparency checking.
Definition palette.hpp:34
Represents a 32-bit RGBA color.
Definition rgba32.hpp:21
static constexpr std::uint8_t alpha_opaque
Definition rgba32.hpp:24
@ blue
Blue text color.
@ green
Green text color.
@ red
Red text color.
std::expected< T, E > Result
A result with some type T on success, otherwise an error of type E.
Definition result.hpp:25
std::vector< std::string > split(std::string input, const std::string &delimiter)
Splits a string into tokens based on a delimiter.
std::string & trim_line_ending(std::string &line)
Removes line ending characters from a string in-place.