CARVIEW |
Navigation Menu
-
-
Notifications
You must be signed in to change notification settings - Fork 6
Textures and custom renderers
When talking about the UImGui::Texture
class, renderers must create their own classes that derive from the UImGui::GenericTexture
abstract class.
However, GenericTexture
and GenericRenderer
do not depend on each other. This produces following side effects:
- Custom renderers can decide whether to implement a texture backend(some applications might prefer their own custom abstractions)
- Custom renderers based on OpenGL, Vulkan and/or WebGPU can decide to reuse the existing texture creation workflows
- Custom renderers can easily mix and match texture and renderer backends
This is why in the RendererData
struct one can see that there are 2 members of the RendererType
enum. One for the renderer, and one for the texture backend.
By default the rendererType
and the textureRendererType
fields are set to be equal to each other. In order for your renderer to reuse one of the existing texture renderer backends use UImGui::Renderer::data().textureRendererType
to set it to another type before creating your texture.
The UImGui::GenericTexture
abstract class looks like this:
class GenericTexture
{
public:
// Event Safety - Any time
virtual void init(TextureData& dt, String location, bool bFiltered) noexcept = 0;
// Event Safety - Post-begin
virtual uintptr_t get(TextureData& dt) noexcept = 0;
// Event Safety - Post-begin
virtual void load(TextureData& dt, void* data, FVector2 size, uint32_t depth, bool bFreeImageData,
const TFunction<void(void*)>& freeFunc) noexcept = 0;
template<TextureFormat format>
static bool saveToFile(TextureData& dt, const String location, const TextureFormat fmt = format, const uint8_t jpegQuality = 100);
// Cleans up the image data
// Event Safety - All initiated
virtual void clear(TextureData& dt) noexcept = 0;
virtual ~GenericTexture() noexcept = default;
protected:
friend class Texture;
static void beginLoad(TextureData& dt, void** data, FVector2& size) noexcept;
static void endLoad(TextureData& dt, void* data, bool bFreeImageData, const TFunction<void(void*)>& freeFunc) noexcept;
static void defaultInit(TextureData& dt, String location, bool bFiltered) noexcept;
static void defaultClear(TextureData& dt) noexcept;
};
If you compare it to the normal UImGui::Texture
class, you'll discover that most of the functions map 1:1, except that most functions in the GenericTexture
class get a TextureData&
as their first argument. This is to ensure that derivations based on GenericTexture
are always code-only, since the same backend instance is used between all textures.
The TextureData
struct looks like this:
struct TextureData
{
String filename;
FVector2 size;
bool bFiltered;
int channels;
uintptr_t id;
void* data;
// This stores the string location for the internal C storage system
size_t storageIndex;
CustomSaveFunction customSaveFunction;
// Data for each custom texture renderer backend
void* context;
size_t contextSize;
};
The context
and contextSize
members are used for storing any additional data that the custom texture backend instance may need.
All other members are part of what all textures store as their data. For more info, refer to the Textures entry.
Here is a pseudo-example that showcases how custom texture backends are generally implemented:
class PseudoTexture final : public UImGui::GenericTexture
{
public:
virtual void init(UImGui::TextureData& dt, const UImGui::String location, const bool bFiltered) noexcept override
{
defaultInit(dt, location, bFiltered);
}
virtual void load(UImGui::TextureData& dt, void* data, UImGui::FVector2 size, uint32_t depth, bool bFreeImageData,
const TFunction<void(void*)>& freeFunc) noexcept override
{
beginLoad(dt, &data, size);
// Load using your renderer API here
endLoad(dt, data, bFreeImageData, freeFunc);
}
virtual uintptr_t get(UImGui::TextureData& dt) noexcept override
{
return dt.id;
}
virtual void clear(UImGui::TextureData& dt) noexcept override
{
// Clear with your renderer API here
dt.id = 0;
defaultClear(dt);
}
virtual ~TestOpenGLTexture() noexcept override = default;
};
To then use the PseudoTexture
backend, create an instance of it and assign its address to the customTexture
field of the InitInfo
struct.
More examples can be found in the following documentation entry.
The C API for the GenericTexture
class looks like this:
UImGui_CGenericTexture* UImGui_CGenericTexture_make(
UImGui_CGenericTexture_InitFun init,
UImGui_CGenericTexture_GetFun get,
UImGui_CGenericTexture_LoadFun load,
UImGui_CGenericTexture_Clear clear
);
void UImGui_CGenericTexture_free(UImGui_CGenericTexture* texture);
As you can see, the callback functions provided to the UImGui_CGenericTexture_make()
function are equivalent to the ones in the C++ class.
These function pointer types are implemented like this:
typedef void UImGui_CGenericTexture;
typedef void(*UImGui_CGenericTexture_VoidFun)(UImGui_TextureData*);
typedef void(*UImGui_CGenericTexture_InitFun)(UImGui_TextureData*, UImGui_String, bool);
typedef uintptr_t(*UImGui_CGenericTexture_GetFun)(UImGui_TextureData*);
typedef void(*UImGui_CGenericTexture_LoadFun)(UImGui_TextureData*, void*, UImGui_FVector2, uint32_t, bool);
typedef UImGui_CGenericTexture_VoidFun UImGui_CGenericTexture_Clear;
All functions in the UImGui::GenericTexture
class or C API are rated with the same event safety as their counterparts in the UImGui::Texture
class.
This project is supported by all the people who joined our discord server and became beta testers. If you want to join the discord you can click here.
- Home
- Beginner content
- Install guide
- Creating and using the UI components
- The Instance
- The Init Info struct
- Building better titlebar menus
- Textures
- Logging
- Unicode support
- Additional features
- Client-side bar
- Custom type definitions
- Memory management
- C API development
- Config files and Folders
- Interfaces
- Internal Event safety
- Customising the build system
- Modules system
- Collaborating with others
- Advanced content
- Developer and contributor resources
- Misc