bool Texture3D::SetData(Image* image, bool useAlpha) { if (!image) { URHO3D_LOGERROR("Null image, can not set data"); return false; } // Use a shared ptr for managing the temporary mip images created during this function SharedPtr<Image> mipImage; unsigned memoryUse = sizeof(Texture3D); int quality = QUALITY_HIGH; Renderer* renderer = GetSubsystem<Renderer>(); if (renderer) quality = renderer->GetTextureQuality(); if (!image->IsCompressed()) { // Convert unsuitable formats to RGBA unsigned components = image->GetComponents(); if (Graphics::GetGL3Support() && ((components == 1 && !useAlpha) || components == 2)) { mipImage = image->ConvertToRGBA(); image = mipImage; if (!image) return false; components = image->GetComponents(); } unsigned char* levelData = image->GetData(); int levelWidth = image->GetWidth(); int levelHeight = image->GetHeight(); int levelDepth = image->GetDepth(); unsigned format = 0; // Discard unnecessary mip levels for (unsigned i = 0; i < mipsToSkip_[quality]; ++i) { mipImage = image->GetNextLevel(); image = mipImage; levelData = image->GetData(); levelWidth = image->GetWidth(); levelHeight = image->GetHeight(); levelDepth = image->GetDepth(); } switch (components) { case 1: format = useAlpha ? Graphics::GetAlphaFormat() : Graphics::GetLuminanceFormat(); break; case 2: format = Graphics::GetLuminanceAlphaFormat(); break; case 3: format = Graphics::GetRGBFormat(); break; case 4: format = Graphics::GetRGBAFormat(); break; default: assert(false); // Should not reach here break; } // If image was previously compressed, reset number of requested levels to avoid error if level count is too high for new size if (IsCompressed() && requestedLevels_ > 1) requestedLevels_ = 0; SetSize(levelWidth, levelHeight, levelDepth, format); if (!object_) return false; for (unsigned i = 0; i < levels_; ++i) { SetData(i, 0, 0, 0, levelWidth, levelHeight, levelDepth, levelData); memoryUse += levelWidth * levelHeight * levelDepth * components; if (i < levels_ - 1) { mipImage = image->GetNextLevel(); image = mipImage; levelData = image->GetData(); levelWidth = image->GetWidth(); levelHeight = image->GetHeight(); levelDepth = image->GetDepth(); } } } else { int width = image->GetWidth(); int height = image->GetHeight(); int depth = image->GetDepth(); unsigned levels = image->GetNumCompressedLevels(); unsigned format = graphics_->GetFormat(image->GetCompressedFormat()); bool needDecompress = false; if (!format) { format = Graphics::GetRGBAFormat(); needDecompress = true; } unsigned mipsToSkip = mipsToSkip_[quality]; if (mipsToSkip >= levels) mipsToSkip = levels - 1; while (mipsToSkip && (width / (1 << mipsToSkip) < 4 || height / (1 << mipsToSkip) < 4 || depth / (1 << mipsToSkip) < 4)) --mipsToSkip; width /= (1 << mipsToSkip); height /= (1 << mipsToSkip); depth /= (1 << mipsToSkip); SetNumLevels(Max((levels - mipsToSkip), 1U)); SetSize(width, height, depth, format); for (unsigned i = 0; i < levels_ && i < levels - mipsToSkip; ++i) { CompressedLevel level = image->GetCompressedLevel(i + mipsToSkip); if (!needDecompress) { SetData(i, 0, 0, 0, level.width_, level.height_, level.depth_, level.data_); memoryUse += level.depth_ * level.rows_ * level.rowSize_; } else { unsigned char* rgbaData = new unsigned char[level.width_ * level.height_ * level.depth_ * 4]; level.Decompress(rgbaData); SetData(i, 0, 0, 0, level.width_, level.height_, level.depth_, rgbaData); memoryUse += level.width_ * level.height_ * level.depth_ * 4; delete[] rgbaData; } } } SetMemoryUse(memoryUse); return true; }
bool Texture2DArray::SetData(unsigned layer, Image* image, bool useAlpha) { if (!image) { URHO3D_LOGERROR("Null image, can not set data"); return false; } if (!layers_) { URHO3D_LOGERROR("Number of layers in the array must be set first"); return false; } if (layer >= layers_) { URHO3D_LOGERROR("Illegal layer for setting data"); return false; } // Use a shared ptr for managing the temporary mip images created during this function SharedPtr<Image> mipImage; unsigned memoryUse = 0; int quality = QUALITY_HIGH; Renderer* renderer = GetSubsystem<Renderer>(); if (renderer) quality = renderer->GetTextureQuality(); if (!image->IsCompressed()) { // Convert unsuitable formats to RGBA unsigned components = image->GetComponents(); if (Graphics::GetGL3Support() && ((components == 1 && !useAlpha) || components == 2)) { mipImage = image->ConvertToRGBA(); image = mipImage; if (!image) return false; components = image->GetComponents(); } unsigned char* levelData = image->GetData(); int levelWidth = image->GetWidth(); int levelHeight = image->GetHeight(); unsigned format = 0; // Discard unnecessary mip levels for (unsigned i = 0; i < mipsToSkip_[quality]; ++i) { mipImage = image->GetNextLevel(); image = mipImage; levelData = image->GetData(); levelWidth = image->GetWidth(); levelHeight = image->GetHeight(); } switch (components) { case 1: format = useAlpha ? Graphics::GetAlphaFormat() : Graphics::GetLuminanceFormat(); break; case 2: format = Graphics::GetLuminanceAlphaFormat(); break; case 3: format = Graphics::GetRGBFormat(); break; case 4: format = Graphics::GetRGBAFormat(); break; default: assert(false); // Should not reach here break; } // Create the texture array when layer 0 is being loaded, check that rest of the layers are same size & format if (!layer) { // If image was previously compressed, reset number of requested levels to avoid error if level count is too high for new size if (IsCompressed() && requestedLevels_ > 1) requestedLevels_ = 0; // Create the texture array (the number of layers must have been already set) SetSize(0, levelWidth, levelHeight, format); } else { if (!object_.name_) { URHO3D_LOGERROR("Texture array layer 0 must be loaded first"); return false; } if (levelWidth != width_ || levelHeight != height_ || format != format_) { URHO3D_LOGERROR("Texture array layer does not match size or format of layer 0"); return false; } } for (unsigned i = 0; i < levels_; ++i) { SetData(layer, i, 0, 0, levelWidth, levelHeight, levelData); memoryUse += levelWidth * levelHeight * components; if (i < levels_ - 1) { mipImage = image->GetNextLevel(); image = mipImage; levelData = image->GetData(); levelWidth = image->GetWidth(); levelHeight = image->GetHeight(); } } } else { int width = image->GetWidth(); int height = image->GetHeight(); unsigned levels = image->GetNumCompressedLevels(); unsigned format = graphics_->GetFormat(image->GetCompressedFormat()); bool needDecompress = false; if (!format) { format = Graphics::GetRGBAFormat(); needDecompress = true; } unsigned mipsToSkip = mipsToSkip_[quality]; if (mipsToSkip >= levels) mipsToSkip = levels - 1; while (mipsToSkip && (width / (1 << mipsToSkip) < 4 || height / (1 << mipsToSkip) < 4)) --mipsToSkip; width /= (1 << mipsToSkip); height /= (1 << mipsToSkip); // Create the texture array when layer 0 is being loaded, assume rest of the layers are same size & format if (!layer) { SetNumLevels(Max((levels - mipsToSkip), 1U)); SetSize(0, width, height, format); } else { if (!object_.name_) { URHO3D_LOGERROR("Texture array layer 0 must be loaded first"); return false; } if (width != width_ || height != height_ || format != format_) { URHO3D_LOGERROR("Texture array layer does not match size or format of layer 0"); return false; } } for (unsigned i = 0; i < levels_ && i < levels - mipsToSkip; ++i) { CompressedLevel level = image->GetCompressedLevel(i + mipsToSkip); if (!needDecompress) { SetData(layer, i, 0, 0, level.width_, level.height_, level.data_); memoryUse += level.rows_ * level.rowSize_; } else { unsigned char* rgbaData = new unsigned char[level.width_ * level.height_ * 4]; level.Decompress(rgbaData); SetData(layer, i, 0, 0, level.width_, level.height_, rgbaData); memoryUse += level.width_ * level.height_ * 4; delete[] rgbaData; } } } layerMemoryUse_[layer] = memoryUse; unsigned totalMemoryUse = sizeof(Texture2DArray) + layerMemoryUse_.Capacity() * sizeof(unsigned); for (unsigned i = 0; i < layers_; ++i) totalMemoryUse += layerMemoryUse_[i]; SetMemoryUse(totalMemoryUse); return true; }