#pragma once #include "AftrOpenGLIncludes.h" #include "Tex.h" #include "TexDataSharedID.h" #include "AftrUtil_image.h" #include #include #include #include #include #include //#include "Texture.h" //#include "TextureData.h" //#include "TextureOwnsTexData.h" //#include "TextureOwnsTexDataSharesGLHandle.h" //#include "TextureOwnsTexDataOwnsGLHandle.h" //#include "TextureDataOwnsGLHandle.h" //#include "TextureSharesTexData.h" //#include "TextureSharesTexDataOwnsGLHandle.h" //#include "TextureDataSharesGLHandle.h" struct SDL_Surface; class PBO_Tex_Xfer_Data; namespace Aftr { class TexDataShared; class ManagerTex { public: ///The func_resume *will always occur* on the *main thread*, so it can mutate OpenGL! ///This is the lower-level function that sends VBO data to GPU memory. using func_send_to_GPU_on_main_thread = std::function; ~ManagerTex(); ManagerTex( ManagerTex const& ) = delete; ManagerTex( ManagerTex&& ) = delete; ManagerTex& operator=( ManagerTex const& ) = delete; ManagerTex& operator=( ManagerTex&& ) = delete; static void init(); static void shutdown(); // Loads the texture at the file path 'fileToLoad'. If a requested pixel // width and heigh are passed in, the texture will be resized to those // dimensions instead of utilizing the native image size specified in // the file. // // Returns an optional. If the optional is not std::nullopt, then // the image was found at the file location and is being asynchronously // loaded by a background thread. Once loaded, the texture will stream // to the GPU and become visible within a few frames. // // If the returned optional *is* nullopt, it is likely, the file // was not found on disk, see the console output for details. // // Once a 'fileToLoad' has been loaded for a specific size, that data // is stored only once on the CPU/GPU in an internal cache. No matter // how many times a user requests to load the same image, it resides in // memory exactly once. This is the TexDataShared Portion of the data. // Each Tex is a lightweight wrapper specifying customization points to // draw the same TexDataShared w/ different properties, such as wrapping, // filtering, etc. // This employs a fly weight pattern, where a Tex is a lightweight, // easy-to-copy, value-semantics wrapper. Internally, the TexDataShared // is in a reference counted shared_ptr and will be destroyed when zero // references to the shared_ptr remain. static std::optional loadTexAsync( std::string const& fileToLoad, unsigned int requested_pixelWidth = 0, unsigned int requested_pixelHeight = 0, bool createMipmap = true, GLint internalFormat = GL_RGBA, GLenum format = GL_RGBA, GLenum type = GL_UNSIGNED_BYTE ); // Identical to loadTexAsync *except* does not internally store the // shared_ptr to the underlying TexDataShared. Which means the returned // Tex, if not std::nullopt, is the *only* Tex which refers to the // corresponding TexDataShared. If no copy of Tex is made, the TexDataShared // will be removed from CPU/GPU memory upon invocation of the Tex's ~Tex(). static std::optional loadTexAsync_unregistered( std::string const& fileToLoad, unsigned int requested_pixelWidth = 0, unsigned int requested_pixelHeight = 0, bool createMipmap = true, GLint internalFormat = GL_RGBA, GLenum format = GL_RGBA, GLenum type = GL_UNSIGNED_BYTE ); // Returns a texture that is completely owned by the caller. This type of texture // is expected to be manipulated by Frame Buffer Objects (FBOs) for rendering to a // texture, or other more advanced usages beyond a simply texture loaded from a file. // // The user is responsible for deleting this Texture and its TextureDataShared as well. static Tex loadDynamicTex( GLenum textureTarget = GL_TEXTURE_2D, GLint level = 0, unsigned int pixelWidth = 1, unsigned int pixelHeight = 1, GLint internalFormat = GL_RGBA, GLint border = 0, GLenum rawTexelFormat = GL_RGBA, GLenum rawTexelType = GL_UNSIGNED_BYTE, const GLvoid* pixels = NULL ); static size_t sendPendingAsyncTexturesToGfxMemory(); ///Returns a clone, use owns and must delete static Tex getDefaultTex() noexcept; ///Returns a clone, use owns and must delete static Tex getDefaultWhite2x2Tex() noexcept; static std::string toString(); private: ManagerTex() = default; static void internal_init( ManagerTex& s ); //only ever called exactly once! struct call_init_once; static ManagerTex& instance(); std::vector< std::future< ManagerTex::func_send_to_GPU_on_main_thread > > parsed_Tex_ready_to_send_to_GPU_via_func; static std::optional< std::tuple< std::shared_ptr, SDL_Surface* > > load_tex_to_cpu_memory_no_gl_calls_sdl_image( std::shared_ptr pending_tds_to_load, unsigned int requested_pixelWidth, unsigned int requested_pixelHeight ); //Calls AftrUtil_image static std::optional< std::tuple< std::shared_ptr, std::shared_ptr> > load_tex_to_cpu_memory_no_gl_calls_stbi_image( std::shared_ptr pending_tds_to_load, unsigned int requested_pixelWidth, unsigned int requested_pixelHeight ); static bool instantiateOpenGLTexture_SDLSurf( std::tuple< std::shared_ptr, SDL_Surface* > tex_n_rawDat ); static bool instantiateOpenGLTexture_stbi( std::shared_ptr tds, std::shared_ptr< Aftr_stb_image > raw_image ); static SDL_Surface* convertSDLImageCoordsToOpenGLTexCoords( SDL_Surface* image ); std::unordered_map< TexDataSharedID, std::shared_ptr > tds_map; //to be removed, and replaced with stb image std::mutex invokeSDLFunctionMutex; //locks SDL function calls that are not thread safe because of the SDL_Surface struct PBO_Tex_Xfer_Data* pbo_dat = nullptr; std::optional default_tex_white; //Must be optional or the Tex needs to be created before ManagerTex is created, chick-n-egg deadlock on startup std::optional default_tex; //Must be optional or the Tex needs to be created before ManagerTex is created, chick-n-egg deadlock on startup }; }