68 {
70 if (loaded_surface == nullptr) {
72 }
73
74 SDL_Surface *
surface = SDL_ConvertSurface(loaded_surface, SDL_PIXELFORMAT_RGBA32);
75 SDL_DestroySurface(loaded_surface);
78 }
79
80 const SDL_PixelFormatDetails *format_details = SDL_GetPixelFormatDetails(surface->format);
81 if (format_details == nullptr) {
82 SDL_DestroySurface(surface);
83 throw mxvk::Exception("Failed to query pixel format details for: " + path);
84 }
85
86 if (!SDL_LockSurface(surface)) {
87 SDL_DestroySurface(surface);
88 throw mxvk::Exception("Failed to lock PNG surface: " + path);
89 }
90
91 auto *pixels = static_cast<std::uint32_t *>(surface->pixels);
92 const int width = surface->w;
93 const int height = surface->h;
94 const int pixel_count = width * height;
95 std::vector<std::uint8_t> background(static_cast<std::size_t>(pixel_count), 0);
96 std::vector<int> stack;
97 stack.reserve(static_cast<std::size_t>(width + height) * 2);
98
99 const auto is_light_checker_pixel = [&](const int index) {
100 std::uint8_t r = 0;
101 std::uint8_t g = 0;
102 std::uint8_t b = 0;
103 std::uint8_t a = 0;
104 SDL_GetRGBA(pixels[index], format_details, nullptr, &r, &g, &b, &a);
105 const int min_channel = std::min({static_cast<int>(r), static_cast<int>(g), static_cast<int>(b)});
106 const int max_channel = std::max({static_cast<int>(r), static_cast<int>(g), static_cast<int>(b)});
107 return a != 0 && min_channel >= 215 && (max_channel - min_channel) <= 28;
108 };
109
110 const auto push_background = [&](const int index) {
111 if (index < 0 || index >= pixel_count || background[static_cast<std::size_t>(index)] != 0 || !is_light_checker_pixel(index)) {
112 return;
113 }
114 background[static_cast<std::size_t>(index)] = 1;
115 stack.push_back(index);
116 };
117
118 for (int x = 0; x < width; ++x) {
119 push_background(x);
120 push_background((height - 1) * width + x);
121 }
122 for (int y = 0; y < height; ++y) {
123 push_background(y * width);
124 push_background(y * width + width - 1);
125 }
126
127 while (!stack.empty()) {
128 const int index = stack.back();
129 stack.pop_back();
130 const int x = index % width;
131 const int y = index / width;
132 if (x > 0) {
133 push_background(index - 1);
134 }
135 if (x + 1 < width) {
136 push_background(index + 1);
137 }
138 if (y > 0) {
139 push_background(index - width);
140 }
141 if (y + 1 < height) {
142 push_background(index + width);
143 }
144 }
145
146 for (int i = 0; i < pixel_count; ++i) {
147 if (background[static_cast<std::size_t>(i)] == 0) {
148 continue;
149 }
150 std::uint8_t r = 0;
151 std::uint8_t g = 0;
152 std::uint8_t b = 0;
153 std::uint8_t a = 0;
154 SDL_GetRGBA(pixels[i], format_details, nullptr, &r, &g, &b, &a);
155 pixels[i] = SDL_MapRGBA(format_details, nullptr, r, g, b, 0);
156 }
157
158 SDL_UnlockSurface(surface);
159 return surface;
160 }
SDL_Surface * LoadPNG(const char *file)
Load a PNG file into an SDL_Surface.