CoronaGraphics.h

Type C header
Revision 2017.3060
Keywords Enterprise, C, CoronaGraphics, plugins
See also TextureResourceExternal

Overview

CoronaGraphics.h contains interfaces to interact with the Corona graphics pipeline.

External Bitmaps

These APIs allow bitmaps loaded from a C plugin to be made displayable in Corona by pushing them to Lua as TextureResourceExternal objects. A bitmap that is wrapped in a Lua TextureResourceExternal object can then be displayed in Corona via APIs that accept image filename and baseDir parameters such as the Lua display.newImage(), display.newImageRect(), and graphics.newImageSheet() functions. Textures can also be applied to display objects that have a fill property such as ShapeObjects.

Please see the texture management guide for examples on how to use and manage textures in Corona.


Functions

CoronaExternalPushTexture()

int CoronaExternalPushTexture( lua_State *L, const CoronaExternalTextureCallbacks *callbacks, void* userData )

Creates a new Lua TextureResourceExternal object with the given callbacks and user data, then pushes the newly created texture to the top of the Lua stack. This works similarly to the Lua graphics.newTexture() function except the return texture object wraps a bitmap loaded by the caller and the given callbacks argument provides an interface for Corona to access this bitmap's information and pixel data.

Will return 1 if the texture object was successfully created and pushed to the top of the Lua stack.

Will return 0 if the function failed to create the texture object and the Lua stack was unchanged. This will happen if given invalid arguments or if the given Lua state does not belong to an actively running Corona runtime.

Note that pushed textures are subject to manual texture management and must be released when no longer needed.

L

Pointer to the Lua state to push the new TextureResourceExternal object to.

callbacks

Pointer to a CoronaExternalTextureCallbacks structure providing callbacks for Corona to invoke when requesting the plugin to provide texture information, perform an operation, and other feedback information. All callbacks will receive the userData value provided to this function. See CoronaExternalTextureCallbacks for more details.

userData

Pointer to user data defined by the caller. This pointer will be passed as an argument to all function callbacks defined in the CoronaExternalTextureCallbacks struct.


CoronaExternalGetUserData()

void* CoronaExternalGetUserData( lua_State *L, int index )

Retrieves the userData that was assigned to a Lua TextureResourceExternal object that was created by a call to the CoronaExternalPushTexture() C function. This function is useful when implementing the callback.onGetField() callback.

Returns the userData pointer specified when creating the texture with CoronaExternalPushTexture() or returns NULL if the given stack index doesn't reference a texture object.

L

Pointer to the Lua state to access the Lua TextureResourceExternal object from.

index

1-based index to the TextureResourceExternal object on the Lua stack.


CoronaExternalFormatBPP()

int CoronaExternalFormatBPP( CoronaExternalBitmapFormat format )

Helper function which returns the number of bytes-per-pixel that the given bitmap format has. For example, this function will return 4 for a kExternalBitmapFormat_RGBA format, 3 for a kExternalBitmapFormat_RGB format, and 1 for a kExternalBitmapFormat_Mask format.

format

The pixel format to be queried for how many bytes it has per pixel.


Enums

CoronaExternalBitmapFormat

CoronaExternalBitmapFormat is an enumerated type describing the pixel format of the bitmap. Bitmap channels are (from left to right) MSB to LSB. Using RGBA as an example, A is in the least-significant 8 bits.

RGBA format uses premultiplied alpha. This means that if the "raw" values of the channels are r, g, b, and a, the red channel will be r*(a/255).

This enum provides the following constants:

  • kExternalBitmapFormat_Undefined — Defaults to kExternalBitmapFormat_RGBA.
  • kExternalBitmapFormat_Mask — Alpha; 1 byte per pixel. Textures with bitmaps of this format can be used only as masks.
  • kExternalBitmapFormat_RGB — RGB; 3 bytes per pixel.
  • kExternalBitmapFormat_RGBA — RGBA; 4 bytes per pixel. RGB channels must be premultiplied with alpha.
