libimg/libimg.h

324 lines
12 KiB
C

#ifndef LIBIMG_H
#define LIBIMG_H
#include <gint/display.h>
#include <stdint.h>
/* This is substituted by CMake at compile-time */
#define IMG_VERSION "@libimg_VERSION@"
#ifdef FX9860G
/* On fx-9860G, the format is 8-bit per color. Although there are much less
than 256 colors (you could find 9 at best including partially-transparent
ones), it makes it possible to share code with the fx-CG 50, which is the
main target for this library. */
typedef uint8_t img_pixel_t;
#define IMG_ALPHA C_NONE
#endif /* FX9860G */
#ifdef FXCG50
/* On fx-CG 50, the format is 16-bit R5G6B5A. A value is reserved for
transparency; currently this is 0x0001. */
typedef uint16_t img_pixel_t;
#define IMG_ALPHA 0x0001
#endif /* FXCG50 */
/* The type of images; this is usually passed by value. The structure itself
only references the memory. Because it is passed by value, const qualifiers
are useless here (since the pixel pointer does not inherit them). */
typedef struct {
/* Image dimensions */
uint16_t width;
uint16_t height;
/* Number of pixels on each storage line */
uint16_t stride;
/* Flags (some internal) */
uint8_t flags;
/* Reserved for future use */
uint8_t _;
/* Pointer to pixels */
img_pixel_t *pixels;
} img_t;
//---
// Surface creation and destruction
//---
/* img_create(): Create a new, uninitialized image
This function creates a new surface and returns it. This surface must be
destroyed with img_destroy() when it is no longer needed. Sub-surfaces can
be created from it, but will no longer be usable when it is destroyed.
If the allocation fails, or the requested size is larger than 65535x65535,
this function returns a surface with zero dimensions and a NULL pixel
pointer. img_null() will return 1 on this error-image.
After creation, the image contains random pixels, which might not even be
valid colors on fx-9860G. It is advised to fill it with img_fill() unless
you know it will be filled by another mechanism such as a transform.
@w @h Dimensions of the new image */
img_t img_create(int w, int h);
/* img_copy(): Create a new image by copying an existing one
This function creates a new surface from a copy of the argument. Much like
with img_create(), the new surface must be destroyed with img_destroy(). */
img_t img_copy(img_t img);
/* img_null(): Check if an image is null (ie. failed to allocate)
A null image does not contain any data. It is correct to pass a null image
to any function of the library, but either nothing will happen or another
null image will be returned. */
int img_null(img_t img);
/* img_sub(): Get a reference to a section of an image
This function returns a surface that references a rectangle inside the
provided image [img]. This is *not* a new image; it is a view on a rectangle
inside [img]; just the same pixels viewed differently. It needs not be
destroyed, and it becomes invalid when [img] is destroyed. If you need an
actual copy, do img_copy(img_sub(img,x,y,w,h)).
The specified rectangle is clipped to fit into [img] before the reference is
created. If w or h is set to -1, then the full width or height of the image
is used.
@img Source image
@x @y Location of the top-left corner of the rectangle to reference
@w @h Size of the referenced rectangle */
img_t img_sub(img_t img, int x, int y, int w, int h);
/* img_at(): Get a reference to a section defined by its top-left corner
This function returns a sub-image of its first argument. The sub-image
starts at position (x,y) of the source image and ends in the bottom-right
corner.
This function is useful when transforming. This is because the result of a
transform is always drawn at position (0,0) on the destination image. To
change the position, one can get a reference using img_at().
For instance, the following call flips src horizontally and draws the result
onto dst at position (0,0):
img_hflip(src, dst);
To draw the flipped src at position (20,10), the call can be modified to:
img_hflip(src, img_at(dst, 20, 10));
If there is not enough space at position (20,10) of dst to draw the entirety
of the transformed src, the transform will fail and do nothing.
Calling img_at() is strictly equivalent to calling img_sub() with w=h=-1.
@img Source image
@x @y Location of the top-left corner to reference */
img_t img_at(img_t img, int x, int y);
#ifdef FXCG50
/* img_vram(): Obtain a reference to the current VRAM as an image
This function returns a reference to gint's VRAM wrapped into a surface
object. This is very useful to render to VRAM with all of the transforming
power of libimg surfaces. This surface needs not be destroyed.
This function is not available on fx-9860G because the format of the VRAM is
not compatible with that of surfaces. However, it is still possible to
render surfaces to VRAM using img_render_vram().
On fx-CG 50, the VRAM address changes at every frame when triple buffering
is active. It is recommended to call img_vram() at every frame to obtain the
correct address every time. (This function always executes instantly.) */
img_t img_vram(void);
#endif /* FXCG50 */
/* img_destroy(): Destroy an image
This function destroys an image. If the image did not own its memory,
nothing happens. Otherwise, the surface memory is released and all
references into it become invalid. */
void img_destroy(img_t img);
//---
// Basic rendering
//---
/* img_fill(): Fill an image with a single color */
void img_fill(img_t img, img_pixel_t color);
/* img_clear(): Fill an image with transparent pixels
Strictly equivalent to img_fill(img, IMG_ALPHA). Just a shortcut. */
void img_clear(img_t img);
/* img_render(): Render an image onto another one
Copies the source image [src] at position (0,0) of target [dst].
-> To copy at position (x,y), replace dst with img_at(dst,x,y).
-> To copy only a section of src, replace src with img_sub(src,x,y,w,h).
Unlike transforms, this function clips the copied rectangle onto the
destination, so the call will work even if src overflows from dst.
Transparent pixels in the source are not copied. If it is necessary to have
transparent pixels of the source become transparent on the destination as
well, first fill the destination with IMG_ALPHA (or use img_clear()).
Note that on fx-CG 50 the VRAM does not support transparency and transparent
pixels will appear as basically black. */
void img_render(img_t src, img_t dst);
/* img_render_vram(): Render an image to the VRAM
This function works like img_render() but renders to VRAM on fx-9860G. This
compensates the lack of img_vram() function on this platform. Rendering to
VRAM supports both monochrome and gray pixels. This function clips the
rendered image onto the VRAM.
This function only renders to black-and-white VRAM. Dark gray and light gray
pixels are replaced by black and while, respectively. To render imges under
the gray engine, use img_render_vram_gray().
On fx-CG 50, this function is exactly equivalent to:
img_render(src, img_at(img_vram(), x, y)).
@src Source image
@x @y Render destination on VRAM */
void img_render_vram(img_t src, int x, int y);
#ifdef FX9860G
/* img_render_vram_gray(): Render a gray image to the VRAM
On fx-9860G, mono and gray rendering code must be separated. This function
is the direct equivalent of img_render_vram(), but it renders to the gray
VRAM and is suitable for gray images.
@src Source image
@x @y Render destination on gray VRAM */
void img_render_vram_gray(img_t src, int x, int y);
#endif
//---
// Geometric transforms
//
// All geometric transforms render to position (0,0) of the target image and
// fail if the target image is not large enough to hold the transformed result
// (unlike the rendering functions which render only the visible portion).
//
// To render at position (x,y) of the target image, use img_at(). For instance:
// img_hflip(src, img_at(dst, x, y));
//
// Each transform function has a [_create] variant which does the same
// transform but allocates the target image on the fly and returns it. Remember
// that allocation can fail, so you need to check whether the returned image is
// null.
//
// (You can still pass a null image to libimg functions when chaining
// transforms. The null image will be ignored or returned unchanged, so you
// can check for it at the end of any large chain.)
//
// Some functions support in-place transforms. This means they can be called
// with the source as destination, and will transform the image without needing
// new memory. For instance, img_hflip(src, src) flips in-place and replaces
// src with a flipped version of itself.
//
// (However, it is not possible to transform in-place if the source and
// destination intersect in non-trivial ways. The result will be incorrect.)
//
// When transforming to a new image, transparent pixels are ignored, so if the
// destination already has some data, it will not be erased automatically. Use
// img_clear() beforehand to achieve that effect. This allows alpha blending
// while transforming, which is especially useful on the VRAM.
//---
/* img_hflip(): Flip horizontally (supports in-place)
The destination image must have the same size as the source. */
void img_hflip(img_t src, img_t dst);
img_t img_hflip_create(img_t src);
/* img_vflip(): Flip vertically (supports in-place)
The destination image must have the same size as the source. */
void img_vflip(img_t src, img_t dst);
img_t img_vflip_create(img_t src);
/* img_rotate(): Rotate by 90, 180 or 270 degrees (supports in-place)
This function applies a rotation of the specified angle (90, 180 or 270) in
degrees from the source image to the destination image. The rotation can be
performed in-place under the following conditions:
* For 180 degrees: no condition
* For 90 and 270 degrees: width and height of source image are equal
Even if the rotation is not in-place, the target image must have exactly the
size of the rotated source. You can use img_sub() to rotate into part of a
larger destination image. */
void img_rotate(img_t src, img_t dst, int angle);
img_t img_rotate_create(img_t src, int angle);
/* img_upscale(): Upscale by an integer ratio (does not support in-place) */
void img_upscale(img_t src, img_t dst, int scale);
img_t img_upscale_create(img_t src, int scale);
//---
// Color transforms
//
// All color transforms operate on a per-pixel basis. They never change the
// size of the image and can always (trivially) operate in-place. They still
// require the size of the output to be at least the size of the input.
//
// As for geometric transforms, all functions have a [_create] variant that
// copies the image before applying the transform.
//---
/* img_dye(): Replace all non-transparent pixels with a single color
This function repaints all non-transparent pixels of [src] with a fixed
color. This transform is commonly used in games to animate interactions
through various colors (red, white, etc). */
void img_dye(img_t src, img_t dst, img_pixel_t color);
img_t img_dye_create(img_t src, img_pixel_t color);
#ifdef FXCG50
/* img_lighten(): Roughly lighten an image
This function produces a lighter version of the specified image by doubling
the value of each color component (while capping to a maximum to prevent
overflow - this is called saturation arithmetic). Because RGB565 is used,
after 6 iterations, the resulting image will always be white.
This function does not work very well on pixel art but produces convincing
results on artworks and photos. */
void img_lighten(img_t src, img_t dst);
img_t img_lighten_create(img_t src);
/* img_whiten(): Fade an image to white
This function fades the provided image to white by halving the distance of
each color component to its maximum value. The result after 6 iterations
will always be white. */
void img_whiten(img_t src, img_t dst);
img_t img_whiten_create(img_t src);
/* img_darken(): Roughly darken an image (same as fading to black)
This function makes an image darken by halving the value of each color
component. After 6 iterations, the resulting image will always be black.
Note that both img_lighten() and img_darken() destroy some of the
information present in the image. They do not cancel each other. If the
original image is needed at some point, a copy must be made before
lightening or darkening it. */
void img_darken(img_t src, img_t dst);
img_t img_darken_create(img_t src);
#endif /* FXCG50 */
#endif /* LIBIMG_H */