5#include <QtQuick3DRuntimeRender/private/qssgrenderloadedtexture_p.h>
6#include <QtQuick3DRuntimeRender/private/qssgrendererutil_p.h>
7#include <QtQuick3DRuntimeRender/private/qssgruntimerenderlogging_p.h>
8#include <QtQuick3DRuntimeRender/private/qssgrendertexturedata_p.h>
9#include <QtGui/QImageReader>
10#include <QtGui/QColorSpace>
13#include <QtQuick3DUtils/private/qssgutils_p.h>
15#include <private/qtexturefilereader_p.h>
17#define TINYEXR_IMPLEMENTATION
18#define TINYEXR_USE_MINIZ 0
19#define TINYEXR_USE_THREAD 1
48 if (!
file && !inQuiet)
59 static const QList<QByteArray> allFormats = textureFormats + hdrFormats + imageFormats;
89 }
else if (!inQuiet) {
276 if (
image.colorCount())
285 image.convertTo(targetFormat);
315 QFile imageFile(inPath);
317 qWarning() <<
"Could not open image file: " << inPath;
323 qWarning() <<
"Unable to read image file: " << inPath;
346typedef unsigned char RGBE[4];
353#define MAXELEN 0x7fff
357inline int calculateLine(
int width,
int bitdepth) {
return ((
width * bitdepth) + 7) / 8; }
359inline int calculatePitch(
int line) {
return (
line + 3) & ~3; }
363 float v =
val / (256.0f);
364 float d = powf(2.0f, (
float)
exponent - 128.0f);
368void decrunchScanline(
const char *&
p,
const char *pEnd, RGBE *scanline,
int w)
370 scanline[0][
R] = *
p++;
371 scanline[0][
G] = *
p++;
372 scanline[0][
B] = *
p++;
373 scanline[0][
E] = *
p++;
375 if (scanline[0][
R] == 2 && scanline[0][
G] == 2 && scanline[0][
B] < 128) {
378 for (
int x = 0;
x <
w &&
p < pEnd; ) {
379 unsigned char c = *
p++;
382 int repCount =
c & 127;
388 while (
c-- &&
p < pEnd)
398 while (x < w && pEnd - p >= 4) {
399 scanline[
x][
R] = *
p++;
400 scanline[
x][
G] = *
p++;
401 scanline[
x][
B] = *
p++;
402 scanline[
x][
E] = *
p++;
404 if (scanline[
x][
R] == 1 && scanline[
x][
G] == 1 && scanline[
x][
B] == 1) {
405 int repCount = scanline[
x][3] << bitshift;
407 memcpy(scanline[
x], scanline[
x - 1], 4);
429 rgbaF32[
R] = convertComponent(scanline[
i][
E], scanline[
i][
R]);
430 rgbaF32[
G] = convertComponent(scanline[
i][
E], scanline[
i][
G]);
431 rgbaF32[
B] = convertComponent(scanline[
i][
E], scanline[
i][
B]);
446 if (!strncmp(sig,
"#?RADIANCE\n", 11)) {
449 const char *pEnd =
p +
buf.size();
471 qWarning(
"Malformed HDR image data at property strings");
483 qWarning(
"Malformed HDR image data at resolution string");
503 const int bytesPerPixel =
format.getSizeofFormat();
504 const int bitCount = bytesPerPixel * 8;
505 const int pitch = calculatePitch(calculateLine(
width, bitCount));
516 RGBE *scanline =
new RGBE[
width];
523 qWarning(
"Unexpected end of HDR data");
527 decrunchScanline(
p, pEnd, scanline,
width);
541 char versionBuffer[tinyexr::kEXRVersionSize];
543 auto size =
source->read(versionBuffer, tinyexr::kEXRVersionSize);
545 if (
size != tinyexr::kEXRVersionSize)
548 EXRVersion exrVersion;
549 if (ParseEXRVersionFromMemory(&exrVersion,
reinterpret_cast<unsigned char *
>(versionBuffer), tinyexr::kEXRVersionSize) != TINYEXR_SUCCESS)
553 if (exrVersion.multipart)
559 const char *err =
nullptr;
562 InitEXRHeader(&exrHeader);
563 if (ParseEXRHeaderFromMemory(&exrHeader,
565 reinterpret_cast<const unsigned char *
>(
buf.constData()),
567 &err) != TINYEXR_SUCCESS) {
568 qWarning(
"Failed to parse EXR Header with error: '%s'", err);
569 FreeEXRErrorMessage(err);
574 for (
int i = 0;
i < exrHeader.num_channels;
i++) {
575 if (exrHeader.pixel_types[
i] == TINYEXR_PIXELTYPE_HALF)
576 exrHeader.requested_pixel_types[
i] = TINYEXR_PIXELTYPE_FLOAT;
582 InitEXRImage(&exrImage);
583 if (LoadEXRImageFromMemory(&exrImage,
585 reinterpret_cast<const unsigned char *
>(
buf.constData()),
587 &err) != TINYEXR_SUCCESS) {
588 qWarning(
"Failed to load EXR Image with error: '%s'", err);
589 FreeEXRHeader(&exrHeader);
590 FreeEXRErrorMessage(err);
595 const int bytesPerPixel =
format.getSizeofFormat();
596 const int bitCount = bytesPerPixel * 8;
597 const int pitch = calculatePitch(calculateLine(exrImage.width, bitCount));
616 for (
int c = 0;
c < exrHeader.num_channels;
c++) {
617 if (strcmp(exrHeader.channels[
c].name,
"R") == 0)
619 else if (strcmp(exrHeader.channels[
c].name,
"G") == 0)
621 else if (strcmp(exrHeader.channels[
c].name,
"B") == 0)
623 else if (strcmp(exrHeader.channels[
c].name,
"A") == 0)
626 const bool isSingleChannel = exrHeader.num_channels == 1;
629 if (exrHeader.tiled) {
630 for (
int it = 0;
it < exrImage.num_tiles;
it++) {
631 for (
int j = 0;
j < exrHeader.tile_size_y;
j++)
632 for (
int i = 0;
i < exrHeader.tile_size_x;
i++) {
634 exrImage.tiles[
it].offset_x * exrHeader.tile_size_x +
i;
636 exrImage.tiles[
it].offset_y * exrHeader.tile_size_y +
j;
637 const int inverseJJ = std::abs(jj - (exrImage.height - 1));
638 const int idx = ii + inverseJJ * exrImage.width;
641 if (ii >= exrImage.width) {
644 if (jj >= exrImage.height) {
647 const int srcIdx =
i +
j * exrHeader.tile_size_x;
648 unsigned char **
src = exrImage.tiles[
it].images;
649 if (isSingleChannel) {
650 rgbaF32[
R] =
reinterpret_cast<float **
>(
src)[0][srcIdx];
651 rgbaF32[
G] = rgbaF32[
R];
652 rgbaF32[
B] = rgbaF32[
R];
653 rgbaF32[3] = rgbaF32[
R];
655 rgbaF32[
R] =
reinterpret_cast<float **
>(
src)[idxR][srcIdx];
656 rgbaF32[
G] =
reinterpret_cast<float **
>(
src)[idxG][srcIdx];
657 rgbaF32[
B] =
reinterpret_cast<float **
>(
src)[idxB][srcIdx];
659 rgbaF32[3] =
reinterpret_cast<float **
>(
src)[idxA][srcIdx];
663 format.encodeToPixel(rgbaF32,
target, idx * bytesPerPixel);
668 for (
int y = exrImage.height - 1;
y >= 0; --
y) {
669 for (
int x = 0;
x < exrImage.width;
x++) {
670 const int i =
y * exrImage.width +
x;
671 if (isSingleChannel) {
672 rgbaF32[
R] =
reinterpret_cast<float **
>(exrImage.images)[0][
i];
673 rgbaF32[
G] = rgbaF32[
R];
674 rgbaF32[
B] = rgbaF32[
R];
675 rgbaF32[3] = rgbaF32[
R];
677 rgbaF32[
R] =
reinterpret_cast<float **
>(exrImage.images)[idxR][
i];
678 rgbaF32[
G] =
reinterpret_cast<float **
>(exrImage.images)[idxG][
i];
679 rgbaF32[
B] =
reinterpret_cast<float **
>(exrImage.images)[idxB][
i];
681 rgbaF32[3] =
reinterpret_cast<float **
>(exrImage.images)[idxA][
i];
685 format.encodeToPixel(rgbaF32,
target, idx * bytesPerPixel);
692 FreeEXRImage(&exrImage);
693 FreeEXRHeader(&exrHeader);
729 const int bitCount = bytesPerPixel * 8;
730 const int pitch = calculatePitch(calculateLine(textureData->
size().
width(), bitCount));
732 if (textureData->
depth() > 0)
774 const quint8 *rowPtr =
reinterpret_cast<const quint8 *
>(inData);
776 if (inAlphaSizeInBits == 0)
778 if (inPixelSizeInBytes != 2 && inPixelSizeInBytes != 4) {
782 if (inAlphaSizeInBits > 8) {
787 quint32 alphaRightShift = inPixelSizeInBytes * 8 - inAlphaSizeInBits;
788 quint32 maxAlphaValue = (1 << inAlphaSizeInBits) - 1;
791 for (
quint32 idx = 0; idx < inWidth && !
hasAlpha; ++idx, rowPtr += inPixelSizeInBytes) {
793 if (inPixelSizeInBytes == 2)
794 pixelValue = *(
reinterpret_cast<const quint16 *
>(rowPtr));
796 pixelValue = *(
reinterpret_cast<const quint32 *
>(rowPtr));
797 pixelValue = pixelValue >> alphaRightShift;
798 if (pixelValue < maxAlphaValue)
883 const char *faces[6] = {
"posx",
"negx",
"posy",
"negy",
"posz",
"negz" };
884 for (
const auto face : faces) {
896 textureFileData->setNumFaces(6);
897 textureFileData->setNumLevels(1);
898 textureFileData->setLogName(inPath.
toUtf8());
900 for (
int i = 0;
i < 6; ++
i) {
911 textureFileData->setData(
face, 0,
i);
912 textureFileData->setSize(
face.size());
923 retval->
image = prevImage;
964 return theLoadedImage;
IOBluetoothL2CAPChannel * channel
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
QByteArray toLower() const &
TransferFunction transferFunction() const noexcept
Returns the predefined transfer function of the color space or TransferFunction::Custom if it doesn't...
void close() override
Calls QFileDevice::flush() and closes the file.
\inmodule QtCore \reentrant
bool isNativePath() const
QString suffix() const
Returns the suffix (extension) of the file.
void setFile(const QString &file)
Sets the file that the QFileInfo provides information about to file.
QString canonicalFilePath() const
Returns the canonical path including the file name, i.e.
bool exists() const
Returns true if the file exists; otherwise returns false.
bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
bool canRead() const
Returns true if an image can be read for the device (i.e., the image format is supported,...
static QList< QByteArray > supportedImageFormats()
Returns the list of image formats supported by QImageReader.
QImage read()
Reads an image from the device.
QColorSpace colorSpace() const
qsizetype sizeInBytes() const
QSize size() const
Returns the size of the image, i.e.
int width() const
Returns the width of the image.
uchar * bits()
Returns a pointer to the first pixel data.
bool isNull() const
Returns true if it is a null image, otherwise returns false.
int height() const
Returns the height of the image.
Format
The following image formats are available in Qt.
@ Format_RGBA8888_Premultiplied
QPixelFormat pixelFormat() const noexcept
Returns the QImage::Format as a QPixelFormat.
const QByteArray & textureData() const
QSSGRenderTextureFormat format() const
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
\macro QT_RESTRICTED_CAST_FROM_ASCII
QByteArray toLatin1() const &
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the string into substrings wherever sep occurs, and returns the list of those strings.
void clear()
Clears the contents of the string and makes it null.
const QChar * constData() const
Returns a pointer to the data stored in the QString.
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
QString & append(QChar c)
QString trimmed() const &
QByteArray toUtf8() const &
QString & prepend(QChar c)
quint32 glInternalFormat() const
static QList< QByteArray > supportedFileFormats()
QSet< QString >::iterator it
Combined button and popup list for selecting options.
#define QByteArrayLiteral(str)
#define qCWarning(category,...)
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei const GLchar * buf
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLint GLsizei GLsizei GLenum format
GLsizei GLenum internalFormat
GLsizei GLsizei GLchar * source
static bool hasAlpha(const QImage &image)
static bool isCompatible(const QImage &img1, const QImage &img2)
static QSSGRenderTextureFormat fromGLtoTextureFormat(quint32 internalFormat)
static QImage loadImage(const QString &inPath, bool flipVertical)
static QSSGLoadedTexture * loadCubeMap(const QString &inPath, bool flipY)
#define qPrintable(string)
QLatin1StringView QLatin1String
#define QStringLiteral(str)
static FileType fileType(const QFileInfo &fi)
QFileInfo fi("c:/temp/foo")
[newstuff]
\inmodule QtCore \reentrant
bool contains(const AT &t) const noexcept
QTextureFileData textureFileData
static QSSGLoadedTexture * loadHdrImage(const QSharedPointer< QIODevice > &source, const QSSGRenderTextureFormat &inFormat)
static QSSGLoadedTexture * loadCompressedImage(const QString &inPath)
QSSGRenderTextureFormat format
static QSSGLoadedTexture * load(const QString &inPath, const QSSGRenderTextureFormat &inFormat, bool inFlipY=true)
void setFormatFromComponents()
static QSSGLoadedTexture * loadTextureData(QSSGRenderTextureData *textureData)
bool scanForTransparency() const
static QSSGLoadedTexture * loadQImage(const QString &inPath, qint32 flipVertical)
@ SRGB8_Alpha8_ASTC_12x10
@ SRGB8_Alpha8_ASTC_12x12
@ SRGB8_Alpha8_ASTC_10x10
@ SRGB8_PunchThrough_Alpha1_ETC2
@ RGB8_PunchThrough_Alpha1_ETC2
void encodeToPixel(float *inPtr, void *outPtr, qint32 byteOfs) const
constexpr bool isCompressedTextureFormat() const noexcept
qint32 getNumberOfComponent() const
qint32 getSizeofFormat() const