Important
  • The width of kExternalBitmapFormat_Mask and kExternalBitmapFormat_RGB bitmaps must be a multiple of 4. If the width is not a multiple of 4, the mask will create visual artifacts, and RGB will be treated as RGBA on Windows.

  • When using kExternalBitmapFormat_RGBA, the red, green, and blue channels must have premultiplied alpha.


Structs

CoronaExternalTextureCallbacks

typedef struct CoronaExternalTextureCallbacks
{
    unsigned long size;
    unsigned int (*getWidth)(void* userData);
    unsigned int (*getHeight)(void* userData);
    const void* (*onRequestBitmap)(void* userData);
    void (*onReleaseBitmap)(void* userData);
    CoronaExternalBitmapFormat (*getFormat)(void* userData);
    void (*onFinalize)(void *userData);
    int (*onGetField)(lua_State *L, const char *field, void* userData);
} CoronaExternalTextureCallbacks;

The CoronaExternalTextureCallbacks structure contains fields which provide information about the texture and callbacks to be invoked by Corona when events occur or when Corona is requesting information about the texture. Textures are managed by Corona and plugins have no control on when the texture is to be released. So, information about a texture's bitmap must be available upon request.

Note

Always initialize an instance of this structure with zeros. Some of the fields are optional and the texture can be created even if they are NULL. Other fields are required, however, and the texture will not be pushed if they aren't present.

CoronaExternalTextureCallbacks callbacks;
memset(&callbacks, 0, sizeof(CoronaExternalTextureCallbacks))
callbacks.size = sizeof(CoronaExternalTextureCallbacks);
size (required)

When creating an instance of this type, set this member to the number of bytes the CoronaExternalTextureCallbacks type is. This field is used for identifying the API version.

size = sizeof(CoronaExternalTextureCallbacks);
getWidth (required)

Callback that will be invoked when Corona is requesting the plugin to provide the bitmap's pixel width. This callback receives the userData pointer passed when the texture resource was created. Please note that some bitmap formats, such as 8-bit masks, require the width to be a multiple of 4 bytes.

getHeight (required)

Callback that will be invoked when Corona is requesting the plugin to provide the bitmap's pixel height. This callback receives the userData pointer passed when the texture resource was created.

onRequestBitmap (required)

Callback that will be invoked by Corona when the bitmap's pixel array has been requested by Corona's rendering system. This function call will always be followed by a call to the onReleaseBitmap callback. This callback receives the userData pointer passed when the texture resource was created.

This function must return a valid pointer to the data containing bitmap information. Corona expects bitmap data to be a row-by-row array of pixels starting from the top left of the image, and each pixel is represented by bpp = CoronaExternalFormatBPP(getFormat()) bytes. Each color channel uses 1 byte and is ordered the same as the format name, left to right. So, with RGBA format, the R index is 0.

The overall size of memory must be at least...

unsigned int bitmapSizeInBytes = getWidth() * getHeight() * bytesPerPixel;

Accessing the left-most value of the bitmap (R in RGBA) could be written as...

void* byteArray = onRequestBitmap();
int bytesPerPixel = CoronaExternalFormatBPP(getFormat());
int red = (int)byteArray[((Y * getWidth()) + X) * bytesPerPixel];

Remember that the default format, RGBA, uses premultiplied alpha.

onReleaseBitmap (optional)

Callback that will be invoked by Corona to notify the plugin that the texture bitmap's data is no longer required. Meaning that the plugin can delete the bitmap data from memory. After this callback is invoked, the pointer previously returned by the onRequestBitmap() callback is no longer expected to be valid. This callback receives the userData pointer passed when the texture resource was created.

getFormat (optional)

Callback that will be invoked by Corona when requesting the pixel format of the bitmap. This callback receives the userData pointer passed when the texture resource was created. This must return a CoronaExternalBitmapFormat enum constant, such as kExternalBitmapFormat_RGBA.

onFinalize (optional)

Callback that will be invoked by Corona to notify the plugin that the Lua TextureResourceExternal object is about to be destroyed. After this callback is invoked, no callbacks or returned bitmap pointers can be accessed. Essentially, this releases all objects and resources associated with this texture resource. This callback receives the userData pointer passed when the texture resource was created.

