NoesisGUI

Resource Providers

In Noesis, the process of loading resources can be customized by using resource providers. There is a provider for each kind of resource: Xaml, Texture and Font. You normally setup each provider after Noesis initialization.

Noesis::GUI::SetXamlProvider(xamlProvider);
Noesis::GUI::SetTextureProvider(textureProvider);
Noesis::GUI::SetFontProvider(fontProvider);

This three kind of provider share the same abstraction for files, the Stream interface.

class Stream: public BaseComponent
{
public:
    /// Set the current position within the stream
    virtual void SetPosition(uint32_t pos) = 0;

    /// Returns the current position within the stream
    virtual uint32_t GetPosition() const = 0;

    /// Returns the length of the stream in bytes
    virtual uint32_t GetLength() const = 0;

    /// Reads data at the current position and advances it by the number of bytes read
    /// Returns the total number of bytes read. This can be less than the number of bytes requested
    virtual uint32_t Read(void* buffer, uint32_t size) = 0;
};

Xaml provider

The base class from implementing a provider of xamls is XamlProvider.

class XamlProvider: public BaseComponent
{
public:
    // Loads the specified XAML file. Returns null if no xaml found
    virtual Ptr<Stream> LoadXaml(const char* uri) = 0;
};

The implementation is straightforward. You basically must provide a stream for each uri that is requested. You can find two XamlProvider implementations in the application framework, LocalXamlProvider for loading XAMLs from disk and EmbeddedXamlProvider for loading XAMLs embedded in the executable.

Texture provider

Texture providers are a bit more complex because you need to implement two different functions. At the main thread the layout process needs information about the dimensions of the texture. You provide that information through the GetTextureInfo function. The function that really loads the texture is LoadTexture and it is always called from the render thread.

class TextureProvider: public BaseComponent
{
public:
    /// Returns metadata for the given texture. 0 x 0 is returned if no texture found
    virtual TextureInfo GetTextureInfo(const char* uri) = 0;

    /// Returns a texture compatible with the given device. Null is returned if no texture found
    virtual Ptr<Texture> LoadTexture(const char* uri, RenderDevice* device) = 0;
};

The application framework provides a helper class, FileTextureProvider, that will create the texture for you from an image. It exposes a virtual function you must implement to load the requested filename.

class FileTextureProvider: public Noesis::TextureProvider
{
protected:
    virtual Ptr<Stream> OpenStream(const char* uri) const = 0;
};

Similar to XamlProvider you can find LocalTextureProvider and EmbeddedTextureProvider implementations within the application framework.

Font provider

The font provider is the more complex to implement. The base class in charge of loading fonts is FontProvider.

class FontProvider: public BaseComponent
{
public:
    /// Finds the font in the given folder that best matches the specified properties
    /// BaseUri is the directory where the search is performed or nullptr for system fonts
    /// Returns a null stream if no matching found
    virtual FontSource MatchFont(const char* baseUri, const char* familyName, FontWeight weight,
        FontStretch stretch, FontStyle style) = 0;

    /// Returns true if the requested font family exists in given directory
    /// BaseUri is the directory where the search is performed or nullptr for system fonts
    virtual bool FamilyExists(const char* baseUri, const char* familyName) = 0;
};

To help with the implementation of this provider there is an intermediate class, CachedFontProvider, that scans folders and extracts family information from .ttf and .otf files. It also implements a font matching algorithm based on the W3C specifications.

CachedFontProvider exposes two virtual functions, ScanFolder and OpenFont:

  • In ScanFolder you must register all the fonts available in the given folder. Each font is registered by calling RegisterFont.
  • OpenFont is the function in charge of providing the stream corresponding to each of the registered filenames.
class CachedFontProvider: public FontProvider
{
protected:
    /// Registers a font filename in the given folder. Each time this function is invoked, the
    /// given filename is opened and scanned (through OpenFont). It is recommened deferring
    /// this call as much as possible (for example, until ScanFolder is invoked)
    void RegisterFont(const char* folder, const char* filename);

    /// First time a font is requested from a folder, this function is invoked to give inheritors
    /// the opportunity to register faces found in that folder
    virtual void ScanFolder(const char* folder);

    /// Returns a stream to a previously registered filename
    virtual Ptr<Stream> OpenFont(const char* folder, const char* filename) const = 0;
};

NOTE

CachedFontProvider will also scan system fonts by default. It can be disabled by doing 'SetUseSystemFonts(false)'.

Similar to the rest of providers, LocalFontProvider and EmbeddedFontProvider are sample implementations available in the application framework.

© 2017 Noesis Technologies