diff --git a/nel/include/nel/gui/view_renderer.h b/nel/include/nel/gui/view_renderer.h index d1ad48d43..d4349e83f 100644 --- a/nel/include/nel/gui/view_renderer.h +++ b/nel/include/nel/gui/view_renderer.h @@ -252,6 +252,19 @@ namespace NLGUI */ bool loadTextures (const std::string &textureFileName, const std::string &uvFileName, bool uploadDXTC); + /* + * newTextureId : Return new placeholder texture id. + * You should call deleteTexture when the texture is not used anymore. + */ + sint32 newTextureId (const std::string &name); + + /* + * reloadTexture : Replace existing global texture with new. + * If previous was texture atlas and still used by 2+ textures, + * then create new global texture. + */ + void reloadTexture (sint32 texId, const std::string &name, bool uploadDXTC=true, bool bReleasable=true); + /* * createTexture : create a texture for the interface, possibly from an externally created texture * If no external texture is given, then 'sGlobalTextureName' is the filename of the big texture @@ -312,6 +325,9 @@ namespace NLGUI /** * get a texture file pointer from a string name. O(logN) + * + * FIXME: only works with textures in atlas loaded with loadTextures() + * * \param id : the id of the texture * \return a texture file pointer. -1 if not found or if sName is empty() */ diff --git a/nel/src/gui/view_renderer.cpp b/nel/src/gui/view_renderer.cpp index 0f0676cfc..38c4a9bde 100644 --- a/nel/src/gui/view_renderer.cpp +++ b/nel/src/gui/view_renderer.cpp @@ -267,10 +267,18 @@ namespace NLGUI TGlobalTextureList::iterator ite = _GlobalTextures.begin(); while (ite != _GlobalTextures.end()) { - UTextureFile *tf = dynamic_cast(ite->Texture); - if (tf) + if (ite->Texture) { - driver->deleteTextureFile (tf); + UTextureFile *tf = dynamic_cast(ite->Texture); + if (tf) + { + driver->deleteTextureFile (tf); + } + else + { + UTextureMem *tf = dynamic_cast(ite->Texture); + if (tf) driver->deleteTextureMem(tf); + } } ite++; } @@ -1067,6 +1075,139 @@ namespace NLGUI return true; } + + sint32 CViewRenderer::newTextureId(const std::string &name) + { + SImage iTmp; + iTmp.Name = toLowerAscii(name); + iTmp.UVMin = CUV(0,0); + iTmp.UVMax = CUV(1,1); + + // lookup global texture with same name + TGlobalTextureList::iterator ite = _GlobalTextures.begin(); + while (ite != _GlobalTextures.end()) + { + std::string sText = toLowerAscii(ite->Name); + if (sText == iTmp.Name) + break; + ite++; + } + + if (ite == _GlobalTextures.end()) + { + SGlobalTexture gtTmp; + gtTmp.Name = iTmp.Name; + gtTmp.FromGlobaleTexture = false; + gtTmp.DefaultWidth = gtTmp.Width = 0; + gtTmp.DefaultHeight = gtTmp.Height = 0; + gtTmp.Texture = NULL; + _GlobalTextures.push_back(gtTmp); + ite = _GlobalTextures.end(); + ite--; + } + iTmp.GlobalTexturePtr = &(*ite); + + // allocate new texture id + return addSImage(iTmp); + } + + void CViewRenderer::reloadTexture(sint32 texId, const std::string &name, bool uploadDXTC, bool bReleasable) + { + if ((uint)texId >= _SImageIterators.size()) + { + nlwarning("Invalid texture id %d, maximum is %u", texId, _SImageIterators.size()); + return; + } + + SImage *sImage = getSImage(texId); + SGlobalTexture *gt = sImage->GlobalTexturePtr; + if (!gt) + { + nlwarning("Unknown texture id %d (file %s)", texId, name.c_str()); + return; + } + + // create new global texture if previous is atlas + if (gt->FromGlobaleTexture) + { + uint count = 0; + TSImageList::iterator ite = _SImages.begin(); + while (ite != _SImages.end() && count != 2) + { + // Same global texture ? + if (ite->GlobalTexturePtr == gt) + count++; + + ite++; + } + + // create new only when atlas is used by 2+ textures + if (count == 2) + { + SGlobalTexture gtTmp; + gtTmp.Name = toLowerAscii(name); + gtTmp.FromGlobaleTexture = false; + gtTmp.DefaultWidth = gtTmp.Width = 0; + gtTmp.DefaultHeight = gtTmp.Height = 0; + gtTmp.Texture = NULL; + _GlobalTextures.push_back(gtTmp); + + TGlobalTextureList::iterator ite = _GlobalTextures.end(); + ite--; + + sImage->GlobalTexturePtr = &(*ite); + gt = sImage->GlobalTexturePtr; + } + } + + NL3D::UTexture *oldTexture = gt->Texture; + + std::string sLwrGTName; + if (startsWith(name, "data:image/")) + { + if (!loadTextureFromString(gt, name)) + return; + + sLwrGTName = getMD5((uint8 *)name.c_str(), (uint32)name.size()).toString(); + } + else + { + sLwrGTName = toLowerAscii(name); + std::string filename = CPath::lookup(sLwrGTName, false); + if (filename.empty()) + { + nlwarning("Unable to find file '%s for texture %d", name.c_str(), texId); + return; + } + + if (!loadTextureFromFile(gt, filename)) + { + nlwarning("Unable to load texture from file '%s'", filename.c_str()); + return; + } + } + + gt->Name = sLwrGTName; + gt->Texture->setFilterMode(UTexture::Nearest, UTexture::NearestMipMapOff); + gt->Texture->setUploadFormat(uploadDXTC ? UTexture::DXTC5 : UTexture::Auto); + gt->Texture->setReleasable(bReleasable); + + // release previous only after successfully loading new one + if (oldTexture) + { + UTextureFile *tf = dynamic_cast(oldTexture); + if (tf) + { + driver->deleteTextureFile (tf); + } + else + { + UTextureMem *tf = dynamic_cast(oldTexture); + if (tf) driver->deleteTextureMem(tf); + } + } + } + /* * createTexture */ @@ -1285,6 +1426,8 @@ namespace NLGUI // This one ? if (&(*iteGT) == gt) { + if (iteGT->Texture == NULL) + return; // Remove this global texture UTextureFile *tf = dynamic_cast(iteGT->Texture); if (tf) @@ -1466,6 +1609,13 @@ namespace NLGUI TGlobalTextureList::iterator ite = _GlobalTextures.begin(); while (ite != _GlobalTextures.end()) { + // texture not loaded yet + if (ite->Texture == NULL) + { + ++ite; + continue; + } + // TMP TMP // volatile SGlobalTexture *sg = &(*ite); CLayer &layer= ite->Layers[layerId];