Files
OpenVulkano/openVulkanoCpp/IO/Files/Pfm.hpp
2023-10-03 19:52:23 +02:00

120 lines
3.1 KiB
C++

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "Base/Utils.hpp"
#include <string>
#include <sstream>
#include <iomanip>
#include <memory>
namespace OpenVulkano
{
//TODO handle comments
class PfmHeader
{
public:
static constexpr std::string_view FILE_TYPE = "PFM";
static constexpr std::string_view FILE_EXT = ".pfm";
uint32_t width, height;
float maxValue;
bool color, littleEndian;
PfmHeader() : width(0), height(0), maxValue(0), color(false), littleEndian(Utils::IsLittleEndian()) {}
PfmHeader(uint32_t width, uint32_t height, float maxValue, bool color) :
width(width), height(height), maxValue(maxValue), color(color), littleEndian(Utils::IsLittleEndian())
{}
constexpr PfmHeader(uint32_t width, uint32_t height, float maxValue, bool color, bool littleEndian) :
width(width), height(height), maxValue(maxValue), color(color), littleEndian(littleEndian)
{}
[[nodiscard]] std::string ToString() const
{
std::stringstream headerStream;
headerStream << *this;
return headerStream.str();
}
friend std::ostream& operator<< (std::ostream& outStream, const PfmHeader& pfmHeader)
{
outStream << (pfmHeader.color ? "PF" : "Pf") << '\n';
outStream << pfmHeader.width << ' ' << pfmHeader.height << '\n';
if (pfmHeader.littleEndian) outStream << '-';
outStream << std::fixed << std::setprecision(1) << pfmHeader.maxValue << '\n';
return outStream;
}
friend std::istream& operator>> (std::istream& inStream, PfmHeader& pfmHeader)
{
std::string marker;
inStream >> marker;
if (marker == "PF") pfmHeader.color = true;
else if (marker == "Pf") pfmHeader.color = false;
else throw std::runtime_error("Malformed PFM header!");
inStream >> pfmHeader.width >> pfmHeader.height;
inStream >> pfmHeader.maxValue;
inStream.get();
if (pfmHeader.maxValue < 0)
{
pfmHeader.maxValue *= -1;
pfmHeader.littleEndian = true;
}
else
{
pfmHeader.littleEndian = false;
}
return inStream;
}
[[nodiscard]] constexpr size_t GetElementCount() const
{
size_t size = height * width;
if (color) size *= 3;
return size;
}
[[nodiscard]] constexpr size_t GetImageSize() const
{
return GetElementCount() * sizeof(float);
}
};
struct PfmImage
{
PfmHeader header;
std::unique_ptr<float[]> image;
void Read(std::istream& inStream)
{
inStream >> header;
size_t size = header.GetElementCount();
if (Utils::IsLittleEndian() != header.littleEndian)
{
char* data = reinterpret_cast<char*>(image.get());
for(size_t i = 0; i < size; i++)
{
size_t idx = i * sizeof(float);
std::reverse(&data[idx], &data[idx + sizeof(float)]);
}
}
image = std::make_unique<float[]>(size);
inStream.read(reinterpret_cast<char*>(image.get()), size * sizeof(float));
}
static PfmImage ReadImage(std::istream& inStream)
{
PfmImage image;
image.Read(inStream);
return image;
}
};
}