diff --git a/source/core/support/imageutil.cpp b/source/core/support/imageutil.cpp index ae50e194e..3619cfe8f 100644 --- a/source/core/support/imageutil.cpp +++ b/source/core/support/imageutil.cpp @@ -1388,11 +1388,17 @@ ImageData *Copy_Image(ImageData *Old) void Destroy_Image(ImageData *image) { if ((image == nullptr) || (--(image->References) > 0)) - return; + return; + + image->data = nullptr; // Prevent the image from being deleted. Images are now cached. + delete image; +} +void Remove_Cached_Image(Image* image) { delete image; } + ImageData::~ImageData() { #ifdef POV_VIDCAP_IMPL diff --git a/source/core/support/imageutil.h b/source/core/support/imageutil.h index b4bf41bc2..c86959443 100644 --- a/source/core/support/imageutil.h +++ b/source/core/support/imageutil.h @@ -143,6 +143,7 @@ int map_pos(const Vector3d& EPoint, const ImageData* pImage, DBL *xcoor, DBL *yc ImageData *Copy_Image(ImageData *old); ImageData *Create_Image(void); void Destroy_Image(ImageData *image); +void Remove_Cached_Image(Image* image); /// @} /// diff --git a/source/parser/ImageCache.cpp b/source/parser/ImageCache.cpp new file mode 100644 index 000000000..d48919619 --- /dev/null +++ b/source/parser/ImageCache.cpp @@ -0,0 +1,135 @@ +//****************************************************************************** +/// +/// @file parser/ImageCache.cpp +/// +/// This module implements a cache for images used in a scene so they only heve +/// to be loaded once during animation rendering or between manual renders +/// +/// @copyright +/// @parblock +/// +/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. +/// Copyright 1991-2019 Persistence of Vision Raytracer Pty. Ltd. +/// +/// POV-Ray is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as +/// published by the Free Software Foundation, either version 3 of the +/// License, or (at your option) any later version. +/// +/// POV-Ray is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program. If not, see . +/// +/// ---------------------------------------------------------------------------- +/// +/// POV-Ray is based on the popular DKB raytracer version 2.12. +/// DKBTrace was originally written by David K. Buck. +/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. +/// +/// @endparblock +/// +//****************************************************************************** + + +// C++ variants of C standard header files +#include + +#include +#include + +#ifndef WIN32 +#include // Unix lib for getting last modified file date and time +#endif +#ifdef WIN32 +#define stat _stat // Windows lib for getting last modified file date and time +#endif + + +// POV-Ray header files (base module) +#include "base/base_fwd.h" +#include "base/messenger_fwd.h" +#include "base/povassert.h" +#include "base/stringtypes.h" +#include "base/textstream_fwd.h" +#include "base/textstreambuffer.h" +#include "base/image/image_fwd.h" +#include "base/stringutilities.h" +#include "core/support/imageutil.h" + +// this must be the last file included +#include "base/povdebug.h" + + +namespace pov_image_cache +{ + using namespace pov_base; + using namespace std; + using namespace pov; + + struct ImageCacheEntry final + { + Image* image; + long lastModified; + }; + + static std::map Cache; // <- The actual cache + + // Gets the last modified time from the filesystem + long GetLastModifiedTime(const std::string filename) + { + const char* cstrFilename = filename.c_str(); + + struct stat result; + if (stat(cstrFilename, &result) == 0) + { + return (long)result.st_mtime; + } + return 0; + } + + // Try to get the image from the cache + Image* GetCachedImage(const UCS2* filename) + { + std::string lookupFilename = pov_base::UCS2toSysString(filename); + + std::map::iterator idx = Cache.find(lookupFilename); + if (idx != Cache.end()) + { + long lastModified = GetLastModifiedTime(lookupFilename); + if (lastModified == Cache[lookupFilename].lastModified) + return idx->second.image; //Cache[lookupFilename].image; + + // Remove old image from cache and release memory so the newer version can be loaded + pov::Remove_Cached_Image(idx->second.image); + Cache.erase(idx); + } + + return nullptr; + } + + // Store a new image into cache + void StoreImageInCache(const UCS2* filename, Image* image) + { + std::string lookupFilename = pov_base::UCS2toSysString(filename); + long lastModified = GetLastModifiedTime(lookupFilename); + Cache[lookupFilename] = ImageCacheEntry{ image = image, lastModified = lastModified }; + } + + // May be called frome some menu item, personally, I'd just close PovRay and start a new process (different scenes often share resources in my case) + // Do not allow calling it while parsing or rendering! + void ClearCache() + { + std::map::iterator it = Cache.begin(); + + // Iterate over the map using Iterator till end. + while (it != Cache.end()) + { + pov::Remove_Cached_Image(it->second.image); + Cache.erase(it); + } + } +} \ No newline at end of file diff --git a/source/parser/ImageCache.h b/source/parser/ImageCache.h new file mode 100644 index 000000000..9f24c5116 --- /dev/null +++ b/source/parser/ImageCache.h @@ -0,0 +1,79 @@ +//****************************************************************************** +/// +/// @file parser/ImageCache.h +/// +/// Declarations related to the Image Cache. +/// +/// @copyright +/// @parblock +/// +/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. +/// Copyright 1991-2019 Persistence of Vision Raytracer Pty. Ltd. +/// +/// POV-Ray is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as +/// published by the Free Software Foundation, either version 3 of the +/// License, or (at your option) any later version. +/// +/// POV-Ray is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program. If not, see . +/// +/// ---------------------------------------------------------------------------- +/// +/// POV-Ray is based on the popular DKB raytracer version 2.12. +/// DKBTrace was originally written by David K. Buck. +/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. +/// +/// @endparblock +/// +//****************************************************************************** + +#ifndef POVRAY_PARSER_IMAGE_CACHE_H +#define POVRAY_PARSER_IMAGE_CACHE_H + +#include +#include + +#ifndef WIN32 +#include // Unix lib for getting last modified file date and time +#endif +#ifdef WIN32 +#define stat _stat // Windows lib for getting last modified file date and time +#endif + + +// POV-Ray header files (base module) +#include "base/base_fwd.h" +#include "base/messenger_fwd.h" +#include "base/povassert.h" +#include "base/stringtypes.h" +#include "base/textstream_fwd.h" +#include "base/textstreambuffer.h" +#include "base/image/image_fwd.h" + +namespace pov +{ + class Blob_Element; + struct ContainedByShape; + struct GenericSpline; + class ImageData; + class Mesh; + struct PavementPattern; + struct TilingPattern; + struct TrueTypeFont; +} + +namespace pov_image_cache +{ + using namespace pov_base; + + Image* GetCachedImage(const UCS2* filename); + void StoreImageInCache(const UCS2* filename, Image* image); +}; + +#endif // POVRAY_PARSER_IMAGE_CACHE_H \ No newline at end of file diff --git a/source/parser/parser.cpp b/source/parser/parser.cpp index 2473903c4..60031b6d3 100644 --- a/source/parser/parser.cpp +++ b/source/parser/parser.cpp @@ -113,7 +113,7 @@ #include "vm/fnpovfpu.h" // POV-Ray header files (parser module) -// (none at the moment) +#include "parser/ImageCache.h" // this must be the last file included #include "base/povdebug.h" @@ -122,6 +122,7 @@ namespace pov_parser { using namespace pov; +using namespace pov_image_cache; using std::min; using std::max; @@ -9971,8 +9972,12 @@ OStream *Parser::CreateFile(const UCS2String& filename, unsigned int stype, bool //****************************************************************************** -Image *Parser::Read_Image(int filetype, const UCS2 *filename, const ImageReadOptions& options) +Image *Parser::Read_Image(int filetype, const UCS2* filename, const ImageReadOptions& options) { + Image* img = pov_image_cache::GetCachedImage(filename); + if (img != nullptr) + return img; + unsigned int stype; Image::ImageFileType type; UCS2String ign; @@ -10040,7 +10045,11 @@ Image *Parser::Read_Image(int filetype, const UCS2 *filename, const ImageReadOpt if (file == nullptr) throw POV_EXCEPTION(kCannotOpenFileErr, "Cannot find image file."); - return Image::Read(type, file.get(), options); + img = Image::Read(type, file.get(), options); + + pov_image_cache::StoreImageInCache(filename, img); + + return img; } //****************************************************************************** diff --git a/windows/vs2015/povparser.vcxproj b/windows/vs2015/povparser.vcxproj index e90289687..bb5dcfdbd 100644 --- a/windows/vs2015/povparser.vcxproj +++ b/windows/vs2015/povparser.vcxproj @@ -400,6 +400,7 @@ + @@ -424,6 +425,7 @@ + diff --git a/windows/vs2015/povparser.vcxproj.filters b/windows/vs2015/povparser.vcxproj.filters index d050cbe31..1efdb1c0d 100644 --- a/windows/vs2015/povparser.vcxproj.filters +++ b/windows/vs2015/povparser.vcxproj.filters @@ -46,6 +46,9 @@ Parser Headers + + Parser Headers + @@ -93,5 +96,8 @@ Parser Source + + Parser Source + \ No newline at end of file