106 lines
2.9 KiB
C++
106 lines
2.9 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/.
|
|
*/
|
|
|
|
#include "ImageLoaderPfm.hpp"
|
|
|
|
#include "Scene/DataFormat.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <stdexcept>
|
|
|
|
namespace
|
|
{
|
|
struct PfmImageHeader
|
|
{
|
|
int width;
|
|
int height;
|
|
bool isColor;
|
|
bool isLittleEndian;
|
|
};
|
|
|
|
PfmImageHeader ParseHeader(std::istringstream& stream)
|
|
{
|
|
PfmImageHeader header;
|
|
std::string magic;
|
|
stream >> magic;
|
|
header.isColor = (magic == "PF");
|
|
|
|
float endianess;
|
|
stream >> header.width >> header.height >> endianess;
|
|
stream.ignore();
|
|
|
|
header.isLittleEndian = endianess < 0;
|
|
|
|
return header;
|
|
}
|
|
}
|
|
|
|
namespace OpenVulkano::Image
|
|
{
|
|
std::unique_ptr<Image> ImageLoaderPfm::loadFromFile(const std::string& filePath)
|
|
{
|
|
std::ifstream file(filePath, std::ios::binary);
|
|
if (!file.is_open())
|
|
{
|
|
throw std::runtime_error("Failed to open PFM file: " + filePath);
|
|
}
|
|
|
|
std::vector<uint8_t> buffer((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
|
return loadFromMemory(buffer);
|
|
}
|
|
|
|
std::unique_ptr<Image> ImageLoaderPfm::loadFromMemory(const std::vector<uint8_t>& buffer)
|
|
{
|
|
std::istringstream stream(std::string(buffer.begin(), buffer.end()), std::ios::binary);
|
|
PfmImageHeader header = ParseHeader(stream);
|
|
|
|
size_t numChannels = header.isColor ? 3 : 1;
|
|
size_t dataSize = header.width * header.height * numChannels * sizeof(float);
|
|
Array<float> data(header.width * header.height * numChannels);
|
|
size_t rowSize = header.width * numChannels * sizeof(float);
|
|
|
|
for (int y = header.height - 1; y >= 0; --y)
|
|
{
|
|
stream.read(reinterpret_cast<char*>(&data[y * header.width * numChannels]), rowSize);
|
|
if (!stream)
|
|
{
|
|
throw std::runtime_error("Error reading PFM image data");
|
|
}
|
|
}
|
|
|
|
if (!header.isLittleEndian)
|
|
{
|
|
for (float& value : data)
|
|
{
|
|
uint8_t* ptr = reinterpret_cast<uint8_t*>(&value);
|
|
std::reverse(ptr, ptr + sizeof(float));
|
|
}
|
|
}
|
|
|
|
auto image = std::make_unique<Image>();
|
|
image->resolution = { static_cast<uint32_t>(header.width), static_cast<uint32_t>(header.height), 1 };
|
|
image->dataFormat = header.isColor ? DataFormat::Format::R32G32B32_SFLOAT : DataFormat::Format::R32_SFLOAT;
|
|
image->data = std::move(*reinterpret_cast<Array<uint8_t>*>(&data));
|
|
return image;
|
|
}
|
|
|
|
Math::Vector2i ImageLoaderPfm::GetImageDimensions(const std::string& filename)
|
|
{
|
|
std::ifstream file(filename, std::ios::binary);
|
|
if (!file.is_open())
|
|
{
|
|
throw std::runtime_error("Failed to open PFM file: " + filename);
|
|
}
|
|
|
|
std::vector<uint8_t> buffer((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
|
std::istringstream stream(std::string(buffer.begin(), buffer.end()), std::ios::binary);
|
|
PfmImageHeader header = ParseHeader(stream);
|
|
return { header.width, header.height };
|
|
}
|
|
} |