Fallback Resources

The fallback resources feature of Gameface allows developers to choose to load different formats from those specified in the HTML. This is very convenient for image formats, for example, because developers would prefer to use ASTC compressed images on Android, ETC2 images on iOS, DDS on Windows, etc. This can be done very easily with our fallback feature.

Example usage can be found in the SampleImageFallbackFormats sample. To use this feature we have to do the following steps:

  1. Add fallback formats to the system settings when initializing the system:
    ...
        // Create system settings
        cohtml::SystemSettings sysSettings;
    ...
        // Create fallback formats data
        SystemSettings::FallBackFormats formats;
        std::vector<const char*> extensionsData;
        std::vector<const char*> baseExtensions;
        std::vector<SystemSettings::FallBackFormats::FallBackFormat> allFallbackFormats;
        allFallbackFormats.resize(1);

        // On iOS we will fallback from png to ktx format
    #if defined(PLATFORM_IOS)
        baseExtensions.push_back("png");
        extensionsData.push_back("ktx");

        // On Android we will fallback from png to astc format
    #elif defined(PLATFORM_ANDROID)
        baseExtensions.push_back("png");
        extensionsData.push_back("astc");

        // On Windows or Mac we will fallback from png to dds format
    #elif defined(PLATFORM_WIN) || defined(PLATFORM_MACOSX)
        baseExtensions.push_back("png");
        extensionsData.push_back("dds");
    #endif
        // We add png again in case we do not find
        // astc, dds or ktx and will try to load png
        extensionsData.push_back("png");
        formats.Formats = allFallbackFormats.data();
        formats.FormatsSize = unsigned(allFallbackFormats.size());
        for (auto i = 0u; i < allFallbackFormats.size(); ++i)
        {
            formats.Formats[i].BaseFormat = baseExtensions[i];
            formats.Formats[i].Extensions = extensionsData.data();
            formats.Formats[i].ExtensionsSize = unsigned(extensionsData.size());
        }
        sysSettings.Formats = formats;
        ...
        // Initialize other things
        ...
        // Initialize the system
        m_System = m_Library->CreateSystem(sysSettings);
  1. Override cohtml::IAsyncResourceHandler::OnResourceRequest in the resource handler.
  • In the OnResourceRequest method, we get the first fallback format that we have specified.
  • If this format is not found, we call cohtml::IAsyncResourceRequest::GetFallbackURLs(). This method will return all the remaining fallback URLs as an array.
  • We traverse this array and try to load the given URLs until an existing one is found. Copy file data to Cohtml and signal success. If no URL is valid, then signal failure.

Here is a pseudocode implementation:

virtual void MyResponseHandler::OnResourceRequest(
    const cohtml::IAsyncResourceRequest* request,
    html::IAsyncResourceResponse* response) override
{
    std::string url = request->GetURL();

    auto rawData = MyApp::GetFileBytes(url);

    if (!rawData)
    {
        // Try other fallback formats that we have specified
        // by calling IAsyncResourceRequest::GetFallbackURLs
        cohtml::IAsyncResourceRequest::FallbackURLsData fallbackData = request->GetFallbackURLs();
        for (unsigned i = 0; i < fallbackData.Count; ++i)
        {
            rawData = MyApp::GetFileBytes(fallbackData.Data[i]);
            if (rawData)
            {
                // We found a existing file with fallback URL
                break;
            }
        }
        if (!rawData)
        {
            // We have not found the any of the fallback URLs
            response->Finish(cohtml::IAsyncResourceResponse::Failure);
            return;
        }
    }

    // We allocate space for the raw data in Cohtml
    auto destPtr = response->GetSpace(rawData.size());

    // Copy file bytes
    MyApp::CopyData(destPtr, rawData, rawData.size());

    response->Finish(cohtml::IAsyncResourceResponse::Success);
}