F4MP/f4mp_originalcode/thirdparty/zpl/code/other/zpl_image.h
Jous99 37b16f1547 code upload
codigo original de f4mp y tilted para referencias
2026-01-06 18:45:00 +01:00

414 lines
12 KiB
C

/*
ZPL - Image module
Usage:
#define ZPLI_IMPLEMENTATION exactly in ONE source file right BEFORE including the library, like:
#define ZPLI_IMPLEMENTATION
#include"zpl_image.h"
Dependencies:
zpl.h
stb_image.h
Make sure you properly include them!
Optional switches:
ZPLI_NO_GIF
ZPLI_NO_IMAGE_OPS
Credits:
Read AUTHORS.md
GitHub:
https://github.com/zpl-c/zpl
Version History:
2.0.0 - New syntax
1.0.2 - Switch fixes
1.0.1 - Got rid of unused switches and fixes
1.0.0 - Initial version
This Software is dual licensed under the following licenses:
Unlicense
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
Apache 2.0
Copyright 2017-2018 Dominik Madarász <zaklaus@outlook.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef ZPL_INCLUDE_ZPL_IMAGE_H
#define ZPL_INCLUDE_ZPL_IMAGE_H
#if defined(__cplusplus)
extern "C" {
#endif
typedef union zpli_rgb_colour {
u32 colour;
struct { u8 r, g, b;};
} zpli_rgb_colour;
typedef struct zpli_hsv_colour {
u32 colour;
struct { u8 h, s, v; };
} zpli_hsv_colour;
ZPL_DEF zpli_rgb_colour zpli_rgb_lerp(zpli_rgb_colour a, zpli_rgb_colour b, f32 t);
////////////////////////////////////////////////////////////////
//
// GIF Loader
//
// Uses stb_image.h for loading gif frames.
//
#ifndef ZPLI_NO_GIF
typedef struct zpli_gif_result {
i32 delay;
u8 *data;
struct zpli_gif_result *next;
} zpli_gif_result;
ZPL_DEF zpli_gif_result *zpli_gif_load(char const *filename, i32 *x, i32 *y, i32 *frames);
ZPL_DEF void zpli_gif_free(zpli_gif_result *gif, b32 aligned);
#endif
////////////////////////////////////////////////////////////////
//
// Image Operations
//
#ifndef ZPLI_NO_IMAGE_OPS
// NOTE(ZaKlaus): This is not sRGB aware!
ZPL_DEF void zpli_rgb_resize(u32 *source, i32 source_w, i32 source_h,
u32 *dest, i32 dest_w, i32 dest_h,
i32 blur_iter, u32 *blur_mem);
ZPL_DEF void zpli_rgb_filter(u32 *source, i32 source_w, i32 source_h,
u32 *dest,
f64 *filter, i32 filter_w, i32 filter_h,
f64 factor, f64 bias);
// TODO(ZaKlaus): Implement this
/*
ZPL_DEF void zpli_init_srgb_table(u8 **table);
ZPL_DEF zpli_rgb_colour zpli_lin_to_srgb (u8 *table, f64 vals[3]);
*/
ZPL_DEF zpli_hsv_colour zpli_rgb_to_hsv (zpli_rgb_colour colour);
ZPL_DEF zpli_rgb_colour zpli_hsv_to_rgb (zpli_hsv_colour colour);
#endif
#if defined(__cplusplus)
}
#endif
#if defined(ZPLI_IMPLEMENTATION) && !defined(ZPLI_IMPLEMENTATION_DONE)
#define ZPLI_IMPLEMENTATION_DONE
#if defined(__cplusplus)
extern "C" {
#endif
zpli_rgb_colour zpli_rgb_lerp(zpli_rgb_colour a, zpli_rgb_colour b, f32 t) {
#define LERP(c1, c2, c3) c1*(1.0-c3) + c2*c3
zpli_rgb_colour result = {0};
result.r = LERP(a.r, b.r, t);
result.g = LERP(a.g, b.g, t);
result.b = LERP(a.b, b.b, t);
return result;
#undef LERP
}
// NOTE(ZaKlaus): Gif
#ifndef ZPL_NO_GIF
zpli_gif_result *zpli_gif_load(char const *filename, i32 *x, i32 *y, i32 *frames) {
FILE *file;
stbi__context s;
zpli_gif_result *result;
if (!(file = stbi__fopen(filename, "rb"))) {
stbi__errpuc("can't open file", "Unable to open file"); return 0;
}
stbi__start_file(&s, file);
if (stbi__gif_test(&s)) {
i32 c;
stbi__gif g;
zpli_gif_result *head = stbi__malloc(zpl_size_of(zpli_gif_result_t));
zpli_gif_result *prev = 0, *gr = head;
zpl_zero_item(&g);
zpl_zero_item(head);
*frames = 0;
while(gr->data = stbi__gif_load_next(&s, &g, &c, 4)) {
if (gr->data == cast(u8 *)&s) {
gr->data = 0;
break;
}
if (prev) prev->next = gr;
gr->delay = g.delay;
prev = gr;
gr = cast(zpli_gif_result *)stbi__malloc(zpl_size_of(zpli_gif_result_t));
zpl_zero_item(gr);
++(*frames);
}
STBI_FREE(g.out);
if (gr != head) {
//STBI_FREE(gr);
}
if (*frames > 0) {
*x = g.w;
*y = g.h;
}
result = head;
}
else {
// TODO(ZaKlaus): Add support.
result = 0; //stbi__load_main(&s, x, y, frames, &bpp, 4, &ri, 8);
*frames = !!result;
}
fclose(file);
return result;
}
void zpli_gif_free(zpli_gif_result *gif, b32 aligned) {
zpli_gif_result *elem, *prev = 0;
for (elem = gif; elem; elem = elem->next) {
if (aligned) {
zpl_mfree(elem->data);
}
else {
STBI_FREE(elem->data);
}
STBI_FREE(prev);
prev = elem;
}
STBI_FREE(prev);
}
#endif
zpli_hsv_colour zpli_rgb_to_hsv(zpli_rgb_colour colour) {
zpli_hsv_colour result = {0};
u8 rgb_min, rgb_max;
rgb_min = colour.r < colour.g ? (colour.r < colour.b ? colour.r : colour.b) : (colour.g < colour.b ? colour.g : colour.b);
rgb_max = colour.r > colour.g ? (colour.r > colour.b ? colour.r : colour.b) : (colour.g > colour.b ? colour.g : colour.b);
result.v = rgb_max;
if (result.v == 0) {
result.h = result.s = 0;
return result;
}
result.s = 255 * cast(i64)(rgb_max - rgb_min) / result.v;
if (result.s == 0) {
result.h = 0;
return result;
}
/**/ if (rgb_max == colour.r) {
result.h = 0 + 43 * (colour.g - colour.b) / (rgb_max - rgb_min);
}
else if (rgb_max == colour.g) {
result.h = 85 + 43 * (colour.b - colour.r) / (rgb_max - rgb_min);
}
else {
result.h = 171 + 43 * (colour.r - colour.g) / (rgb_max - rgb_min);
}
return result;
}
zpli_rgb_colour zpli_hsv_to_rgb(zpli_hsv_colour colour) {
zpli_rgb_colour result = {0};
u8 region, rem, p, q, t;
if (colour.s == 0) {
result.r = result.g = result.b = colour.v;
return result;
}
region = colour.h / 43;
rem = (colour.h - (region * 43)) * 6;
p = (colour.v * (255 - colour.s)) >> 8;
q = (colour.v * (255 - ((colour.s * rem) >> 8))) >> 8;
t = (colour.v * (255 - ((colour.s * (255 - rem)) >> 8))) >> 8;
switch (region)
{
case 0: result.r = colour.v; result.g = t; result.b = p; break;
case 1: result.r = q; result.g = colour.v; result.b = p; break;
case 2: result.r = p; result.g = colour.v; result.b = t; break;
case 3: result.r = p; result.g = q; result.b = colour.v; break;
case 4: result.r = t; result.g = p; result.b = colour.v; break;
default:result.r = colour.v; result.g = p; result.b = q; break;
}
return result;
}
#ifndef ZPL_NO_IMAGE_OPS
void zpli_rgb_resize(u32 *source, i32 source_w, i32 source_h,
u32 *dest, i32 dest_w, i32 dest_h,
i32 blur_iter, u32 *blur_mem) {
zpli_rgb_colour *src = cast(zpli_rgb_colour *)&(source);
zpli_rgb_colour *dst = cast(zpli_rgb_colour *)&(dest);
b32 x_down = dest_w < source_w;
b32 y_down = dest_h < source_h;
i32 step_x;
i32 step_y;
if(x_down) {
step_x = cast(i32)(source_w / cast(f32)dest_w);
}
else {
step_x = cast(i32)(dest_w / cast(f32)source_w);
}
if(y_down) {
step_y = cast(i32)(source_h / cast(f32)dest_h);
}
else {
step_y = cast(i32)(dest_h / cast(f32)source_h);
}
for (i32 y = 0; y < dest_h; ++y) {
for(i32 x = 0; x < dest_w; ++x) {
zpli_rgb_colour colour = {0};
i32 o_x = x/step_x;
if (x_down) o_x = x*step_x;
i32 o_y = y/step_y;
if (y_down) o_y = y*step_y;
colour = src[o_y*source_w + o_x];
dst[y*dest_w + x] = colour;
}
}
if (blur_iter > 0) {
ZPL_ASSERT_NOT_NULL(blur_mem);
zpl_local_persist f64 filter[5][5] = {
0, 0, 1, 0, 0,
0, 1, 1, 1, 0,
1, 1, 1, 1, 1,
0, 1, 1, 1, 0,
0, 0, 1, 0, 0,
};
f64 factor = 1.0 / 13.0;
f64 bias = 0.0;
zpl_memcopy(blur_mem, dest, dest_w*dest_h*4);
zpli_rgb_filter(blur_mem, dest_w, dest_h,
cast(u32 *)dest,
&filter[0][0], 5, 5,
factor, bias);
}
}
void zpli_rgb_filter(u32 *source, i32 source_w, i32 source_h,
u32 *dest,
f64 *filter, i32 filter_w, i32 filter_h,
f64 factor, f64 bias) {
zpli_rgb_colour *src = cast(zpli_rgb_colour *)(source);
zpli_rgb_colour *dst = cast(zpli_rgb_colour *)(dest);
for (i32 y = 0; y < source_h; ++y) {
for(i32 x = 0; x < source_w; ++x) {
i32 r = 0, g = 0, b = 0;
for (i32 fy = 0; fy < filter_h; ++fy) {
for (i32 fx = 0; fx < filter_w; ++fx) {
i32 img_x = (x - filter_w / 2 + fx + source_w) % source_w;
i32 img_y = (y - filter_h / 2 + fy + source_h) % source_h;
r += src[img_y * source_w + img_x].r * filter[fy*filter_w + fx];
g += src[img_y * source_w + img_x].g * filter[fy*filter_w + fx];
b += src[img_y * source_w + img_x].b * filter[fy*filter_w + fx];
}
}
dst[y * source_w + x].r = zpl_min(zpl_max(cast(i32)(factor * r + bias), 0), 255);
dst[y * source_w + x].g = zpl_min(zpl_max(cast(i32)(factor * g + bias), 0), 255);
dst[y * source_w + x].b = zpl_min(zpl_max(cast(i32)(factor * b + bias), 0), 255);
}
}
}
#endif
#if defined(__cplusplus)
}
#endif
#endif
#endif // ZPL_INCLUDE_ZPL_IMAGE_H