onGetField (optional)

Callback to be invoked when an unknown Lua property has been accessed from the Lua TextureResourceExternal object. This is the plugin's opportunity to provide custom read-only fields from the Lua object. Argument field provides the name of the property being accessed from the TextureResourceExternal object. Argument userData is the pointer passed when the texture resource was created. This function must returns the number of values pushed onto the Lua stack.

Example

External Bitmap

This example is a hypothetical plugin.texturer with a single function, newTexture(), that pushes an image from third-party APIs (prefixed with TPA_). Images have indices and third-party APIs can retrieve images with these indices.

  1. Declare the plugin with the luaopen_ function. This is common for all plugins.
CORONA_EXPORT int luaopen_plugin_texturer( lua_State *L )
{
    // Functions in library
    const luaL_Reg kVTable[] =
    {
        { "newTexture", newTexture },
        { NULL, NULL }
    };

    luaL_openlib( L, kName, kVTable, 0 );

    return 1;
}
  1. Implement the newTexture() function which will push images:
/** TextureResourceExternal texturer.newTexture(image) */
int newTexture(lua_State* luaStatePointer)
{
    int image = 0;
    if (lua_type(luaStatePointer, 1) == LUA_TNUMBER)
    {
        image = (int)lua_tointeger(luaStatePointer, 1);
    }
    else
    {
        luaL_argerror( L, 1, "image must be a number")
    }

    // creating callbacks structure and initializing it with zeros
    CoronaExternalTextureCallbacks callbacks = {0};
    // setting size
    callbacks.size = sizeof(CoronaExternalTextureCallbacks);
    // setting callbacks
    callbacks.getWidth = getWidth;
    callbacks.getHeight = getHeight;
    callbacks.onRequestBitmap = onRequestBitmap;
    callbacks.onReleaseBitmap = onReleaseBitmap;
    callbacks.onFinalize = onFinalize;

    // Creating helper structure
    HelperStruct* helper = new HelperStruct();
    helper->image = image;    
    helper->w = TPA_GetImageWidth(image);   //caching width and height
    helper->h = TPA_GetImageHeight(image);

    int ret = CoronaExternalPushTexture(L, &callbacks, (image));

    // Note that we're not deleting `helper` when everything is OK. It would be released in finalizing callback.
    if (ret == 0)
    {
        // something went wrong. Texture was not pushed, so should clean up to prevent memory leak
        delete helper;
    }
    return ret;
}
  1. Implement callbacks and helper:
struct HelperStruct
{
    unsigned w;
    unsigned h;
    int image;
    void *buff;    
}


unsigned getWidth(void* userData)
{
    HelperStruct* self = (HelperStruct*)userData;
    return self->w;
}

unsigned getHeight(void* userData)
{
    HelperStruct* self = (HelperStruct*)userData;
    return self->h;
}

const void* onRequestBitmap(void* userData)
{
    HelperStruct* self = (HelperStruct*)userData;

    int sz = self->w*self->h*4; // we know that our API always return 4 byte RGBA
    self->buff = new unsigned char[sz];
    TPA_GetImageRGBA(self->image, self->buff, sz);
    return self->buff;
}

void onReleaseBitmap(void* userData)
{
    HelperStruct* self = (HelperStruct*)userData;
    delete [] self->buff;
}

void onFinalize(void *userData)
{
    HelperStruct* self = (HelperStruct*)userData;
    // release helper when texture is no longer required
    delete self;
}
  1. Use the plugin in Lua code:
local texturer = require( "plugin.texturer" )

local tex = texturer.newTexture( 42 )
display.newImageRect( tex.filename, tex.baseDir, tex.width, tex.height )
tex:releaseSelf()
Note

When the texture is created, callbacks will not be instantly called. Corona creates textures between frames and only when they're required. Also, after texture:releaseSelf() is called, texture is not necessarily released — only this Lua reference is. If any display objects are using the texture, it will not be released, such that they can still be rendered correctly.