LCOV - code coverage report
Current view: top level - src - image.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 51 51
Test Date: 2025-06-27 11:12:05 Functions: 100.0 % 2 2

            Line data    Source code
       1              : // Copyright (c) 2025 Milton McDonald
       2              : // This source code is licensed under the MIT License. See LICENSE file in the
       3              : // project root for details.
       4              : 
       5              : #include "graphics-engine/image.h"
       6              : 
       7              : #include <array>
       8              : #include <cassert>
       9              : #include <span>
      10              : #include <vector>
      11              : 
      12              : #include "error.h"
      13              : #include "glad/glad.h"
      14              : #include "stb/stb_image.h"
      15              : #include "stb/stb_image_write.h"
      16              : 
      17              : using ::graphics_engine::error::CheckGLError;
      18              : using ::graphics_engine::error::MakeErrorCode;
      19              : using enum ::graphics_engine::types::ErrorCode;
      20              : using ::graphics_engine::types::Expected;
      21              : 
      22              : using ::std::array;
      23              : using ::std::byte;
      24              : using ::std::is_same_v;
      25              : using ::std::optional;
      26              : using ::std::span;
      27              : using ::std::string;
      28              : using ::std::unexpected;
      29              : using ::std::vector;
      30              : using ::std::filesystem::path;
      31              : using ::std::filesystem::temp_directory_path;
      32              : 
      33              : namespace graphics_engine::image {
      34              : 
      35            5 : auto AreIdentical(const path& png0, const path& png1) -> Expected<bool> {
      36            5 :   int width1{};
      37            5 :   int height1{};
      38            5 :   int channels1{};
      39            5 :   int width2{};
      40            5 :   int height2{};
      41            5 :   int channels2{};
      42              : 
      43            5 :   const string str_filename0 = png0.string();
      44            5 :   const char* filename0 = str_filename0.c_str();
      45              : 
      46            5 :   const string str_filename1 = png1.string();
      47            5 :   const char* filename1 = str_filename1.c_str();
      48              : 
      49            5 :   stbi_uc* img1 = stbi_load(filename0, &width1, &height1, &channels1, 0);
      50            5 :   stbi_uc* img2 = stbi_load(filename1, &width2, &height2, &channels2, 0);
      51              : 
      52            5 :   if ((img1 == nullptr) || (img2 == nullptr)) {
      53            1 :     return unexpected(MakeErrorCode(kStbErrorLoad));
      54              :   }
      55              : 
      56            4 :   if (width1 != width2 || height1 != height2 || channels1 != channels2) {
      57            1 :     return false;
      58              :   }
      59              : 
      60            3 :   auto sz_width1 = static_cast<size_t>(width1);
      61            3 :   auto sz_height1 = static_cast<size_t>(height1);
      62            3 :   auto sz_channels1 = static_cast<size_t>(channels1);
      63            3 :   size_t size = sz_width1 * sz_height1 * sz_channels1;
      64            3 :   span<const stbi_uc> span1(img1, size);
      65            3 :   span<const stbi_uc> span2(img2, size);
      66            3 :   bool identical = equal(span1.begin(), span1.end(), span2.begin());
      67              : 
      68            3 :   stbi_image_free(img1);
      69            3 :   stbi_image_free(img2);
      70              : 
      71            3 :   return identical;
      72            5 : }
      73              : 
      74            2 : auto CaptureScreenshot(const optional<path>& dest) -> Expected<void> {
      75            4 :   const path png_path = dest.value_or(temp_directory_path() / "screenshot.png");
      76            2 :   array<GLint, 4> viewport{};
      77            2 :   glGetIntegerv(GL_VIEWPORT, viewport.data());
      78            2 :   CheckGLError();
      79              : 
      80            2 :   static_assert(is_same_v<GLsizei, GLint>,
      81              :                 "GLsizei and GLint are not the same type!");
      82            2 :   const GLsizei width = viewport[2];
      83            2 :   const GLsizei height = viewport[3];
      84              : 
      85            2 :   auto sz_width = static_cast<size_t>(width);
      86            2 :   auto sz_height = static_cast<size_t>(height);
      87            2 :   size_t num_channels{4};
      88            2 :   size_t size = sz_width * sz_height * num_channels;
      89            2 :   vector<byte> pixels(size);
      90            2 :   glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
      91            2 :   CheckGLError();
      92              : 
      93            2 :   stbi_flip_vertically_on_write(static_cast<int>(true));
      94              : 
      95            2 :   const string str_filename = png_path.string();
      96            2 :   const char* filename = str_filename.c_str();
      97            2 :   void* data = pixels.data();
      98            2 :   if (stbi_write_png(filename, width, height, 4, data, width * 4) == 0) {
      99            1 :     return unexpected(MakeErrorCode(kStbErrorWritePng));
     100              :   }
     101              : 
     102            1 :   return {};
     103            4 : }
     104              : 
     105              : }  // namespace graphics_engine::image
        

Generated by: LCOV version 2.0-1