// Copyright (c) 2008-2023 the Urho3D project // License: MIT #include "../Precompiled.h" #include "../Core/Context.h" #include "../Core/Profiler.h" #include "../Graphics/Graphics.h" #include "../Graphics/GraphicsEvents.h" #include "../Graphics/Renderer.h" #include "../GraphicsAPI/GraphicsImpl.h" #include "../GraphicsAPI/Texture3D.h" #include "../IO/FileSystem.h" #include "../IO/Log.h" #include "../Resource/ResourceCache.h" #include "../Resource/XMLFile.h" #include "../DebugNew.h" namespace Urho3D { Texture3D::Texture3D(Context* context) : Texture(context) { #ifdef URHO3D_OPENGL #ifndef URHO3D_GLES2 if (Graphics::GetGAPI() == GAPI_OPENGL) target_ = GL_TEXTURE_3D; #endif #endif } Texture3D::~Texture3D() { Release(); } void Texture3D::RegisterObject(Context* context) { context->RegisterFactory(); } bool Texture3D::BeginLoad(Deserializer& source) { auto* cache = GetSubsystem(); // In headless mode, do not actually load the texture, just return success if (!graphics_) return true; // If device is lost, retry later if (graphics_->IsDeviceLost()) { URHO3D_LOGWARNING("Texture load while device is lost"); dataPending_ = true; return true; } String texPath, texName, texExt; SplitPath(GetName(), texPath, texName, texExt); cache->ResetDependencies(this); loadParameters_ = new XMLFile(context_); if (!loadParameters_->Load(source)) { loadParameters_.Reset(); return false; } XMLElement textureElem = loadParameters_->GetRoot(); XMLElement volumeElem = textureElem.GetChild("volume"); XMLElement colorlutElem = textureElem.GetChild("colorlut"); if (volumeElem) { String name = volumeElem.GetAttribute("name"); String volumeTexPath, volumeTexName, volumeTexExt; SplitPath(name, volumeTexPath, volumeTexName, volumeTexExt); // If path is empty, add the XML file path if (volumeTexPath.Empty()) name = texPath + name; loadImage_ = cache->GetTempResource(name); // Precalculate mip levels if async loading if (loadImage_ && GetAsyncLoadState() == ASYNC_LOADING) loadImage_->PrecalculateLevels(); cache->StoreResourceDependency(this, name); return true; } else if (colorlutElem) { String name = colorlutElem.GetAttribute("name"); String colorlutTexPath, colorlutTexName, colorlutTexExt; SplitPath(name, colorlutTexPath, colorlutTexName, colorlutTexExt); // If path is empty, add the XML file path if (colorlutTexPath.Empty()) name = texPath + name; SharedPtr file = GetSubsystem()->GetFile(name); loadImage_ = new Image(context_); if (!loadImage_->LoadColorLUT(*(file.Get()))) { loadParameters_.Reset(); loadImage_.Reset(); return false; } // Precalculate mip levels if async loading if (loadImage_ && GetAsyncLoadState() == ASYNC_LOADING) loadImage_->PrecalculateLevels(); cache->StoreResourceDependency(this, name); return true; } URHO3D_LOGERROR("Texture3D XML data for " + GetName() + " did not contain either volume or colorlut element"); return false; } bool Texture3D::EndLoad() { // In headless mode, do not actually load the texture, just return success if (!graphics_ || graphics_->IsDeviceLost()) return true; // If over the texture budget, see if materials can be freed to allow textures to be freed CheckTextureBudget(GetTypeStatic()); SetParameters(loadParameters_); bool success = SetData(loadImage_); loadImage_.Reset(); loadParameters_.Reset(); return success; } bool Texture3D::SetSize(int width, int height, int depth, unsigned format, TextureUsage usage) { if (width <= 0 || height <= 0 || depth <= 0) { URHO3D_LOGERROR("Zero or negative 3D texture dimensions"); return false; } if (usage >= TEXTURE_RENDERTARGET) { URHO3D_LOGERROR("Rendertarget or depth-stencil usage not supported for 3D textures"); return false; } usage_ = usage; width_ = width; height_ = height; depth_ = depth; format_ = format; return Create(); } void Texture3D::OnDeviceLost() { GAPI gapi = Graphics::GetGAPI(); #ifdef URHO3D_OPENGL if (gapi == GAPI_OPENGL) return OnDeviceLost_OGL(); #endif #ifdef URHO3D_D3D11 if (gapi == GAPI_D3D11) return OnDeviceLost_D3D11(); #endif } void Texture3D::OnDeviceReset() { GAPI gapi = Graphics::GetGAPI(); #ifdef URHO3D_OPENGL if (gapi == GAPI_OPENGL) return OnDeviceReset_OGL(); #endif #ifdef URHO3D_D3D11 if (gapi == GAPI_D3D11) return OnDeviceReset_D3D11(); #endif } void Texture3D::Release() { GAPI gapi = Graphics::GetGAPI(); #ifdef URHO3D_OPENGL if (gapi == GAPI_OPENGL) return Release_OGL(); #endif #ifdef URHO3D_D3D11 if (gapi == GAPI_D3D11) return Release_D3D11(); #endif } bool Texture3D::SetData(unsigned level, int x, int y, int z, int width, int height, int depth, const void* data) { GAPI gapi = Graphics::GetGAPI(); #ifdef URHO3D_OPENGL if (gapi == GAPI_OPENGL) return SetData_OGL(level, x, y, z, width, height, depth, data); #endif #ifdef URHO3D_D3D11 if (gapi == GAPI_D3D11) return SetData_D3D11(level, x, y, z, width, height, depth, data); #endif return {}; // Prevent warning } bool Texture3D::SetData(Image* image, bool useAlpha) { GAPI gapi = Graphics::GetGAPI(); #ifdef URHO3D_OPENGL if (gapi == GAPI_OPENGL) return SetData_OGL(image, useAlpha); #endif #ifdef URHO3D_D3D11 if (gapi == GAPI_D3D11) return SetData_D3D11(image, useAlpha); #endif return {}; // Prevent warning } bool Texture3D::GetData(unsigned level, void* dest) const { GAPI gapi = Graphics::GetGAPI(); #ifdef URHO3D_OPENGL if (gapi == GAPI_OPENGL) return GetData_OGL(level, dest); #endif #ifdef URHO3D_D3D11 if (gapi == GAPI_D3D11) return GetData_D3D11(level, dest); #endif return {}; // Prevent warning } bool Texture3D::Create() { GAPI gapi = Graphics::GetGAPI(); #ifdef URHO3D_OPENGL if (gapi == GAPI_OPENGL) return Create_OGL(); #endif #ifdef URHO3D_D3D11 if (gapi == GAPI_D3D11) return Create_D3D11(); #endif return {}; // Prevent warning } }