120 lines
3.1 KiB
C++
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 openVulkanoCpp
|
|
{
|
|
//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;
|
|
}
|
|
};
|
|
} |