mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 16:55:07 +02:00
MOving the actual creation of the texture and the pixel manipulation required from TextureCache to TextureSOurce
This commit is contained in:
parent
6914caac9d
commit
3614812681
8 changed files with 465 additions and 26 deletions
|
@ -200,34 +200,66 @@ NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArr
|
|||
}
|
||||
}
|
||||
|
||||
NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content) :
|
||||
Resource(url, !content.isEmpty()),
|
||||
// _type(type),
|
||||
_textureLoader(textureLoader),
|
||||
_translucent(false),
|
||||
_width(0),
|
||||
_height(0) {
|
||||
|
||||
_textureStorage.reset(new model::TextureStorage());
|
||||
|
||||
if (!url.isValid()) {
|
||||
_loaded = true;
|
||||
}
|
||||
|
||||
std::string theName = url.toString().toStdString();
|
||||
// if we have content, load it after we have our self pointer
|
||||
if (!content.isEmpty()) {
|
||||
_startedLoading = true;
|
||||
QMetaObject::invokeMethod(this, "loadContent", Qt::QueuedConnection, Q_ARG(const QByteArray&, content));
|
||||
}
|
||||
}
|
||||
|
||||
NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
|
||||
if (_type != CUBE_TEXTURE) {
|
||||
|
||||
return TextureLoaderFunc(model::TextureStorage::create2DTextureFromImage);
|
||||
} else {
|
||||
return TextureLoaderFunc(model::TextureStorage::createCubeTextureFromImage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ImageReader : public QRunnable {
|
||||
public:
|
||||
|
||||
ImageReader(const QWeakPointer<Resource>& texture, TextureType type, const QByteArray& data, const QUrl& url = QUrl());
|
||||
ImageReader(const QWeakPointer<Resource>& texture, const NetworkTexture::TextureLoaderFunc& textureLoader, const QByteArray& data, const QUrl& url = QUrl());
|
||||
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
|
||||
QWeakPointer<Resource> _texture;
|
||||
TextureType _type;
|
||||
NetworkTexture::TextureLoaderFunc _textureLoader;
|
||||
QUrl _url;
|
||||
QByteArray _content;
|
||||
};
|
||||
|
||||
void NetworkTexture::downloadFinished(const QByteArray& data) {
|
||||
// send the reader off to the thread pool
|
||||
QThreadPool::globalInstance()->start(new ImageReader(_self, _type, data, _url));
|
||||
QThreadPool::globalInstance()->start(new ImageReader(_self, getTextureLoader(), data, _url));
|
||||
}
|
||||
|
||||
void NetworkTexture::loadContent(const QByteArray& content) {
|
||||
QThreadPool::globalInstance()->start(new ImageReader(_self, _type, content, _url));
|
||||
QThreadPool::globalInstance()->start(new ImageReader(_self, getTextureLoader(), content, _url));
|
||||
}
|
||||
|
||||
ImageReader::ImageReader(const QWeakPointer<Resource>& texture, TextureType type, const QByteArray& data,
|
||||
ImageReader::ImageReader(const QWeakPointer<Resource>& texture, const NetworkTexture::TextureLoaderFunc& textureLoader, const QByteArray& data,
|
||||
const QUrl& url) :
|
||||
_texture(texture),
|
||||
_type(type),
|
||||
_textureLoader(textureLoader),
|
||||
_url(url),
|
||||
_content(data)
|
||||
{
|
||||
|
@ -246,7 +278,7 @@ void listSupportedImageFormats() {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
class CubeLayout {
|
||||
public:
|
||||
int _widthRatio = 1;
|
||||
|
@ -280,6 +312,7 @@ public:
|
|||
_faceZPos(fZP),
|
||||
_faceZNeg(fZN) {}
|
||||
};
|
||||
*/
|
||||
|
||||
void ImageReader::run() {
|
||||
QSharedPointer<Resource> texture = _texture.toStrongRef();
|
||||
|
@ -309,8 +342,17 @@ void ImageReader::run() {
|
|||
return;
|
||||
}
|
||||
|
||||
int imageArea = image.width() * image.height();
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
auto ntex = dynamic_cast<NetworkTexture*>(&*texture);
|
||||
if (ntex) {
|
||||
theTexture = ntex->getTextureLoader()(image, _url.toString().toStdString());
|
||||
}
|
||||
|
||||
/*
|
||||
int imageArea = image.width() * image.height();
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
|
||||
if (ntex && (ntex->getType() == CUBE_TEXTURE)) {
|
||||
qCDebug(gpunetwork) << "Cube map size:" << _url << image.width() << image.height();
|
||||
}
|
||||
|
@ -535,21 +577,21 @@ void ImageReader::run() {
|
|||
theTexture->autoGenerateMips(-1);
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
QMetaObject::invokeMethod(texture.data(), "setImage",
|
||||
Q_ARG(const QImage&, image),
|
||||
Q_ARG(void*, theTexture),
|
||||
Q_ARG(bool, isTransparent),
|
||||
Q_ARG(const QColor&, averageColor),
|
||||
// Q_ARG(bool, isTransparent),
|
||||
// Q_ARG(const QColor&, averageColor),
|
||||
Q_ARG(int, originalWidth), Q_ARG(int, originalHeight));
|
||||
|
||||
|
||||
}
|
||||
|
||||
void NetworkTexture::setImage(const QImage& image, void* voidTexture, bool translucent, const QColor& averageColor, int originalWidth,
|
||||
void NetworkTexture::setImage(const QImage& image, void* voidTexture,/* bool translucent, const QColor& averageColor, */ int originalWidth,
|
||||
int originalHeight) {
|
||||
_translucent = translucent;
|
||||
_averageColor = averageColor;
|
||||
// _translucent = translucent;
|
||||
// _averageColor = averageColor;
|
||||
_originalWidth = originalWidth;
|
||||
_originalHeight = originalHeight;
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include <DependencyManager.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <model/TextureStorage.h>
|
||||
#include <model/TextureMap.h>
|
||||
|
||||
namespace gpu {
|
||||
class Batch;
|
||||
|
@ -63,7 +63,13 @@ public:
|
|||
/// Loads a texture from the specified URL.
|
||||
NetworkTexturePointer getTexture(const QUrl& url, TextureType type = DEFAULT_TEXTURE,
|
||||
const QByteArray& content = QByteArray());
|
||||
|
||||
|
||||
typedef gpu::Texture* TextureLoader(const QImage& image, const std::string& srcImageName);
|
||||
|
||||
typedef std::function<TextureLoader> TextureLoaderFunc;
|
||||
|
||||
NetworkTexturePointer getTexture(const QUrl& url, const TextureLoaderFunc& textureLoader,
|
||||
const QByteArray& content = QByteArray());
|
||||
protected:
|
||||
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url,
|
||||
|
@ -107,27 +113,33 @@ class NetworkTexture : public Resource, public Texture {
|
|||
|
||||
public:
|
||||
|
||||
typedef TextureCache::TextureLoaderFunc TextureLoaderFunc;
|
||||
|
||||
NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content);
|
||||
NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content);
|
||||
|
||||
/// Checks whether it "looks like" this texture is translucent
|
||||
/// (majority of pixels neither fully opaque or fully transparent).
|
||||
bool isTranslucent() const { return _translucent; }
|
||||
// bool isTranslucent() const { return _translucent; }
|
||||
|
||||
/// Returns the lazily-computed average texture color.
|
||||
const QColor& getAverageColor() const { return _averageColor; }
|
||||
// const QColor& getAverageColor() const { return _averageColor; }
|
||||
|
||||
int getOriginalWidth() const { return _originalWidth; }
|
||||
int getOriginalHeight() const { return _originalHeight; }
|
||||
int getWidth() const { return _width; }
|
||||
int getHeight() const { return _height; }
|
||||
TextureType getType() const { return _type; }
|
||||
// TextureType getType() const { return _type; }
|
||||
|
||||
TextureLoaderFunc getTextureLoader() const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
|
||||
Q_INVOKABLE void loadContent(const QByteArray& content);
|
||||
// FIXME: This void* should be a gpu::Texture* but i cannot get it to work for now, moving on...
|
||||
Q_INVOKABLE void setImage(const QImage& image, void* texture, bool translucent, const QColor& averageColor, int originalWidth,
|
||||
Q_INVOKABLE void setImage(const QImage& image, void* texture, /*bool translucent, const QColor& averageColor, */int originalWidth,
|
||||
int originalHeight);
|
||||
|
||||
virtual void imageLoaded(const QImage& image);
|
||||
|
@ -135,6 +147,7 @@ protected:
|
|||
TextureType _type;
|
||||
|
||||
private:
|
||||
TextureLoaderFunc _textureLoader;
|
||||
bool _translucent;
|
||||
QColor _averageColor;
|
||||
int _originalWidth;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
#include "Material.h"
|
||||
|
||||
#include "TextureStorage.h"
|
||||
#include "TextureMap.h"
|
||||
|
||||
using namespace model;
|
||||
using namespace gpu;
|
||||
|
|
11
libraries/model/src/model/ModelLogging.cpp
Normal file
11
libraries/model/src/model/ModelLogging.cpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// Created by Sam Gateau on 2015/09/21
|
||||
// Copyright 2013-2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ModelLogging.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(modelLog, "hifi.model")
|
14
libraries/model/src/model/ModelLogging.h
Normal file
14
libraries/model/src/model/ModelLogging.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// ModelLogging.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Sam Gateau on 9/20/15.
|
||||
// Copyright 2013-2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QLoggingCategory>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(modelLog)
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// TextureStorage.cpp
|
||||
// TextureMap.cpp
|
||||
// libraries/model/src/model
|
||||
//
|
||||
// Created by Sam Gateau on 5/6/2015.
|
||||
|
@ -8,7 +8,13 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "TextureStorage.h"
|
||||
#include "TextureMap.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
|
||||
#include "ModelLogging.h"
|
||||
|
||||
using namespace model;
|
||||
using namespace gpu;
|
||||
|
@ -69,3 +75,349 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) {
|
|||
_lightmapOffsetScale.y = scale;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
gpu::Texture* TextureStorage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
QImage image = srcImage;
|
||||
|
||||
int imageArea = image.width() * image.height();
|
||||
|
||||
int opaquePixels = 0;
|
||||
int translucentPixels = 0;
|
||||
bool isTransparent = false;
|
||||
int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
const int EIGHT_BIT_MAXIMUM = 255;
|
||||
QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM);
|
||||
|
||||
if (!image.hasAlphaChannel()) {
|
||||
if (image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb rgb = image.pixel(x, y);
|
||||
redTotal += qRed(rgb);
|
||||
greenTotal += qGreen(rgb);
|
||||
blueTotal += qBlue(rgb);
|
||||
}
|
||||
}
|
||||
if (imageArea > 0) {
|
||||
averageColor.setRgb(redTotal / imageArea, greenTotal / imageArea, blueTotal / imageArea);
|
||||
}
|
||||
} else {
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
// check for translucency/false transparency
|
||||
// int opaquePixels = 0;
|
||||
// int translucentPixels = 0;
|
||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb rgb = image.pixel(x, y);
|
||||
redTotal += qRed(rgb);
|
||||
greenTotal += qGreen(rgb);
|
||||
blueTotal += qBlue(rgb);
|
||||
int alpha = qAlpha(rgb);
|
||||
alphaTotal += alpha;
|
||||
if (alpha == EIGHT_BIT_MAXIMUM) {
|
||||
opaquePixels++;
|
||||
} else if (alpha != 0) {
|
||||
translucentPixels++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opaquePixels == imageArea) {
|
||||
qCDebug(modelLog) << "Image with alpha channel is completely opaque:" << QString(srcImageName.c_str());
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
averageColor = QColor(redTotal / imageArea,
|
||||
greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea);
|
||||
|
||||
isTransparent = (translucentPixels >= imageArea / 2);
|
||||
}
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||
theTexture->autoGenerateMips(-1);
|
||||
}
|
||||
|
||||
return theTexture;
|
||||
}
|
||||
|
||||
class CubeLayout {
|
||||
public:
|
||||
int _widthRatio = 1;
|
||||
int _heightRatio = 1;
|
||||
|
||||
class Face {
|
||||
public:
|
||||
int _x = 0;
|
||||
int _y = 0;
|
||||
bool _horizontalMirror = false;
|
||||
bool _verticalMirror = false;
|
||||
|
||||
Face() {}
|
||||
Face(int x, int y, bool horizontalMirror, bool verticalMirror) : _x(x), _y(y), _horizontalMirror(horizontalMirror), _verticalMirror(verticalMirror) {}
|
||||
};
|
||||
|
||||
Face _faceXPos;
|
||||
Face _faceXNeg;
|
||||
Face _faceYPos;
|
||||
Face _faceYNeg;
|
||||
Face _faceZPos;
|
||||
Face _faceZNeg;
|
||||
|
||||
CubeLayout(int wr, int hr, Face fXP, Face fXN, Face fYP, Face fYN, Face fZP, Face fZN) :
|
||||
_widthRatio(wr),
|
||||
_heightRatio(hr),
|
||||
_faceXPos(fXP),
|
||||
_faceXNeg(fXN),
|
||||
_faceYPos(fYP),
|
||||
_faceYNeg(fYN),
|
||||
_faceZPos(fZP),
|
||||
_faceZNeg(fZN) {}
|
||||
};
|
||||
|
||||
gpu::Texture* TextureStorage::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
QImage image = srcImage;
|
||||
|
||||
int imageArea = image.width() * image.height();
|
||||
|
||||
|
||||
qCDebug(modelLog) << "Cube map size:" << QString(srcImageName.c_str()) << image.width() << image.height();
|
||||
|
||||
int opaquePixels = 0;
|
||||
int translucentPixels = 0;
|
||||
bool isTransparent = false;
|
||||
int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
const int EIGHT_BIT_MAXIMUM = 255;
|
||||
QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM);
|
||||
|
||||
if (!image.hasAlphaChannel()) {
|
||||
if (image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb rgb = image.pixel(x, y);
|
||||
redTotal += qRed(rgb);
|
||||
greenTotal += qGreen(rgb);
|
||||
blueTotal += qBlue(rgb);
|
||||
}
|
||||
}
|
||||
if (imageArea > 0) {
|
||||
averageColor.setRgb(redTotal / imageArea, greenTotal / imageArea, blueTotal / imageArea);
|
||||
}
|
||||
} else {
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
// check for translucency/false transparency
|
||||
// int opaquePixels = 0;
|
||||
// int translucentPixels = 0;
|
||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb rgb = image.pixel(x, y);
|
||||
redTotal += qRed(rgb);
|
||||
greenTotal += qGreen(rgb);
|
||||
blueTotal += qBlue(rgb);
|
||||
int alpha = qAlpha(rgb);
|
||||
alphaTotal += alpha;
|
||||
if (alpha == EIGHT_BIT_MAXIMUM) {
|
||||
opaquePixels++;
|
||||
} else if (alpha != 0) {
|
||||
translucentPixels++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opaquePixels == imageArea) {
|
||||
qCDebug(modelLog) << "Image with alpha channel is completely opaque:" << QString(srcImageName.c_str());
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
averageColor = QColor(redTotal / imageArea,
|
||||
greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea);
|
||||
|
||||
isTransparent = (translucentPixels >= imageArea / 2);
|
||||
}
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
|
||||
|
||||
const CubeLayout CUBEMAP_LAYOUTS[] = {
|
||||
// Here is the expected layout for the faces in an image with the 1/6 aspect ratio:
|
||||
//
|
||||
// WIDTH
|
||||
// <------>
|
||||
// ^ +------+
|
||||
// | | |
|
||||
// | | +X |
|
||||
// | | |
|
||||
// H +------+
|
||||
// E | |
|
||||
// I | -X |
|
||||
// G | |
|
||||
// H +------+
|
||||
// T | |
|
||||
// | | +Y |
|
||||
// | | |
|
||||
// | +------+
|
||||
// | | |
|
||||
// | | -Y |
|
||||
// | | |
|
||||
// H +------+
|
||||
// E | |
|
||||
// I | +Z |
|
||||
// G | |
|
||||
// H +------+
|
||||
// T | |
|
||||
// | | -Z |
|
||||
// | | |
|
||||
// V +------+
|
||||
//
|
||||
// FaceWidth = width = height / 6
|
||||
{ 1, 6,
|
||||
{0, 0, true, false},
|
||||
{0, 1, true, false},
|
||||
{0, 2, false, true},
|
||||
{0, 3, false, true},
|
||||
{0, 4, true, false},
|
||||
{0, 5, true, false}
|
||||
},
|
||||
|
||||
// Here is the expected layout for the faces in an image with the 3/4 aspect ratio:
|
||||
//
|
||||
// <-----------WIDTH----------->
|
||||
// ^ +------+------+------+------+
|
||||
// | | | | | |
|
||||
// | | | +Y | | |
|
||||
// | | | | | |
|
||||
// H +------+------+------+------+
|
||||
// E | | | | |
|
||||
// I | -X | -Z | +X | +Z |
|
||||
// G | | | | |
|
||||
// H +------+------+------+------+
|
||||
// T | | | | |
|
||||
// | | | -Y | | |
|
||||
// | | | | | |
|
||||
// V +------+------+------+------+
|
||||
//
|
||||
// FaceWidth = width / 4 = height / 3
|
||||
{ 4, 3,
|
||||
{2, 1, true, false},
|
||||
{0, 1, true, false},
|
||||
{1, 0, false, true},
|
||||
{1, 2, false, true},
|
||||
{3, 1, true, false},
|
||||
{1, 1, true, false}
|
||||
},
|
||||
|
||||
// Here is the expected layout for the faces in an image with the 4/3 aspect ratio:
|
||||
//
|
||||
// <-------WIDTH-------->
|
||||
// ^ +------+------+------+
|
||||
// | | | | |
|
||||
// | | | +Y | |
|
||||
// | | | | |
|
||||
// H +------+------+------+
|
||||
// E | | | |
|
||||
// I | -X | -Z | +X |
|
||||
// G | | | |
|
||||
// H +------+------+------+
|
||||
// T | | | |
|
||||
// | | | -Y | |
|
||||
// | | | | |
|
||||
// | +------+------+------+
|
||||
// | | | | |
|
||||
// | | | +Z! | | <+Z is upside down!
|
||||
// | | | | |
|
||||
// V +------+------+------+
|
||||
//
|
||||
// FaceWidth = width / 3 = height / 4
|
||||
{ 3, 4,
|
||||
{2, 1, true, false},
|
||||
{0, 1, true, false},
|
||||
{1, 0, false, true},
|
||||
{1, 2, false, true},
|
||||
{1, 3, false, true},
|
||||
{1, 1, true, false}
|
||||
}
|
||||
};
|
||||
const int NUM_CUBEMAP_LAYOUTS = sizeof(CUBEMAP_LAYOUTS) / sizeof(CubeLayout);
|
||||
|
||||
// Find the layout of the cubemap in the 2D image
|
||||
int foundLayout = -1;
|
||||
for (int i = 0; i < NUM_CUBEMAP_LAYOUTS; i++) {
|
||||
if ((image.height() * CUBEMAP_LAYOUTS[i]._widthRatio) == (image.width() * CUBEMAP_LAYOUTS[i]._heightRatio)) {
|
||||
foundLayout = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<QImage> faces;
|
||||
// If found, go extract the faces as separate images
|
||||
if (foundLayout >= 0) {
|
||||
auto& layout = CUBEMAP_LAYOUTS[foundLayout];
|
||||
int faceWidth = image.width() / layout._widthRatio;
|
||||
|
||||
faces.push_back(image.copy(QRect(layout._faceXPos._x * faceWidth, layout._faceXPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXPos._horizontalMirror, layout._faceXPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceXNeg._x * faceWidth, layout._faceXNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXNeg._horizontalMirror, layout._faceXNeg._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceYPos._x * faceWidth, layout._faceYPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYPos._horizontalMirror, layout._faceYPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceYNeg._x * faceWidth, layout._faceYNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYNeg._horizontalMirror, layout._faceYNeg._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror));
|
||||
} else {
|
||||
qCDebug(modelLog) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// If the 6 faces have been created go on and define the true Texture
|
||||
if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) {
|
||||
theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
|
||||
theTexture->autoGenerateMips(-1);
|
||||
int f = 0;
|
||||
for (auto& face : faces) {
|
||||
theTexture->assignStoredMipFace(0, formatMip, face.byteCount(), face.constBits(), f);
|
||||
f++;
|
||||
}
|
||||
|
||||
// GEnerate irradiance while we are at it
|
||||
theTexture->generateIrradiance();
|
||||
}
|
||||
}
|
||||
|
||||
return theTexture;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_model_TextureStorage_h
|
||||
#define hifi_model_TextureStorage_h
|
||||
#ifndef hifi_model_TextureMap_h
|
||||
#define hifi_model_TextureMap_h
|
||||
|
||||
#include "gpu/Texture.h"
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include <qurl.h>
|
||||
|
||||
class QImage;
|
||||
|
||||
namespace model {
|
||||
|
||||
typedef glm::vec3 Color;
|
||||
|
@ -47,6 +49,9 @@ public:
|
|||
void resetTexture(gpu::Texture* texture);
|
||||
|
||||
bool isDefined() const;
|
||||
|
||||
static gpu::Texture* create2DTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createCubeTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
|
||||
protected:
|
||||
gpu::TexturePointer _gpuTexture;
|
||||
|
@ -55,6 +60,8 @@ protected:
|
|||
};
|
||||
typedef std::shared_ptr< TextureStorage > TextureStoragePointer;
|
||||
|
||||
|
||||
|
||||
class TextureMap {
|
||||
public:
|
||||
TextureMap() {}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
#include "gpu/StandardShaderLib.h"
|
||||
|
||||
#include "model/TextureStorage.h"
|
||||
#include "model/TextureMap.h"
|
||||
|
||||
//#define WANT_DEBUG
|
||||
|
||||
|
|
Loading…
Reference in a new issue