diff --git a/libraries/gpu-networking/src/gpu-networking/TextureCache.cpp b/libraries/gpu-networking/src/gpu-networking/TextureCache.cpp index 12b9ce423d..e77c7c1145 100644 --- a/libraries/gpu-networking/src/gpu-networking/TextureCache.cpp +++ b/libraries/gpu-networking/src/gpu-networking/TextureCache.cpp @@ -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& texture, TextureType type, const QByteArray& data, const QUrl& url = QUrl()); + ImageReader(const QWeakPointer& texture, const NetworkTexture::TextureLoaderFunc& textureLoader, const QByteArray& data, const QUrl& url = QUrl()); virtual void run(); private: QWeakPointer _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& texture, TextureType type, const QByteArray& data, +ImageReader::ImageReader(const QWeakPointer& 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 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(&*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; diff --git a/libraries/gpu-networking/src/gpu-networking/TextureCache.h b/libraries/gpu-networking/src/gpu-networking/TextureCache.h index d17691a484..b33ede975b 100644 --- a/libraries/gpu-networking/src/gpu-networking/TextureCache.h +++ b/libraries/gpu-networking/src/gpu-networking/TextureCache.h @@ -20,7 +20,7 @@ #include #include -#include +#include 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 TextureLoaderFunc; + + NetworkTexturePointer getTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, + const QByteArray& content = QByteArray()); protected: virtual QSharedPointer 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; diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 679e22c9e7..cf91836254 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -10,7 +10,7 @@ // #include "Material.h" -#include "TextureStorage.h" +#include "TextureMap.h" using namespace model; using namespace gpu; diff --git a/libraries/model/src/model/ModelLogging.cpp b/libraries/model/src/model/ModelLogging.cpp new file mode 100644 index 0000000000..3b3fbed82c --- /dev/null +++ b/libraries/model/src/model/ModelLogging.cpp @@ -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") \ No newline at end of file diff --git a/libraries/model/src/model/ModelLogging.h b/libraries/model/src/model/ModelLogging.h new file mode 100644 index 0000000000..33ed6fb059 --- /dev/null +++ b/libraries/model/src/model/ModelLogging.h @@ -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 + +Q_DECLARE_LOGGING_CATEGORY(modelLog) diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index cc098e7356..70e855bb15 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -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 +#include +#include + +#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 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; +} diff --git a/libraries/model/src/model/TextureMap.h b/libraries/model/src/model/TextureMap.h index c879918ea9..cb5f510043 100755 --- a/libraries/model/src/model/TextureMap.h +++ b/libraries/model/src/model/TextureMap.h @@ -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 +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() {} diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index f56c2cb191..40857dedf2 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -29,7 +29,7 @@ #include "gpu/StandardShaderLib.h" -#include "model/TextureStorage.h" +#include "model/TextureMap.h" //#define WANT_DEBUG