void RenderableZoneEntityItemMeta::updateSkyboxMap() { if (_pendingSkyboxTexture) { if (_skyboxTexture && _skyboxTexture->isLoaded()) { _pendingSkyboxTexture = false; auto texture = _skyboxTexture->getGPUTexture(); if (texture) { editSkybox()->setCubemap(texture); _validSkyboxTexture = true; } else { qCDebug(entitiesrenderer) << "Failed to load Skybox texture:" << _skyboxTexture->getURL(); } } } }
void RenderableZoneEntityItemMeta::updateAmbientMap() { if (_pendingAmbientTexture) { if (_ambientTexture && _ambientTexture->isLoaded()) { _pendingAmbientTexture = false; auto texture = _ambientTexture->getGPUTexture(); if (texture) { if (texture->getIrradiance()) { _ambientLight->setAmbientSphere(*texture->getIrradiance()); } else { _ambientLight->setAmbientSpherePreset(gpu::SphericalHarmonics::BREEZEWAY); } editAmbientLight()->setAmbientMap(texture); _validAmbientTexture = true; } else { qCDebug(entitiesrenderer) << "Failed to load ambient texture:" << _ambientTexture->getURL(); } } } }
void RenderableZoneEntityItemMeta::setSkyboxURL(const QString& skyboxUrl) { // nothing change if nothing change if (_skyboxTextureURL == skyboxUrl) { return; } _skyboxTextureURL = skyboxUrl; if (_skyboxTextureURL.isEmpty()) { _validSkyboxTexture = false; _pendingSkyboxTexture = false; _skyboxTexture.clear(); editSkybox()->setCubemap(nullptr); } else { _pendingSkyboxTexture = true; auto textureCache = DependencyManager::get<TextureCache>(); _skyboxTexture = textureCache->getTexture(_skyboxTextureURL, image::TextureUsage::CUBE_TEXTURE); } }
void RenderableZoneEntityItemMeta::setAmbientURL(const QString& ambientUrl) { // nothing change if nothing change if (_ambientTextureURL == ambientUrl) { return; } _ambientTextureURL = ambientUrl; if (_ambientTextureURL.isEmpty()) { _validAmbientTexture = false; _pendingAmbientTexture = false; _ambientTexture.clear(); _ambientLight->setAmbientMap(nullptr); _ambientLight->setAmbientSpherePreset(gpu::SphericalHarmonics::BREEZEWAY); } else { _pendingAmbientTexture = true; auto textureCache = DependencyManager::get<TextureCache>(); _ambientTexture = textureCache->getTexture(_ambientTextureURL, image::TextureUsage::CUBE_TEXTURE); // keep whatever is assigned on the ambient map/sphere until texture is loaded } }
const gpu::TexturePointer& TextureCache::getPermutationNormalTexture() { if (!_permutationNormalTexture) { // the first line consists of random permutation offsets unsigned char data[256 * 2 * 3]; #if (USE_CHRIS_NOISE==1) for (int i = 0; i < 256; i++) { data[3*i+0] = permutation[i]; data[3*i+1] = permutation[i]; data[3*i+2] = permutation[i]; #else for (int i = 0; i < 256 * 3; i++) { data[i] = rand() % 256; #endif } for (int i = 256 * 3; i < 256 * 3 * 2; i += 3) { glm::vec3 randvec = glm::sphericalRand(1.0f); data[i] = ((randvec.x + 1.0f) / 2.0f) * 255.0f; data[i + 1] = ((randvec.y + 1.0f) / 2.0f) * 255.0f; data[i + 2] = ((randvec.z + 1.0f) / 2.0f) * 255.0f; } _permutationNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB), 256, 2)); _permutationNormalTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(data), data); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } return _permutationNormalTexture; } const unsigned char OPAQUE_WHITE[] = { 0xFF, 0xFF, 0xFF, 0xFF }; const unsigned char OPAQUE_GRAY[] = { 0x80, 0x80, 0x80, 0xFF }; const unsigned char OPAQUE_BLUE[] = { 0x80, 0x80, 0xFF, 0xFF }; const unsigned char OPAQUE_BLACK[] = { 0x00, 0x00, 0x00, 0xFF }; /* static void loadSingleColorTexture(const unsigned char* color) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, color); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } */ const gpu::TexturePointer& TextureCache::getWhiteTexture() { if (!_whiteTexture) { _whiteTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1)); _whiteTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_WHITE); } return _whiteTexture; } const gpu::TexturePointer& TextureCache::getGrayTexture() { if (!_grayTexture) { _grayTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1)); _grayTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_GRAY); } return _grayTexture; } const gpu::TexturePointer& TextureCache::getBlueTexture() { if (!_blueTexture) { _blueTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1)); _blueTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(OPAQUE_BLUE), OPAQUE_BLUE); } return _blueTexture; } const gpu::TexturePointer& TextureCache::getBlackTexture() { if (!_blackTexture) { _blackTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1)); _blackTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_BLACK), OPAQUE_BLACK); } return _blackTexture; } /// Extra data for creating textures. class TextureExtra { public: TextureType type; const QByteArray& content; }; NetworkTexturePointer TextureCache::getTexture(const QUrl& url, TextureType type, bool dilatable, const QByteArray& content) { if (!dilatable) { TextureExtra extra = { type, content }; return ResourceCache::getResource(url, QUrl(), false, &extra).staticCast<NetworkTexture>(); } NetworkTexturePointer texture = _dilatableNetworkTextures.value(url); if (texture.isNull()) { texture = NetworkTexturePointer(new DilatableNetworkTexture(url, content), &Resource::allReferencesCleared); texture->setSelf(texture); texture->setCache(this); _dilatableNetworkTextures.insert(url, texture); } else { removeUnusedResource(texture); } return texture; } void TextureCache::createPrimaryFramebuffer() { _primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); auto width = _frameBufferSize.width(); auto height = _frameBufferSize.height(); auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); _primaryColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); _primaryNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); _primarySpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); _primaryFramebuffer->setRenderBuffer(0, _primaryColorTexture); _primaryFramebuffer->setRenderBuffer(1, _primaryNormalTexture); _primaryFramebuffer->setRenderBuffer(2, _primarySpecularTexture); auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); _primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler)); _primaryFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); }
const gpu::TexturePointer& TextureCache::getPermutationNormalTexture() { if (!_permutationNormalTexture) { // the first line consists of random permutation offsets unsigned char data[256 * 2 * 3]; #if (USE_CHRIS_NOISE==1) for (int i = 0; i < 256; i++) { data[3*i+0] = permutation[i]; data[3*i+1] = permutation[i]; data[3*i+2] = permutation[i]; #else for (int i = 0; i < 256 * 3; i++) { data[i] = rand() % 256; #endif } for (int i = 256 * 3; i < 256 * 3 * 2; i += 3) { glm::vec3 randvec = glm::sphericalRand(1.0f); data[i] = ((randvec.x + 1.0f) / 2.0f) * 255.0f; data[i + 1] = ((randvec.y + 1.0f) / 2.0f) * 255.0f; data[i + 2] = ((randvec.z + 1.0f) / 2.0f) * 255.0f; } _permutationNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB), 256, 2)); _permutationNormalTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(data), data); } return _permutationNormalTexture; } const unsigned char OPAQUE_WHITE[] = { 0xFF, 0xFF, 0xFF, 0xFF }; const unsigned char OPAQUE_GRAY[] = { 0x80, 0x80, 0x80, 0xFF }; const unsigned char OPAQUE_BLUE[] = { 0x80, 0x80, 0xFF, 0xFF }; const unsigned char OPAQUE_BLACK[] = { 0x00, 0x00, 0x00, 0xFF }; const gpu::TexturePointer& TextureCache::getWhiteTexture() { if (!_whiteTexture) { _whiteTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1)); _whiteTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_WHITE); } return _whiteTexture; } const gpu::TexturePointer& TextureCache::getGrayTexture() { if (!_grayTexture) { _grayTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1)); _grayTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_GRAY); } return _grayTexture; } const gpu::TexturePointer& TextureCache::getBlueTexture() { if (!_blueTexture) { _blueTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1)); _blueTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(OPAQUE_BLUE), OPAQUE_BLUE); } return _blueTexture; } const gpu::TexturePointer& TextureCache::getBlackTexture() { if (!_blackTexture) { _blackTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1)); _blackTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_BLACK), OPAQUE_BLACK); } return _blackTexture; } /// Extra data for creating textures. class TextureExtra { public: TextureType type; const QByteArray& content; }; NetworkTexturePointer TextureCache::getTexture(const QUrl& url, TextureType type, bool dilatable, const QByteArray& content) { if (!dilatable) { TextureExtra extra = { type, content }; return ResourceCache::getResource(url, QUrl(), false, &extra).staticCast<NetworkTexture>(); } NetworkTexturePointer texture = _dilatableNetworkTextures.value(url); if (texture.isNull()) { texture = NetworkTexturePointer(new DilatableNetworkTexture(url, content), &Resource::allReferencesCleared); texture->setSelf(texture); texture->setCache(this); _dilatableNetworkTextures.insert(url, texture); } else { removeUnusedResource(texture); } return texture; } /// Returns a texture version of an image file gpu::TexturePointer TextureCache::getImageTexture(const QString& path) { QImage image = QImage(path).mirrored(false, true); gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB); gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB); if (image.hasAlphaChannel()) { formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA); formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::BGRA); } gpu::TexturePointer texture = gpu::TexturePointer( gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); texture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); texture->autoGenerateMips(-1); return texture; }