mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-29 13:03:36 +01:00
image: arbitrary linear transforms [WIP]
This commit is contained in:
parent
818f950fff
commit
780acb3fc9
12 changed files with 200 additions and 17 deletions
|
@ -174,6 +174,10 @@ set(SOURCES_CG
|
||||||
src/image/image_get_pixel.c
|
src/image/image_get_pixel.c
|
||||||
src/image/image_hflip.c
|
src/image/image_hflip.c
|
||||||
src/image/image_hflip_alloc.c
|
src/image/image_hflip_alloc.c
|
||||||
|
src/image/image_rotate.c
|
||||||
|
src/image/image_rotate_around.c
|
||||||
|
src/image/image_rotate_around_scale.c
|
||||||
|
src/image/image_scale.c
|
||||||
src/image/image_set_palette.c
|
src/image/image_set_palette.c
|
||||||
src/image/image_set_pixel.c
|
src/image/image_set_pixel.c
|
||||||
src/image/image_sub.c
|
src/image/image_sub.c
|
||||||
|
|
|
@ -448,15 +448,101 @@ image_t *image_sub(image_t const *src, int x, int y, int w, int h,
|
||||||
// while transforming, which is especially useful on the VRAM.
|
// while transforming, which is especially useful on the VRAM.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/* image_hflip(): Flip horizontally (supports in-place) */
|
/* image_hflip(): Flip horizontally
|
||||||
void image_hflip(image_t const *src, image_t *dst);
|
Formats: RGB16, P8
|
||||||
|
Size requirement: destination at least as large as source (no clipping)
|
||||||
|
Supports in-place: Yes */
|
||||||
|
void image_hflip(image_t const *src, image_t *dst, bool copy_alpha);
|
||||||
image_t *image_hflip_alloc(image_t const *src);
|
image_t *image_hflip_alloc(image_t const *src);
|
||||||
|
|
||||||
/* image_vflip(): Flip vertically (supports in-place) */
|
/* image_vflip(): Flip vertically
|
||||||
void image_vflip(image_t const *src, image_t *dst);
|
Formats: RGB16, P8
|
||||||
|
Size requirement: destination at least as large as source (no clipping)
|
||||||
|
Supports in-place: Yes */
|
||||||
|
void image_vflip(image_t const *src, image_t *dst, bool copy_alpha);
|
||||||
image_t *image_vflip_alloc(image_t const *src);
|
image_t *image_vflip_alloc(image_t const *src);
|
||||||
|
|
||||||
/* TODO: Geometric transforms */
|
/* image_linear(): Linear transformation
|
||||||
|
|
||||||
|
This function implements a generic linear transformation. This is a powerful
|
||||||
|
function that can perform any combination of rotation, mirroring and scaling
|
||||||
|
with nearest-neighbor sampling.
|
||||||
|
|
||||||
|
The [image_linear_opt] structure defines the settings for the transform.
|
||||||
|
Users familiar with linear algebra might want to use it directly, but they
|
||||||
|
are most conveniently generated with the rotation and scaling functions
|
||||||
|
listed below.
|
||||||
|
|
||||||
|
Formats: RGB16, P8
|
||||||
|
Size requirement: none (clipping through image_linear_opt settings)
|
||||||
|
Supports in-place: No */
|
||||||
|
|
||||||
|
struct image_linear_map {
|
||||||
|
/* The following parameters define the linear transformation as a mapping
|
||||||
|
from coordinates in the destination image (x and y) into coordinates in
|
||||||
|
the source image (u and v).
|
||||||
|
- (u, v) indicate where the top-left corner of the destination lands in
|
||||||
|
the source image.
|
||||||
|
- (dx_u, dx_v) indicate the source-image movement for each movement of
|
||||||
|
x += 1 in the destination.
|
||||||
|
- (dy_u, dy_v) indicate the source-image movement for each movement of
|
||||||
|
y += 1 in the destination.
|
||||||
|
All of these values are specified as 16:16 fixed-point, ie. they encode
|
||||||
|
decimal values by multiplying them by 65536. */
|
||||||
|
int u, v, dx_u, dx_v, dy_u, dy_v;
|
||||||
|
|
||||||
|
/* Dimensions of the source and destination */
|
||||||
|
int src_w, src_h, dst_w, dst_h;
|
||||||
|
};
|
||||||
|
|
||||||
|
void image_linear(image_t const *src, image_t *dst,
|
||||||
|
struct image_linear_map const *map);
|
||||||
|
image_t *image_linear_alloc(image_t const *src,
|
||||||
|
struct image_linear_map const *map);
|
||||||
|
|
||||||
|
/* image_scale(): Upscale or downscale an image
|
||||||
|
|
||||||
|
This function generates a linear map to be used in image_linear() to scale
|
||||||
|
the input image. The scaling factor gamma can be specified independently for
|
||||||
|
the x and y dimensions. It is expressed as 16:16 fixed-point; you can set
|
||||||
|
any decimal value multiplied by 65536, for instance 1.5*65536 to increase
|
||||||
|
the width and height by 50%. */
|
||||||
|
void image_scale(image_t const *src, int gamma_x, int gamma_y,
|
||||||
|
struct image_linear_map *map);
|
||||||
|
|
||||||
|
/* image_rotate(): Rotate an image around its center
|
||||||
|
|
||||||
|
This function generates a linear map to be used in image_linear() to perform
|
||||||
|
a rotation around the center of an image. If [resize=true], the target is
|
||||||
|
enlarged to make sure all the rotated pixels can be represented. This can
|
||||||
|
increase the final surface by a factor of up to 2. If the original image
|
||||||
|
doesn't extend to its corners, it is recommended to leave [resize=false] as
|
||||||
|
it noticeably affects performance. */
|
||||||
|
void image_rotate(image_t const *src, float angle, bool resize,
|
||||||
|
struct image_linear_map *map);
|
||||||
|
|
||||||
|
/* image_rotate_around(): Rotate an image around any point
|
||||||
|
|
||||||
|
This function generalizes image_rotate() by allowing rotations around any
|
||||||
|
center, even a point not within the image. The center is specified through
|
||||||
|
two coordinates (*center_x, *center_y). If the center is near the side of
|
||||||
|
the image, a normal rotation would move most of the pixels out of frame;
|
||||||
|
this function moves the frame to make sure the whole image remains visible.
|
||||||
|
*center_x and *center_y are updated to indicate the position of the center
|
||||||
|
of rotation within the new frame (the target image). */
|
||||||
|
void image_rotate_around(image_t const *src, float angle, bool resize,
|
||||||
|
int *center_x, int *center_y, struct image_linear_map *map);
|
||||||
|
|
||||||
|
/* image_rotate_around_scale(): Rotate an image around any point and scale it
|
||||||
|
|
||||||
|
This function generalizes image_rotate_around() by adding a scaling factor
|
||||||
|
to the transformation. The scaling factor gamma is expressed as 16:16
|
||||||
|
fixed-point. If [resize=true] the image is further extended to make sure no
|
||||||
|
parts are cut out, as in other rotation functions. */
|
||||||
|
void image_rotate_around_scale(
|
||||||
|
image_t const *src, float angle, int gamma,
|
||||||
|
bool resize, int *center_x, int *center_y,
|
||||||
|
struct image_linear_map *map);
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Color transforms
|
// Color transforms
|
||||||
|
@ -733,6 +819,10 @@ bool image_target(image_t const *src, image_t *dst, ...);
|
||||||
#define image_target_arg6(c, ...) \
|
#define image_target_arg6(c, ...) \
|
||||||
IMAGE_TARGET_ ## c __VA_OPT__(, image_target_too_many_args(__VA_ARGS__))
|
IMAGE_TARGET_ ## c __VA_OPT__(, image_target_too_many_args(__VA_ARGS__))
|
||||||
|
|
||||||
|
/* image_alpha_2(): Conditional alpha */
|
||||||
|
#define image_alpha_2(fmt, copy_alpha) \
|
||||||
|
((copy_alpha) ? 0x10000 : image_alpha(fmt))
|
||||||
|
|
||||||
#endif /* FXCG50 */
|
#endif /* FXCG50 */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
29
src/image/fixed.h
Normal file
29
src/image/fixed.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//---
|
||||||
|
// gint:image:fixed - Minimal fixed-point interface for linear transformations
|
||||||
|
//---
|
||||||
|
|
||||||
|
#ifndef GINT_IMAGE_FIXED
|
||||||
|
#define GINT_IMAGE_FIXED
|
||||||
|
|
||||||
|
/* Constants */
|
||||||
|
#define fconst(x) ((x) * 65536)
|
||||||
|
|
||||||
|
/* Multiplication */
|
||||||
|
static inline int fmul(int x, int y)
|
||||||
|
{
|
||||||
|
return ((int64_t)x * (int64_t)y) >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Multiplication with a scalar */
|
||||||
|
static inline int fmuls(int x, int s)
|
||||||
|
{
|
||||||
|
return ((int64_t)x * (int64_t)s) >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Division */
|
||||||
|
static inline int fdiv(int x, int y)
|
||||||
|
{
|
||||||
|
return ((int64_t)x << 16) / y;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* GINT_IMAGE_FIXED */
|
|
@ -16,8 +16,8 @@ void image_copy(image_t const *src, image_t *dst, bool copy_alpha)
|
||||||
|
|
||||||
void *src_px = src->data;
|
void *src_px = src->data;
|
||||||
void *dst_px = dst->data;
|
void *dst_px = dst->data;
|
||||||
int src_alpha = copy_alpha ? 0x10000 : image_alpha(src->format);
|
int src_alpha = image_alpha_2(src->format, copy_alpha);
|
||||||
int dst_alpha = copy_alpha ? 0x10000 : image_alpha(dst->format);
|
int dst_alpha = image_alpha_2(dst->format, copy_alpha);
|
||||||
|
|
||||||
if(IMAGE_IS_RGB16(src->format) && IMAGE_IS_RGB16(dst->format)) {
|
if(IMAGE_IS_RGB16(src->format) && IMAGE_IS_RGB16(dst->format)) {
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
#include <gint/image.h>
|
#include <gint/image.h>
|
||||||
|
|
||||||
void image_hflip(image_t const *src, image_t *dst)
|
void image_hflip(image_t const *src, image_t *dst, bool copy_alpha)
|
||||||
{
|
{
|
||||||
if(!image_target(src, dst, DATA_RW, SAME_DEPTH, SAME_SIZE))
|
if(!image_target(src, dst, DATA_RW, SAME_DEPTH, SAME_SIZE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
void *src_px = src->data;
|
void *src_px = src->data;
|
||||||
void *dst_px = dst->data;
|
void *dst_px = dst->data;
|
||||||
int src_alpha = image_alpha(src->format);
|
int src_alpha = image_alpha_2(src->format, copy_alpha);
|
||||||
int dst_alpha = image_alpha(dst->format);
|
int dst_alpha = image_alpha_2(dst->format, copy_alpha);
|
||||||
int h = src->height;
|
int h = src->height;
|
||||||
|
|
||||||
if(IMAGE_IS_RGB16(src->format)) {
|
if(IMAGE_IS_RGB16(src->format)) {
|
||||||
|
|
|
@ -11,7 +11,6 @@ image_t *image_hflip_alloc(image_t const *src)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
image_clear(dst);
|
image_hflip(src, dst, true);
|
||||||
image_hflip(src, dst);
|
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
13
src/image/image_rotate.c
Normal file
13
src/image/image_rotate.c
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include <gint/image.h>
|
||||||
|
|
||||||
|
void image_rotate(image_t const *src, float angle, bool resize,
|
||||||
|
struct image_linear_map *map)
|
||||||
|
{
|
||||||
|
if(!image_valid(src))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int center_x = src->width / 2;
|
||||||
|
int center_y = src->height / 2;
|
||||||
|
|
||||||
|
image_rotate_around(src, angle, resize, ¢er_x, ¢er_y, map);
|
||||||
|
}
|
9
src/image/image_rotate_around.c
Normal file
9
src/image/image_rotate_around.c
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#include <gint/image.h>
|
||||||
|
#include "fixed.h"
|
||||||
|
|
||||||
|
void image_rotate_around(image_t const *src, float angle, bool resize,
|
||||||
|
int *center_x, int *center_y, struct image_linear_map *map)
|
||||||
|
{
|
||||||
|
image_rotate_around_scale(src, angle, fconst(1.0), resize, center_x,
|
||||||
|
center_y, map);
|
||||||
|
}
|
16
src/image/image_rotate_around_scale.c
Normal file
16
src/image/image_rotate_around_scale.c
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include <gint/image.h>
|
||||||
|
#include "fixed.h"
|
||||||
|
|
||||||
|
void image_rotate_around_scale(image_t const *src, float angle, int gamma,
|
||||||
|
bool resize, int *center_x, int *center_y, struct image_linear_map *map)
|
||||||
|
{
|
||||||
|
if(!image_valid(src))
|
||||||
|
return;
|
||||||
|
|
||||||
|
map->src_w = src->width;
|
||||||
|
map->src_h = src->height;
|
||||||
|
|
||||||
|
/* Don't try to resize cleanly; just add a √2 factor in both dimensions if
|
||||||
|
[resize=true] to make sure everything fits */
|
||||||
|
;
|
||||||
|
}
|
24
src/image/image_scale.c
Normal file
24
src/image/image_scale.c
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include <gint/image.h>
|
||||||
|
#include "fixed.h"
|
||||||
|
|
||||||
|
void image_scale(image_t const *src, int gamma_x, int gamma_y,
|
||||||
|
struct image_linear_map *map)
|
||||||
|
{
|
||||||
|
if(!image_valid(src))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int inv_gamma_x = fdiv(fconst(1), gamma_x);
|
||||||
|
int inv_gamma_y = fdiv(fconst(1), gamma_y);
|
||||||
|
|
||||||
|
map->u = fconst(0);
|
||||||
|
map->v = fconst(0);
|
||||||
|
map->dx_u = inv_gamma_x;
|
||||||
|
map->dx_v = 0;
|
||||||
|
map->dy_u = 0;
|
||||||
|
map->dy_v = inv_gamma_y;
|
||||||
|
|
||||||
|
map->src_w = src->width;
|
||||||
|
map->src_h = src->height;
|
||||||
|
map->dst_w = fmuls(src->width, gamma_x);
|
||||||
|
map->dst_h = fmuls(src->height, gamma_y);
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ static void copy_row_p8(int8_t *src, int8_t *dst, int src_alpha, int width)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void image_vflip(image_t const *src, image_t *dst)
|
void image_vflip(image_t const *src, image_t *dst, bool copy_alpha)
|
||||||
{
|
{
|
||||||
if(!image_target(src, dst, DATA_RW, SAME_DEPTH, SAME_SIZE))
|
if(!image_target(src, dst, DATA_RW, SAME_DEPTH, SAME_SIZE))
|
||||||
return;
|
return;
|
||||||
|
@ -32,8 +32,8 @@ void image_vflip(image_t const *src, image_t *dst)
|
||||||
void *dst_top = dst->data;
|
void *dst_top = dst->data;
|
||||||
void *dst_bot = dst->data + (h - 1) * dst->stride;
|
void *dst_bot = dst->data + (h - 1) * dst->stride;
|
||||||
|
|
||||||
int src_alpha = image_alpha(src->format);
|
int src_alpha = image_alpha_2(src->format, copy_alpha);
|
||||||
int dst_alpha = image_alpha(dst->format);
|
int dst_alpha = image_alpha_2(dst->format, copy_alpha);
|
||||||
|
|
||||||
int row_length = src->stride;
|
int row_length = src->stride;
|
||||||
void *row = malloc(row_length);
|
void *row = malloc(row_length);
|
||||||
|
|
|
@ -11,7 +11,6 @@ image_t *image_vflip_alloc(image_t const *src)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
image_clear(dst);
|
image_vflip(src, dst, true);
|
||||||
image_vflip(src, dst);
|
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue